gaeunseo commited on
Commit
1e50702
ยท
verified ยท
1 Parent(s): af3ed33

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +131 -111
app.py CHANGED
@@ -3,99 +3,124 @@ import gradio as gr
3
  import random
4
  import os
5
  import threading
6
- import pandas as pd
7
  from datasets import load_dataset
8
- from datasets import Dataset
9
- from huggingface_hub import HfApi, HfFolder
10
- from huggingface_hub import login
11
 
 
 
 
12
 
13
- # CSV ํŒŒ์ผ ๊ฒฝ๋กœ์™€ ๋™์‹œ ์ ‘๊ทผ์„ ์œ„ํ•œ Lock ์„ ์–ธ
14
- DATA_FILE = "global_data.csv"
15
- data_lock = threading.Lock()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
 
 
 
17
 
18
- def initialize_global_data():
 
 
 
 
19
  """
20
- DATA_FILE์ด ์กด์žฌํ•˜์ง€ ์•Š์œผ๋ฉด, gaeunseo/Taskmaster_sample_data ๋ฐ์ดํ„ฐ์…‹์„ ๋กœ๋“œํ•˜์—ฌ DataFrame์œผ๋กœ ๋ณ€ํ™˜ํ•œ ํ›„ CSV ํŒŒ์ผ๋กœ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.
21
- ์ด๋ฏธ ํŒŒ์ผ์ด ์žˆ์œผ๋ฉด ํŒŒ์ผ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ์–ด DataFrame์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
22
  """
23
- if not os.path.exists(DATA_FILE):
24
- ds = load_dataset("gaeunseo/Taskmaster_sample_data", split="train")
25
- data = ds.to_pandas()
26
- # ํ•„์š”ํ•œ ์ปฌ๋Ÿผ์ด ์—†์œผ๋ฉด ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
27
- if "used" not in data.columns:
28
- data["used"] = False
29
- if "overlapping" not in data.columns:
30
- data["overlapping"] = ""
31
- if "text" not in data.columns:
32
- data["text"] = ""
33
- data.to_csv(DATA_FILE, index=False)
34
- return data
35
- else:
36
- with data_lock:
37
- df = pd.read_csv(DATA_FILE)
38
- return df
 
 
 
 
 
39
 
40
- def load_global_data():
41
- """CSV ํŒŒ์ผ์—์„œ global_data DataFrame์„ ์ฝ์–ด์˜ต๋‹ˆ๋‹ค."""
42
- with data_lock:
43
- df = pd.read_csv(DATA_FILE)
44
- return df
45
 
46
- def save_global_data(df):
47
- """DataFrame์„ Interface1 ๋ฐ์ดํ„ฐ์…‹์— ์—…๋กœ๋“œํ•ฉ๋‹ˆ๋‹ค."""
48
- hf_token = os.getenv("HF_TOKEN")
49
- login(token=hf_token)
50
- dataset = Dataset.from_pandas(df)
51
- dataset.push_to_hub("gaeunseo/Taskmaster_sample_data")
52
-
53
- # CSV ํŒŒ์ผ์— ์ €์žฅ๋œ global_data ์ดˆ๊ธฐํ™”
54
- global_data = initialize_global_data()
55
 
56
  def get_random_row_from_dataset():
57
  """
58
- CSV ํŒŒ์ผ์— ์ €์žฅ๋œ global_data์—์„œ,
59
- 1. conversation_id๋ณ„๋กœ ๊ทธ๋ฃนํ™”ํ•˜๊ณ ,
60
- 2. ๊ฐ ๊ทธ๋ฃน์—์„œ ๋ชจ๋“  ํ–‰์˜ used ์ปฌ๋Ÿผ์ด False์ด๋ฉฐ, ๊ทธ๋ฃน ๋‚ด์— overlapping ์ปฌ๋Ÿผ์ด "TT"์ธ ํ–‰์ด ์กด์žฌํ•˜๋Š” ๊ทธ๋ฃน๋งŒ valid๋กœ ๊ฐ„์ฃผํ•ฉ๋‹ˆ๋‹ค.
61
- validํ•œ ๊ทธ๋ฃน๋“ค ์ค‘ ๋žœ๋คํ•˜๊ฒŒ ํ•˜๋‚˜์˜ ๊ทธ๋ฃน์„ ์„ ํƒํ•œ ํ›„,
62
- - ํ•ด๋‹น ๊ทธ๋ฃน์˜ ๋ชจ๋“  ํ–‰์˜ used ๊ฐ’์„ True๋กœ ์—…๋ฐ์ดํŠธ(์ฆ‰, ์ „์ฒด ๊ทธ๋ฃน์„ ํ• ๋‹น)ํ•˜๊ณ  CSV ํŒŒ์ผ์— ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.
63
- - ์„ ํƒ๋œ ๊ทธ๋ฃน ๋‚ด์—์„œ overlapping ์ปฌ๋Ÿผ์ด "TT"์ธ ํ–‰(์—ฌ๋Ÿฌ ๊ฐœ๋ผ๋ฉด ์ฒซ ๋ฒˆ์งธ)์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
64
  """
