gaeunseo commited on
Commit
4c05efc
ยท
verified ยท
1 Parent(s): bee660a

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +60 -71
app.py CHANGED
@@ -6,14 +6,13 @@ import os
6
  import threading
7
  from datasets import load_dataset
8
 
9
- # ํŒŒ์ผ ๊ฒฝ๋กœ์™€ ๋™์‹œ ์ ‘๊ทผ์„ ์œ„ํ•œ Lock ์„ ์–ธ
10
  DATA_FILE = "global_data.json"
11
  data_lock = threading.Lock()
12
 
13
  def initialize_global_data():
14
  """
15
- DATA_FILE์ด ์กด์žฌํ•˜์ง€ ์•Š์œผ๋ฉด, Dataset์„ ๋กœ๋“œํ•˜์—ฌ ํŒŒ์ผ์— ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.
16
- ์ด๋ฏธ ํŒŒ์ผ์ด ์žˆ์œผ๋ฉด ํŒŒ์ผ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ์–ด ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
17
  """
18
  if not os.path.exists(DATA_FILE):
19
  ds = load_dataset("gaeunseo/Taskmaster_sample_data", split="train")
@@ -41,60 +40,58 @@ def save_global_data(data):
41
  with open(DATA_FILE, "w", encoding="utf-8") as f:
42
  json.dump(data, f, ensure_ascii=False, indent=2)
43
 
44
- # ํŒŒ์ผ์— ์ €์žฅ๋œ global_data ์ดˆ๊ธฐํ™”
45
  global_data = initialize_global_data()
46
 
47
  def get_random_row_from_dataset():
48
  """
49
  DATA_FILE์— ์ €์žฅ๋œ global_data์—์„œ,
50
- conversation_id๋ณ„๋กœ ๊ทธ๋ฃนํ™”ํ•œ ํ›„,
51
- - ๋ชจ๋“  ํ–‰์˜ used ์ปฌ๋Ÿผ์ด False์ธ ๊ทธ๋ฃน์ด๊ณ ,
52
- - ๊ทธ๋ฃน ๋‚ด์— overlapping ์ปฌ๋Ÿผ์ด "TT"์ธ ํ–‰์ด ์กด์žฌํ•˜๋Š” ๊ทธ๋ฃน๋“ค ์ค‘์—์„œ
53
- ๋žœ๋คํ•˜๊ฒŒ ํ•˜๋‚˜์˜ ๊ทธ๋ฃน์„ ์„ ํƒํ•˜๊ณ , ํ•ด๋‹น ๊ทธ๋ฃน ๋‚ด์—์„œ overlapping ์ปฌ๋Ÿผ์ด "TT"์ธ ํ–‰์„ ์„ ํƒํ•˜์—ฌ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
54
- ๋ฐ˜ํ™˜ ์ „์— ํ•ด๋‹น ํ–‰์˜ used ๊ฐ’์„ True๋กœ ์—…๋ฐ์ดํŠธํ•˜๊ณ  ํŒŒ์ผ์— ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.
 
 
 
55
  """
56
- global global_data
57
- global_data = load_global_data()
58
- # conversation_id๋ณ„ ๊ทธ๋ฃนํ™”
59
- conversation_groups = {}
60
- for row in global_data:
61
- cid = row["conversation_id"]
62
- conversation_groups.setdefault(cid, []).append(row)
63
- # ์กฐ๊ฑด์— ๋งž๋Š” ๊ทธ๋ฃน ํ•„ํ„ฐ๋ง
64
- valid_groups = [
65
- group for group in conversation_groups.values()
66
- if all(not r["used"] for r in group) and any(r["overlapping"] == "TT" for r in group)
67
- ]
68
- if not valid_groups:
69
- return None
70
- chosen_group = random.choice(valid_groups)
71
- chosen_row = None
72
- for row in chosen_group:
73
- if row["overlapping"] == "TT":
74
- row["used"] = True # ์—…๋ฐ์ดํŠธ
75
- chosen_row = row
76
- break
77
- save_global_data(global_data)
78
- return chosen_row
79
 
