Chatbot / app.py
brignt's picture
Update app.py
a567730 verified
raw
history blame contribute delete
11 kB
import os
import openai
import gradio as gr
import pandas as pd
import numpy as np
from sentence_transformers import SentenceTransformer
from sklearn.metrics.pairwise import cosine_similarity
# OpenAI API Key (Hugging Face Secrets)
openai.api_key = os.getenv("OPENAI_API_KEY", "")
# =============== 0) ๋ชจ๋ธ / df ์ค€๋น„ ===============
# SentenceTransformer
model = SentenceTransformer('jhgan/ko-sroberta-multitask')
# ์ •์‹ ์˜ํ•™์ฑ—๋ด‡ CSV ๋กœ๋“œ
df = pd.read_csv('https://raw.githubusercontent.com/kairess/mental-health-chatbot/master/wellness_dataset_original.csv')
df = df.dropna()
# Unnamed ์ปฌ๋Ÿผ ์ œ๊ฑฐ
if 'Unnamed: 3' in df.columns:
df = df.drop(columns=['Unnamed: 3'])
# ์ž„๋ฒ ๋”ฉ ํ•„๋“œ
df['embedding'] = df['์œ ์ €'].map(lambda x: model.encode(str(x)))
# ============== 1) ํŒŒ๋ผ๋ฏธํ„ฐ/ํ”„๋กฌํ”„ํŠธ ==============
MAX_TURN = 5 # ์ตœ๋Œ€ ์†Œํฌ๋ผํ…Œ์Šค ์งˆ๋ฌธ ํšŒ์ˆ˜
def set_openai_model():
"""
GPT-4 ๋Œ€์‹  'gpt-4o' (์‹ค์ œ๋ก  ๋น„์กด์žฌ ๋ชจ๋ธ)
=> ์‹ค์ œ๋กœ๋Š” 'gpt-3.5-turbo' ๋“ฑ์œผ๋กœ ๊ต์ฒด ๊ถŒ์žฅ
"""
return "gpt-4o"
EMPATHY_PROMPT = """\
๋‹น์‹ ์€ ์นœ์ ˆํ•œ ์ •์‹ ์˜ํ•™๊ณผ ์ „๋ฌธ์˜์ด๋ฉฐ ์‹ฌ๋ฆฌ์ƒ๋‹ด ์ „๋ฌธ๊ฐ€์ž…๋‹ˆ๋‹ค.
์‚ฌ์šฉ์ž์˜ ๋ฌธ์žฅ์„ ๊ฑฐ์˜ ๊ทธ๋Œ€๋กœ ์š”์•ฝํ•˜๋˜, ๋์— '๋Š”๊ตฐ์š”.' ๊ฐ™์€ ๊ณต๊ฐ ์–ด๋ฏธ๋กœ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์‘๋‹ตํ•˜๊ณ ,
๊ทธ ๋‹ค์Œ ์ค„์— ํ•œ ๋ฌธ์žฅ์œผ๋กœ ์งˆ๋ฌธ์„ ์ž‘์„ฑํ•˜์„ธ์š”.
์œ ์˜์‚ฌํ•ญ:
1) ์ฒซ ๋ฌธ์žฅ์€ ๊ณต๊ฐํ˜• ์š”์•ฝ (์˜ˆ: "์‹œํ—˜์„ ์•ž๋‘๊ณ  ๋ถˆ์•ˆํ•ด์„œ ๋ฉฐ์น ์งธ ์ž ์„ ๋ชป ์ž๊ณ  ๊ณ„์‹œ๋Š”๊ตฐ์š”.")
2) ๋‘ ๋ฒˆ์งธ ๋ฌธ์žฅ์€ ํƒ์ƒ‰/์œ ๋„ ์งˆ๋ฌธ
- ์˜ˆ: "์–ด๋–ค ๊ณ ๋ฏผ๋“ค์ด ๋ฐค์— ๊ฐ€์žฅ ๋งŽ์ด ๋– ์˜ค๋ฅด์‹œ๋‚˜์š”?"
(์˜ˆ์‹œ)
์‚ฌ์šฉ์ž: "์‹œํ—˜์„ ์•ž๋‘๊ณ  ๋ถˆ์•ˆํ•ด์„œ ๋ฉฐ์น ์งธ ์ž ์ด ์•ˆ ์™€์š”."
์ฑ—๋ด‡:
"์‹œํ—˜์„ ์•ž๋‘๊ณ  ๋ถˆ์•ˆํ•ด์„œ ๋ฉฐ์น ์งธ ์ž ์„ ๋ชป ์ž๊ณ  ๊ณ„์‹œ๋Š”๊ตฐ์š”.
์‹œํ—˜ ๊ธฐ๊ฐ„์ด ๋‹ค๊ฐ€์˜ฌ ๋•Œ ๊ฐ€์žฅ ํž˜๋“œ์‹  ๋ถ€๋ถ„์€ ๋ฌด์—‡์ธ๊ฐ€์š”?"
์ด์ œ ์‚ฌ์šฉ์ž ๋ฐœํ™”๋ฅผ ์•„๋ž˜์— ์ฃผ๊ฒ ์Šต๋‹ˆ๋‹ค:
์‚ฌ์šฉ์ž ๋ฐœํ™”: "{sentence}"
์ฑ—๋ด‡:
"""
SOCRATIC_PROMPT = """\
๋‹น์‹ ์€ ์ •์‹ ์˜ํ•™๊ณผ ์ „๋ฌธ์˜์ด๋ฉฐ Socratic CBT ๊ธฐ๋ฒ•์„ ์‚ฌ์šฉํ•˜๋Š” ์‹ฌ๋ฆฌ์ƒ๋‹ด ์ „๋ฌธ๊ฐ€์ž…๋‹ˆ๋‹ค.
์•„๋ž˜ '๋Œ€ํ™” ํžŒํŠธ'์—๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ์ง์ „๊นŒ์ง€ ์ด์•ผ๊ธฐํ•œ ์ƒํ™ฉ์ด๋‚˜ ๊ณ ๋ฏผ์ด ์š”์•ฝ๋˜์–ด ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ฉ๋‹ˆ๋‹ค.
์ด ๋‚ด์šฉ์— **๊ณต๊ฐ**์„ ํ‘œ์‹œํ•œ ๋’ค, ๊ทธ ํ๋ฆ„์„ ์ด์–ด๋ฐ›์•„ **์ž์—ฐ์Šค๋Ÿฝ๊ณ  ๊ตฌ์ฒด์ ์ธ ํ›„์† ์งˆ๋ฌธ**์„ ํ•œ ๋ฌธ์žฅ์œผ๋กœ ์ž‘์„ฑํ•˜์„ธ์š”.
**์„ธ๋ถ€ ์ง€์นจ**:
1) ์ฒซ ๋ฌธ์žฅ์€ ์‚ฌ์šฉ์ž์˜ ์ƒํ™ฉ์„ ๊ฐ„๋‹จํžˆ ๊ณต๊ฐํ•ด ์ฃผ๋˜, ๋์— '๋Š”๊ตฐ์š”.' ๋“ฑ์˜ ์–ด๋ฏธ๋กœ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๋งˆ๋ฌด๋ฆฌํ•˜์„ธ์š”.
- ์˜ˆ: "์‹œํ—˜ ๊ธฐ๊ฐ„ ๋™์•ˆ ์ •๋ง ๋งŽ์€ ๋ถ€๋‹ด์„ ๋А๋ผ๊ณ  ๊ณ„์‹œ๋Š”๊ตฐ์š”."
2) ๋‘ ๋ฒˆ์งธ ๋ฌธ์žฅ์€ ํƒ์ƒ‰/์œ ๋„ ์งˆ๋ฌธ์„ ๋”ฑ ํ•œ ๋ฌธ์žฅ์œผ๋กœ ์ž‘์„ฑํ•˜์„ธ์š”.
- '์งˆ๋ฌธ:' ๊ฐ™์€ ์ ‘๋‘์–ด๋Š” ์“ฐ์ง€ ๋ง๊ณ , ๋ฐ”๋กœ ๋ฌธ์žฅ์œผ๋กœ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค.
- ๋ฐ˜๋“œ์‹œ ๋ฌผ์Œํ‘œ๋กœ ๋๋‚˜์•ผ ํ•ฉ๋‹ˆ๋‹ค (์˜ˆ: "...์–ด๋–ค ๊ฒƒ๋“ค์ด ๊ฐ€์žฅ ํž˜๋“œ์…จ๋‚˜์š”?").
3) ์งˆ๋ฌธ์€ ์‚ฌ์šฉ์ž์˜ ํ˜„์žฌ ๊ณ ๋ฏผ๊ณผ ์ง์ ‘์ ์œผ๋กœ ์—ฐ๊ฒฐ๋˜์–ด, ์‹ฌ์ธต์ ์ธ ์ž๊ธฐ ํƒ์ƒ‰์„ ์œ ๋„ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
- ์˜ˆ: "๋ฐค์— ๋“ค๋ ค์˜ค๋Š” ์–ด๋–ค ์ƒ๊ฐ๋“ค์ด ์ž ์„ ๋” ์„ค์น˜๊ฒŒ ๋งŒ๋“œ๋Š”์ง€ ํ˜น์‹œ ๋– ์˜ค๋ฅด์‹œ๋‚˜์š”?"
4) Bullet Point๋‚˜ ๋ชฉ๋ก ๋Œ€์‹ , ๊ฐ„๋‹จํžˆ ๋‘ ์ค„(๊ณต๊ฐ + ์งˆ๋ฌธ) ๊ตฌ์กฐ๋กœ ์ž‘์„ฑํ•˜๋˜, ๋„ˆ๋ฌด ๊ธธ๊ฒŒ ์“ฐ์ง€ ๋ง๊ณ  ๋ถ€๋“œ๋Ÿฌ์šด ํ†ค์„ ์œ ์ง€ํ•˜์„ธ์š”.
(์˜ˆ์‹œ)
์‚ฌ์šฉ์ž ๋ฐœํ™”: "๋‚จํŽธ์ด ๋น„ํŠธ์ฝ”์ธ ํˆฌ์ž๋กœ ์†์„ ์ฉ์ด๋„ค"
์ฑ—๋ด‡:
"๋‚จํŽธ๋ถ„์˜ ํˆฌ์ž ๋ฌธ์ œ๋กœ ์†์ด ๋งŽ์ด ์ƒํ•˜์‹œ๋Š”๊ตฐ์š”.
ํ˜น์‹œ ๊ทธ๋กœ ์ธํ•ด ๊ฐ€์žฅ ํž˜๋“ค๋‹ค๊ณ  ๋А๋ผ๋Š” ๋ถ€๋ถ„์€ ๋ฌด์—‡์ธ๊ฐ€์š”?"
์ด์ œ ์•„๋ž˜ '๋Œ€ํ™” ํžŒํŠธ'๋ฅผ ์ฐธ์กฐํ•˜์—ฌ, 1์ค„ ๊ณต๊ฐ + 1์ค„ ์งˆ๋ฌธ ๋‘ ์ค„๋กœ ๋‹ต๋ณ€ํ•ด ์ฃผ์„ธ์š”.
๋Œ€ํ™” ํžŒํŠธ:
{context}
"""
ADVICE_PROMPT = """\
๋‹น์‹ ์€ ์ •์‹ ์˜ํ•™๊ณผ ์ „๋ฌธ์˜์ด๋ฉฐ Socratic CBT ๊ธฐ๋ฒ•์„ ์‚ฌ์šฉํ•˜๋Š” ์‹ฌ๋ฆฌ์ƒ๋‹ด ์ „๋ฌธ๊ฐ€์ž…๋‹ˆ๋‹ค.
์•„๋ž˜ ํžŒํŠธ(๋Œ€ํ™” ์š”์•ฝ)์™€ ํ•จ๊ป˜, ๋‹ค์Œ์— ์ œ์‹œ๋œ 5๊ฐ€์ง€ CBT ๊ธฐ๋ฒ•์„ ์ ์ ˆํžˆ ์ฐธ๊ณ ํ•˜์—ฌ,
์‚ฌ์šฉ์ž ๋งž์ถคํ˜•์œผ๋กœ ๊ตฌ์ฒด์ ์ด๊ณ  ๊ณต๊ฐ ์–ด๋ฆฐ ์กฐ์–ธ์„ ํ•œ๊ตญ์–ด๋กœ ์ž‘์„ฑํ•˜์„ธ์š”:
(1) ์ˆ˜๋ฉด ์ œํ•œ ์š”๋ฒ• (Sleep Restriction):
"์ˆ˜๋ฉด ์ œํ•œ ์š”๋ฒ•์€ ์นจ๋Œ€์— ๋จธ๋ฌด๋Š” ์‹œ๊ฐ„์„ ์˜๋„์ ์œผ๋กœ ์ค„์—ฌ, ์นจ๋Œ€์™€ ์ˆ˜๋ฉด ์‚ฌ์ด์˜ ์˜ฌ๋ฐ”๋ฅธ ์—ฐ๊ฒฐ๊ณ ๋ฆฌ๋ฅผ ์žฌ๊ตฌ์ถ•ํ•˜๋Š” ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.
์˜ˆ๋ฅผ ๋“ค์–ด, ์นจ๋Œ€์— 10์‹œ๊ฐ„ ๋จธ๋ฌผ์ง€๋งŒ ์‹ค์ œ ์ˆ˜๋ฉด ์‹œ๊ฐ„์ด 5์‹œ๊ฐ„์ธ ๊ฒฝ์šฐ, ์ฒ˜์Œ์—๋Š” 5์‹œ๊ฐ„๋งŒ ์นจ๋Œ€์—์„œ ์ž๊ณ  ์ ์ฐจ ์‹œ๊ฐ„์„ ๋Š˜๋ ค๊ฐ€๋ฉฐ
'์นจ๋Œ€๋Š” ์ˆ˜๋ฉด์„ ์œ„ํ•œ ์žฅ์†Œ'๋กœ ์ธ์‹ํ•˜๋„๋ก ๋•์Šต๋‹ˆ๋‹ค."
(2) ์ž๊ทน ์กฐ์ ˆ ์š”๋ฒ• (Stimulus Control):
"์ž๊ทน ์กฐ์ ˆ ์š”๋ฒ•์€ ์นจ๋Œ€์™€ ์ˆ˜๋ฉด์˜ ํ™˜๊ฒฝ์„ ์žฌ์ •๋ฆฝํ•˜๋ฉฐ, ์นจ๋Œ€๋ฅผ ์˜ค์ง ์ˆ˜๋ฉด๋งŒ์„ ์œ„ํ•œ ์žฅ์†Œ๋กœ ์ธ์‹ํ•˜๊ฒŒ ๋งŒ๋“œ๋Š” ์น˜๋ฃŒ๋ฒ•์ž…๋‹ˆ๋‹ค.
์˜ˆ๋ฅผ ๋“ค์–ด, ์นจ๋Œ€์— ๋ˆ„์›Œ ์žˆ์„ ๋•Œ๋Š” ์ฆ‰์‹œ ์ž ๋“ค์ง€ ๋ชปํ•˜๋”๋ผ๋„, ์นจ๋Œ€์—์„œ๋Š” ์˜ค์ง ์ˆ˜๋ฉด์„ ์ทจํ•˜๋Š” ์Šต๊ด€์„ ๊ธฐ๋ฅด๋Š” ๊ฒƒ์ด ํ•ต์‹ฌ์ž…๋‹ˆ๋‹ค."
(3) ์ˆ˜๋ฉด ์œ„์ƒ ๊ต์œก (Sleep Hygiene):
"์ˆ˜๋ฉด ์œ„์ƒ ๊ต์œก์€ ๊ฑด๊ฐ•ํ•œ ์ˆ˜๋ฉด์„ ์œ„ํ•ด ์ƒํ™œ ์Šต๊ด€์„ ๊ฐœ์„ ํ•˜๋Š” ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.
์นดํŽ˜์ธ ์„ญ์ทจ๋ฅผ ์ค„์ด๊ฑฐ๋‚˜ ๋Šฆ์€ ์‹œ๊ฐ„์˜ ์ „์ž๊ธฐ๊ธฐ ์‚ฌ์šฉยท๋ฐ์€ ์กฐ๋ช… ๋“ฑ์„ ํ”ผํ•˜๊ณ , ๋‚ฎ์—๋Š” ๊ฐ€๋ฒผ์šด ์šด๋™์„ ํ•ด๋‘๋Š” ๋“ฑ์˜ ์Šต๊ด€์„ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค."
(4) ์ด์™„ ๊ธฐ๋ฒ• (Relaxation Techniques):
"์ด์™„ ๊ธฐ๋ฒ•์€ ์‹ฌํ˜ธํก, ์ ์ง„์  ๊ทผ์œก์ด์™„, ๋ช…์ƒ ๊ฐ™์€ ๋ฐฉ๋ฒ•์„ ํ†ตํ•ด ์ž์—ฐ์Šค๋Ÿฌ์šด ์ˆ˜๋ฉด์„ ์œ ๋„ํ•˜๋Š” ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.
๋ชธ์„ ์Šค์บ”ํ•˜๊ณ , ๊ฑฐ๋ถํ•œ ์ŠคํŠธ๋ ˆ์นญ์„ ํ’€๊ณ , ๊ทผ์œก ์ด์™„์„ ์—ฐ์Šตํ•˜๋ฉฐ ๊ธด์žฅ์„ ๋‚ฎ์ถ”๋Š” ๊ฒƒ์ด ์ฃผ๋œ ๋ชฉํ‘œ์ž…๋‹ˆ๋‹ค."
(5) ์ธ์ง€ ์žฌ๊ตฌ์„ฑ (Cognitive Restructuring):
"์ธ์ง€ ์žฌ๊ตฌ์„ฑ์€ โ€˜์šฐ๋ฆฌ๊ฐ€ ์ƒํ™ฉ์„ ์–ด๋–ป๊ฒŒ ๋ฐ”๋ผ๋ณด๋А๋ƒ์— ๋”ฐ๋ผ ๋ชธ์˜ ๋ฐ˜์‘๋„ ๋‹ฌ๋ผ์งˆ ์ˆ˜ ์žˆ๋‹คโ€™๋Š” ๊ธ์ •์  ๊ด€์ ์œผ๋กœ ์ „ํ™˜์‹œํ‚ค๋ฉฐ,
๊ฑฑ์ •์ด๋‚˜ ๋ถˆ์•ˆ, ๋ถ€์ •์ ์ธ ์‚ฌ๊ณ  ํŒจํ„ด์„ ์ ๊ฒ€ยท์กฐ์ ˆํ•˜๋Š” ๊ธฐ๋ฒ•์ž…๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ์‚ฌ์šฉ์ž์˜ ๊ฑฑ์ •์„ ์™„ํ™”ํ•˜๊ณ 
์ž๊ธฐํšจ๋Šฅ๊ฐ์„ ๋†’์ด๋„๋ก ๋•์Šต๋‹ˆ๋‹ค."
์•„๋ž˜ ์‚ฌํ•ญ์„ ๊ผญ ๋ฐ˜์˜ํ•ด ์ฃผ์„ธ์š”:
- ๋ถˆ์•ˆ์„ ์™„ํ™”ํ•˜๊ธฐ ์œ„ํ•œ ์œ„ ๊ธฐ๋ฒ•๋“ค์„ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๋…น์ด๋˜, ์‚ฌ์šฉ์ž์˜ ํ˜„์žฌ ์ƒํ™ฉ(ํžŒํŠธ์— ๋‹ด๊ธด ๊ณ ๋ฏผ)๊ณผ ์—ฐ๊ฒฐํ•ด ์ด์•ผ๊ธฐํ•˜์„ธ์š”.
- ๋„ˆ๋ฌด ๋”ฑ๋”ฑํ•˜์ง€ ์•Š๊ฒŒ, ๋ถ€๋“œ๋Ÿฝ๊ณ  ์นœ์ ˆํ•œ ๋งํˆฌ๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”.
ํžŒํŠธ:
{hints}
์กฐ์–ธ:
"""
# ============== 2) OpenAI ํ˜ธ์ถœ ํ•จ์ˆ˜๋“ค ==============
def call_empathy(user_input: str) -> str:
""" ๊ณต๊ฐ ์š”์•ฝ ์ƒ์„ฑ """
prompt = EMPATHY_PROMPT.format(sentence=user_input)
resp = openai.ChatCompletion.create(
model=set_openai_model(),
messages=[
{"role":"system","content":"๋‹น์‹ ์€ ์นœ์ ˆํ•œ ์‹ฌ๋ฆฌ์ƒ๋‹ด ์ „๋ฌธ๊ฐ€์ž…๋‹ˆ๋‹ค."},
{"role":"user","content":prompt}
],
max_tokens=150,
temperature=0.7
)
return resp.choices[0].message.content.strip()
def call_socratic_question(context: str) -> str:
""" ์†Œํฌ๋ผํ…Œ์Šค ํ›„์†์งˆ๋ฌธ 1๋ฌธ์žฅ ์ƒ์„ฑ """
prompt = f"{SOCRATIC_PROMPT}\n\n๋Œ€ํ™” ํžŒํŠธ:\n{context}"
resp = openai.ChatCompletion.create(
model=set_openai_model(),
messages=[
{"role":"system","content":"๋‹น์‹ ์€ Socratic CBT ์ „๋ฌธ๊ฐ€์ž…๋‹ˆ๋‹ค."},
{"role":"user","content":prompt}
],
max_tokens=200,
temperature=0.7
)
return resp.choices[0].message.content.strip()
def call_advice(hints: str) -> str:
""" ์ตœ์ข… CBT ์กฐ์–ธ """
final_prompt = ADVICE_PROMPT.format(hints=hints)
resp = openai.ChatCompletion.create(
model=set_openai_model(),
messages=[
{"role":"system","content":"๋‹น์‹ ์€ Socratic CBT ๊ธฐ๋ฒ• ์ „๋ฌธ๊ฐ€์ž…๋‹ˆ๋‹ค."},
{"role":"user","content":final_prompt}
],
max_tokens=700,
temperature=0.8
)
return resp.choices[0].message.content.strip()
# ============== 3) predict ํ•จ์ˆ˜: EMPATHYโ†’SQโ†’ADVICE ==============
def predict(user_input: str, state: dict):
history = state.get("history", [])
stage = state.get("stage", "EMPATHY")
turn = state.get("turn", 0)
hints = state.get("hints", [])
# 1) ์‚ฌ์šฉ์ž ๋ฐœํ™” ๊ธฐ๋ก
history.append(("User", user_input))
# 2) ์œ ์‚ฌ๋„ ๊ณ„์‚ฐ โ†’ df['์ฑ—๋ด‡']
query_emb = model.encode(user_input)
df["sim"] = df["embedding"].map(lambda emb: cosine_similarity([query_emb],[emb]).squeeze())
# idxmax() ์—๋Ÿฌ ๋ฐฉ์ง€: df๊ฐ€ ๋น„์—ˆ๊ฑฐ๋‚˜ sim์ด NaN์ธ ๊ฒฝ์šฐ ์ฒ˜๋ฆฌ
if df["sim"].count() == 0:
# fallback: ๊ทธ๋ƒฅ "์ง€์‹๋ฒ ์ด์Šค๊ฐ€ ๋น„์–ด ์žˆ์Šต๋‹ˆ๋‹ค" ๋“ฑ
kb_answer = "์ ํ•ฉํ•œ ์ง€์‹๋ฒ ์ด์Šค ์‘๋‹ต์„ ์ฐพ์ง€ ๋ชปํ–ˆ์–ด์š”."
else:
kb_answer = df.loc[df["sim"].idxmax(), "์ฑ—๋ด‡"]
hints.append(f"[KB] {kb_answer}")
# 3) ๋‹จ๊ณ„๋ณ„ ๋ถ„๊ธฐ
if stage == "EMPATHY":
empathic = call_empathy(user_input)
history.append(("Chatbot", empathic))
hints.append(empathic)
stage = "SQ"
turn = 0
return history, {"history": history, "stage": stage, "turn": turn, "hints": hints}
if stage == "SQ" and turn < MAX_TURN:
# ์ „์ฒด ๋Œ€ํ™” + hints โ†’ ์†Œํฌ๋ผํ…Œ์Šค ์งˆ๋ฌธ
context_text = "\n".join([f"{r}: {c}" for (r,c) in history]) + "\n" + "\n".join(hints)
sq = call_socratic_question(context_text)
history.append(("Chatbot", sq))
hints.append(sq)
turn += 1
return history, {"history": history, "stage": stage, "turn": turn, "hints": hints}
# ADVICE ๋‹จ๊ณ„
stage = "END"
combined_hints = "\n".join(hints)
advice = call_advice(combined_hints)
history.append(("Chatbot", advice))
return history, {"history":history, "stage":stage, "turn":turn, "hints":hints}
# ============== 4) Gradio UI ==============
def gradio_predict(user_input, chat_state):
new_history, new_state = predict(user_input, chat_state)
# display_history: list of [์‚ฌ์šฉ์ž๋ฌธ์ž์—ด, ์ฑ—๋ด‡๋ฌธ์ž์—ด]
display_history = []
for (role, txt) in new_history:
if role == "User":
display_history.append([txt, ""])
else:
if len(display_history) == 0:
display_history.append(["", txt])
else:
display_history[-1][1] = txt
# ์„ธ ๋ฒˆ์งธ ๊ฐ’์œผ๋กœ "" ๋ฐ˜ํ™˜ํ•˜๋ฉด, textbox๊ฐ€ ์ž๋™์œผ๋กœ ๋น„์›Œ์ง
return display_history, new_state, ""
def create_app():
with gr.Blocks() as demo:
chatbot = gr.Chatbot()
chat_state = gr.State({"history": [], "stage": "EMPATHY", "turn": 0, "hints": []})
txt = gr.Textbox(show_label=False, placeholder="ํ˜น์‹œ ์ž ์„ ์ด๋ฃจ์ง€ ๋ชปํ•˜๊ณ  ๊ณ„์‹ ๊ฐ€์š”? ๋‹น์‹ ์˜ ์ด์•ผ๊ธฐ๋ฅผ ๋“ฃ๊ณ  ์‹ถ์–ด์š”! ๊ฑฑ์ •์ด ์žˆ์œผ์‹œ๋ฉด ํŽธํ•˜๊ฒŒ ๋ง์”€ํ•ด์ฃผ์„ธ์š” :D")
# outputs์— txt๋ฅผ ์ถ”๊ฐ€ + ์ฝœ๋ฐฑ์—์„œ ์„ธ ๋ฒˆ์งธ ๊ฐ’์„ ""๋กœ ๋ฆฌํ„ด
txt.submit(
fn=gradio_predict,
inputs=[txt, chat_state],
outputs=[chatbot, chat_state, txt]
)
return demo
app = create_app()
if __name__ == "__main__":
# ์‹ค์ œ ๋ฐฐํฌ/์‹คํ–‰
app.launch(debug=True, share=True)