65
- global global_data
66
- global_data = load_global_data() # ์ตœ์‹  ๋ฐ์ดํ„ฐ ๋กœ๋“œ
67
- groups = global_data.groupby('conversation_id')
68
- valid_groups = []
69
- for cid, group in groups:
70
- # ๋ชจ๋“  ํ–‰์˜ used ๊ฐ’์ด False์ด๊ณ , ๊ทธ๋ฃน ๋‚ด์— overlapping ๊ฐ’์ด "TT"์ธ ํ–‰์ด ์žˆ๋Š” ๊ทธ๋ฃน ํ•„ํ„ฐ๋ง
71
- if group['used'].apply(lambda x: bool(x) == False).all() and (group['overlapping'] == "TT").any():
72
- valid_groups.append((cid, group))
73
- if not valid_groups:
74
- return None
75
- chosen_cid, chosen_group = random.choice(valid_groups)
76
- # ์ „์ฒด ๊ทธ๋ฃน์˜ used ๊ฐ’์„ True๋กœ ์—…๋ฐ์ดํŠธ
77
- global_data.loc[global_data['conversation_id'] == chosen_cid, 'used'] = True
78
- save_global_data(global_data)
79
- # ์„ ํƒ๋œ ๊ทธ๋ฃน ๋‚ด์—์„œ overlapping ์ปฌ๋Ÿผ์ด "TT"์ธ ํ–‰์„ ๋ฐ˜ํ™˜ (์—ฌ๋Ÿฌ ๊ฐœ๋ผ๋ฉด ์ฒซ ๋ฒˆ์งธ)
80
- chosen_rows = chosen_group[chosen_group['overlapping'] == "TT"]
81
- if chosen_rows.empty:
82
- return None
83
- chosen_row = chosen_rows.iloc[0]
84
- return chosen_row.to_dict()
 
 
 
85
 
86
- # --- ์ดˆ๊ธฐ ๋Œ€ํ™” ๋ถˆ๋Ÿฌ์˜ค๊ธฐ ---
87
- # ๋ฐ์ดํ„ฐ์…‹์˜ text ์ปฌ๋Ÿผ์€ "[turn]"์„ ๊ธฐ์ค€์œผ๋กœ ๋Œ€ํ™”๊ฐ€ ๊ตฌ๋ถ„๋˜์–ด ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ฉ๋‹ˆ๋‹ค.
88
- row = get_random_row_from_dataset()
89
- if row is None:
 
 
90
  human_message = "No valid conversation available."
91
  ai_message = "No valid conversation available."
92
  else:
93
- raw_text = row['text']
94
- human_message = raw_text.split("[turn]")[0].strip()
95
- ai_message = raw_text.split("[turn]")[1].strip()
96
 
97
  #############################################
98
- # ์ฑ„ํŒ… ์ธํ„ฐํŽ˜์ด์Šค ๊ด€๋ จ ํ•จ์ˆ˜ (๋งํ’์„ , ํƒ€์ดํ•‘ ํšจ๊ณผ, ํŽธ์ง‘ ๊ธฐ๋Šฅ)
99
  #############################################
100
 
101
  def get_initial_human_html():
@@ -124,47 +149,44 @@ def stream_human_message():
124
  bubble_end = "</div>"
125
  emoji_html = "<div class='emoji'>๐Ÿง‘</div>"
126
  wrapper_end = "</div>"
127
-
128
- # ์ดˆ๊ธฐ ์ƒํƒœ: ๋นˆ ๋งํ’์„ ๊ณผ ์ด๋ชจํ‹ฐ์ฝ˜
129
  yield wrapper_start + bubble_start + bubble_end + emoji_html + wrapper_end
