gaeunseo commited on
Commit
55b371e
ยท
verified ยท
1 Parent(s): bf32481

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +117 -35
app.py CHANGED
@@ -3,26 +3,28 @@ import gradio as gr
3
  import random
4
  from datasets import load_dataset
5
 
 
 
 
6
  def get_random_row_from_dataset():
7
  """
8
- Hugging Face Dataset repository 'gaeunseo/Taskmaster_sample_data'์˜ train split์—์„œ
9
- conversation_id๋ณ„๋กœ ๊ทธ๋ฃนํ™”ํ•œ ํ›„, ๊ฐ™์€ conversation_id๋ฅผ ๊ฐ€์ง„ ๋ชจ๋“  ํ–‰๋“ค์˜ used ์ปฌ๋Ÿผ์ด False์ด๊ณ ,
10
- ๊ทธ ๊ทธ๋ฃน ๋‚ด์— overlapping ์ปฌ๋Ÿผ์ด "TT"์ธ ํ–‰์ด ์กด์žฌํ•˜๋Š” ๊ทธ๋ฃน๋“ค ์ค‘์—์„œ ๋žœ๋คํ•˜๊ฒŒ ํ•˜๋‚˜์˜ ๊ทธ๋ฃน์„ ์„ ํƒํ•˜๊ณ ,
11
- ํ•ด๋‹น ๊ทธ๋ฃน ๋‚ด์—์„œ overlapping ์ปฌ๋Ÿผ์ด "TT"์ธ ํ–‰์„ ์„ ํƒํ•˜์—ฌ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
 
12
  """
13
- # ๋ฐ์ดํ„ฐ์…‹ ๋กœ๋“œ (split ์ด๋ฆ„์€ ์ƒํ™ฉ์— ๋งž๊ฒŒ ์กฐ์ •)
14
- ds = load_dataset("gaeunseo/Taskmaster_sample_data", split="train")
15
-
16
- # conversation_id๋ณ„๋กœ ํ–‰๋“ค์„ ๊ทธ๋ฃนํ™”
17
  conversation_groups = {}
18
- for row in ds:
19
  cid = row["conversation_id"]
20
  conversation_groups.setdefault(cid, []).append(row)
21
 
22
- # ๋ชจ๋“  ํ–‰๋“ค์˜ used ์ปฌ๋Ÿผ์ด False์ด๊ณ , ๊ทธ๋ฃน ๋‚ด์— overlapping ์ปฌ๋Ÿผ์ด "TT"์ธ ํ–‰์ด ์กด์žฌํ•˜๋Š” ๊ทธ๋ฃน๋งŒ ํ•„ํ„ฐ๋ง
23
  valid_groups = [
24
- group for group in conversation_groups.values()
25
- if all(not row["used"] for row in group) and any(row["overlapping"] == "TT" for row in group)
26
  ]
27
 
28
  if not valid_groups:
@@ -30,28 +32,32 @@ def get_random_row_from_dataset():
30
 
31
  # ์œ ํšจํ•œ ๊ทธ๋ฃน ์ค‘ ๋žœ๋คํ•˜๊ฒŒ ํ•˜๋‚˜ ์„ ํƒ
32
  chosen_group = random.choice(valid_groups)
33
- # ์„ ํƒ๋œ ๊ทธ๋ฃน ๋‚ด์—์„œ overlapping ์ปฌ๋Ÿผ์ด "TT"์ธ ํ–‰์„ ์„ ํƒ (์—ฌ๋Ÿฌ ๊ฐœ๋ผ๋ฉด ์ฒซ ๋ฒˆ์งธ ๊ฒƒ์„ ์‚ฌ์šฉ)
34
  for row in chosen_group:
35
  if row["overlapping"] == "TT":
 
36
  return row
37
 
38
- # ๋ฐ์ดํ„ฐ์…‹์—์„œ ํ•˜๋‚˜์˜ ํ–‰์„ ๊ฐ€์ ธ์™€์„œ human_message์™€ ai_message์— ํ• ๋‹น
 
39
  row = get_random_row_from_dataset()
40
  if row is None:
41
  human_message = "No valid conversation available."
42
  ai_message = "No valid conversation available."
 
43
  else:
44
  raw_text = row['text']
