import hashlib from pathlib import Path from app.config import Settings from app.database.supabase import SupabaseRepository from app.services.embedding_service import JinaEmbeddingService from app.services.trip_indexing import build_trip_embedding_record class AdminService: def __init__( self, *, repository: SupabaseRepository, embeddings: JinaEmbeddingService, settings: Settings, info_path: Path | None = None, ) -> None: self.repository = repository self.embeddings = embeddings self.settings = settings self.info_path = info_path or Path("prompts/falzh_info.md") async def seed_info(self) -> int: text = self.info_path.read_text(encoding="utf-8") chunk_texts = _chunk_markdown(text) embeddings = await self.embeddings.embed_passages(chunk_texts) chunks = [] for chunk, embedding in zip(chunk_texts, embeddings, strict=True): digest = hashlib.sha256(chunk.encode("utf-8")).hexdigest()[:24] chunks.append( { "id": f"info-{digest}", "chunk_text": chunk, "source": str(self.info_path), "embedding": embedding, "embedding_model": self.settings.jina_embedding_model, } ) return await self.repository.upsert_info_chunks(chunks) async def sync_trips(self) -> int: trips = await self.repository.list_active_trips() trip_records = [ build_trip_embedding_record(trip, self.settings.jina_embedding_model) for trip in trips ] embeddings = await self.embeddings.embed_passages( [record["chunk_text"] for record in trip_records] ) for record, embedding in zip(trip_records, embeddings, strict=True): record["embedding"] = embedding return await self.repository.upsert_trip_embeddings(trip_records) def _chunk_markdown(text: str, *, max_chars: int = 1200) -> list[str]: sections = [section.strip() for section in text.split("\n## ") if section.strip()] chunks: list[str] = [] for index, section in enumerate(sections): content = section if index == 0 else f"## {section}" if len(content) <= max_chars: chunks.append(content) continue for start in range(0, len(content), max_chars): chunks.append(content[start : start + max_chars].strip()) return chunks