130
-
131
- # human_message๋ฅผ ํ•œ ๊ธ€์ž์”ฉ ์ถ”๊ฐ€ (ํƒ€์ดํ•‘ ํšจ๊ณผ)
132
  for i, ch in enumerate(human_message):
133
- bubble_content += f"<span data-index='{i}'>{ch}</span>"
134
- current_html = wrapper_start + bubble_start + bubble_content + bubble_end + emoji_html + wrapper_end
135
- yield current_html
136
- time.sleep(0.05)
137
 
138
  def submit_edit(edited_text):
139
  """
140
  Submit ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ ํ˜ธ์ถœ๋˜๋Š” ํ•จ์ˆ˜.
141
- 1. ํŽธ์ง‘๋œ human ๋ฉ”์‹œ์ง€(โœ‚๏ธ ์•ž๋ถ€๋ถ„)๋ฅผ ์ƒˆ ํ–‰์œผ๋กœ global_data์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
142
  2. get_random_row_from_dataset()์„ ํ†ตํ•ด ์ƒˆ๋กœ์šด ๋Œ€ํ™”๋ฅผ ๊ฐ€์ ธ์˜ค๊ณ , ์ „์—ญ ๋ณ€์ˆ˜ human_message์™€ ai_message๋ฅผ ์—…๋ฐ์ดํŠธํ•ฉ๋‹ˆ๋‹ค.
143
  3. ์ดˆ๊ธฐ ์ƒํƒœ์˜ human ๋งํ’์„ ๊ณผ ai ๋งํ’์„  HTML์„ ๋ฐ˜ํ™˜ํ•˜์—ฌ ์ธํ„ฐํŽ˜๏ฟฝ๏ฟฝ์Šค๋ฅผ ๋ฆฌ์…‹ํ•ฉ๋‹ˆ๋‹ค.
144
  """
145
- global human_message, ai_message
146
- data = load_global_data()
147
- new_row = {
148
- "conversation_id": "edited_" + str(random.randint(1000, 9999)),
149
- "used": False,
150
- "overlapping": "",
151
- "text": edited_text,
152
- "human_message": edited_text,
153
- "ai_message": ""
154
- }
155
- new_df = pd.DataFrame([new_row])
156
- data = pd.concat([data, new_df], ignore_index=True)
157
- save_global_data(data)
158
-
159
- new_row_data = get_random_row_from_dataset()
160
- if new_row_data is None:
161
- human_message = "No valid conversation available."
162
- ai_message = "No valid conversation available."
163
- else:
164
- raw_text = new_row_data['text']
165
- human_message = raw_text.split("[turn]")[0].strip()
166
- ai_message = raw_text.split("[turn]")[1].strip()
167
-
 
168
  new_human_html = get_initial_human_html()
169
  new_ai_html = f"""
170
  <div class="ai-wrapper" style="display: flex; align-items: flex-end; justify-content: flex-start; gap: 5px; width: 100%;">
@@ -175,11 +197,11 @@ def submit_edit(edited_text):
175
  return new_human_html, new_ai_html
176
 
177
  #############################################
178
- # Gradio ์ธํ„ฐํŽ˜์ด์Šค ๊ตฌ์„ฑ
179
  #############################################
180
 
181
  with gr.Blocks() as demo:
182
- # (A) ํŽ˜์ด์ง€ ์ƒ๋‹จ ์Šคํฌ๋ฆฝํŠธ: Human ๋งํ’์„  ๋‚ด์˜ ๊ฐ <span data-index="...">๋ฅผ ํด๋ฆญํ•˜๋ฉด,
183
  # ํ•ด๋‹น ์œ„์น˜์— โœ‚๏ธ ์•„์ด์ฝ˜์ด ์‚ฝ์ž…๋˜๊ณ , ๊ทธ ์ดํ›„ ํ…์ŠคํŠธ๊ฐ€ ํšŒ์ƒ‰์œผ๋กœ ๋ณ€๊ฒฝ๋ฉ๋‹ˆ๋‹ค.
184
  gr.HTML(
185
  """
@@ -208,8 +230,7 @@ with gr.Blocks() as demo:
208
  </script>
209
  """
210
  )
211
-
212
- # (B) ์ถ”๊ฐ€ ์Šคํฌ๋ฆฝํŠธ: Submit ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ, human_message div์˜ innerText์—์„œ "โœ‚๏ธ"๋ฅผ ๊ธฐ์ค€์œผ๋กœ ํŽธ์ง‘๋œ ํ…์ŠคํŠธ(์•ž๋ถ€๋ถ„)๋ฅผ ์ˆจ๊น€ ํ…์ŠคํŠธ๋ฐ•์Šค์— ์—…๋ฐ์ดํŠธ
213
  gr.HTML(
214
  """
