""" =============================================================================== FILE: modules/web_api/routers/chat.py PROJECT: SCUD Orion AI (Unified Architecture) MODULE: web_api / routers ROLE: Маршрутизация диалогов с LLM и эндпоинт сохранения онлайн-черновиков. =============================================================================== """ # ANCHOR[CHAT_ROUTER_IMPORTS] from typing import Optional, Dict, Any from fastapi import APIRouter, Depends, UploadFile, File, Form, HTTPException from pydantic import BaseModel from .auth import get_current_user from llm.agent import process_chat_message from llm.file_parser import extract_text_from_file from llm.db_tools import db_set_session_state, db_get_session_state router = APIRouter(prefix="/api/v1/chat", tags=["chat"]) # ANCHOR[DRAFT_SCHEMA] class UpdateDraftRequest(BaseModel): session_id: str draft_text: str # ANCHOR[CHAT_ENDPOINTS] @router.post("") async def chat_endpoint( session_id: str = Form("web_session_main"), message: str = Form(""), file: Optional[UploadFile] = File(default=None), current_user: Dict[str, Any] = Depends(get_current_user) ): """Диалог авторизованного пользователя с агентом.""" parsed_file = {"text": "", "image_b64": None} if file and file.filename: file_bytes = await file.read() parsed_file = extract_text_from_file(file_bytes, file.filename) reply, history, action_type = process_chat_message( user_id=current_user["id"], user_message=message, file_context=parsed_file["text"], image_b64=parsed_file["image_b64"], session_id=session_id ) return {"reply": reply, "history": history, "action_type": action_type} @router.post("/guest") async def guest_chat_endpoint( session_id: str = Form("web_session_main"), message: str = Form(""), file: Optional[UploadFile] = File(default=None) ): """Гостевой диалог (user_id=0).""" parsed_file = {"text": "", "image_b64": None} if file and file.filename: file_bytes = await file.read() parsed_file = extract_text_from_file(file_bytes, file.filename) reply, history, action_type = process_chat_message( user_id=0, user_message=message, file_context=parsed_file["text"], image_b64=parsed_file["image_b64"], session_id=session_id ) return {"reply": reply, "history": history, "action_type": action_type} @router.post("/draft") def update_draft_endpoint( req: UpdateDraftRequest, current_user: Dict[str, Any] = Depends(get_current_user) ): """Обновляет черновик системного промпта напрямую из интерактивной онлайн-формы.""" state = db_get_session_state(req.session_id) if not state or state.get("state_type") != "PROMPT_PREVIEW": raise HTTPException(status_code=400, detail="Нет активного превью для редактирования") # Сохраняем чистый текст с пометкой MANUAL_EDIT db_set_session_state(req.session_id, "PROMPT_PREVIEW", { "draft_text": req.draft_text.strip(), "action": "MANUAL_EDIT", "section_id": None, "item_id": None, "content": "" }) return {"status": "success", "message": "Черновик успешно обновлен в сессии"}