ИИ-Ассистент
-- Привет! Я подключен к вашей базе задач и системным промптам. Вы можете писать команды прямо в чат или управлять задачами через панель задач. +
+ Привет! Задавайте вопросы нейросети прямо в чат.
diff --git a/main.py b/main.py index 67dad4d..5abcee8 100644 --- a/main.py +++ b/main.py @@ -1,166 +1,73 @@ -# === ANCHOR: IMPORTS_START === -import os import json -import sqlite3 -from typing import List, Optional, Dict, Any - -from fastapi import FastAPI, HTTPException, Depends, Security +import urllib.request +from typing import List, Dict, Any, Optional +from fastapi import FastAPI, Depends, HTTPException, status from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials from fastapi.staticfiles import StaticFiles -from fastapi.responses import FileResponse, HTMLResponse +from fastapi.responses import FileResponse from pydantic import BaseModel from llm.agent import process_chat_message -# === ANCHOR: IMPORTS_END === +from llm.db_tools import db_get_tasks +API_TOKEN = "scud_secret_token_2026" +OLLAMA_URL = "http://192.168.11.3:11434/api/chat" +MODEL_NAME = "qwen2.5:14b" -# === ANCHOR: APP_INIT_START === -app = FastAPI( - title="SCUD Orion AI Context & Task Tracker API", - version="2.0.0", - description="REST API локального контекста, памяти и трекинга задач для ИИ-аудитора" -) - -DB_NAME = "/home/puh/scud_orion_ai_v2/data/scud_orion_ai.db" -SECURITY_TOKEN = os.getenv("API_BEARER_TOKEN", "scud_secret_token_2026") security = HTTPBearer() -# === ANCHOR: APP_INIT_END === - -# === ANCHOR: DATABASE_HELPERS_START === -def init_chat_table(): - """Создает таблицу истории чата, если она не существует.""" - conn = sqlite3.connect(DB_NAME) - cursor = conn.cursor() - cursor.execute(""" - CREATE TABLE IF NOT EXISTS chat_sessions ( - session_id TEXT PRIMARY KEY, - history_json TEXT NOT NULL, - updated_at TEXT DEFAULT CURRENT_TIMESTAMP - ) - """) - conn.commit() - conn.close() - -init_chat_table() - - -def verify_token(credentials: HTTPAuthorizationCredentials = Security(security)): - if credentials.credentials != SECURITY_TOKEN: - raise HTTPException(status_code=403, detail="Недействительный токен доступа") +def verify_token(credentials: HTTPAuthorizationCredentials = Depends(security)): + if credentials.credentials != API_TOKEN: + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail="Неверный токен доступа", + headers={"WWW-Authenticate": "Bearer"}, + ) return credentials.credentials +app = FastAPI(title="SCUD Orion AI Context API") -def get_db_connection(): - conn = sqlite3.connect(DB_NAME) - conn.row_factory = sqlite3.Row - return conn -# === ANCHOR: DATABASE_HELPERS_END === - - -# === ANCHOR: SCHEMAS_START === -class TaskSchema(BaseModel): - task_id: str - module: str - title: str - status: str - priority: str - completed_at: Optional[str] = None - - -class RuleSchema(BaseModel): - id: int - category: str - rule_text: str - is_active: int - - -class ChatRequest(BaseModel): - session_id: str = "default" - message: str - - -class ChatResponse(BaseModel): - session_id: str - reply: str -# === ANCHOR: SCHEMAS_END === - - -# === ANCHOR: STATIC_ROUTES_START === -# Подключаем папку static для отдачи HTML-интерфейса app.mount("/static", StaticFiles(directory="static"), name="static") -@app.get("/", response_class=HTMLResponse) +class ChatRequest(BaseModel): + session_id: str + message: str + +@app.get("/") def read_root(): return FileResponse("static/index.html") -# === ANCHOR: STATIC_ROUTES_END === +@app.get("/api/v1/tasks") +def get_tasks(token: str = Depends(verify_token)): + return db_get_tasks() -# === ANCHOR: TASKS_ENDPOINTS_START === -@app.get("/api/v1/tasks", response_model=List[TaskSchema], dependencies=[Depends(verify_token)]) -def get_all_tasks(status: Optional[str] = None): - conn = get_db_connection() - cursor = conn.cursor() - if status: - cursor.execute("SELECT * FROM tasks WHERE status = ? ORDER BY task_id", (status.upper(),)) - else: - cursor.execute("SELECT * FROM tasks ORDER BY task_id") - rows = cursor.fetchall() - conn.close() - return [dict(r) for r in rows] +@app.post("/api/v1/chat") +def chat_endpoint(req: ChatRequest, token: str = Depends(verify_token)): + reply, _ = process_chat_message(req.message) + return {"reply": reply} - -@app.post("/api/v1/tasks/{task_id}/complete", dependencies=[Depends(verify_token)]) -def mark_task_completed(task_id: str): - conn = get_db_connection() - cursor = conn.cursor() - cursor.execute( - "UPDATE tasks SET status = 'COMPLETED', completed_at = CURRENT_TIMESTAMP WHERE task_id = ?", - (task_id.upper(),) - ) - if cursor.rowcount == 0: - conn.close() - raise HTTPException(status_code=404, detail=f"Задача {task_id} не найдена") - conn.commit() - conn.close() - return {"status": "success", "message": f"Задача {task_id} успешно выполнена"} -# === ANCHOR: TASKS_ENDPOINTS_END === - - -# === ANCHOR: RULES_AND_CHAT_ENDPOINTS_START === -@app.get("/api/v1/rules", response_model=List[RuleSchema], dependencies=[Depends(verify_token)]) -def get_active_rules(): - conn = get_db_connection() - cursor = conn.cursor() - cursor.execute("SELECT * FROM architecture_memory WHERE is_active = 1 ORDER BY id") - rows = cursor.fetchall() - conn.close() - return [dict(r) for r in rows] - - -@app.post("/api/v1/chat", response_model=ChatResponse, dependencies=[Depends(verify_token)]) -def chat_endpoint(req: ChatRequest): - """Принимает сообщение, подтягивает историю из БД, выполняет вызовы функций к БД и сохраняет историю.""" - conn = get_db_connection() - cursor = conn.cursor() - cursor.execute("SELECT history_json FROM chat_sessions WHERE session_id = ?", (req.session_id,)) - row = cursor.fetchone() +# Эндпоинт для гостевого режима (без авторизации и без привязки к проекту) +@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} + } - chat_history = json.loads(row["history_json"]) if row else [] - - reply, updated_history = process_chat_message(req.message, chat_history) - - cursor.execute( - "INSERT OR REPLACE INTO chat_sessions (session_id, history_json, updated_at) VALUES (?, ?, CURRENT_TIMESTAMP)", - (req.session_id, json.dumps(updated_history, ensure_ascii=False)) - ) - conn.commit() - conn.close() - - return ChatResponse(session_id=req.session_id, reply=reply) - - -@app.get("/health") -def health_check(): - return {"status": "healthy", "service": "scud_context_api", "version": "2.0.0"} -# === ANCHOR: RULES_AND_CHAT_ENDPOINTS_END === \ No newline at end of file + 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}"} diff --git a/static/index.html b/static/index.html index 4f48abe..e92b28c 100644 --- a/static/index.html +++ b/static/index.html @@ -2,98 +2,147 @@
- +Авторизация в системе
+ИИ-Ассистент
-- Привет! Я подключен к вашей базе задач и системным промптам. Вы можете писать команды прямо в чат или управлять задачами через панель задач. +
+ Привет! Задавайте вопросы нейросети прямо в чат.