Doleeee commited on
Commit
889ca74
ยท
1 Parent(s): cfe6a99

Reflect changes to gradio_app.py

Browse files
api_server.py CHANGED
@@ -83,23 +83,110 @@ sys.stdout = _stdout_proxy
83
 
84
  class PersonaRequest(BaseModel):
85
  info: str
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
86
 
87
 
88
  @app.post("/persona/")
89
  async def create_persona(request: PersonaRequest):
90
  info = (request.info or "").strip()
 
 
91
  if not info:
92
  return JSONResponse(status_code=400, content={"error": "info ํ•„๋“œ๊ฐ€ ๋น„์–ด ์žˆ์Šต๋‹ˆ๋‹ค."})
93
 
94
- try:
95
- persona = make_persona(info)
96
- except Exception as exc:
97
- return JSONResponse(status_code=500, content={"error": str(exc)})
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
98
 
99
- if persona is None:
100
- return JSONResponse(status_code=500, content={"error": "ํŽ˜๋ฅด์†Œ๋‚˜ ์ƒ์„ฑ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค."})
 
 
 
 
 
 
 
101
 
102
- return JSONResponse(content=persona.model_dump())
 
 
 
 
 
103
 
104
  class QueryRequest(BaseModel):
105
  query: str
 
83
 
84
  class PersonaRequest(BaseModel):
85
  info: str
86
+ stream: bool = True
87
+
88
+
89
+ PERSONA_STATUS_MESSAGES = [
90
+ "์ธ๋ฌผ ์ •๋ณด ์ˆ˜์ง‘ ์ค‘...",
91
+ "์›น ๊ฒ€์ƒ‰์„ ํ†ตํ•ด ๋ฐฐ๊ฒฝ ์กฐ์‚ฌ ์ค‘...",
92
+ "๊ธˆ์œต ์‚ฌ๊ณ  ๋ฐฉ์‹ ๋ถ„์„ ์ค‘...",
93
+ "๋ฐ์ดํ„ฐ ๋ถ„์„ ์ ‘๊ทผ๋ฒ• ํ‰๊ฐ€ ์ค‘...",
94
+ "๋‹ต๋ณ€ ์Šคํƒ€์ผ ํŠน์„ฑ ํŒŒ์•… ์ค‘...",
95
+ "ํ•ต์‹ฌ ํˆฌ์ž ์›์น™ ์ถ”์ถœ ์ค‘...",
96
+ "๋Œ€ํ‘œ ์–ด๋ก ์ •๋ฆฌ ์ค‘...",
97
+ "ํŽ˜๋ฅด์†Œ๋‚˜ ํ”„๋กœํ•„ ๊ตฌ์„ฑ ์ค‘...",
98
+ "์ตœ์ข… ๊ฒ€์ฆ ๋ฐ ์ €์žฅ ์ค€๋น„ ์ค‘...",
99
+ ]
100
+
101
+
102
+ def _build_persona_payload(persona) -> dict:
103
+ return {
104
+ "type": "result",
105
+ "name": persona.name,
106
+ "full_name": persona.full_name,
107
+ "summary": persona.summary,
108
+ "financial_mindset": persona.financial_mindset,
109
+ "data_analysis_approach": persona.data_analysis_approach,
110
+ "response_style": persona.response_style,
111
+ "key_principles": persona.key_principles,
112
+ "famous_quotes": getattr(persona, "famous_quotes", None),
113
+ }
114
 
115
 
116
  @app.post("/persona/")
117
  async def create_persona(request: PersonaRequest):
118
  info = (request.info or "").strip()
119
+ stream = request.stream
120
+
121
  if not info:
122
  return JSONResponse(status_code=400, content={"error": "info ํ•„๋“œ๊ฐ€ ๋น„์–ด ์žˆ์Šต๋‹ˆ๋‹ค."})
123
 
