import json from decimal import Decimal from infrastructure.ai import prompts from domain import CurrencyConverter, FinancialModel from application.forecast import ForecastService class AssistantError(Exception): pass class _DecimalEncoder(json.JSONEncoder): """JSON-сериализатор: Decimal → str (для AI-промптов).""" def default(self, o): if isinstance(o, Decimal): return str(o) return super().default(o) class AssistantService: def __init__( self, model: FinancialModel, converter: CurrencyConverter | None = None, display_currency: str | None = None, ): self.model = model self.converter = converter or CurrencyConverter(model.exchange_rates) self.display_currency = display_currency or model.base_currency def analyze(self, months: int = 12) -> dict: forecast_service = ForecastService(self.model) forecast_result = forecast_service.forecast_cashflow(months) summary = forecast_service.summary(months) prompt = prompts.format_context( model_json=json.dumps(self.model.to_dict(), indent=2, ensure_ascii=False, cls=_DecimalEncoder), forecast_json=json.dumps(forecast_result, indent=2, ensure_ascii=False, cls=_DecimalEncoder), months=months, base_currency=self.model.base_currency, display_currency=self.display_currency, ) return { "prompt": prompt, "summary": summary, "forecast": forecast_result, "ai_response": None, } def advice(self, question: str, months: int = 12) -> dict: forecast_service = ForecastService(self.model) forecast_result = forecast_service.forecast_cashflow(months) prompt = prompts.ADVICE_PROMPT.format( model_json=json.dumps(self.model.to_dict(), indent=2, ensure_ascii=False, cls=_DecimalEncoder), forecast_json=json.dumps(forecast_result, indent=2, ensure_ascii=False, cls=_DecimalEncoder), question=question, base_currency=self.model.base_currency, display_currency=self.display_currency, ) return { "prompt": prompt, "ai_response": None, } def compare_scenarios(self, scenarios_json: str) -> dict: prompt = prompts.SCENARIO_COMPARISON_PROMPT.format( scenarios_json=scenarios_json, base_currency=self.model.base_currency, display_currency=self.display_currency, ) return { "prompt": prompt, "ai_response": None, }