215
  <script>
@@ -228,7 +249,6 @@ with gr.Blocks() as demo:
228
  </script>
229
  """
230
  )
231
-
232
  # (C) CSS ์Šคํƒ€์ผ
233
  gr.HTML(
234
  """
 
3
  import random
4
  import os
5
  import threading
 
6
  from datasets import load_dataset
 
 
 
7
 
8
+ from sqlalchemy import create_engine, Column, Integer, String, Boolean, Text
9
+ from sqlalchemy.ext.declarative import declarative_base
10
+ from sqlalchemy.orm import sessionmaker
11
 
12
+ #############################################
13
+ # 1. SQLAlchemy ์„ค์ • ๋ฐ ๋ชจ๋ธ ์ •์˜
14
+ #############################################
15
+
16
+ DATABASE_URL = "mysql://root:0112@127.0.0.1:3306/Taskmaster_sample_data"
17
+
18
+ # SQLite์˜ ๋™์‹œ ์ ‘๊ทผ์„ ์œ„ํ•ด check_same_thread ์˜ต์…˜ ์„ค์ •
19
+ engine = create_engine(DATABASE_URL, connect_args={"check_same_thread": False})
20
+ SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
21
+ Base = declarative_base()
22
+
23
+ class Conversation(Base):
24
+ __tablename__ = "conversations"
25
+ id = Column(Integer, primary_key=True, index=True)
26
+ conversation_id = Column(String, index=True)
27
+ used = Column(Boolean, default=False)
28
+ overlapping = Column(String)
29
+ text = Column(Text)
30
+ human_message = Column(Text)
31
+ ai_message = Column(Text)
32
+
33
+ # ํ…Œ์ด๋ธ” ์ƒ์„ฑ
34
+ Base.metadata.create_all(bind=engine)
35
 
36
+ # ๋™์‹œ ์ ‘๊ทผ์„ ์œ„ํ•œ ์ „์—ญ ๋ฝ
37
+ db_lock = threading.Lock()
38
 
39
+ #############################################
40
+ # 2. ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ดˆ๊ธฐํ™” ํ•จ์ˆ˜
41
+ #############################################
42
+
43
+ def init_db():
44
  """
45
+ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ๋ฐ์ดํ„ฐ๊ฐ€ ์—†์œผ๋ฉด, Hugging Face ๋ฐ์ดํ„ฐ์…‹์„ ๋กœ๋“œํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์‚ฝ์ž…ํ•ฉ๋‹ˆ๋‹ค.
 
46
  """
47
+ session = SessionLocal()
48
+ try:
49
+ count = session.query(Conversation).count()
50
+ if count == 0:
51
+ ds = load_dataset("gaeunseo/Taskmaster_sample_data", split="train")
52
+ data = list(ds)
53
+ for row in data:
54
+ # ๊ธฐ๋ณธ๊ฐ’ ์ฑ„์šฐ๊ธฐ: used๋Š” False, overlapping์€ row์— ์—†๋‹ค๋ฉด ๋นˆ ๋ฌธ์ž์—ด๋กœ ์ฒ˜๋ฆฌ
55
+ text = row.get("text", "")
56
+ conv = Conversation(
57
+ conversation_id = row.get("conversation_id", ""),
58
+ used = row.get("used", False),
59
+ overlapping = row.get("overlapping", ""),
60
+ text = text,
61
+ human_message = text.split("[turn]")[0].strip() if "[turn]" in text else text,
62
+ ai_message = text.split("[turn]")[1].strip() if "[turn]" in text and len(text.split("[turn]")) > 1 else ""
63
+ )
64
+ session.add(conv)
65
+ session.commit()
66
+ finally:
67
+ session.close()
68
 
69
+ # ์ดˆ๊ธฐ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ƒ์„ฑ (์ตœ์ดˆ ์‹คํ–‰ ์‹œ ๋ฐ์ดํ„ฐ์…‹์„ ๋ถˆ๋Ÿฌ์™€ DB์— ์ €์žฅ)
70
+ init_db()
 
 
 
71
 