124
+ if not stream:
125
+ try:
126
+ persona = make_persona(info)
127
+ except Exception as exc:
128
+ return JSONResponse(status_code=500, content={"error": str(exc)})
129
+
130
+ if persona is None:
131
+ return JSONResponse(status_code=500, content={"error": "ํŽ˜๋ฅด์†Œ๋‚˜ ์ƒ์„ฑ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค."})
132
+
133
+ return JSONResponse(content=persona.model_dump())
134
+
135
+ def event_stream():
136
+ event_queue: Queue = Queue()
137
+
138
+ def status_sender():
139
+ import asyncio
140
+
141
+ async def send_status():
142
+ for i, message in enumerate(PERSONA_STATUS_MESSAGES[:-1]): # ๋งˆ์ง€๋ง‰ ๋ฉ”์‹œ์ง€๋Š” ์™„๋ฃŒ ์‹œ์ ์— ์‚ฌ์šฉ
143
+ event_queue.put({"type": "status", "message": message})
144
+ await asyncio.sleep(7)
145
+
146
+ # ๋น„๋™๊ธฐ ์ด๋ฒคํŠธ ๋ฃจํ”„์—์„œ ์‹คํ–‰
147
+ loop = asyncio.new_event_loop()
148
+ asyncio.set_event_loop(loop)
149
+ loop.run_until_complete(send_status())
150
+
151
+ def worker():
152
+ thread_id = threading.get_ident()
153
+ _stdout_proxy.register(thread_id, _QueueingStdoutTee(_stdout_proxy._target, event_queue))
154
+ try:
155
+ # status ๋ฉ”์‹œ์ง€ ์ „์†ก ์Šค๋ ˆ๋“œ ์‹œ์ž‘
156
+ status_thread = Thread(target=status_sender, daemon=True)
157
+ status_thread.start()
158
+
159
+ persona = make_persona(info)
160
+
161
+ if persona is None:
162
+ event_queue.put({"type": "error", "message": "ํŽ˜๋ฅด์†Œ๋‚˜ ์ƒ์„ฑ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค."})
163
+ else:
164
+ event_queue.put(_build_persona_payload(persona))
165
+ except Exception as exc:
166
+ event_queue.put({"type": "error", "message": str(exc)})
167
+ finally:
168
+ _stdout_proxy.unregister(thread_id)
169
+ event_queue.put({"type": "done"})
170
+
171
+ yield _sse({"type": "status", "message": "ํŽ˜๋ฅด์†Œ๋‚˜ ์ƒ์„ฑ ์ค€๋น„ ์ค‘..."})
172
+ Thread(target=worker, daemon=True).start()
173
 
174
+ done = False
175
+ while not done:
176
+ try:
177
+ event = event_queue.get(timeout=0.2)
178
+ except Empty:
179
+ continue
180
+ yield _sse(jsonable_encoder(event))
181
+ if event.get("type") == "done":
182
+ done = True
183
 
184
+ headers = {
185
+ "Cache-Control": "no-cache",
186
+ "Connection": "keep-alive",
187
+ "X-Accel-Buffering": "no",
188
+ }
189
+ return StreamingResponse(event_stream(), media_type="text/event-stream", headers=headers)
190
 
191
  class QueryRequest(BaseModel):
192
  query: str
llm/generator.py CHANGED
@@ -62,7 +62,7 @@ def generate_news_info(client, user_query, intent):
62
  class Persona(BaseModel):
63
  name: str # ์ธ๋ฌผ ์ด๋ฆ„
64
  full_name: str # ์ธ๋ฌผ ์ด๋ฆ„
65
- background: str # ์ธ๋ฌผ ๋ฐฐ๊ฒฝ (๊ฒฝ๋ ฅ, ์ฃผ์š” ์—…์  ๋“ฑ)
66
  financial_mindset: str # ๊ธˆ์œต ์‚ฌ๊ณ  ๋ฐฉ์‹
67
  data_analysis_approach: str # ๋ฐ์ดํ„ฐ ๋ถ„์„ ๋ฐฉ์‹
68
  response_style: str # ์งˆ๋ฌธ์— ๋Œ€ํ•œ ๋‹ต๋ณ€ ์Šคํƒ€์ผ
@@ -76,6 +76,7 @@ def generate_persona(client, user_query):
76
  "- full_name: ์ธ๋ฌผ์˜ ์›๋ฌธ/์ •์‹ ์ „์ฒด ์ด๋ฆ„.\n"
