refacto: dashboard Flask Blueprints + templates Jinja2, engine run/lore_enricher mis a jour
This commit is contained in:
@@ -0,0 +1,138 @@
|
||||
import os
|
||||
import json
|
||||
import urllib.request
|
||||
|
||||
from flask import Blueprint, render_template, jsonify, request, redirect, url_for
|
||||
|
||||
from ..db import query, query_one, execute, get_all_sessions
|
||||
from ..chroma import upsert_sim_enriched, upsert_sim_reject, CHROMA_SIM_COL
|
||||
|
||||
bp = Blueprint("sim_proposals", __name__)
|
||||
|
||||
|
||||
def _get_proposals(ptype: str = "", status: str = "pending") -> list:
|
||||
sql = "SELECT * FROM sim_proposals WHERE 1=1"
|
||||
params = []
|
||||
if ptype:
|
||||
sql += " AND proposal_type = %s"
|
||||
params.append(ptype)
|
||||
if status:
|
||||
sql += " AND status = %s"
|
||||
params.append(status)
|
||||
sql += " ORDER BY id DESC LIMIT 100"
|
||||
return query(sql, params or None)
|
||||
|
||||
|
||||
def _get_stats() -> dict:
|
||||
rows = query("SELECT status, COUNT(*) as n FROM sim_proposals GROUP BY status")
|
||||
m = {r["status"]: r["n"] for r in rows}
|
||||
return {"pending": m.get("pending", 0), "accepted": m.get("accepted", 0),
|
||||
"rejected": m.get("rejected", 0)}
|
||||
|
||||
|
||||
def _get_types() -> list:
|
||||
rows = query("SELECT DISTINCT proposal_type FROM sim_proposals ORDER BY proposal_type")
|
||||
return [r["proposal_type"] for r in rows]
|
||||
|
||||
|
||||
@bp.route("/sim-proposals")
|
||||
def sim_proposals_view():
|
||||
all_sessions = get_all_sessions()
|
||||
sid = int(request.args.get("sid", all_sessions[-1]["id"] if all_sessions else 1))
|
||||
filt_type = request.args.get("type", "")
|
||||
filt_status = request.args.get("status", "pending")
|
||||
proposals = _get_proposals(filt_type, filt_status)
|
||||
flash_msg = request.args.get("msg")
|
||||
flash_ok = request.args.get("ok", "1") == "1"
|
||||
|
||||
threads_raw = query("SELECT * FROM sim_proposal_threads ORDER BY created_at ASC") if proposals else []
|
||||
proposal_threads = {}
|
||||
for row in (threads_raw or []):
|
||||
pid = row["proposal_id"]
|
||||
proposal_threads.setdefault(pid, []).append(row)
|
||||
|
||||
return render_template("sim_proposals.html",
|
||||
tab="sim_proposals", current_sid=sid, all_sessions=all_sessions,
|
||||
proposals=proposals, sim_stats=_get_stats(), sim_types=_get_types(),
|
||||
filt_type=filt_type, filt_status=filt_status,
|
||||
proposal_threads=proposal_threads, flash_msg=flash_msg, flash_ok=flash_ok,
|
||||
)
|
||||
|
||||
|
||||
@bp.route("/sim-proposals/action", methods=["POST"])
|
||||
def sim_proposals_action():
|
||||
prop_id = int(request.form.get("id", 0))
|
||||
action = request.form.get("action", "")
|
||||
filt_type = request.form.get("filt_type", "")
|
||||
filt_status = request.form.get("filt_status", "pending")
|
||||
|
||||
proposal = query_one("SELECT * FROM sim_proposals WHERE id = %s", (prop_id,))
|
||||
if not proposal:
|
||||
return redirect(url_for("sim_proposals.sim_proposals_view", msg="Proposition introuvable", ok=0))
|
||||
try:
|
||||
if action == "accept":
|
||||
execute("UPDATE sim_proposals SET status='accepted', reviewed_at=NOW() WHERE id=%s", (prop_id,))
|
||||
upsert_sim_enriched(dict(proposal))
|
||||
msg = f"Proposition #{prop_id} acceptée → indexée dans {CHROMA_SIM_COL}."
|
||||
elif action == "reject":
|
||||
reason = request.form.get("reject_reason", "").strip()
|
||||
execute("UPDATE sim_proposals SET status='rejected', reviewed_at=NOW(), reject_reason=%s WHERE id=%s",
|
||||
(reason or None, prop_id))
|
||||
if reason:
|
||||
try:
|
||||
upsert_sim_reject(dict(proposal), reason)
|
||||
except Exception:
|
||||
pass
|
||||
msg = f"Proposition #{prop_id} rejetée." + (" Motif indexé." if reason else "")
|
||||
else:
|
||||
msg = "Action inconnue."
|
||||
ok = 1
|
||||
except Exception as e:
|
||||
msg = f"Erreur: {e}"
|
||||
ok = 0
|
||||
|
||||
return redirect(url_for("sim_proposals.sim_proposals_view", msg=msg, ok=ok,
|
||||
type=filt_type, status=filt_status))
|
||||
|
||||
|
||||
@bp.route("/sim-proposals/<int:prop_id>/discuss", methods=["POST"])
|
||||
def sim_proposals_discuss(prop_id):
|
||||
proposal = query_one("SELECT * FROM sim_proposals WHERE id=%s", (prop_id,))
|
||||
if not proposal:
|
||||
return jsonify({"error": "Proposition introuvable"}), 404
|
||||
data = request.get_json(silent=True) or {}
|
||||
user_msg = data.get("message", "").strip()
|
||||
temperature = float(data.get("temperature", 0.75))
|
||||
num_predict = int(data.get("num_predict", 512))
|
||||
if not user_msg:
|
||||
return jsonify({"error": "Message vide"}), 400
|
||||
|
||||
execute("INSERT INTO sim_proposal_threads (proposal_id,role,content,temperature,num_predict) VALUES (%s,'user',%s,%s,%s)",
|
||||
(prop_id, user_msg, temperature, num_predict))
|
||||
|
||||
context = [
|
||||
"Tu es un assistant de game design pour un JDR Fallout post-apocalyptique (Louisiane, 'Venice of Wasteland').",
|
||||
f"Proposition de règle : [{proposal.get('proposal_type','')}] {proposal.get('title','')}",
|
||||
f"Description : {proposal.get('description','')}",
|
||||
f"Rationale : {proposal.get('rationale','')}",
|
||||
"",
|
||||
f"Le maître de jeu demande : {user_msg}",
|
||||
"",
|
||||
"Réponds de façon concise et pratique. Si tu proposes une version modifiée, structure-la clairement.",
|
||||
]
|
||||
ollama_url = os.getenv("OLLAMA_URL", "http://10.8.0.2:11434")
|
||||
model = os.getenv("MODEL_MJ", "qwen2.5:14b")
|
||||
try:
|
||||
payload = json.dumps({"model": model, "prompt": "\n".join(context), "stream": False,
|
||||
"options": {"temperature": temperature, "num_predict": num_predict}}).encode()
|
||||
req = urllib.request.Request(f"{ollama_url}/api/generate",
|
||||
data=payload, headers={"Content-Type": "application/json"}, method="POST")
|
||||
with urllib.request.urlopen(req, timeout=120) as resp:
|
||||
result = json.loads(resp.read())
|
||||
llm_response = result.get("response", "").strip()
|
||||
except Exception as e:
|
||||
return jsonify({"error": f"Erreur LLM : {e}"}), 500
|
||||
|
||||
execute("INSERT INTO sim_proposal_threads (proposal_id,role,content,temperature,num_predict) VALUES (%s,'llm',%s,%s,%s)",
|
||||
(prop_id, llm_response, temperature, num_predict))
|
||||
return jsonify({"ok": True, "response": llm_response})
|
||||
Reference in New Issue
Block a user