72
+ #############################################
73
+ # 3. ๋Œ€ํ™” ๊ทธ๋ฃน์„ ํ• ๋‹นํ•˜๋Š” ํ•จ์ˆ˜ (๋™์‹œ์„ฑ ๋ฌธ์ œ๋ฅผ ๋ฐฉ์ง€)
74
+ #############################################
 
 
 
 
 
 
75
 
76
  def get_random_row_from_dataset():
77
  """
78
+ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ conversation_id๋ณ„๋กœ ๊ทธ๋ฃนํ™”ํ•œ ํ›„,
79
+ - ๊ทธ๋ฃน ๋‚ด์˜ ๋ชจ๋“  ํ–‰์˜ used๊ฐ€ False์ด๊ณ ,
80
+ - ๊ทธ๋ฃน ๋‚ด์— overlapping ์ปฌ๋Ÿผ์ด "TT"์ธ ํ–‰์ด ์žˆ๋Š” ๊ทธ๋ฃน๋งŒ valid๋กœ ๊ฐ„์ฃผํ•ฉ๋‹ˆ๋‹ค.
81
+ validํ•œ ๊ทธ๋ฃน ์ค‘ ๋žœ๋คํ•˜๊ฒŒ ํ•˜๋‚˜์˜ ๊ทธ๋ฃน์„ ์„ ํƒํ•œ ํ›„,
82
+ - ํ•ด๋‹น ๊ทธ๋ฃน์˜ ๋ชจ๋“  ํ–‰์˜ used ๊ฐ’์„ True๋กœ ์—…๋ฐ์ดํŠธํ•˜์—ฌ(์ฆ‰, ๊ทธ๋ฃน ์ „์ฒด๋ฅผ ํ• ๋‹น)
83
+ - ์„ ํƒ๋œ ๊ทธ๋ฃน ๋‚ด์—์„œ overlapping ์ปฌ๋Ÿผ์ด "TT"์ธ ์ฒซ ๋ฒˆ์งธ ํ–‰์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
84
  """
85
+ session = SessionLocal()
86
+ try:
87
+ with db_lock:
88
+ convs = session.query(Conversation).all()
89
+ groups = {}
90
+ for conv in convs:
91
+ groups.setdefault(conv.conversation_id, []).append(conv)
92
+ valid_groups = []
93
+ for cid, group in groups.items():
94
+ if all(not conv.used for conv in group) and any(conv.overlapping == "TT" for conv in group):
95
+ valid_groups.append(group)
96
+ if not valid_groups:
97
+ return None
98
+ chosen_group = random.choice(valid_groups)
99
+ for conv in chosen_group:
100
+ conv.used = True
101
+ session.commit()
102
+ for conv in chosen_group:
103
+ if conv.overlapping == "TT":
104
+ return conv
105
+ return None
106
+ finally:
107
+ session.close()
108
 
109
+ #############################################
110
+ # 4. ์ดˆ๊ธฐ ๋Œ€ํ™” ์„ค์ • (์ „์—ญ ๋ณ€์ˆ˜ ์„ค์ •)
111
+ #############################################
112
+
113
+ initial_conv = get_random_row_from_dataset()
114
+ if initial_conv is None:
115
  human_message = "No valid conversation available."
116
  ai_message = "No valid conversation available."
117
  else:
118
+ raw_text = initial_conv.text
119
+ human_message = raw_text.split("[turn]")[0].strip() if "[turn]" in raw_text else raw_text
120
+ ai_message = raw_text.split("[turn]")[1].strip() if "[turn]" in raw_text and len(raw_text.split("[turn]")) > 1 else ""
121
 
122
  #############################################
123
+ # 5. ์ฑ„ํŒ… ์ธํ„ฐํŽ˜์ด์Šค ๊ด€๋ จ ํ•จ์ˆ˜ (๋งํ’์„ , ํƒ€์ดํ•‘ ํšจ๊ณผ, ํŽธ์ง‘ ๊ธฐ๋Šฅ)
124
  #############################################
125
 
126
  def get_initial_human_html():
 
149
  bubble_end = "</div>"
150
  emoji_html = "<div class='emoji'>๐Ÿง‘</div>"
151
  wrapper_end = "</div>"
 
 
152
  yield wrapper_start + bubble_start + bubble_end + emoji_html + wrapper_end
 
 
153
  for i, ch in enumerate(human_message):
154
+ bubble_content += f"<span data-index='{i}'>{ch}</span>"
155
+ current_html = wrapper_start + bubble_start + bubble_content + bubble_end + emoji_html + wrapper_end
156
+ yield current_html
157
+ time.sleep(0.05)
158
 