77
  "- name: ์‚ฌ์šฉ์ž๊ฐ€ ์ดํ•ดํ•˜๊ธฐ ์‰ฌ์šด ํ‘œ์‹œ ์ด๋ฆ„(ํ•œ๊ตญ์–ด ํ†ต์šฉ๋ช… ์šฐ์„ , ์—†์œผ๋ฉด ๊ฐ„๊ฒฐํ•œ ์˜์–ด).\n"
78
  "- ๊ด„ํ˜ธ ๋ณ„์นญ/์›๋ฌธ ๋ณ‘๊ธฐ๋Š” full_name์—๋งŒ ํฌํ•จํ•˜๊ณ  name์—๋Š” ๋„ฃ์ง€ ๋ง ๊ฒƒ.\n"
 
79
  "๋‚˜๋จธ์ง€ ํ•„๋“œ๋Š” ์‚ฌ์‹ค ๊ธฐ๋ฐ˜์œผ๋กœ ์ถฉ์‹คํžˆ ์ž‘์„ฑํ•˜์‹œ์˜ค."
80
  )
81
 
@@ -123,7 +124,7 @@ def build_full_prompt(user_query, context, intent, persona=None):
123
 
124
  [์„ ํƒ๋œ ํŽ˜๋ฅด์†Œ๋‚˜]
125
  ์ด๋ฆ„: {persona.name}
126
- ๋ฐฐ๊ฒฝ: {persona.background}
127
  ๊ธˆ์œต ์‚ฌ๊ณ ๋ฐฉ์‹: {persona.financial_mindset}
128
  ๋ฐ์ดํ„ฐ ๋ถ„์„ ๋ฐฉ์‹: {persona.data_analysis_approach}
129
  ๋‹ต๋ณ€ ์Šคํƒ€์ผ: {persona.response_style}
 
62
  class Persona(BaseModel):
63
  name: str # ์ธ๋ฌผ ์ด๋ฆ„
64
  full_name: str # ์ธ๋ฌผ ์ด๋ฆ„
65
+ summary: str # ์ธ๋ฌผ ์š”์•ฝ (๊ฐ„๋‹จํ•œ ์†Œ๊ฐœ)
66
  financial_mindset: str # ๊ธˆ์œต ์‚ฌ๊ณ  ๋ฐฉ์‹
67
  data_analysis_approach: str # ๋ฐ์ดํ„ฐ ๋ถ„์„ ๋ฐฉ์‹
68
  response_style: str # ์งˆ๋ฌธ์— ๋Œ€ํ•œ ๋‹ต๋ณ€ ์Šคํƒ€์ผ
 
76
  "- full_name: ์ธ๋ฌผ์˜ ์›๋ฌธ/์ •์‹ ์ „์ฒด ์ด๋ฆ„.\n"
77
  "- name: ์‚ฌ์šฉ์ž๊ฐ€ ์ดํ•ดํ•˜๊ธฐ ์‰ฌ์šด ํ‘œ์‹œ ์ด๋ฆ„(ํ•œ๊ตญ์–ด ํ†ต์šฉ๋ช… ์šฐ์„ , ์—†์œผ๋ฉด ๊ฐ„๊ฒฐํ•œ ์˜์–ด).\n"
78
  "- ๊ด„ํ˜ธ ๋ณ„์นญ/์›๋ฌธ ๋ณ‘๊ธฐ๋Š” full_name์—๋งŒ ํฌํ•จํ•˜๊ณ  name์—๋Š” ๋„ฃ์ง€ ๋ง ๊ฒƒ.\n"
79
+ "- summary: ์ธ๋ฌผ์˜ ๊ฐ„๋‹จํ•œ ์†Œ๊ฐœ ์š”์•ฝ (2-3๋ฌธ์žฅ ์ •๋„๋กœ ๊ฐ„๊ฒฐํ•˜๊ฒŒ).\n"
80
  "๋‚˜๋จธ์ง€ ํ•„๋“œ๋Š” ์‚ฌ์‹ค ๊ธฐ๋ฐ˜์œผ๋กœ ์ถฉ์‹คํžˆ ์ž‘์„ฑํ•˜์‹œ์˜ค."
81
  )