80
- # ์ดˆ๊ธฐ ๋Œ€ํ™” ๋ถˆ๋Ÿฌ์˜ค๊ธฐ
 
81
  row = get_random_row_from_dataset()
82
  if row is None:
83
  human_message = "No valid conversation available."
84
  ai_message = "No valid conversation available."
85
  else:
86
  raw_text = row['text']
87
- # text ์ปฌ๋Ÿผ์€ "[turn]"์„ ๊ธฐ์ค€์œผ๋กœ ๋Œ€ํ™”๊ฐ€ ๊ตฌ๋ถ„๋˜์–ด ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ฉ๋‹ˆ๋‹ค.
88
  human_message = raw_text.split("[turn]")[0].strip()
89
  ai_message = raw_text.split("[turn]")[1].strip()
90
 
91
- #############################################
92
- # ์ฑ„ํŒ… ์ธํ„ฐํŽ˜์ด์Šค ๊ด€๋ จ ํ•จ์ˆ˜ (๋งํ’์„ , ํƒ€์ดํ•‘ ํšจ๊ณผ, ํŽธ์ง‘ ๊ธฐ๋Šฅ)
93
- #############################################
94
-
95
  def get_initial_human_html():
96
  """
97
- ํŽ˜์ด์ง€ ๋กœ๋“œ ์‹œ, ๋นˆ Human ๋งํ’์„ ๊ณผ ์˜ค๋ฅธ์ชฝ ๐Ÿง‘ ์ด๋ชจํ‹ฐ์ฝ˜์„ ํฌํ•จํ•œ ์ดˆ๊ธฐ HTML ๋ฐ˜ํ™˜
98
  """
