remove EntityContent from markdown

This commit is contained in:
phernandez
2025-01-26 09:24:52 -06:00
parent 18bd850019
commit d31f481405
11 changed files with 148 additions and 185 deletions
-2
View File
@@ -4,7 +4,6 @@ from basic_memory.file_utils import ParseError
from basic_memory.markdown.entity_parser import EntityParser
from basic_memory.markdown.schemas import (
EntityMarkdown,
EntityContent,
EntityFrontmatter,
Observation,
Relation,
@@ -12,7 +11,6 @@ from basic_memory.markdown.schemas import (
__all__ = [
"EntityMarkdown",
"EntityContent",
"EntityFrontmatter",
"EntityParser",
"Observation",
+2 -8
View File
@@ -15,7 +15,6 @@ from basic_memory.markdown.plugins import observation_plugin, relation_plugin
from basic_memory.markdown.schemas import (
EntityMarkdown,
EntityFrontmatter,
EntityContent,
Observation,
Relation,
)
@@ -103,18 +102,13 @@ class EntityParser:
rels = token.meta["relations"]
relations.extend([Relation.model_validate(r) for r in rels])
# Create EntityContent
entity_content = EntityContent(
return EntityMarkdown(
frontmatter=entity_frontmatter,
content=post.content,
observations=observations,
relations=relations,
)
return EntityMarkdown(
frontmatter=entity_frontmatter,
content=entity_content,
)
def parse_tags(self, tags: Any) -> list[str]:
"""Parse tags into list of strings."""
if isinstance(tags, str):
+16 -11
View File
@@ -104,23 +104,28 @@ class MarkdownProcessor:
frontmatter_dict = {
"type": markdown.frontmatter.type,
"permalink": markdown.frontmatter.permalink,
"created": markdown.frontmatter.created.isoformat() if markdown.frontmatter.created else None,
"modified": markdown.frontmatter.modified.isoformat() if markdown.frontmatter.modified else None,
**metadata
"created": markdown.frontmatter.created.isoformat()
if markdown.frontmatter.created
else None,
"modified": markdown.frontmatter.modified.isoformat()
if markdown.frontmatter.modified
else None,
**metadata,
}
frontmatter_dict = {k: v for k, v in frontmatter_dict.items() if v is not None}
# Start with user content (or minimal title for new files)
content = markdown.content.content or f"# {markdown.frontmatter.title}\n"
content = markdown.content or f"# {markdown.frontmatter.title}\n"
# Add structured sections if present
if markdown.content.observations:
content += (
"\n\n## Observations\n\n"
+ self.format_observations(markdown.content.observations)
# Add structured sections with proper spacing
content = content.rstrip() # Remove trailing whitespace
if markdown.observations:
content += "\n\n## Observations\n\n" + self.format_observations(
markdown.observations
)
if markdown.content.relations:
content += "\n## Relations\n\n" + self.format_relations(markdown.content.relations)
if markdown.relations:
content += "\n\n## Relations\n\n" + self.format_relations(markdown.relations)
# Create Post object for frontmatter
post = Post(content, **frontmatter_dict)
+3 -8
View File
@@ -66,16 +66,11 @@ class EntityFrontmatter(BaseModel):
def modified(self) -> datetime:
return self.metadata.get("modified") if self.metadata else None
class EntityContent(BaseModel):
"""Content sections of an entity markdown file."""
content: Optional[str] = None
observations: List[Observation] = []
relations: List[Relation] = []
class EntityMarkdown(BaseModel):
"""Complete entity combining frontmatter, content, and metadata."""
frontmatter: EntityFrontmatter
content: EntityContent
content: Optional[str] = None
observations: List[Observation] = []
relations: List[Relation] = []
+8 -18
View File
@@ -1,13 +1,10 @@
from typing import Optional
from basic_memory.markdown import EntityMarkdown, EntityFrontmatter, EntityContent, Observation, Relation
from basic_memory.markdown import EntityMarkdown, EntityFrontmatter, Observation, Relation
from basic_memory.models import Entity
class EntityModel:
pass
def entity_model_to_markdown(entity: EntityModel, content: Optional[str] = None) -> EntityMarkdown:
def entity_model_to_markdown(entity: Entity, content: Optional[str] = None) -> EntityMarkdown:
"""Convert entity model to markdown schema.
Args:
@@ -17,18 +14,15 @@ def entity_model_to_markdown(entity: EntityModel, content: Optional[str] = None)
Returns:
EntityMarkdown schema
"""
metadata=entity.entity_metadata or {}
metadata = entity.entity_metadata or {}
metadata["permalink"] = entity.permalink
metadata["type"] = entity.entity_type or "note"
metadata["title"] = entity.title
metadata["created"] = entity.created_at
metadata["modified"] = entity.updated_at
entity_frontmatter = EntityFrontmatter(
metadata=metadata
)
entity_content = EntityContent(
return EntityMarkdown(
frontmatter=EntityFrontmatter(metadata=metadata),
content=content, # Use provided content
observations=[
Observation(
@@ -37,11 +31,7 @@ def entity_model_to_markdown(entity: EntityModel, content: Optional[str] = None)
for obs in entity.observations
],
relations=[
Relation(type=r.relation_type, target=r.to_entity.title, context=r.context) for r in entity.outgoing_relations
Relation(type=r.relation_type, target=r.to_entity.title, context=r.context)
for r in entity.outgoing_relations
],
)
return EntityMarkdown(
frontmatter=entity_frontmatter,
content=entity_content,
)
+3 -6
View File
@@ -6,13 +6,10 @@ from typing import Optional, Tuple
from loguru import logger
from basic_memory import file_utils
from basic_memory.markdown import EntityFrontmatter, EntityContent, EntityMarkdown, Observation, Relation
from basic_memory.markdown.markdown_processor import MarkdownProcessor
from basic_memory.markdown.utils import entity_model_to_markdown
from basic_memory.services.exceptions import FileOperationError
from basic_memory.models import Entity as EntityModel
from basic_memory.services.exceptions import FileOperationError
class FileService:
@@ -75,7 +72,7 @@ class FileService:
# merge content with entity
# if content is supplied use it or existing content
markdown = entity_model_to_markdown(
entity, content=content or existing_markdown.content.content
entity, content=content or existing_markdown.content
)
else:
# Create new file structure with provided content
@@ -109,7 +106,7 @@ class FileService:
try:
file_path = self.get_entity_path(entity)
markdown = await self.markdown_processor.read_file(file_path)
return markdown.content.content or ""
return markdown.content or ""
except Exception as e:
logger.error(f"Failed to read entity content: {e}")
+12 -11
View File
@@ -1,15 +1,16 @@
"""Service for managing entities in the database."""
from pathlib import Path
from loguru import logger
from sqlalchemy.exc import IntegrityError
from basic_memory.models import Entity as EntityModel, Observation, Relation, ObservationCategory
from basic_memory.markdown.schemas import EntityMarkdown
from basic_memory.utils import generate_permalink
from basic_memory.models import Entity as EntityModel, Observation, Relation, ObservationCategory
from basic_memory.repository import EntityRepository, ObservationRepository, RelationRepository
from basic_memory.services.exceptions import EntityNotFoundError
from basic_memory.services.link_resolver import LinkResolver
from basic_memory.utils import generate_permalink
def entity_model_from_markdown(file_path: str, markdown: EntityMarkdown) -> EntityModel:
@@ -38,7 +39,7 @@ def entity_model_from_markdown(file_path: str, markdown: EntityMarkdown) -> Enti
updated_at=markdown.frontmatter.modified,
observations=[
Observation(content=obs.content, category=get_valid_category(obs), context=obs.context)
for obs in markdown.content.observations
for obs in markdown.observations
],
)
return model
@@ -78,18 +79,18 @@ class EntitySyncService:
# Set timestamps from frontmatter
created_at = markdown.frontmatter.created
updated_at = markdown.frontmatter.modified
model.created_at = created_at
model.updated_at = updated_at
for obs in model.observations:
obs.created_at = created_at
obs.updated_at = updated_at
for rel in model.relations:
rel.created_at = created_at
rel.updated_at = updated_at
return await self.entity_repository.add(model)
async def update_entity_and_observations(
@@ -108,7 +109,7 @@ class EntitySyncService:
# Update fields from markdown
db_entity.title = markdown.frontmatter.title
db_entity.entity_type = markdown.frontmatter.type
db_entity.summary = markdown.content.content
db_entity.summary = markdown.content
# Clear observations for entity
await self.observation_repository.delete_by_fields(entity_id=db_entity.id)
@@ -121,7 +122,7 @@ class EntitySyncService:
category=obs.category,
context=obs.context,
)
for obs in markdown.content.observations
for obs in markdown.observations
]
await self.observation_repository.add_all(observations)
@@ -153,13 +154,13 @@ class EntitySyncService:
await self.relation_repository.delete_outgoing_relations_from_entity(db_entity.id)
# Process each relation
for rel in markdown.content.relations:
for rel in markdown.relations:
# Resolve the target permalink
target_entity = await self.link_resolver.resolve_link(
rel.target,
)
# if the target is found, store the id
# if the target is found, store the id
target_id = target_entity.id if target_entity else None
# if the target is found, store the title, otherwise add the target for a "forward link"
target_name = target_entity.title if target_entity else rel.target