82
 
 
124
 
125
  [์„ ํƒ๋œ ํŽ˜๋ฅด์†Œ๋‚˜]
126
  ์ด๋ฆ„: {persona.name}
127
+ ์š”์•ฝ: {persona.summary}
128
  ๊ธˆ์œต ์‚ฌ๊ณ ๋ฐฉ์‹: {persona.financial_mindset}
129
  ๋ฐ์ดํ„ฐ ๋ถ„์„ ๋ฐฉ์‹: {persona.data_analysis_approach}
130
  ๋‹ต๋ณ€ ์Šคํƒ€์ผ: {persona.response_style}
persona/make_persona.py CHANGED
@@ -68,13 +68,13 @@ def save_persona_jsonl(persona, query, file_name=None):
68
  def print_persona(persona):
69
  print("\n[Persona ์ƒ์„ฑ ๊ฒฐ๊ณผ]")
70
  print(f"- ์ด๋ฆ„: {persona.name}")
71
- print(f"- ๋ฐฐ๊ฒฝ: {persona.background}")
72
  print(f"- ๊ธˆ์œต ์‚ฌ๊ณ  ๋ฐฉ์‹: {persona.financial_mindset}")
73
  print(f"- ๋ฐ์ดํ„ฐ ๋ถ„์„ ๋ฐฉ์‹: {persona.data_analysis_approach}")
74
  print(f"- ๋‹ต๋ณ€ ์Šคํƒ€์ผ: {persona.response_style}")
75
- print(f"- ํ•ต์‹ฌ ์›์น™: {', '.join(persona.key_principles)}")
76
  if getattr(persona, "famous_quotes", None):
77
- print(f"- ์–ด๋ก: {', '.join(persona.famous_quotes)}")
78
 
79
 
80
  def make_persona(info):
 
68
  def print_persona(persona):
69
  print("\n[Persona ์ƒ์„ฑ ๊ฒฐ๊ณผ]")
70
  print(f"- ์ด๋ฆ„: {persona.name}")
71
+ print(f"- ์š”์•ฝ: {persona.summary}")
72
  print(f"- ๊ธˆ์œต ์‚ฌ๊ณ  ๋ฐฉ์‹: {persona.financial_mindset}")
73
  print(f"- ๋ฐ์ดํ„ฐ ๋ถ„์„ ๋ฐฉ์‹: {persona.data_analysis_approach}")
74
  print(f"- ๋‹ต๋ณ€ ์Šคํƒ€์ผ: {persona.response_style}")
75
+ print(f"- ํ•ต์‹ฌ ์›์น™: {', '.join(persona.key_principles)}", flush=True)
76
  if getattr(persona, "famous_quotes", None):
77
+ print(f"- ์–ด๋ก: {', '.join(persona.famous_quotes)}", flush=True)
78
 
79
 
80
  def make_persona(info):
persona/persona_loader.py CHANGED
@@ -13,6 +13,10 @@ def load_personas():
13
  line = line.strip()
14
  if line:
15
  data = json.loads(line)
 
 
 
 
16
  # full_name ์—†์œผ๋ฉด name ์‚ฌ์šฉํ•˜์—ฌ ์ฑ„์›€
17
  if isinstance(data, dict) and not data.get("full_name"):
18
  data["full_name"] = data.get("name", "")
 
13
  line = line.strip()
14
  if line:
15
  data = json.loads(line)
16
+ # ํ˜ธํ™˜์„ฑ: background ํ•„๋“œ๊ฐ€ ์žˆ์œผ๋ฉด summary๋กœ ๋งคํ•‘
17
+ if isinstance(data, dict) and "background" in data and "summary" not in data:
18
+ data["summary"] = data["background"]
19
+ # background ํ•„๋“œ๋Š” ์ œ๊ฑฐํ•˜์ง€ ์•Š๊ณ  ์œ ์ง€ (ํ˜ธํ™˜์„ฑ)
20
  # full_name ์—†์œผ๋ฉด name ์‚ฌ์šฉํ•˜์—ฌ ์ฑ„์›€
21
  if isinstance(data, dict) and not data.get("full_name"):
22
  data["full_name"] = data.get("name", "")