99
  wrapper_start = (
100
  """<div class="human-wrapper" style="display: flex; align-items: flex-end; justify-content: flex-end; gap: 5px; width: 100%;">"""
@@ -119,36 +116,38 @@ def stream_human_message():
119
  emoji_html = "<div class='emoji'>๐Ÿง‘</div>"
120
  wrapper_end = "</div>"
121
 
122
- # ์ดˆ๊ธฐ ์ƒํƒœ: ๋นˆ ๋งํ’์„ ๊ณผ ์ด๋ชจํ‹ฐ์ฝ˜
123
  yield wrapper_start + bubble_start + bubble_end + emoji_html + wrapper_end
124
 
125
- # ํ•œ ๊ธ€์ž์”ฉ ์ถ”๊ฐ€ (ํƒ€์ดํ•‘ ํšจ๊ณผ)
126
  for i, ch in enumerate(human_message):
127
- bubble_content += f"<span data-index='{i}'>{ch}</span>"
128
- current_html = wrapper_start + bubble_start + bubble_content + bubble_end + emoji_html + wrapper_end
129
- yield current_html
130
- time.sleep(0.05)
131
 
132
  def submit_edit(edited_text):
133
  """
134
  Submit ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ ํ˜ธ์ถœ๋˜๋Š” ํ•จ์ˆ˜.
135
  1. ํŽธ์ง‘๋œ human ๋ฉ”์‹œ์ง€(โœ‚๏ธ ์•ž๋ถ€๋ถ„)๋ฅผ ์ƒˆ ํ–‰์œผ๋กœ global_data์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
136
- 2. get_random_row_from_dataset()์„ ํ†ตํ•ด ์ƒˆ๋กœ์šด ๋Œ€ํ™”๋ฅผ ๊ฐ€์ ธ์˜ค๊ณ , ์ „์—ญ ๋ณ€์ˆ˜ human_message์™€ ai_message๋ฅผ ์—…๋ฐ์ดํŠธํ•ฉ๋‹ˆ๋‹ค.
 
137
  3. ์ดˆ๊ธฐ ์ƒํƒœ์˜ human ๋งํ’์„ ์™€ ai ๋งํ’์„  HTML์„ ๋ฐ˜ํ™˜ํ•˜์—ฌ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๋ฆฌ์…‹ํ•ฉ๋‹ˆ๋‹ค.
138
  """
139
- global global_data, human_message, ai_message
140
- # ์ƒˆ ํ–‰ ์ƒ์„ฑ (์ƒˆ conversation_id๋Š” ์ž„์˜๋กœ ์ƒ์„ฑ)
141
  new_row = {
142
- "conversation_id": "edited_" + str(random.randint(1000,9999)),
143
  "used": False,
144
  "overlapping": "",
145
  "text": edited_text,
146
  "human_message": edited_text,
147
  "ai_message": ""
148
  }
149
- global_data = load_global_data()
150
- global_data.append(new_row)
151
- save_global_data(global_data)
 
152
 
153
  new_row_data = get_random_row_from_dataset()
154
  if new_row_data is None:
@@ -168,16 +167,7 @@ def submit_edit(edited_text):
168
  """
169
  return new_human_html, new_ai_html
170
 
171
- def download_global_data():
172
- """
173
- Download Data ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ, global_data.json ํŒŒ์ผ์˜ ๊ฒฝ๋กœ๋ฅผ ๋ฐ˜ํ™˜ํ•˜์—ฌ ๋‹ค์šด๋กœ๋“œํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.
174
- """
175
- return DATA_FILE
176
-
177
- #############################################
178
- # Gradio ์ธํ„ฐํŽ˜์ด์Šค ๊ตฌ์„ฑ
179
- #############################################
180
-
181
  with gr.Blocks() as demo:
182
  # (A) ํŽ˜์ด์ง€ ์ƒ๋‹จ ์Šคํฌ๋ฆฝํŠธ: Human ๋งํ’์„  ๋‚ด์˜ ๊ฐ <span data-index="...">๋ฅผ ํด๋ฆญํ•˜๋ฉด,
183
  # ํ•ด๋‹น ์œ„์น˜์— โœ‚๏ธ ์•„์ด์ฝ˜์ด ์‚ฝ์ž…๋˜๊ณ , ๊ทธ ์ดํ›„ ํ…์ŠคํŠธ๊ฐ€ ํšŒ์ƒ‰์œผ๋กœ ๋ณ€๊ฒฝ๋ฉ๋‹ˆ๋‹ค.
@@ -209,7 +199,8 @@ with gr.Blocks() as demo:
209
  """
210
  )
211
 
212
- # (B) ์ถ”๊ฐ€ ์Šคํฌ๋ฆฝํŠธ: Submit ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ, human_message div์˜ innerText์—์„œ "โœ‚๏ธ"๋ฅผ ๊ธฐ์ค€์œผ๋กœ ํŽธ์ง‘๋œ ํ…์ŠคํŠธ(์•ž๋ถ€๋ถ„)๋ฅผ ์ˆจ๊น€ ํ…์ŠคํŠธ๋ฐ•์Šค์— ์—…๋ฐ์ดํŠธ
 
