2026-02-21 18:35:20 -06:00

101 lines
3.6 KiB
Python

from dataclasses import dataclass, field
# Define canonical section titles for parsing and reconstruction
SECTION_TITLES = [
"Summary",
"Cognitive State",
"Mental / Emotional Snapshot",
"Memory / Mind Failures",
"Events / Triggers",
"Communication / Expression Log",
"Coping / Tools Used",
"Reflection",
"Core Events or Memories",
"Autism/ADHD-Related Elements",
"Emotional & Bodily Reactions",
"Truth to Anchor Myself To",
]
@dataclass
class Fragment:
type: str
description: str
time: str | None = None
tags: list[str] = field(default_factory=list)
@dataclass
class ParsedSection:
title: str
content: list[str] = field(default_factory=list) # Each item is a line or a block
checkboxes: dict[str, bool] = field(
default_factory=dict
) # { "checkbox_text": is_checked }
@dataclass
class JournalEntry:
date: str
fragments: list[Fragment] = field(default_factory=list)
raw_content: str = ""
# New: Structured representation of sections
sections: dict[str, ParsedSection] = field(default_factory=dict)
def merge_with(self, other_entry: "JournalEntry"):
"""Merges another entry's data into this one."""
# Merge sections: Overwrite if the new section has meaningful content
for title, new_section in other_entry.sections.items():
# Heuristic: content is meaningful if it's not empty or just whitespace
if any(line.strip() for line in new_section.content):
self.sections[title] = new_section
# Merge fragments: Add new fragments, avoid duplicates by description
existing_fragment_descs = {f.description for f in self.fragments}
for new_fragment in other_entry.fragments:
if new_fragment.description not in existing_fragment_descs:
self.fragments.append(new_fragment)
def to_markdown(self) -> str:
"""Reconstructs the journal entry as a markdown string."""
lines: list[str] = []
# Frontmatter (simplified for now)
lines.append("---")
lines.append("type: journal")
lines.append("---")
lines.append(f"**Date:** {self.date}\n")
# Write sections in canonical order
for title in SECTION_TITLES:
if title in self.sections:
section = self.sections[title]
lines.append(f"## {section.title}\n")
# The content list no longer contains the header
lines.extend(section.content)
lines.append("") # newline after section
# Append all fragments at the end
if self.fragments:
lines.append("# Fragments\n")
for frag in self.fragments:
time_str = f"@{frag.time}" if frag.time else ""
tags_str = " ".join([f"#{tag}" for tag in frag.tags])
header = f"{frag.type} {time_str} {tags_str}".strip()
lines.append(f"{header}\n{frag.description}\n")
return "\n".join(lines)
def get_section(self, section_title: str) -> str:
# This method will now retrieve content from the parsed sections
if section_title in self.sections:
return "\n".join(self.sections[section_title].content)
return ""
def get_checkbox_state(self, section_title: str, checkbox_text: str) -> bool | None:
if (
section_title in self.sections
and checkbox_text in self.sections[section_title].checkboxes
):
return self.sections[section_title].checkboxes[checkbox_text]
return None