mirror of
https://github.com/R0m1k3/Loki.git
synced 2026-10-14 18:58:43 +02:00
Backend : - tools.py : read_file / write_file / list_dir confinés au workspace (anti-traversal) - agent.py : boucle de tool-calling itérative au-dessus d'Ollama, génère des événements (token, tool_call, tool_result, final) - routes/chat.py : pilote run_agent, relaie les événements en SSE, persiste la réponse finale + le récap des outils (meta) - routes/files.py : arborescence et contenu du workspace (confiné) - db.py : colonne meta sur messages (+ migration douce), list_messages_for_model Frontend : - ToolCard : carte d'appel d'outil dans le fil (statut en cours/terminé/échec) - streamChat : événements tool_call / tool_result - store : streamTools, fileTree, preview (ouverture auto d'un HTML écrit) - LeftPanel : arborescence réelle du workspace, clic -> aperçu - PreviewPanel : rendu HTML en iframe + onglet Code - ChatPanel : rendu des outils dans les bulles agent (streaming + persisté) Tests manuels : outils + confinement, boucle agent (mock Ollama), chat HTTP de bout en bout (SSE, persistance meta, fichiers écrits, confinement route). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SVay7z3y7q2gEe54ByAE6N
64 lines
1.7 KiB
Python
64 lines
1.7 KiB
Python
"""Point d'entrée FastAPI de Loki.
|
|
|
|
Sert l'API (/api/*) et, en production, le frontend React compilé (static/).
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
from contextlib import asynccontextmanager
|
|
|
|
from fastapi import FastAPI
|
|
from fastapi.middleware.cors import CORSMiddleware
|
|
from fastapi.responses import FileResponse
|
|
from fastapi.staticfiles import StaticFiles
|
|
|
|
from . import db
|
|
from .config import settings
|
|
from .routes import chat, files, models, sessions
|
|
|
|
|
|
@asynccontextmanager
|
|
async def lifespan(_: FastAPI):
|
|
db.init_db()
|
|
yield
|
|
|
|
|
|
app = FastAPI(
|
|
title="Loki", description="Agent IA local sur Ollama", lifespan=lifespan
|
|
)
|
|
|
|
# En dev, le front tourne sur Vite (5173). On autorise le CORS large ;
|
|
# en prod le front est servi par le même origin, donc sans impact.
|
|
app.add_middleware(
|
|
CORSMiddleware,
|
|
allow_origins=["*"],
|
|
allow_methods=["*"],
|
|
allow_headers=["*"],
|
|
)
|
|
|
|
app.include_router(models.router)
|
|
app.include_router(sessions.router)
|
|
app.include_router(chat.router)
|
|
app.include_router(files.router)
|
|
|
|
|
|
@app.get("/api/health")
|
|
async def health() -> dict:
|
|
return {"status": "ok", "service": "loki"}
|
|
|
|
|
|
# ── Service du frontend compilé (présent uniquement en image Docker) ─────
|
|
_STATIC_DIR = os.path.join(os.path.dirname(__file__), "..", "static")
|
|
if os.path.isdir(_STATIC_DIR):
|
|
app.mount(
|
|
"/assets",
|
|
StaticFiles(directory=os.path.join(_STATIC_DIR, "assets")),
|
|
name="assets",
|
|
)
|
|
|
|
@app.get("/{full_path:path}")
|
|
async def spa_fallback(full_path: str):
|
|
"""Renvoie index.html pour toutes les routes (SPA React)."""
|
|
index = os.path.join(_STATIC_DIR, "index.html")
|
|
return FileResponse(index)
|