Spaces:
Runtime error
Runtime error
| """Reference style service β builds and caches the KB reference style profile. | |
| The reference profile is extracted from Behrang's indexed reports (``__rics_kb__`` | |
| tenant) and stored in the style cache under the same tenant ID. | |
| Used as a fallback in ``_get_or_build_style_profile`` when a user has not yet | |
| uploaded any documents of their own. | |
| """ | |
| from __future__ import annotations | |
| import logging | |
| from app.async_executor import run_sync_in_executor | |
| from app.cache import style_cache | |
| from app.config import settings | |
| from app.generator.style_analyzer import build_reference_style_profile | |
| from app.retrieval.retriever import retrieve_async | |
| logger = logging.getLogger(__name__) | |
| # Diverse queries to sample a broad cross-section of survey writing from the KB | |
| _REFERENCE_QUERIES = [ | |
| "building condition survey inspection findings", | |
| "roof structure tiles condition recommendation", | |
| "main walls external condition damp penetration", | |
| "services electrical gas plumbing drainage condition", | |
| "property description construction type age", | |
| "chimney stack flashing pointing condition", | |
| "floors structure condition movement settlement", | |
| "windows doors frames condition repair", | |
| ] | |
| async def seed_reference_style_profile() -> None: | |
| """Build and cache the reference style profile from the KB tenant. | |
| 1. Checks the style cache first β skips if already cached. | |
| 2. Retrieves representative chunks from the KB vectorstore using multiple | |
| RICS-relevant queries. | |
| 3. Calls ``build_reference_style_profile`` (richer analyser with example | |
| paragraph extraction). | |
| 4. Stores the result under the KB tenant key in the style cache. | |
| Safe to call on every startup β the cache check makes it a no-op once seeded. | |
| """ | |
| if not settings.knowledge_base_enabled: | |
| return | |
| tenant = settings.knowledge_base_tenant_id | |
| if style_cache.get(tenant) is not None: | |
| logger.debug("Reference style cache hit for KB tenant β skipping seed") | |
| return | |
| if not settings.openai_api_key: | |
| logger.info("No OpenAI key β reference style profile will use mock fallback") | |
| return | |
| logger.info("Building reference style profile from KB tenant '%s'", tenant) | |
| all_texts: list[str] = [] | |
| seen: set[str] = set() | |
| async def _collect() -> None: | |
| for query in _REFERENCE_QUERIES: | |
| try: | |
| results = await retrieve_async(query=query, tenant_id=tenant, k=6) | |
| for r in results: | |
| text = r.text.strip() | |
| if text and text not in seen: | |
| seen.add(text) | |
| all_texts.append(text) | |
| except Exception as exc: | |
| logger.debug("KB retrieve failed for query '%s': %s", query, exc) | |
| await _collect() | |
| if not all_texts: | |
| logger.warning( | |
| "No chunks found in KB tenant '%s' β reference style not seeded. " | |
| "Upload reference documents or check knowledge_base_dirs config.", | |
| tenant, | |
| ) | |
| return | |
| logger.info("Analysing reference style from %d unique KB chunks", len(all_texts)) | |
| profile = await run_sync_in_executor( | |
| build_reference_style_profile, | |
| sample_texts=all_texts, | |
| openai_api_key=settings.openai_api_key, | |
| chat_model=settings.chat_model, | |
| ) | |
| style_cache.set(tenant, profile) | |
| logger.info( | |
| "Reference style cached: tone=%s formality=%s example_paragraphs=%d", | |
| profile.tone, | |
| profile.formality_level, | |
| len(profile.example_paragraphs), | |
| ) | |