159
  def submit_edit(edited_text):
160
  """
161
  Submit ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ ํ˜ธ์ถœ๋˜๋Š” ํ•จ์ˆ˜.
162
+ 1. ํŽธ์ง‘๋œ human ๋ฉ”์‹œ์ง€(โœ‚๏ธ ์•ž๋ถ€๋ถ„)๋ฅผ ์ƒˆ ํ–‰์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
163
  2. get_random_row_from_dataset()์„ ํ†ตํ•ด ์ƒˆ๋กœ์šด ๋Œ€ํ™”๋ฅผ ๊ฐ€์ ธ์˜ค๊ณ , ์ „์—ญ ๋ณ€์ˆ˜ human_message์™€ ai_message๋ฅผ ์—…๋ฐ์ดํŠธํ•ฉ๋‹ˆ๋‹ค.
164
  3. ์ดˆ๊ธฐ ์ƒํƒœ์˜ human ๋งํ’์„ ๊ณผ ai ๋งํ’์„  HTML์„ ๋ฐ˜ํ™˜ํ•˜์—ฌ ์ธํ„ฐํŽ˜๏ฟฝ๏ฟฝ์Šค๋ฅผ ๋ฆฌ์…‹ํ•ฉ๋‹ˆ๋‹ค.
165
  """
166
+ session = SessionLocal()
167
+ try:
168
+ with db_lock:
169
+ new_conv = Conversation(
170
+ conversation_id = "edited_" + str(random.randint(1000, 9999)),
171
+ used = False,
172
+ overlapping = "",
173
+ text = edited_text,
174
+ human_message = edited_text,
175
+ ai_message = ""
176
+ )
177
+ session.add(new_conv)
178
+ session.commit()
179
+ new_conv_data = get_random_row_from_dataset()
180
+ if new_conv_data is None:
181
+ global human_message, ai_message
182
+ human_message = "No valid conversation available."
183
+ ai_message = "No valid conversation available."
184
+ else:
185
+ raw_text = new_conv_data.text
186
+ human_message = raw_text.split("[turn]")[0].strip() if "[turn]" in raw_text else raw_text
187
+ ai_message = raw_text.split("[turn]")[1].strip() if "[turn]" in raw_text and len(raw_text.split("[turn]")) > 1 else ""
188
+ finally:
189
+ session.close()
190
  new_human_html = get_initial_human_html()
191
  new_ai_html = f"""
192
  <div class="ai-wrapper" style="display: flex; align-items: flex-end; justify-content: flex-start; gap: 5px; width: 100%;">
 
197
  return new_human_html, new_ai_html
198
 
199
  #############################################
200
+ # 6. Gradio ์ธํ„ฐํŽ˜์ด์Šค ๊ตฌ์„ฑ
201
  #############################################
202
 
203
  with gr.Blocks() as demo:
204
+ # (A) ํŽ˜์ด์ง€ ์ƒ๋‹จ ์Šคํฌ๋ฆฝํŠธ: Human ๋งํ’์„  ๋‚ด์˜ ๊ฐ <span data-index="..."> ํด๋ฆญ ์‹œ,
205
  # ํ•ด๋‹น ์œ„์น˜์— โœ‚๏ธ ์•„์ด์ฝ˜์ด ์‚ฝ์ž…๋˜๊ณ , ๊ทธ ์ดํ›„ ํ…์ŠคํŠธ๊ฐ€ ํšŒ์ƒ‰์œผ๋กœ ๋ณ€๊ฒฝ๋ฉ๋‹ˆ๋‹ค.
206
  gr.HTML(
207
  """
 
230
  </script>
231
  """
232
  )
233
+ # (B) ์ถ”๊ฐ€ ์Šคํฌ๋ฆฝํŠธ: Submit ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ, human_message div์˜ innerText์—์„œ "โœ‚๏ธ" ๊ธฐ์ค€์œผ๋กœ ํŽธ์ง‘๋œ ํ…์ŠคํŠธ(์•ž๋ถ€๋ถ„)๋ฅผ ์ˆจ๊น€ ํ…์ŠคํŠธ๋ฐ•์Šค์— ์—…๋ฐ์ดํŠธ
 
234
  gr.HTML(
235
  """
236
  <script>
 
249
  </script>
250
  """
251
  )
 
252
  # (C) CSS ์Šคํƒ€์ผ
253
  gr.HTML(
254
  """