213
  gr.HTML(
214
  """
215
  <script>
@@ -285,9 +276,9 @@ with gr.Blocks() as demo:
285
  gr.Markdown("## Chat Interface")
286
 
287
  with gr.Column(elem_classes="chat-container"):
288
- # Human ๋งํ’์„  (์ดˆ๊ธฐ: ๋นˆ ๋ฉ”์‹œ์ง€ + ๐Ÿง‘ ์ด๋ชจํ‹ฐ์ฝ˜)
289
  human_bubble = gr.HTML(get_initial_human_html())
290
- # AI ๋งํ’์„  (์™ผ์ชฝ: ๐Ÿค– ์ด๋ชจํ‹ฐ์ฝ˜ + ๋ฉ”์‹œ์ง€)
291
  ai_html = f"""
292
  <div class="ai-wrapper" style="display: flex; align-items: flex-end; justify-content: flex-start; gap: 5px; width: 100%;">
293
  <div class="emoji">๐Ÿค–</div>
@@ -296,18 +287,16 @@ with gr.Blocks() as demo:
296
  """
297
  ai_bubble = gr.HTML(ai_html)
298
 
299
- # ์ˆจ๊น€ ํ…์ŠคํŠธ๋ฐ•์Šค (ํŽธ์ง‘๋œ ํ…์ŠคํŠธ ์ €์žฅ์šฉ)
300
  edited_text_input = gr.Textbox(visible=False, elem_id="edited_text_input")
301
 
302
- # ๋ฒ„ํŠผ ์˜์—ญ: Start Typing, Submit, Download Data ๋ฒ„ํŠผ์„ ๊ฐ™์€ ํ–‰์— ๋ฐฐ์น˜
303
  with gr.Row():
304
  start_button = gr.Button("Start Typing")
305
  submit_button = gr.Button("Submit", elem_id="submit_btn")
306
- download_button = gr.Button("Download Data")
307
 
308
  # ๋ฒ„ํŠผ ์ด๋ฒคํŠธ ์—ฐ๊ฒฐ
309
  start_button.click(fn=stream_human_message, outputs=human_bubble)
310
  submit_button.click(fn=submit_edit, inputs=edited_text_input, outputs=[human_bubble, ai_bubble])
311
- download_button.click(fn=download_global_data, outputs=[], show_progress=False)
312
-
313
- demo.launch()
 
6
  import threading
7
  from datasets import load_dataset
8
 
9
+ # --- ํŒŒ์ผ ๊ธฐ๋ฐ˜ ๋ฐ์ดํ„ฐ ๊ด€๋ฆฌ ์„ค์ • ---
10
  DATA_FILE = "global_data.json"
11
  data_lock = threading.Lock()
12
 
13
  def initialize_global_data():
14
  """
15
+ DATA_FILE์ด ์—†์œผ๋ฉด Dataset์„ ๋ถˆ๋Ÿฌ์™€์„œ ์ €์žฅํ•˜๊ณ , ์žˆ์œผ๋ฉด ํŒŒ์ผ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
 
16
  """
17
  if not os.path.exists(DATA_FILE):
18
  ds = load_dataset("gaeunseo/Taskmaster_sample_data", split="train")
 
40
  with open(DATA_FILE, "w", encoding="utf-8") as f:
41
  json.dump(data, f, ensure_ascii=False, indent=2)
42
 
43
+ # ์ดˆ๊ธฐ global_data ํŒŒ์ผ ์ƒ์„ฑ ๋˜๋Š” ๋กœ๋“œ
44
  global_data = initialize_global_data()
45
 
46
  def get_random_row_from_dataset():
47
  """
48
  DATA_FILE์— ์ €์žฅ๋œ global_data์—์„œ,
49
+ - conversation_id๋ณ„๋กœ ๊ทธ๋ฃนํ™”ํ•˜๊ณ ,
50
+ - ๊ฐ ๊ทธ๋ฃน์˜ ๋ชจ๋“  ํ–‰์˜ used๊ฐ€ False์ด๋ฉฐ,
51
+ - ๊ทธ๋ฃน ๋‚ด์— overlapping ์ปฌ๋Ÿผ์ด "TT"์ธ ํ–‰์ด ์žˆ๋Š” ๊ทธ๋ฃน๋งŒ valid๋กœ ๊ฐ„์ฃผํ•ฉ๋‹ˆ๋‹ค.
52
+ validํ•œ ๊ทธ๋ฃน๋“ค ์ค‘ ๋žœ๋คํ•˜๊ฒŒ ํ•˜๋‚˜์˜ ๊ทธ๋ฃน์„ ์„ ํƒํ•œ ํ›„,
53
+ - ํ•ด๋‹น ๊ทธ๋ฃน์˜ ๋ชจ๋“  ํ–‰์˜ used ๊ฐ’์„ True๋กœ ์—…๋ฐ์ดํŠธ(์ฆ‰, ์ „์ฒด ๊ทธ๋ฃน์„ ํ• ๋‹น)ํ•˜๊ณ  ํŒŒ์ผ์— ์ €์žฅํ•œ ๋’ค,
54
+ - ์„ ํƒ๋œ ๊ทธ๋ฃน ๋‚ด์—์„œ overlapping ์ปฌ๋Ÿผ์ด "TT"์ธ ํ–‰์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
55
+ ์ด ๋ฐฉ์‹์œผ๋กœ ์—ฌ๋Ÿฌ ์‚ฌ์šฉ์ž๊ฐ€ ๋™์‹œ์— ํ˜ธ์ถœํ•˜๋”๋ผ๋„ ์ž ๊ธˆ์„ ํ†ตํ•ด atomicํ•˜๊ฒŒ ์—…๋ฐ์ดํŠธํ•˜๋ฏ€๋กœ,
56
+ ์„œ๋กœ ๋‹ค๋ฅธ ์‚ฌ์šฉ์ž์—๊ฒŒ ์„œ๋กœ ๋‹ค๋ฅธ conversation_id ๊ทธ๋ฃน์ด ํ• ๋‹น๋ฉ๋‹ˆ๋‹ค.
57
  """
58
+ with data_lock:
59
+ data = load_global_data()
60
+ conversation_groups = {}
61
+ for row in data:
62
+ cid = row["conversation_id"]
63
+ conversation_groups.setdefault(cid, []).append(row)
64
+ valid_groups = [
65
+ group for group in conversation_groups.values()
66
+ if all(not r["used"] for r in group) and any(r["overlapping"] == "TT" for r in group)
67
+ ]
68
+ if not valid_groups:
69
+ return None
70
+ chosen_group = random.choice(valid_groups)
71
+ # ๊ทธ๋ฃน ๋‚ด์˜ ๋ชจ๋“  ํ–‰์˜ used๋ฅผ True๋กœ ์—…๋ฐ์ดํŠธํ•˜์—ฌ ์ „์ฒด ๊ทธ๋ฃน์ด ํ• ๋‹น๋˜๋„๋ก ํ•จ
72
+ for row in chosen_group:
73
+ row["used"] = True
74
+ save_global_data(data)
75
+ # ์„ ํƒ๋œ ๊ทธ๋ฃน ๋‚ด์—์„œ overlapping ์ปฌ๋Ÿผ์ด "TT"์ธ ํ–‰์„ ๋ฐ˜ํ™˜ (์—ฌ๋Ÿฌ ๊ฐœ๋ผ๋ฉด ์ฒซ ๋ฒˆ์งธ)
76
+ for row in chosen_group:
77
+ if row["overlapping"] == "TT":
78
+ return row
 
 
79
 
80
+ # --- ์ดˆ๊ธฐ ๋Œ€ํ™” ์„ค์ • ---
81
+ # Dataset์˜ text ์ปฌ๋Ÿผ์€ "[turn]"์„ ๊ธฐ์ค€์œผ๋กœ ๋Œ€ํ™”๊ฐ€ ๊ตฌ๋ถ„๋˜์–ด ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ฉ๋‹ˆ๋‹ค.
82
  row = get_random_row_from_dataset()
83
  if row is None:
84
  human_message = "No valid conversation available."
85
  ai_message = "No valid conversation available."
86
  else:
87
  raw_text = row['text']
 
88
  human_message = raw_text.split("[turn]")[0].strip()
89
  ai_message = raw_text.split("[turn]")[1].strip()
90
 
91
+ # --- ์ฑ„ํŒ… ์ธํ„ฐํŽ˜์ด์Šค ๊ด€๋ จ ํ•จ์ˆ˜ ---
 
 
 
92
  def get_initial_human_html():
93
  """
94
+ ํŽ˜์ด์ง€ ๋กœ๋“œ ์‹œ, ๋นˆ Human ๋งํ’์„ ๊ณผ ์˜ค๋ฅธ์ชฝ ๐Ÿง‘ ์ด๋ชจํ‹ฐ์ฝ˜์ด ๋ณด์ด๋„๋ก ์ดˆ๊ธฐ HTML ๋ฐ˜ํ™˜
95
  """
96
  wrapper_start = (
97
  """<div class="human-wrapper" style="display: flex; align-items: flex-end; justify-content: flex-end; gap: 5px; width: 100%;">"""
 
116
  emoji_html = "<div class='emoji'>๐Ÿง‘</div>"
117
  wrapper_end = "</div>"
118
 
119
+ # ์ดˆ๊ธฐ ์ƒํƒœ (๋นˆ ๋งํ’์„ ๊ณผ ์ด๋ชจํ‹ฐ์ฝ˜)
120
  yield wrapper_start + bubble_start + bubble_end + emoji_html + wrapper_end
121
 
122
+ # human_message๋ฅผ ํ•œ ๊ธ€์ž์”ฉ ์ถ”๊ฐ€ (ํƒ€์ดํ•‘ ํšจ๊ณผ)
123
  for i, ch in enumerate(human_message):
124
+ bubble_content += f"<span data-index='{i}'>{ch}</span>"
125
+ current_html = wrapper_start + bubble_start + bubble_content + bubble_end + emoji_html + wrapper_end
126
+ yield current_html
127
+ time.sleep(0.05)
128
 
129
  def submit_edit(edited_text):
130
  """
131
  Submit ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ ํ˜ธ์ถœ๋˜๋Š” ํ•จ์ˆ˜.
132
  1. ํŽธ์ง‘๋œ human ๋ฉ”์‹œ์ง€(โœ‚๏ธ ์•ž๋ถ€๋ถ„)๋ฅผ ์ƒˆ ํ–‰์œผ๋กœ global_data์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
133
+ 2. get_random_row_from_dataset()์„ ํ†ตํ•ด ์ƒˆ๋กœ์šด ๋Œ€ํ™”๋ฅผ ๊ฐ€์ ธ์˜ค๊ณ ,
134
+ ์ „์—ญ ๋ณ€์ˆ˜ human_message์™€ ai_message๋ฅผ ์—…๋ฐ์ดํŠธํ•ฉ๋‹ˆ๋‹ค.
135
  3. ์ดˆ๊ธฐ ์ƒํƒœ์˜ human ๋งํ’์„ ์™€ ai ๋งํ’์„  HTML์„ ๋ฐ˜ํ™˜ํ•˜์—ฌ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๋ฆฌ์…‹ํ•ฉ๋‹ˆ๋‹ค.
136
  """
137
+ global human_message, ai_message
138
+ # ์ƒˆ ํ–‰ ์ƒ์„ฑ (์ƒˆ conversation_id๋Š” ์ž„์˜ ์ƒ์„ฑ)
139
  new_row = {
140
+ "conversation_id": "edited_" + str(random.randint(1000, 9999)),
141
  "used": False,
142
  "overlapping": "",
143
  "text": edited_text,
144
  "human_message": edited_text,
145
  "ai_message": ""
146
  }
147
+ # ํŒŒ์ผ์—์„œ global_data ๋ถˆ๋Ÿฌ์™€์„œ ์ƒˆ ํ–‰ ์ถ”๊ฐ€ ๋ฐ ์ €์žฅ
148
+ data = load_global_data()
149
+ data.append(new_row)
150
+ save_global_data(data)
151
 
152
  new_row_data = get_random_row_from_dataset()
153
  if new_row_data is None:
 
167
  """
168
  return new_human_html, new_ai_html
169
 
170
+ # --- Gradio ์ธํ„ฐํŽ˜์ด์Šค ๊ตฌ์„ฑ ---
 
 
 
 
 
 
 
 
 
171
  with gr.Blocks() as demo:
172
  # (A) ํŽ˜์ด์ง€ ์ƒ๋‹จ ์Šคํฌ๋ฆฝํŠธ: Human ๋งํ’์„  ๋‚ด์˜ ๊ฐ <span data-index="...">๋ฅผ ํด๋ฆญํ•˜๋ฉด,
173
  # ํ•ด๋‹น ์œ„์น˜์— โœ‚๏ธ ์•„์ด์ฝ˜์ด ์‚ฝ์ž…๋˜๊ณ , ๊ทธ ์ดํ›„ ํ…์ŠคํŠธ๊ฐ€ ํšŒ์ƒ‰์œผ๋กœ ๋ณ€๊ฒฝ๋ฉ๋‹ˆ๋‹ค.
 
199
  """
200
  )
201
 
202
+ # (B) ์ถ”๊ฐ€ ์Šคํฌ๋ฆฝํŠธ: Submit ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ, human_message div์˜ innerText์—์„œ "โœ‚๏ธ"๋ฅผ ๊ธฐ์ค€์œผ๋กœ
203
+ # ํŽธ์ง‘๋œ ํ…์ŠคํŠธ(์•ž๋ถ€๋ถ„)๋ฅผ ์ˆจ๊น€ ํ…์ŠคํŠธ๋ฐ•์Šค์— ์—…๋ฐ์ดํŠธํ•ฉ๋‹ˆ๋‹ค.
204
  gr.HTML(
205
  """
206
  <script>
 
276
  gr.Markdown("## Chat Interface")
277
 
278
  with gr.Column(elem_classes="chat-container"):
279
+ # Human ๋งํ’์„  (์ดˆ๊ธฐ: ๋นˆ ๋ฉ”์‹œ์ง€์™€ ๐Ÿง‘ ์ด๋ชจํ‹ฐ์ฝ˜)
280
  human_bubble = gr.HTML(get_initial_human_html())
281
+ # AI ๋งํ’์„  (์™ผ์ชฝ: ๐Ÿค– ์ด๋ชจํ‹ฐ์ฝ˜๊ณผ ํ•จ๊ป˜ ๋ฉ”์‹œ์ง€)
282
  ai_html = f"""
283
  <div class="ai-wrapper" style="display: flex; align-items: flex-end; justify-content: flex-start; gap: 5px; width: 100%;">
284
  <div class="emoji">๐Ÿค–</div>
 
287
  """
288
  ai_bubble = gr.HTML(ai_html)
289
 
290
+ # ์ˆจ๊น€ ํ…์ŠคํŠธ๋ฐ•์Šค: ํŽธ์ง‘๋œ ํ…์ŠคํŠธ(โœ‚๏ธ ์•ž๋ถ€๋ถ„)๋ฅผ ์ €์žฅ (visible=False)
291
  edited_text_input = gr.Textbox(visible=False, elem_id="edited_text_input")
292
 
293
+ # ๋ฒ„ํŠผ ์˜์—ญ: Start Typing๊ณผ Submit ๋ฒ„ํŠผ์„ ๊ฐ™์€ ํ–‰์— ๋ฐฐ์น˜ (Download ๋ฒ„ํŠผ ์ œ๊ฑฐ)
294
  with gr.Row():
295
  start_button = gr.Button("Start Typing")
296
  submit_button = gr.Button("Submit", elem_id="submit_btn")
 
297
 
298
  # ๋ฒ„ํŠผ ์ด๋ฒคํŠธ ์—ฐ๊ฒฐ
299
  start_button.click(fn=stream_human_message, outputs=human_bubble)
300
  submit_button.click(fn=submit_edit, inputs=edited_text_input, outputs=[human_bubble, ai_bubble])
301
+
302
+ demo.launch()