Spaces:
Building
Building
Update chat_handler.py
Browse files- chat_handler.py +27 -17
chat_handler.py
CHANGED
@@ -1,25 +1,39 @@
|
|
1 |
"""
|
2 |
-
Flare – Chat Handler (Spark /generate + safe-intent)
|
3 |
-
|
4 |
• X-Session-ID header
|
5 |
-
•
|
6 |
-
• Eğer model #DETECTED_INTENT:<label> döndürür ve <label> izinli liste
|
7 |
-
dışında ise, mesaj small-talk olarak kabul edilir.
|
8 |
"""
|
9 |
|
10 |
-
import re, json, uuid, httpx, commentjson
|
11 |
from datetime import datetime
|
12 |
from typing import Dict, List, Optional
|
13 |
|
14 |
from fastapi import APIRouter, HTTPException, Header
|
15 |
from pydantic import BaseModel
|
|
|
16 |
|
17 |
from prompt_builder import build_intent_prompt, build_parameter_prompt, log
|
18 |
|
19 |
# --------------------------------------------------------------------------- #
|
20 |
-
# CONFIG
|
21 |
# --------------------------------------------------------------------------- #
|
22 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
23 |
PROJECTS = {p["name"]: p for p in CFG["projects"]}
|
24 |
APIS = {a["name"]: a for a in CFG["apis"]}
|
25 |
SPARK_URL = CFG["config"]["spark_endpoint"].rstrip("/") + "/generate"
|
@@ -32,7 +46,7 @@ class Session:
|
|
32 |
def __init__(self, project_name: str):
|
33 |
self.id = str(uuid.uuid4())
|
34 |
self.project = PROJECTS[project_name]
|
35 |
-
self.history: List[Dict[str, str]] = []
|
36 |
self.variables: Dict[str, str] = {}
|
37 |
self.awaiting: Optional[Dict] = None
|
38 |
log(f"🆕 Session {self.id} for {project_name}")
|
@@ -99,25 +113,22 @@ async def chat(body: ChatBody,
|
|
99 |
user_msg = body.user_input.strip()
|
100 |
s.history.append({"role": "user", "content": user_msg})
|
101 |
|
102 |
-
# ---------------- Follow-up?
|
103 |
if s.awaiting:
|
104 |
answer = await _followup(s, user_msg)
|
105 |
s.history.append({"role": "assistant", "content": answer})
|
106 |
return ChatResponse(session_id=s.id, answer=answer)
|
107 |
|
108 |
-
# ---------------- Intent
|
109 |
gen_prompt = s.project["versions"][0]["general_prompt"]
|
110 |
intent_raw = await spark_generate(s, gen_prompt, user_msg)
|
111 |
|
112 |
-
# --- Etiket yoksa → small talk cevabı olduğu gibi döndür
|
113 |
if not intent_raw.startswith("#DETECTED_INTENT:"):
|
114 |
s.history.append({"role": "assistant", "content": intent_raw})
|
115 |
return ChatResponse(session_id=s.id, answer=intent_raw)
|
116 |
|
117 |
-
# --- Etiket var → ayrıştır
|
118 |
intent_name = intent_raw.split(":", 1)[1].strip()
|
119 |
if intent_name not in ALLOWED_INTENTS:
|
120 |
-
# Etiket geçersiz → small talk olarak ilk kısmı döndür
|
121 |
clean = intent_raw.split("#DETECTED_INTENT")[0].split("\nassistant")[0].strip()
|
122 |
s.history.append({"role": "assistant", "content": clean})
|
123 |
return ChatResponse(session_id=s.id, answer=clean)
|
@@ -145,7 +156,6 @@ def _missing(s, intent_cfg):
|
|
145 |
|
146 |
async def _handle_intent(s, intent_cfg, user_msg):
|
147 |
missing = _missing(s, intent_cfg)
|
148 |
-
|
149 |
if missing:
|
150 |
p_prompt = build_parameter_prompt(intent_cfg, missing, user_msg, s.history)
|
151 |
p_raw = await spark_generate(s, p_prompt, user_msg)
|
@@ -166,8 +176,8 @@ async def _handle_intent(s, intent_cfg, user_msg):
|
|
166 |
async def _followup(s, user_msg):
|
167 |
intent_cfg = s.awaiting["intent"]
|
168 |
missing = s.awaiting["missing"]
|
169 |
-
p_prompt
|
170 |
-
p_raw
|
171 |
if not p_raw.startswith("#PARAMETERS:"):
|
172 |
return "Üzgünüm, anlayamadım."
|
173 |
if bad := _process_params(s, intent_cfg, p_raw):
|
|
|
1 |
"""
|
2 |
+
Flare – Chat Handler (Spark /generate + safe-intent + config-validate)
|
3 |
+
======================================================================
|
4 |
• X-Session-ID header
|
5 |
+
• Config JSONC parse hatası -> log + graceful exit
|
|
|
|
|
6 |
"""
|
7 |
|
8 |
+
import re, json, uuid, sys, httpx, commentjson
|
9 |
from datetime import datetime
|
10 |
from typing import Dict, List, Optional
|
11 |
|
12 |
from fastapi import APIRouter, HTTPException, Header
|
13 |
from pydantic import BaseModel
|
14 |
+
from commentjson import JSONLibraryException
|
15 |
|
16 |
from prompt_builder import build_intent_prompt, build_parameter_prompt, log
|
17 |
|
18 |
# --------------------------------------------------------------------------- #
|
19 |
+
# CONFIG LOADING + VALIDATION
|
20 |
# --------------------------------------------------------------------------- #
|
21 |
+
def load_config(path: str = "service_config.jsonc") -> dict:
|
22 |
+
try:
|
23 |
+
with open(path, encoding="utf-8") as f:
|
24 |
+
cfg = commentjson.load(f)
|
25 |
+
log("✅ service_config.jsonc parsed successfully.")
|
26 |
+
return cfg
|
27 |
+
except JSONLibraryException as e:
|
28 |
+
log("❌ CONFIG PARSE ERROR:")
|
29 |
+
log(str(e))
|
30 |
+
sys.exit(1)
|
31 |
+
except FileNotFoundError:
|
32 |
+
log(f"❌ Config file '{path}' not found.")
|
33 |
+
sys.exit(1)
|
34 |
+
|
35 |
+
CFG = load_config()
|
36 |
+
|
37 |
PROJECTS = {p["name"]: p for p in CFG["projects"]}
|
38 |
APIS = {a["name"]: a for a in CFG["apis"]}
|
39 |
SPARK_URL = CFG["config"]["spark_endpoint"].rstrip("/") + "/generate"
|
|
|
46 |
def __init__(self, project_name: str):
|
47 |
self.id = str(uuid.uuid4())
|
48 |
self.project = PROJECTS[project_name]
|
49 |
+
self.history: List[Dict[str, str]] = []
|
50 |
self.variables: Dict[str, str] = {}
|
51 |
self.awaiting: Optional[Dict] = None
|
52 |
log(f"🆕 Session {self.id} for {project_name}")
|
|
|
113 |
user_msg = body.user_input.strip()
|
114 |
s.history.append({"role": "user", "content": user_msg})
|
115 |
|
116 |
+
# ---------------- Follow-up?
|
117 |
if s.awaiting:
|
118 |
answer = await _followup(s, user_msg)
|
119 |
s.history.append({"role": "assistant", "content": answer})
|
120 |
return ChatResponse(session_id=s.id, answer=answer)
|
121 |
|
122 |
+
# ---------------- Intent detect
|
123 |
gen_prompt = s.project["versions"][0]["general_prompt"]
|
124 |
intent_raw = await spark_generate(s, gen_prompt, user_msg)
|
125 |
|
|
|
126 |
if not intent_raw.startswith("#DETECTED_INTENT:"):
|
127 |
s.history.append({"role": "assistant", "content": intent_raw})
|
128 |
return ChatResponse(session_id=s.id, answer=intent_raw)
|
129 |
|
|
|
130 |
intent_name = intent_raw.split(":", 1)[1].strip()
|
131 |
if intent_name not in ALLOWED_INTENTS:
|
|
|
132 |
clean = intent_raw.split("#DETECTED_INTENT")[0].split("\nassistant")[0].strip()
|
133 |
s.history.append({"role": "assistant", "content": clean})
|
134 |
return ChatResponse(session_id=s.id, answer=clean)
|
|
|
156 |
|
157 |
async def _handle_intent(s, intent_cfg, user_msg):
|
158 |
missing = _missing(s, intent_cfg)
|
|
|
159 |
if missing:
|
160 |
p_prompt = build_parameter_prompt(intent_cfg, missing, user_msg, s.history)
|
161 |
p_raw = await spark_generate(s, p_prompt, user_msg)
|
|
|
176 |
async def _followup(s, user_msg):
|
177 |
intent_cfg = s.awaiting["intent"]
|
178 |
missing = s.awaiting["missing"]
|
179 |
+
p_prompt = build_parameter_prompt(intent_cfg, missing, user_msg, s.history)
|
180 |
+
p_raw = await spark_generate(s, p_prompt, user_msg)
|
181 |
if not p_raw.startswith("#PARAMETERS:"):
|
182 |
return "Üzgünüm, anlayamadım."
|
183 |
if bad := _process_params(s, intent_cfg, p_raw):
|