ciyidogan commited on
Commit
01da95c
·
verified ·
1 Parent(s): 5e0179c

Update chat_handler.py

Browse files
Files changed (1) hide show
  1. chat_handler.py +60 -47
chat_handler.py CHANGED
@@ -1,72 +1,84 @@
1
  """
2
- Flare – Chat Handler (header edition)
3
- ====================================
4
- /start_session -> JSON body döner
5
- /chat -> X-Session-ID header + {"user_input": "..."}
 
6
  """
7
 
8
  import re, json, uuid, httpx, commentjson
9
  from datetime import datetime
10
  from typing import Dict, List, Optional
11
 
12
- from fastapi import APIRouter, HTTPException, Header, Request
13
  from pydantic import BaseModel
14
 
15
  from prompt_builder import build_intent_prompt, build_parameter_prompt, log
16
 
17
- # ----------------------------------------------------------------------------
18
  # CONFIG
19
- # ----------------------------------------------------------------------------
20
  CFG = commentjson.load(open("service_config.jsonc", encoding="utf-8"))
21
  PROJECTS = {p["name"]: p for p in CFG["projects"]}
22
  APIS = {a["name"]: a for a in CFG["apis"]}
 
23
 
24
- # ----------------------------------------------------------------------------
25
  # SESSION
26
- # ----------------------------------------------------------------------------
27
  class Session:
28
  def __init__(self, project_name: str):
29
  self.id = str(uuid.uuid4())
30
  self.project = PROJECTS[project_name]
31
- self.history: List[Dict[str, str]] = []
32
  self.variables: Dict[str, str] = {}
33
  self.awaiting: Optional[Dict] = None
34
  log(f"🆕 Session {self.id} for {project_name}")
35
 
36
  SESSIONS: Dict[str, Session] = {}
37
 
38
- # ----------------------------------------------------------------------------
39
- # SPARK
40
- # ----------------------------------------------------------------------------
41
- async def spark_generate(prompt: str) -> str:
 
 
 
 
 
 
 
 
 
42
  async with httpx.AsyncClient(timeout=60) as c:
43
- r = await c.post(CFG["config"]["spark_endpoint"], json={"prompt": prompt})
44
  r.raise_for_status()
45
- return r.json()["text"]
 
 
46
 
47
- # ----------------------------------------------------------------------------
48
  # FASTAPI ROUTER
49
- # ----------------------------------------------------------------------------
50
  router = APIRouter()
51
 
52
  @router.get("/")
53
  def health():
54
  return {"status": "ok"}
55
 
56
- # Schemas
57
  class StartSessionRequest(BaseModel):
58
  project_name: str
59
 
60
  class ChatBody(BaseModel):
61
  user_input: str
62
- # session_id optional for legacy
63
- session_id: Optional[str] = None
64
 
65
  class ChatResponse(BaseModel):
66
  session_id: str
67
  answer: str
68
 
69
- # Endpoints
 
 
70
  @router.post("/start_session", response_model=ChatResponse)
71
  async def start_session(req: StartSessionRequest):
72
  if req.project_name not in PROJECTS:
@@ -77,14 +89,11 @@ async def start_session(req: StartSessionRequest):
77
 
78
  @router.post("/chat", response_model=ChatResponse)
79
  async def chat(body: ChatBody,
80
- request: Request,
81
- x_session_id: Optional[str] = Header(None)):
82
- # 1) Session ID alma: header > body
83
- sid = x_session_id or body.session_id
84
- if not sid or sid not in SESSIONS:
85
- raise HTTPException(404, "Invalid or missing session")
86
-
87
- s = SESSIONS[sid]
88
  user_msg = body.user_input.strip()
89
  s.history.append({"role": "user", "content": user_msg})
90
 
