import json
from typing import Any
import structlog
from vmk_data_collector.core.config import settings
from vmk_data_collector.domain.entities import AiEnrichmentResult, NormalizedProperty
from vmk_data_collector.services.ollama_client import OllamaClient
logger = structlog.get_logger()
_SYSTEM_PROMPT = """Ты — эксперт по оценке объявлений о недвижимости.
Проанализируй объявление и верни ТОЛЬКО JSON:
{
"extracted_features": {"ключевая_особенность": "значение"},
"price_assessment": {
"estimated_market_price": 150000,
"price_reasonableness": "ниже рынка/на уровне рынка/выше рынка",
"currency": "UAH"
},
"listing_quality_score": 7,
"reliability_rating": 4,
"sentiment_score": 0.5,
"classification": "жилая_недвижимость",
"image_analysis_results": {"общее_впечатление": "хорошее"},
"generated_description": "Краткое привлекательное описание для покупателя...",
"summary": "Краткая сводка: что за объект, цена, состояние, плюсы/минусы.",
"model_version": "llama3.2",
"processing_time_ms": 1200
}
Оценка качества объявления (listing_quality_score): 1–10.
Надёжность (reliability_rating): 1–5.
Sentiment (-1 до 1)."""
_MOCK_RESPONSE: dict[str, Any] = {
"extracted_features": {"area": "50 м²", "rooms": "2"},
"price_assessment": {
"estimated_market_price": 120000,
"price_reasonableness": "на уровне рынка",
"currency": "UAH",
},
"listing_quality_score": 6,
"reliability_rating": 3,
"sentiment_score": 0.2,
"classification": "жилая_недвижимость",
"image_analysis_results": {},
"generated_description": "Уютная двухкомнатная квартира в центре города.",
"summary": "Квартира 50 м², 2 комнаты, цена адекватна.",
"model_version": "llama3.2-mock",
"processing_time_ms": 0,
}
class AiEnricher:
def __init__(self, client: OllamaClient) -> None:
self._client = client
async def enrich(
self,
normalized: NormalizedProperty,
image_analysis_results: dict[str, Any],
) -> AiEnrichmentResult:
if settings.ollama_mock:
logger.info("ai_enricher_mock_mode")
return AiEnrichmentResult(**_MOCK_RESPONSE)
text = self._build_prompt(normalized, image_analysis_results)
messages = [
{"role": "system", "content": _SYSTEM_PROMPT},
{"role": "user", "content": text},
]
try:
response = await self._client.chat(
model=settings.ollama_text_model,
messages=messages,
json_mode=True,
)
content = response["message"]["content"]
data = json.loads(content)
return AiEnrichmentResult(**data)
except Exception as exc:
logger.error("ai_enricher_error", error=str(exc))
return AiEnrichmentResult()
@staticmethod
def _build_prompt(
normalized: NormalizedProperty,
image_analysis_results: dict[str, Any],
) -> str:
lines = [
f"Заголовок: {normalized.title or '—'}",
f"Описание: {normalized.description or '—'}",
f"Тип: {normalized.property_type or '—'}",
f"Сделка: {normalized.deal_type or '—'}",
f"Цена: {normalized.price or '—'} {normalized.currency or ''}",
f"Площадь: {normalized.total_area or '—'} м²",
f"Комнат: {normalized.rooms_count or '—'}",
f"Этаж: {normalized.floor or '—'} / {normalized.floors_total or '—'}",
f"Адрес: {normalized.address_raw or '—'}",
f"Город: {normalized.city or '—'}",
]
if image_analysis_results:
lines.append(
f"Анализ фото: {json.dumps(image_analysis_results, ensure_ascii=False)}"
)
return "\n".join(lines)