Fix: Beta testing fixes (#16)

Co-authored-by: phernandez <phernandez@basicmachines.co>
This commit is contained in:
Paul Hernandez
2025-02-28 20:23:53 -06:00
committed by GitHub
parent 4bcbeacdd2
commit f8078cdd46
49 changed files with 1075 additions and 1215 deletions
+3 -3
View File
@@ -165,7 +165,7 @@ class ContextService:
from_id,
to_id,
relation_type,
content,
content_snippet as content,
category,
entity_id,
0 as depth,
@@ -189,7 +189,7 @@ class ContextService:
r.from_id,
r.to_id,
r.relation_type,
r.content,
r.content_snippet as content,
r.category,
r.entity_id,
cg.depth + 1,
@@ -218,7 +218,7 @@ class ContextService:
e.from_id,
e.to_id,
e.relation_type,
e.content,
e.content_snippet as content,
e.category,
e.entity_id,
cg.depth + 1, -- Increment depth for entities
+5 -45
View File
@@ -1,12 +1,11 @@
"""Service for resolving markdown links to permalinks."""
from typing import Optional, Tuple, List
from typing import Optional, Tuple
from loguru import logger
from basic_memory.models import Entity
from basic_memory.repository.entity_repository import EntityRepository
from basic_memory.repository.search_repository import SearchIndexRow
from basic_memory.schemas.search import SearchQuery, SearchItemType
from basic_memory.services.search_service import SearchService
@@ -41,8 +40,9 @@ class LinkResolver:
return entity
# 2. Try exact title match
entity = await self.entity_repository.get_by_title(clean_text)
if entity:
found = await self.entity_repository.get_by_title(clean_text)
if found and len(found) == 1:
entity = found[0]
logger.debug(f"Found title match: {entity.title}")
return entity
@@ -54,7 +54,7 @@ class LinkResolver:
if results:
# Look for best match
best_match = self._select_best_match(clean_text, results)
best_match = min(results, key=lambda x: x.score) # pyright: ignore
logger.debug(
f"Selected best match from {len(results)} results: {best_match.permalink}"
)
@@ -88,43 +88,3 @@ class LinkResolver:
alias = alias.strip()
return text, alias
def _select_best_match(self, search_text: str, results: List[SearchIndexRow]) -> SearchIndexRow:
"""Select best match from search results.
Uses multiple criteria:
1. Word matches in title field
2. Word matches in path
3. Overall search score
"""
# Get search terms for matching
terms = search_text.lower().split()
# Score each result
scored_results = []
for result in results:
# Start with base score (lower is better)
score = result.score or 0
if result.permalink:
# Parse path components
path_parts = result.permalink.lower().split("/")
last_part = path_parts[-1] if path_parts else ""
else:
last_part = "" # pragma: no cover
# Title word match boosts
term_matches = [term for term in terms if term in last_part]
if term_matches:
score *= 0.5 # Boost for each matching term
# Exact title match is best
if last_part == search_text.lower():
score *= 0.2
scored_results.append((score, result))
# Sort by score (lowest first) and return best
scored_results.sort(key=lambda x: x[0], reverse=True)
return scored_results[0][1]
+22 -9
View File
@@ -145,6 +145,7 @@ class SearchService:
await self.repository.index_item(
SearchIndexRow(
id=entity.id,
entity_id=entity.id,
type=SearchItemType.ENTITY.value,
title=entity.title,
file_path=entity.file_path,
@@ -182,29 +183,33 @@ class SearchService:
"entity.permalink should not be None for markdown entities"
)
content_parts = []
content_stems = []
content_snippet = ""
title_variants = self._generate_variants(entity.title)
content_parts.extend(title_variants)
content_stems.extend(title_variants)
content = await self.file_service.read_entity_content(entity)
if content:
content_parts.append(content)
content_stems.append(content)
content_snippet = f"{content[:250]}"
content_parts.extend(self._generate_variants(entity.permalink))
content_parts.extend(self._generate_variants(entity.file_path))
content_stems.extend(self._generate_variants(entity.permalink))
content_stems.extend(self._generate_variants(entity.file_path))
entity_content = "\n".join(p for p in content_parts if p and p.strip())
entity_content_stems = "\n".join(p for p in content_stems if p and p.strip())
assert entity.permalink is not None, (
"entity.permalink should not be None for markdown entities"
)
# Index entity
await self.repository.index_item(
SearchIndexRow(
id=entity.id,
type=SearchItemType.ENTITY.value,
title=entity.title,
content=entity_content,
content_stems=entity_content_stems,
content_snippet=content_snippet,
permalink=entity.permalink,
file_path=entity.file_path,
entity_id=entity.id,
@@ -219,12 +224,16 @@ class SearchService:
# Index each observation with permalink
for obs in entity.observations:
# Index with parent entity's file path since that's where it's defined
obs_content_stems = "\n".join(
p for p in self._generate_variants(obs.content) if p and p.strip()
)
await self.repository.index_item(
SearchIndexRow(
id=obs.id,
type=SearchItemType.OBSERVATION.value,
title=f"{obs.category}: {obs.content[:50]}...",
content=obs.content,
title=f"{obs.category}: {obs.content[:100]}...",
content_stems=obs_content_stems,
content_snippet=obs.content,
permalink=obs.permalink,
file_path=entity.file_path,
category=obs.category,
@@ -246,11 +255,15 @@ class SearchService:
else f"{rel.from_entity.title}"
)
rel_content_stems = "\n".join(
p for p in self._generate_variants(relation_title) if p and p.strip()
)
await self.repository.index_item(
SearchIndexRow(
id=rel.id,
title=relation_title,
permalink=rel.permalink,
content_stems=rel_content_stems,
file_path=entity.file_path,
type=SearchItemType.RELATION.value,
entity_id=entity.id,