@@ -94,10 +103,9 @@ async def chat(body: ChatBody,
94
  s.history.append({"role": "assistant", "content": answer})
95
  return ChatResponse(session_id=s.id, answer=answer)
96
 
97
- # ---------------- intent detect
98
  gen_prompt = s.project["versions"][0]["general_prompt"]
99
- intent_prompt = build_intent_prompt(gen_prompt, s.history, user_msg)
100
- intent_out = await spark_generate(intent_prompt)
101
 
102
  if not intent_out.startswith("#DETECTED_INTENT:"):
103
  s.history.append({"role": "assistant", "content": intent_out})
@@ -114,28 +122,31 @@ async def chat(body: ChatBody,
114
  s.history.append({"role": "assistant", "content": answer})
115
  return ChatResponse(session_id=s.id, answer=answer)
116
 
117
- # ----------------------------------------------------------------------------
118
- # Helper funcs (aynı)
119
- # ----------------------------------------------------------------------------
120
  def _find_intent(project, name_):
121
  return next((i for i in project["versions"][0]["intents"] if i["name"] == name_), None)
122
 
123
  def _missing(s, intent_cfg):
124
- return [p["name"] for p in intent_cfg["parameters"] if p["variable_name"] not in s.variables]
 
125
 
126
  async def _handle_intent(s, intent_cfg, user_msg):
127
  missing = _missing(s, intent_cfg)
128
  if missing:
129
  p_prompt = build_parameter_prompt(intent_cfg, missing, user_msg, s.history)
130
- out = await spark_generate(p_prompt)
131
- if out.startswith("#PARAMETERS:"):
132
- if bad := _process_params(s, intent_cfg, out):
133
  return bad
134
  missing = _missing(s, intent_cfg)
 
135
  if missing:
136
  s.awaiting = {"intent": intent_cfg, "missing": missing}
137
  cap = next(p for p in intent_cfg["parameters"] if p["name"] == missing[0])["caption"]
138
  return f"{cap} nedir?"
 
139
  s.awaiting = None
140
  return await _call_api(s, intent_cfg)
141
 
@@ -143,22 +154,24 @@ async def _followup(s, user_msg):
143
  intent_cfg = s.awaiting["intent"]
144
  missing = s.awaiting["missing"]
145
  p_prompt = build_parameter_prompt(intent_cfg, missing, user_msg, s.history)
146
- out = await spark_generate(p_prompt)
147
- if not out.startswith("#PARAMETERS:"):
148
  return "Üzgünüm, anlayamadım."
149
- if bad := _process_params(s, intent_cfg, out):
150
  return bad
 
151
  missing = _missing(s, intent_cfg)
152
  if missing:
153
  s.awaiting["missing"] = missing
154
  cap = next(p for p in intent_cfg["parameters"] if p["name"] == missing[0])["caption"]
155
  return f"{cap} nedir?"
 
156
  s.awaiting = None
157
  return await _call_api(s, intent_cfg)
158
 
159
- def _process_params(s, intent_cfg, out):
160
  try:
161
- data = json.loads(out[len("#PARAMETERS:"):])
162
  except json.JSONDecodeError:
163
  return "Parametreleri çözemedim."
164
  for pair in data.get("extracted", []):
@@ -188,7 +201,7 @@ async def _call_api(s, intent_cfg):
188
  except Exception:
189
  return intent_cfg["fallback_error_prompt"]
190
 
191
- summary = api["response_prompt"].replace(
192
  "{{api_response}}", json.dumps(api_json, ensure_ascii=False)
193
  )
194
- return await spark_generate(summary)
 
1
  """
2
+ Flare – Chat Handler (Spark /generate format)
3
+ =============================================
4
+ X-Session-ID header
5
+ /generate payload:
6
+ {project_name, user_input, context, system_prompt}
7
  """
8
 
9
  import re, json, uuid, httpx, commentjson
10
  from datetime import datetime
11
  from typing import Dict, List, Optional
12
 
13
+ from fastapi import APIRouter, HTTPException, Header
14
  from pydantic import BaseModel
15
 
16
  from prompt_builder import build_intent_prompt, build_parameter_prompt, log
17
 
18
+ # --------------------------------------------------------------------------- #
19
  # CONFIG
20
+ # --------------------------------------------------------------------------- #
21
  CFG = commentjson.load(open("service_config.jsonc", encoding="utf-8"))
22
  PROJECTS = {p["name"]: p for p in CFG["projects"]}
23
  APIS = {a["name"]: a for a in CFG["apis"]}
24
+ SPARK_URL = CFG["config"]["spark_endpoint"].rstrip("/") + "/generate"
25
 
26
+ # --------------------------------------------------------------------------- #
27
  # SESSION
28
+ # --------------------------------------------------------------------------- #
29
  class Session:
30
  def __init__(self, project_name: str):
31
  self.id = str(uuid.uuid4())
32
  self.project = PROJECTS[project_name]
33
+ self.history: List[Dict[str, str]] = [] # {role, content}
34
  self.variables: Dict[str, str] = {}
35
  self.awaiting: Optional[Dict] = None
36
  log(f"🆕 Session {self.id} for {project_name}")
37
 
38
  SESSIONS: Dict[str, Session] = {}
39
 
40
+ # --------------------------------------------------------------------------- #
41
+ # Spark client
42
+ # --------------------------------------------------------------------------- #
43
+ async def spark_generate(session: Session,
44
+ system_prompt: str,
45
+ user_input: str) -> str:
46
+ """Send request to Spark /generate endpoint"""
47
+ payload = {
48
+ "project_name": session.project["name"],
49
+ "user_input": user_input,
50
+ "context": session.history[-10:], # only last 10 turns
51
+ "system_prompt": system_prompt
52
+ }
53
  async with httpx.AsyncClient(timeout=60) as c:
54
+ r = await c.post(SPARK_URL, json=payload)
55
  r.raise_for_status()
56
+ # Spark örneğinde cevap key'i "model_answer" olabilir.
57
+ data = r.json()
58
+ return data.get("assistant") or data.get("model_answer") or data.get("text", "")
59
 
60
+ # --------------------------------------------------------------------------- #
61
  # FASTAPI ROUTER
62
+ # --------------------------------------------------------------------------- #
63
  router = APIRouter()
64
 
65
  @router.get("/")
66
  def health():
67
  return {"status": "ok"}
68
 
 
69
  class StartSessionRequest(BaseModel):
70
  project_name: str
71
 
72
  class ChatBody(BaseModel):
73
  user_input: str
 
 
74
 
75
  class ChatResponse(BaseModel):
76
  session_id: str
77
  answer: str
78
 
79
+ # --------------------------------------------------------------------------- #
80
+ # ENDPOINTS
81
+ # --------------------------------------------------------------------------- #
82
  @router.post("/start_session", response_model=ChatResponse)
83
  async def start_session(req: StartSessionRequest):
84
  if req.project_name not in PROJECTS:
 
89
 
90
  @router.post("/chat", response_model=ChatResponse)
91
  async def chat(body: ChatBody,
92
+ x_session_id: str = Header(...)):
93
+ if x_session_id not in SESSIONS:
94
+ raise HTTPException(404, "Invalid session")
95
+
96
+ s = SESSIONS[x_session_id]
 
 
 
97
  user_msg = body.user_input.strip()
98
  s.history.append({"role": "user", "content": user_msg})
99
 
 
103
  s.history.append({"role": "assistant", "content": answer})
104
  return ChatResponse(session_id=s.id, answer=answer)
105
 
106
+ # ---------------- intent detection ----------------
107
  gen_prompt = s.project["versions"][0]["general_prompt"]
108
+ intent_out = await spark_generate(s, gen_prompt, user_msg)
 
109
 
110
  if not intent_out.startswith("#DETECTED_INTENT:"):
111
  s.history.append({"role": "assistant", "content": intent_out})
 
122
  s.history.append({"role": "assistant", "content": answer})
123
  return ChatResponse(session_id=s.id, answer=answer)
124
 
125
+ # --------------------------------------------------------------------------- #
126
+ # Helper functions
127
+ # --------------------------------------------------------------------------- #
128
  def _find_intent(project, name_):
129
  return next((i for i in project["versions"][0]["intents"] if i["name"] == name_), None)
130
 
131
  def _missing(s, intent_cfg):
132
+ return [p["name"] for p in intent_cfg["parameters"]
133
+ if p["variable_name"] not in s.variables]
134
 
135
  async def _handle_intent(s, intent_cfg, user_msg):
136
  missing = _missing(s, intent_cfg)
137
  if missing:
138
  p_prompt = build_parameter_prompt(intent_cfg, missing, user_msg, s.history)
139
+ p_out = await spark_generate(s, p_prompt, user_msg)
140
+ if p_out.startswith("#PARAMETERS:"):
141
+ if bad := _process_params(s, intent_cfg, p_out):
142
  return bad
143
  missing = _missing(s, intent_cfg)
144
+
145
  if missing:
146
  s.awaiting = {"intent": intent_cfg, "missing": missing}
147
  cap = next(p for p in intent_cfg["parameters"] if p["name"] == missing[0])["caption"]
148
  return f"{cap} nedir?"
149
+
150
  s.awaiting = None
151
  return await _call_api(s, intent_cfg)
152
 
 
154
  intent_cfg = s.awaiting["intent"]
155
  missing = s.awaiting["missing"]
156
  p_prompt = build_parameter_prompt(intent_cfg, missing, user_msg, s.history)
157
+ p_out = await spark_generate(s, p_prompt, user_msg)
158
+ if not p_out.startswith("#PARAMETERS:"):
159
  return "Üzgünüm, anlayamadım."
160
+ if bad := _process_params(s, intent_cfg, p_out):
161
  return bad
162
+
163
  missing = _missing(s, intent_cfg)
164
  if missing:
165
  s.awaiting["missing"] = missing
166
  cap = next(p for p in intent_cfg["parameters"] if p["name"] == missing[0])["caption"]
167
  return f"{cap} nedir?"
168
+
169
  s.awaiting = None
170
  return await _call_api(s, intent_cfg)
171
 
172
+ def _process_params(s, intent_cfg, p_out):
173
  try:
174
+ data = json.loads(p_out[len("#PARAMETERS:"):])
175
  except json.JSONDecodeError:
176
  return "Parametreleri çözemedim."
177
  for pair in data.get("extracted", []):
 
201
  except Exception:
202
  return intent_cfg["fallback_error_prompt"]
203
 
204
+ summary_prompt = api["response_prompt"].replace(
205
  "{{api_response}}", json.dumps(api_json, ensure_ascii=False)
206
  )
207
+ return await spark_generate(s, summary_prompt, "")