45
  human_message = raw_text.split("[turn]")[0].strip()
46
  ai_message = raw_text.split("[turn]")[1].strip()
 
47
 
48
  #############################################
49
- # ์ดํ›„ ์•„๋ž˜๋Š” ๊ธฐ์กด ์ฑ„ํŒ… ์ธํ„ฐํŽ˜์ด์Šค ์ฝ”๋“œ (๋งํ’์„ , ์ด๋ชจํ‹ฐ์ฝ˜, ํƒ€์ดํ•‘ ํšจ๊ณผ, ํด๋ฆญ ์ธํ„ฐ๋ž™์…˜) ์ž…๋‹ˆ๋‹ค.
50
  #############################################
51
 
52
  def get_initial_human_html():
53
  """
54
- ํŽ˜์ด์ง€ ๋กœ๋“œ ์‹œ Human ๋งํ’์„ (๋นˆ ๋‚ด์šฉ)๊ณผ ์˜ค๋ฅธ์ชฝ์— ๐Ÿง‘ ์ด๋ชจํ‹ฐ์ฝ˜์ด ๋ณด์ด๋„๋ก ์ดˆ๊ธฐ HTML ๋ฐ˜ํ™˜
55
  """
56
  wrapper_start = (
57
  """<div class="human-wrapper" style="display: flex; align-items: flex-end; justify-content: flex-end; gap: 5px; width: 100%;">"""
@@ -64,7 +70,7 @@ def get_initial_human_html():
64
 
65
  def stream_human_message():
66
  """
67
- Start Typing ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ human_message๋ฅผ ํ•œ ๊ธ€์ž์”ฉ ํƒ€์ดํ•‘ ํšจ๊ณผ๋กœ ์ถœ๋ ฅ.
68
  ์ด์ „ ์ƒํƒœ(โœ‚๏ธ ์•„์ด์ฝ˜, ํšŒ์ƒ‰ ์ฒ˜๋ฆฌ ๋“ฑ)๋Š” ๋ฆฌ์…‹๋ฉ๋‹ˆ๋‹ค.
69
  """
70
  bubble_content = ""
@@ -81,27 +87,69 @@ def stream_human_message():
81
 
82
  # human_message๋ฅผ ํ•œ ๊ธ€์ž์”ฉ ์ถ”๊ฐ€ (ํƒ€์ดํ•‘ ํšจ๊ณผ)
83
  for i, ch in enumerate(human_message):
84
- bubble_content += f"<span data-index='{i}'>{ch}</span>"
85
- current_html = wrapper_start + bubble_start + bubble_content + bubble_end + emoji_html + wrapper_end
86
- yield current_html
87
- time.sleep(0.05)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
88
 
89
  with gr.Blocks() as demo:
90
- # ํŽ˜์ด์ง€ ์ƒ๋‹จ์— ๋‹จ ํ•œ ๋ฒˆ ๋กœ๋“œ๋  ์Šคํฌ๋ฆฝํŠธ:
91
- # - Human ๋งํ’์„  ๋‚ด์˜ ๊ฐ <span data-index="...">๋ฅผ ํด๋ฆญํ•˜๋ฉด โœ‚๏ธ ์ด๋ชจํ‹ฐ์ฝ˜์ด ํ•ด๋‹น ์œ„์น˜์— ์‚ฝ์ž…๋˜๊ณ ,
92
- # ๊ทธ ์ดํ›„์˜ ํ…์ŠคํŠธ ์ƒ‰์ƒ์ด ํšŒ์ƒ‰์œผ๋กœ ๋ณ€๊ฒฝ๋˜๋„๋ก ์ด๋ฒคํŠธ ์œ„์ž„ ๋ฐฉ์‹์œผ๋กœ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.
93
  gr.HTML(
94
  """
95
  <script>
96
  document.addEventListener("click", function(event) {
97
- // Human ๋งํ’์„  ๋‚ด์˜ <span data-index="...">๊ฐ€ ํด๋ฆญ๋˜์—ˆ์„ ๋•Œ๋งŒ ์ฒ˜๋ฆฌ
98
  if (event.target && event.target.matches("div.speech-bubble.human span[data-index]")) {
99
  var span = event.target;
100
  var container = span.closest("div.speech-bubble.human");
101
- // ๊ธฐ์กด์— ์‚ฝ์ž…๋œ โœ‚๏ธ ์ด๋ชจํ‹ฐ์ฝ˜(ํด๋ž˜์Šค "scissor") ์ œ๊ฑฐ
102
  var oldScissors = container.querySelectorAll("span.scissor");
103
  oldScissors.forEach(function(s) { s.remove(); });
104
- // ๋ชจ๋“  span์˜ ์ƒ‰์ƒ์„ ์ดˆ๊ธฐํ™”
105
  var spans = container.querySelectorAll("span[data-index]");
106
  spans.forEach(function(s) { s.style.color = ''; });
107
  // ํด๋ฆญํ•œ span ๋ฐ”๋กœ ๋’ค์— โœ‚๏ธ ์•„์ด์ฝ˜ ์‚ฝ์ž…
@@ -123,7 +171,31 @@ with gr.Blocks() as demo:
123
  """
124
  )
125
 
126
- # CSS ์Šคํƒ€์ผ (๋งํ’์„  ๋ชจ์–‘, ์ด๋ชจํ‹ฐ์ฝ˜, ์œ„์น˜ ๋“ฑ)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
127
  gr.HTML(
128
  """
129
  <style>
@@ -184,21 +256,31 @@ with gr.Blocks() as demo:
184
  gr.Markdown("## Chat Interface")
185
 
186
  with gr.Column(elem_classes="chat-container"):
187
- # ํŽ˜์ด์ง€ ๋กœ๋“œ ์‹œ Human ๋งํ’์„ (๋นˆ ๋ฉ”์‹œ์ง€)๊ณผ ์˜ค๋ฅธ์ชฝ ๐Ÿง‘ ์ด๋ชจํ‹ฐ์ฝ˜์ด ๋ณด์ด๋„๋ก ์ดˆ๊ธฐ HTML ์ ์šฉ
188
  human_bubble = gr.HTML(get_initial_human_html())
189
-
190
- # AI ๋งํ’์„ : ์™ผ์ชฝ์— ๐Ÿค– ์ด๋ชจํ‹ฐ์ฝ˜๊ณผ ํ•จ๊ป˜ ๊ณ ์ • ๋ฉ”์‹œ์ง€ ์ถœ๋ ฅ
191
- ai_html = """
192
  <div class="ai-wrapper" style="display: flex; align-items: flex-end; justify-content: flex-start; gap: 5px; width: 100%;">
193
  <div class="emoji">๐Ÿค–</div>
194
- <div id="ai_message" class="speech-bubble ai">""" + ai_message + """</div>
195
  </div>
196
  """
197
  ai_bubble = gr.HTML(ai_html)
198
 
199
- # Start Typing ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด human_message๊ฐ€ ์ŠคํŠธ๋ฆฌ๋ฐ(ํƒ€์ดํ•‘ ํšจ๊ณผ)๋˜๋ฉฐ, ์ด์ „์— ์žˆ๋˜ โœ‚๏ธ/ํšŒ์ƒ‰ ์ฒ˜๋ฆฌ ๋“ฑ์€ ๋ฆฌ์…‹๋ฉ๋‹ˆ๋‹ค.
200
- start_button = gr.Button("Start Typing")
 
 
 
 
 
 
 
 
201
  start_button.click(fn=stream_human_message, outputs=human_bubble)
 
 
 
202
 
203
  demo.launch()
204
 
 
3
  import random
4
  from datasets import load_dataset
5
 
6
+ # 1. ๋ฐ์ดํ„ฐ์…‹ ๋กœ๋“œ ๋ฐ ์ „์—ญ ๋ณ€์ˆ˜๋กœ ์ €์žฅ (๋ฉ”๋ชจ๋ฆฌ ๋‚ด์—์„œ ์—…๋ฐ์ดํŠธ)
7
+ global_data = list(load_dataset("gaeunseo/Taskmaster_sample_data", split="train"))
8
+
9
  def get_random_row_from_dataset():
10
  """
11
+ Hugging Face Dataset์˜ train split์—์„œ
12
+ conversation_id๋ณ„๋กœ ๊ทธ๋ฃนํ™”ํ•œ ํ›„,
13
+ ๋ชจ๋“  ํ–‰์˜ used ์ปฌ๋Ÿผ์ด False์ด๊ณ , ๊ทธ๋ฃน ๋‚ด์— overlapping ์ปฌ๋Ÿผ์ด "TT"์ธ ํ–‰์ด ์กด์žฌํ•˜๋Š” ๊ทธ๋ฃน๋“ค ์ค‘
14
+ ๋žœ๋คํ•˜๊ฒŒ ํ•˜๋‚˜์˜ ๊ทธ๋ฃน์„ ์„ ํƒํ•˜๊ณ , ํ•ด๋‹น ๊ทธ๋ฃน ๋‚ด์—์„œ overlapping ์ปฌ๋Ÿผ์ด "TT"์ธ ํ–‰์„ ์„ ํƒํ•˜์—ฌ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
15
+ ๋ฐ˜ํ™˜ ์ „ ํ•ด๋‹น ํ–‰์˜ used ๊ฐ’์„ True๋กœ ์—…๋ฐ์ดํŠธํ•ฉ๋‹ˆ๋‹ค.
16
  """
17
+ global global_data
18
+ # conversation_id๋ณ„๋กœ ๊ทธ๋ฃนํ™”
 
 
19
  conversation_groups = {}
20
+ for row in global_data:
21
  cid = row["conversation_id"]
22
  conversation_groups.setdefault(cid, []).append(row)
23
 
24
+ # ๋ชจ๋“  ํ–‰์˜ used ์ปฌ๋Ÿผ์ด False์ด๋ฉฐ, ๊ทธ๋ฃน ๋‚ด์— overlapping ์ปฌ๋Ÿผ์ด "TT"์ธ ํ–‰์ด ์žˆ๋Š” ๊ทธ๋ฃน๋งŒ ํ•„ํ„ฐ๋ง
25
  valid_groups = [
26
+ group for group in conversation_groups.values()
27
+ if all(not r["used"] for r in group) and any(r["overlapping"] == "TT" for r in group)
28
  ]
29
 
30
  if not valid_groups:
 
32
 
33
  # ์œ ํšจํ•œ ๊ทธ๋ฃน ์ค‘ ๋žœ๋คํ•˜๊ฒŒ ํ•˜๋‚˜ ์„ ํƒ
34
  chosen_group = random.choice(valid_groups)
35
+ # ์„ ํƒ๋œ ๊ทธ๋ฃน ๋‚ด์—์„œ overlapping ์ปฌ๋Ÿผ์ด "TT"์ธ ํ–‰์„ ์„ ํƒ (์—ฌ๋Ÿฌ ๊ฐœ๋ผ๋ฉด ์ฒซ ๋ฒˆ์งธ)
36
  for row in chosen_group:
37
  if row["overlapping"] == "TT":
38
+ row["used"] = True # ํ•ด๋‹น ํ–‰์„ ์‚ฌ์šฉํ•จ์œผ๋กœ ์—…๋ฐ์ดํŠธ
39
  return row
40
 
41
+ # 2. ์ดˆ๊ธฐ ๋Œ€ํ™” ๊ฐ€์ ธ์˜ค๊ธฐ (human_message, ai_message)
42
+ # Dataset์˜ text ์ปฌ๋Ÿผ์€ "[turn]"์„ ๊ธฐ์ค€์œผ๋กœ ๋Œ€ํ™”๊ฐ€ ๊ตฌ๋ถ„๋˜์–ด ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ฉ๋‹ˆ๋‹ค.
43
  row = get_random_row_from_dataset()
44
  if row is None:
45
  human_message = "No valid conversation available."
46
  ai_message = "No valid conversation available."
47
+ conversation_id = "none"
48
  else:
49
  raw_text = row['text']
50
  human_message = raw_text.split("[turn]")[0].strip()
51
  ai_message = raw_text.split("[turn]")[1].strip()
52
+ conversation_id = row['conversation_id']
53
 
54
  #############################################
55
+ # ์ธํ„ฐํŽ˜์ด์Šค ๊ด€๋ จ ํ•จ์ˆ˜ (๋งํ’์„ , ํƒ€์ดํ•‘ ํšจ๊ณผ, ํด๋ฆญ ํŽธ์ง‘)
56
  #############################################
57
 
58
  def get_initial_human_html():
59
  """
60
+ ํŽ˜์ด์ง€ ๋กœ๋“œ ์‹œ, ๋นˆ Human ๋งํ’์„ ๊ณผ ์˜ค๋ฅธ์ชฝ ๐Ÿง‘ ์ด๋ชจํ‹ฐ์ฝ˜์„ ํฌํ•จํ•œ ์ดˆ๊ธฐ HTML์„ ๋ฐ˜ํ™˜
61
  """
62
  wrapper_start = (
63
  """<div class="human-wrapper" style="display: flex; align-items: flex-end; justify-content: flex-end; gap: 5px; width: 100%;">"""
 
70
 
71
  def stream_human_message():
72
  """
73
+ Start Typing ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ, ์ „์—ญ ๋ณ€์ˆ˜ human_message์˜ ๋‚ด์šฉ์„ ํ•œ ๊ธ€์ž์”ฉ ํƒ€์ดํ•‘ ํšจ๊ณผ๋กœ ์ถœ๋ ฅ.
74
  ์ด์ „ ์ƒํƒœ(โœ‚๏ธ ์•„์ด์ฝ˜, ํšŒ์ƒ‰ ์ฒ˜๋ฆฌ ๋“ฑ)๋Š” ๋ฆฌ์…‹๋ฉ๋‹ˆ๋‹ค.
75
  """
76
  bubble_content = ""
 
87
 
88
  # human_message๋ฅผ ํ•œ ๊ธ€์ž์”ฉ ์ถ”๊ฐ€ (ํƒ€์ดํ•‘ ํšจ๊ณผ)
89
  for i, ch in enumerate(human_message):
90
+ bubble_content += f"<span data-index='{i}'>{ch}</span>"
91
+ current_html = wrapper_start + bubble_start + bubble_content + bubble_end + emoji_html + wrapper_end
92
+ yield current_html
93
+ time.sleep(0.05)
94
+
95
+ def submit_edit(edited_text):
96
+ """
97
+ Submit ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ ํ˜ธ์ถœ๋˜๋Š” ํ•จ์ˆ˜.
98
+ 1. ํŽธ์ง‘๋œ human ๋ฉ”์‹œ์ง€(โœ‚๏ธ ์•ž๋ถ€๋ถ„)๋ฅผ ์ƒˆ ํ–‰์œผ๋กœ global_data์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
99
+ 2. get_random_row_from_dataset() ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ์ƒˆ๋กœ์šด ๋Œ€ํ™”(row)๋ฅผ ๊ฐ€์ ธ์˜ค๊ณ ,
100
+ ์ „์—ญ ๋ณ€์ˆ˜ human_message์™€ ai_message๋ฅผ ์—…๋ฐ์ดํŠธํ•ฉ๋‹ˆ๋‹ค.
101
+ 3. ์ดˆ๊ธฐ ์ƒํƒœ์˜ human ๋งํ’์„  HTML๊ณผ ai ๋งํ’์„  HTML์„ ๋ฐ˜ํ™˜ํ•˜์—ฌ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๋ฆฌ์…‹ํ•ฉ๋‹ˆ๋‹ค.
102
+ """
103
+ global global_data, human_message, ai_message, conversation_id
104
+ # ์ƒˆ ํ–‰ ์ƒ์„ฑ (์ƒˆ๋กœ์šด conversation_id๋Š” ์ž„์˜ ์ƒ์„ฑ)
105
+ new_row = {
106
+ "conversation_id": conversation_id,
107
+ "overlapping": "I1",
108
+ "text": f"{edited_text}[turn]\n{ai_message}",
109
+ "used": False,
110
+ }
111
+ global_data.append(new_row)
112
+
113
+ # ์ƒˆ๋กœ์šด ๋Œ€ํ™” ํ–‰์„ ๊ฐ€์ ธ์˜ด (์ด์ „์— ์‚ฌ์šฉ๋˜์ง€ ์•Š์€ ๋Œ€ํ™”)
114
+ new_row_data = get_random_row_from_dataset()
115
+ if new_row_data is None:
116
+ human_message = "No valid conversation available."
117
+ ai_message = "No valid conversation available."
118
+ else:
119
+ raw_text = new_row_data['text']
120
+ human_message = raw_text.split("[turn]")[0].strip()
121
+ ai_message = raw_text.split("[turn]")[1].strip()
122
+
123
+ # ์ƒˆ๋กœ ์—…๋ฐ์ดํŠธ๋œ ๋งํ’์„  HTML ๋ฐ˜ํ™˜ (human์€ ๋นˆ ์ƒํƒœ, ai๋Š” ์ƒˆ ๋ฉ”์‹œ์ง€)
124
+ new_human_html = get_initial_human_html()
125
+ new_ai_html = f"""
126
+ <div class="ai-wrapper" style="display: flex; align-items: flex-end; justify-content: flex-start; gap: 5px; width: 100%;">
127
+ <div class="emoji">๐Ÿค–</div>
128
+ <div id="ai_message" class="speech-bubble ai">{ai_message}</div>
129
+ </div>
130
+ """
131
+ return new_human_html, new_ai_html
132
+
133
+ #############################################
134
+ # Gradio ์ธํ„ฐํŽ˜์ด์Šค ๊ตฌ์„ฑ
135
+ #############################################
136
 
137
  with gr.Blocks() as demo:
138
+ # (A) ํŽ˜์ด์ง€ ์ƒ๋‹จ์— ๋‹จ ํ•œ ๋ฒˆ ๋กœ๋“œ๋  ์Šคํฌ๋ฆฝํŠธ:
139
+ # - Human ๋งํ’์„  ๋‚ด์˜ <span data-index="...">๋ฅผ ํด๋ฆญํ•˜๋ฉด โœ‚๏ธ ์ด๋ชจํ‹ฐ์ฝ˜์ด ํ•ด๋‹น ์œ„์น˜์— ์‚ฝ์ž…๋˜๊ณ ,
140
+ # ํด๋ฆญํ•œ ์œ„์น˜ ์ดํ›„์˜ ํ…์ŠคํŠธ ์ƒ‰์ƒ์ด ํšŒ์ƒ‰์œผ๋กœ ๋ณ€๊ฒฝ๋ฉ๋‹ˆ๋‹ค.
141
  gr.HTML(
142
  """
143
  <script>
144
  document.addEventListener("click", function(event) {
145
+ // Human ๋งํ’์„  ๋‚ด์˜ <span data-index="..."> ํด๋ฆญ ์‹œ ์ฒ˜๋ฆฌ
146
  if (event.target && event.target.matches("div.speech-bubble.human span[data-index]")) {
147
  var span = event.target;
148
  var container = span.closest("div.speech-bubble.human");
149
+ // ๊ธฐ์กด์˜ โœ‚๏ธ ์ด๋ชจํ‹ฐ์ฝ˜(ํด๋ž˜์Šค "scissor") ์ œ๊ฑฐ
150
  var oldScissors = container.querySelectorAll("span.scissor");
151
  oldScissors.forEach(function(s) { s.remove(); });
152
+ // ๋ชจ๋“  span ์ƒ‰์ƒ ์ดˆ๊ธฐํ™”
153
  var spans = container.querySelectorAll("span[data-index]");
154
  spans.forEach(function(s) { s.style.color = ''; });
155
  // ํด๋ฆญํ•œ span ๋ฐ”๋กœ ๋’ค์— โœ‚๏ธ ์•„์ด์ฝ˜ ์‚ฝ์ž…
 
171
  """
172
  )
173
 
174
+ # (B) ์ถ”๊ฐ€ ์Šคํฌ๋ฆฝํŠธ:
175
+ # - Submit ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ, human_message div์˜ innerText์—์„œ "โœ‚๏ธ"๋ฅผ ๊ธฐ์ค€์œผ๋กœ ํŽธ์ง‘๋œ ํ…์ŠคํŠธ(์•ž๋ถ€๋ถ„)๋ฅผ
176
+ # ์ˆจ๊น€ ํ…์ŠคํŠธ๋ฐ•์Šค(edited_text_input)์— ์—…๋ฐ์ดํŠธํ•ฉ๋‹ˆ๋‹ค.
177
+ gr.HTML(
178
+ """
179
+ <script>
180
+ // DOMContentLoaded ์ด๋ฒคํŠธ ์ดํ›„์— ๋ฒ„ํŠผ ์š”์†Œ๊ฐ€ ์ค€๋น„๋˜์—ˆ์„ ๋•Œ ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ ๋“ฑ๋ก
181
+ document.addEventListener("DOMContentLoaded", function() {
182
+ var submitBtn = document.getElementById("submit_btn");
183
+ if(submitBtn){
184
+ submitBtn.addEventListener("click", function(){
185
+ var humanDiv = document.getElementById("human_message");
186
+ if(humanDiv){
187
+ // innerText์—์„œ "โœ‚๏ธ"๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์•ž๋ถ€๋ถ„ ์ถ”์ถœ
188
+ var edited_text = humanDiv.innerText.split("โœ‚๏ธ")[0];
189
+ document.getElementById("edited_text_input").value = edited_text;
190
+ }
191
+ });
192
+ }
193
+ });
194
+ </script>
195
+ """
196
+ )
197
+
198
+ # (C) CSS ์Šคํƒ€์ผ
199
  gr.HTML(
200
  """
201
  <style>
 
256
  gr.Markdown("## Chat Interface")
257
 
258
  with gr.Column(elem_classes="chat-container"):
259
+ # Human ๋งํ’์„  (์ดˆ๊ธฐ: ๋นˆ ๋ฉ”์‹œ์ง€์™€ ๐Ÿง‘ ์ด๋ชจํ‹ฐ์ฝ˜)
260
  human_bubble = gr.HTML(get_initial_human_html())
261
+ # AI ๋งํ’์„  (์™ผ์ชฝ์— ๐Ÿค– ์ด๋ชจํ‹ฐ์ฝ˜๊ณผ ํ•จ๊ป˜ ๊ณ ์ • ๋ฉ”์‹œ์ง€)
262
+ ai_html = f"""
 
263
  <div class="ai-wrapper" style="display: flex; align-items: flex-end; justify-content: flex-start; gap: 5px; width: 100%;">
264
  <div class="emoji">๐Ÿค–</div>
265
+ <div id="ai_message" class="speech-bubble ai">{ai_message}</div>
266
  </div>
267
  """
268
  ai_bubble = gr.HTML(ai_html)
269
 
270
+ # (D) ์ˆจ๊น€ ํ…์ŠคํŠธ๋ฐ•์Šค: ํŽธ์ง‘๋œ ํ…์ŠคํŠธ(โœ‚๏ธ ์•ž๋ถ€๋ถ„)๋ฅผ ์ €์žฅ (visible=False)
271
+ edited_text_input = gr.Textbox(visible=False, elem_id="edited_text_input")
272
+
273
+ # (E) ๋ฒ„ํŠผ ์˜์—ญ: Start Typing๊ณผ Submit ๋ฒ„ํŠผ์„ ๊ฐ™์€ ํ–‰์— ๋ฐฐ์น˜
274
+ with gr.Row():
275
+ start_button = gr.Button("Start Typing")
276
+ # Submit ๋ฒ„ํŠผ์— elem_id "submit_btn"์„ ๋ถ€์—ฌํ•˜์—ฌ JS์—์„œ ์ฐธ์กฐํ•ฉ๋‹ˆ๋‹ค.
277
+ submit_button = gr.Button("Submit", elem_id="submit_btn")
278
+
279
+ # Start Typing ๋ฒ„ํŠผ: human_message ์ŠคํŠธ๋ฆฌ๋ฐ ์‹œ์ž‘ (ํƒ€์ดํ•‘ ํšจ๊ณผ)
280
  start_button.click(fn=stream_human_message, outputs=human_bubble)
281
+
282
+ # Submit ๋ฒ„ํŠผ: hidden edited_text_input ๊ฐ’์„ ์ž…๋ ฅ๋ฐ›์•„ submit_edit ํ•จ์ˆ˜ ํ˜ธ์ถœ โ†’ ์ƒˆ๋กœ์šด ๋Œ€ํ™”๋กœ ์—…๋ฐ์ดํŠธ
283
+ submit_button.click(fn=submit_edit, inputs=edited_text_input, outputs=[human_bubble, ai_bubble])
284
 
285
  demo.launch()
286