""" =============================================================================== FILE: modules/web_api/routers/chat.py ROLE: Обработка сообщений веб-чата с поддержкой токенов и гостевого доступа. =============================================================================== """ from fastapi import APIRouter, Header, HTTPException, Request from pydantic import BaseModel from typing import Optional, List, Dict, Any import logging from services.text_reporter import ask_ollama from services.knowledge_base import load_knowledge_base from core.database import get_connection logger = logging.getLogger("CHAT_API") router = APIRouter(prefix="/api/v1", tags=["Chat"]) class ChatMessageRequest(BaseModel): message: str session_id: Optional[str] = "web_session_main" user_id: Optional[int] = 1 def resolve_user_id(authorization: Optional[str] = None, explicit_user_id: Optional[int] = None) -> int: """ Извлекает ID пользователя из Bearer-токена. Если токен не передан или сессия новая — использует user_id=1 по умолчанию, не блокируя работу ошибкой 403 Forbidden. """ if explicit_user_id and explicit_user_id > 0: return explicit_user_id if authorization and authorization.startswith("Bearer "): token = authorization.replace("Bearer ", "").strip() # Если используется простой токен вида 'user_1' или JWT if token.isdigit(): return int(token) elif token.startswith("dev_token_"): try: return int(token.replace("dev_token_", "")) except ValueError: pass # Дефолтный пользователь (гостевой / основной аккаунт) return 1 @router.post("/chat") async def chat_endpoint(payload: ChatMessageRequest, authorization: Optional[str] = Header(None)): user_id = resolve_user_id(authorization, payload.user_id) session_id = payload.session_id or "web_session_main" user_msg = payload.message.strip() if not user_msg: raise HTTPException(status_code=400, detail="Пустое сообщение") logger.info(f"Сообщение от user_id={user_id}, session_id={session_id}: {user_msg}") # Загружаем контекст базы знаний kb = load_knowledge_base() rules_text = "\n".join([f"- {r}" for r in kb.get("rules", [])]) system_prompt = ( "Ты — ИИ-ассистент системы кадровой безопасности и контроллинга СКУД Orion AI.\n" "Отвечай четко, профессионально и на русском языке.\n" f"Актуальные правила системы:\n{rules_text}" ) try: reply_text = ask_ollama(user_msg, system_prompt=system_prompt) # Сохранение истории в SQLite при необходимости try: with get_connection() as conn: conn.execute( "INSERT INTO chat_messages (session_id, role, content) VALUES (?, ?, ?), (?, ?, ?)", (session_id, "user", user_msg, session_id, "assistant", reply_text) ) conn.commit() except Exception: pass return { "status": "success", "user_id": user_id, "session_id": session_id, "response": reply_text } except Exception as e: logger.error(f"Ошибка вызова нейросети: {e}") return { "status": "error", "response": f"⚠️ Ошибка обработки запроса: {str(e)}" }