текст из pdf распознается, все работает, добавлены все функции из файла работы с базой данных db_cli.py. Готовность к оптимизации интерфейса.
This commit is contained in:
@@ -8,7 +8,7 @@ from typing import List, Dict, Any, Optional
|
||||
|
||||
import jwt
|
||||
from passlib.context import CryptContext
|
||||
from fastapi import FastAPI, Depends, HTTPException, status
|
||||
from fastapi import FastAPI, Depends, HTTPException, status, UploadFile, File, Form
|
||||
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
from fastapi.responses import FileResponse
|
||||
@@ -16,9 +16,10 @@ from pydantic import BaseModel
|
||||
|
||||
from llm.agent import process_chat_message
|
||||
from llm.db_tools import db_get_tasks, DB_PATH
|
||||
from llm.file_parser import extract_text_from_file
|
||||
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
level=logging.DEBUG,
|
||||
format="%(asctime)s [%(levelname)s] %(message)s",
|
||||
handlers=[logging.StreamHandler()]
|
||||
)
|
||||
@@ -65,6 +66,16 @@ app = FastAPI(title="SCUD Orion AI Context API")
|
||||
|
||||
if os.path.exists("static"):
|
||||
app.mount("/static", StaticFiles(directory="static"), name="static")
|
||||
from fastapi.exceptions import RequestValidationError
|
||||
from fastapi.responses import JSONResponse
|
||||
|
||||
@app.exception_handler(RequestValidationError)
|
||||
async def validation_exception_handler(request, exc):
|
||||
logging.error(f"❌ ОШИБКА ВАЛИДАЦИИ 422 НА {request.url}: {exc.errors()}")
|
||||
return JSONResponse(
|
||||
status_code=422,
|
||||
content={"detail": exc.errors(), "body": str(exc)}
|
||||
)
|
||||
|
||||
class AuthRequest(BaseModel):
|
||||
username: str
|
||||
@@ -80,16 +91,42 @@ class ChangePasswordRequest(BaseModel):
|
||||
old_password: str
|
||||
new_password: str
|
||||
|
||||
class ChatRequest(BaseModel):
|
||||
session_id: str
|
||||
message: str
|
||||
|
||||
# === API МАРШРУТЫ ===
|
||||
|
||||
@app.get("/")
|
||||
def read_root():
|
||||
return FileResponse("static/index.html")
|
||||
|
||||
@app.get("/favicon.ico")
|
||||
async def favicon():
|
||||
file_path = os.path.join("static", "favicon.ico")
|
||||
if os.path.exists(file_path):
|
||||
return FileResponse(file_path)
|
||||
raise HTTPException(status_code=404)
|
||||
|
||||
@app.get("/{file_path:path}")
|
||||
def serve_static_fallback(file_path: str):
|
||||
clean_path = file_path.lstrip("/")
|
||||
|
||||
# Игнорируем сканеры WordPress / PHP
|
||||
if any(clean_path.startswith(prefix) for prefix in ["wp-", "wordpress", "php", "cms", "shop"]):
|
||||
raise HTTPException(status_code=404, detail="Not Found")
|
||||
|
||||
target = os.path.join("static", clean_path)
|
||||
if os.path.isfile(target):
|
||||
return FileResponse(target)
|
||||
|
||||
filename = os.path.basename(clean_path)
|
||||
target_js = os.path.join("static/js", filename)
|
||||
if filename.endswith(".js") and os.path.isfile(target_js):
|
||||
return FileResponse(target_js, media_type="application/javascript")
|
||||
|
||||
target_css = os.path.join("static/css", filename)
|
||||
if filename.endswith(".css") and os.path.isfile(target_css):
|
||||
return FileResponse(target_css, media_type="text/css")
|
||||
|
||||
raise HTTPException(status_code=404, detail="File not found")
|
||||
|
||||
@app.post("/api/v1/auth/login")
|
||||
def login(req: AuthRequest):
|
||||
username = req.username.strip().lower()
|
||||
@@ -200,34 +237,48 @@ def delete_user(user_id: int, current_user: Dict[str, Any] = Depends(get_current
|
||||
def get_tasks(user: Dict[str, Any] = Depends(get_current_user)):
|
||||
return db_get_tasks(user_id=user["id"])
|
||||
|
||||
# ЧАТ С ПОДДЕРЖКОЙ ФАЙЛОВ И АВТОРИЗАЦИИ
|
||||
@app.post("/api/v1/chat")
|
||||
def chat_endpoint(req: ChatRequest, user: Dict[str, Any] = Depends(get_current_user)):
|
||||
reply, _ = process_chat_message(user_id=user["id"], user_message=req.message)
|
||||
return {"reply": reply}
|
||||
async def chat_endpoint(
|
||||
session_id: str = Form("web_session_main"),
|
||||
message: str = Form(""),
|
||||
file: Optional[UploadFile] = File(default=None),
|
||||
current_user: dict = Depends(get_current_user)
|
||||
):
|
||||
logging.info(f"=== [CHAT API] Входящий запрос от user_id={current_user['id']}, file={file.filename if file else 'None'} ===")
|
||||
file_content_text = ""
|
||||
if file and file.filename:
|
||||
file_bytes = await file.read()
|
||||
file_content_text = extract_text_from_file(file_bytes, file.filename)
|
||||
|
||||
reply, history = process_chat_message(
|
||||
user_id=current_user["id"],
|
||||
user_message=message,
|
||||
file_context=file_content_text,
|
||||
session_id=session_id
|
||||
)
|
||||
return {"reply": reply, "history": history}
|
||||
|
||||
# ЕДИНЫЙ ГОСТЕВОЙ ЧАТ (FormData + Файлы)
|
||||
@app.post("/api/v1/chat/guest")
|
||||
def guest_chat_endpoint(req: ChatRequest):
|
||||
payload = {
|
||||
"model": MODEL_NAME,
|
||||
"messages": [
|
||||
{"role": "system", "content": "Ты — полезный ИИ-ассистент. Отвечай на вопросы пользователя четко и по существу."},
|
||||
{"role": "user", "content": req.message}
|
||||
],
|
||||
"stream": False,
|
||||
"options": {"num_predict": 2048, "temperature": 0.3}
|
||||
}
|
||||
try:
|
||||
req_ollama = urllib.request.Request(
|
||||
OLLAMA_URL,
|
||||
data=json.dumps(payload).encode("utf-8"),
|
||||
headers={"Content-Type": "application/json"}
|
||||
)
|
||||
with urllib.request.urlopen(req_ollama) as response:
|
||||
res_data = json.loads(response.read().decode("utf-8"))
|
||||
reply = res_data.get("message", {}).get("content", "").strip()
|
||||
return {"reply": reply}
|
||||
except Exception as e:
|
||||
return {"reply": f"Ошибка связи с локальной нейросетью: {e}"}
|
||||
async def guest_chat_endpoint(
|
||||
session_id: str = Form("web_session_main"),
|
||||
message: str = Form(""),
|
||||
file: Optional[UploadFile] = File(default=None)
|
||||
):
|
||||
logging.info(f"=== [GUEST CHAT API] Входящий запрос, file={file.filename if file else 'None'} ===")
|
||||
file_content_text = ""
|
||||
if file and file.filename:
|
||||
file_bytes = await file.read()
|
||||
file_content_text = extract_text_from_file(file_bytes, file.filename)
|
||||
|
||||
reply, history = process_chat_message(
|
||||
user_id=0,
|
||||
user_message=message,
|
||||
file_context=file_content_text,
|
||||
session_id=session_id
|
||||
)
|
||||
return {"reply": reply, "history": history}
|
||||
|
||||
# === СТРОГО В КОНЦЕ: ФОЛЛБЭК СТАТИКИ ===
|
||||
|
||||
|
||||
Reference in New Issue
Block a user