gaeunseo commited on
Commit
7dd799a
ยท
verified ยท
1 Parent(s): 36dbbcc

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +68 -28
app.py CHANGED
@@ -7,17 +7,14 @@ ai_message = "Hello, how can I help you?"
7
 
8
  def stream_human_message():
9
  """
10
- Human ๋ฉ”์‹œ์ง€๋ฅผ ๋ฌธ์ž ๋‹จ์œ„๋กœ ํƒ€์ดํ•‘ํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ์ŠคํŠธ๋ฆฌ๋ฐํ•˜๋ฉด์„œ,
11
- ๊ฐ ๋ฌธ์ž์— ํด๋ฆญ ์ด๋ฒคํŠธ๋ฅผ ๋ถ€์—ฌํ•˜์—ฌ, ํด๋ฆญ ์‹œ ํ•ด๋‹น ๋ฌธ์ž ์ดํ›„์— โœ‚๏ธ ์ด๋ชจํ‹ฐ์ฝ˜ ์‚ฝ์ž… ๋ฐ ์ž”์—ฌ ๋ฌธ์ž ํšŒ์ƒ‰ ์ฒ˜๋ฆฌ๋ฅผ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.
12
-
13
- ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ํ•จ์ˆ˜๋กœ ๊ตฌํ˜„ํ•˜์—ฌ, ๋งค๋ฒˆ yield๋กœ HTML์„ ๋ฐ˜ํ™˜ํ•จ์œผ๋กœ์จ ์ŠคํŠธ๋ฆฌ๋ฐ ํšจ๊ณผ๋ฅผ ๋ƒ…๋‹ˆ๋‹ค.
14
  """
15
- # ํŽ˜์ด์ง€์— ์‚ฝ์ž…ํ•  JavaScript ์ฝ”๋“œ (ํ•œ ๋ฒˆ๋งŒ ์‹คํ–‰๋˜๋„๋ก ์ „์—ญ ํ”Œ๋ž˜๊ทธ ์‚ฌ์šฉ)
16
  js_script = """
17
  <script>
18
  if (window.cutDone === undefined) { window.cutDone = false; }
19
  function handleClick(span) {
20
- if (window.cutDone) return; // ์ด๋ฏธ ํด๋ฆญํ•œ ๊ฒฝ์šฐ ๋ฌด์‹œ
21
  window.cutDone = true;
22
  // ํด๋ฆญํ•œ span ๋ฐ”๋กœ ๋’ค์— โœ‚๏ธ ์ด๋ชจํ‹ฐ์ฝ˜ ์‚ฝ์ž…
23
  var scissor = document.createElement('span');
@@ -35,41 +32,84 @@ def stream_human_message():
35
  }
36
  </script>
37
  """
38
- # Human ๋งํ’์„ ์˜ HTML ์ปจํ…Œ์ด๋„ˆ ์‹œ์ž‘ (์˜ค๋ฅธ์ชฝ ์ •๋ ฌ, ๋ฐฐ๊ฒฝ์ƒ‰ ๋“ฑ ์Šคํƒ€์ผ ์ง€์ •)
39
- html = js_script + (
40
- "<div id='human_message' style='text-align: right; background-color: #d0f0d0; "
41
- "padding: 10px; border-radius: 10px; display: inline-block;'>"
42
- )
43
- # ์ดˆ๊ธฐ ์ƒํƒœ: ์•„์ง ๋‚ด์šฉ์ด ์—†์„ ๋•Œ yield
44
  yield html
45
- # ๋ฉ”์‹œ์ง€๋ฅผ ํ•œ ๊ธ€์ž์”ฉ ์ถ”๊ฐ€ํ•˜๋ฉฐ yield (ํƒ€์ดํ•‘ ํšจ๊ณผ)
46
  for i, ch in enumerate(human_message):
47
  html += f"<span data-index='{i}' onclick='handleClick(this)'>{ch}</span>"
48
  yield html
49
- time.sleep(0.05) # ํƒ€์ดํ•‘ ํšจ๊ณผ๋ฅผ ์œ„ํ•œ ๋”œ๋ ˆ์ด (0.05์ดˆ)
50
- # ์ปจํ…Œ์ด๋„ˆ ์ข…๋ฃŒ ํƒœ๊ทธ ์ถ”๊ฐ€
51
  html += "</div>"
52
  yield html
53
 
54
  # Gradio ์ธํ„ฐํŽ˜์ด์Šค ๊ตฌ์„ฑ
55
  with gr.Blocks() as demo:
56
  gr.Markdown("## Chat Interface")
57
- with gr.Row():
58
- # ์™ผ์ชฝ: AI ๋งํ’์„  (๊ณ ์ • ํ…์ŠคํŠธ)
59
- with gr.Column():
60
- ai_bubble = gr.HTML(
61
- f"<div style='text-align: left; background-color: #e0e0e0; padding: 10px; "
62
- "border-radius: 10px; display: inline-block;'>"
63
- f"{ai_message}"
64
- "</div>"
65
- )
66
- # ์˜ค๋ฅธ์ชฝ: Human ๋งํ’์„  (์ŠคํŠธ๋ฆฌ๋ฐ ํ…์ŠคํŠธ)
67
- with gr.Column():
68
- human_bubble = gr.HTML("")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
69
 
70
  # ํƒ€์ดํ•‘ ํšจ๊ณผ๋ฅผ ์‹œ์ž‘ํ•  ๋ฒ„ํŠผ
71
  start_button = gr.Button("Start Typing")
72
- # ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ํ•จ์ˆ˜๋ฅผ click ์ด๋ฒคํŠธ์— ๋“ฑ๋ก (stream ์ธ์ž ์—†์ด๋„ ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ํ•จ์ˆ˜์˜ yield๊ฐ€ ์ˆœ์ฐจ์ ์œผ๋กœ ๋ฐ˜์˜๋ฉ๋‹ˆ๋‹ค)
73
  start_button.click(fn=stream_human_message, outputs=human_bubble)
74
 
75
  demo.launch()
 
7
 
8
  def stream_human_message():
9
  """
10
+ Human ๋ฉ”์‹œ์ง€๋ฅผ ํ•œ ๊ธ€์ž์”ฉ ํƒ€์ดํ•‘ํ•˜๋Š” ํšจ๊ณผ๋กœ ์ŠคํŠธ๋ฆฌ๋ฐํ•˜๋ฉด์„œ,
11
+ ๊ฐ ๋ฌธ์ž์— ํด๋ฆญ ์ด๋ฒคํŠธ(handleClick)๋ฅผ ๋ถ€์—ฌํ•ฉ๋‹ˆ๋‹ค.
 
 
12
  """
 
13
  js_script = """
14
  <script>
15
  if (window.cutDone === undefined) { window.cutDone = false; }
16
  function handleClick(span) {
17
+ if (window.cutDone) return;
18
  window.cutDone = true;
19
  // ํด๋ฆญํ•œ span ๋ฐ”๋กœ ๋’ค์— โœ‚๏ธ ์ด๋ชจํ‹ฐ์ฝ˜ ์‚ฝ์ž…
20
  var scissor = document.createElement('span');
 
32
  }
33
  </script>
34
  """
35
+ # Human ๋งํ’์„  ์ปจํ…Œ์ด๋„ˆ (CSS ํด๋ž˜์Šค 'speech-bubble human'๋ฅผ ์ ์šฉ)
36
+ html = js_script + "<div id='human_message' class='speech-bubble human'>"
 
 
 
 
37
  yield html
38
+ # ํ•œ ๊ธ€์ž์”ฉ <span> ํƒœ๊ทธ๋กœ ์ถ”๊ฐ€ (ํด๋ฆญ ์‹œ handleClick(this) ํ˜ธ์ถœ)
39
  for i, ch in enumerate(human_message):
40
  html += f"<span data-index='{i}' onclick='handleClick(this)'>{ch}</span>"
41
  yield html
42
+ time.sleep(0.05) # ํƒ€์ดํ•‘ ํšจ๊ณผ ๋”œ๋ ˆ์ด (0.05์ดˆ)
 
43
  html += "</div>"
44
  yield html
45
 
46
  # Gradio ์ธํ„ฐํŽ˜์ด์Šค ๊ตฌ์„ฑ
47
  with gr.Blocks() as demo:
48
  gr.Markdown("## Chat Interface")
49
+ # CSS ์Šคํƒ€์ผ์„ ์ ์šฉํ•˜์—ฌ ๋งํ’์„  ๋ชจ์–‘๊ณผ ๋ฐฐ์น˜ ์„ค์ •
50
+ gr.HTML(
51
+ """
52
+ <style>
53
+ /* ์ฑ„ํŒ… ์ „์ฒด ์ปจํ…Œ์ด๋„ˆ (์„ธ๋กœ ๋ฐฐ์น˜) */
54
+ .chat-container {
55
+ display: flex;
56
+ flex-direction: column;
57
+ gap: 10px;
58
+ }
59
+ /* ๊ณตํ†ต ๋งํ’์„  ์Šคํƒ€์ผ */
60
+ .speech-bubble {
61
+ position: relative;
62
+ padding: 10px 15px;
63
+ border-radius: 15px;
64
+ max-width: 70%;
65
+ font-family: sans-serif;
66
+ font-size: 16px;
67
+ line-height: 1.4;
68
+ }
69
+ /* Human ๋งํ’์„  (์˜ค๋ฅธ์ชฝ ์ •๋ ฌ, ๋งํ’์„  ๊ผฌ๋ฆฌ ์˜ค๋ฅธ์ชฝ) */
70
+ .human {
71
+ background: #d0f0d0;
72
+ align-self: flex-end;
73
+ margin-right: 10px;
74
+ }
75
+ .human::after {
76
+ content: "";
77
+ position: absolute;
78
+ right: -10px;
79
+ top: 10px;
80
+ border-width: 10px 0 10px 10px;
81
+ border-style: solid;
82
+ border-color: transparent transparent transparent #d0f0d0;
83
+ }
84
+ /* AI ๋งํ’์„  (์™ผ์ชฝ ์ •๋ ฌ, ๋งํ’์„  ๊ผฌ๋ฆฌ ์™ผ์ชฝ) */
85
+ .ai {
86
+ background: #e0e0e0;
87
+ align-self: flex-start;
88
+ margin-left: 10px;
89
+ }
90
+ .ai::after {
91
+ content: "";
92
+ position: absolute;
93
+ left: -10px;
94
+ top: 10px;
95
+ border-width: 10px 10px 10px 0;
96
+ border-style: solid;
97
+ border-color: transparent #e0e0e0 transparent transparent;
98
+ }
99
+ </style>
100
+ """
101
+ )
102
+
103
+ # ์ฑ„ํŒ… ๋ฉ”์‹œ์ง€๋“ค์ด ๋‹ด๊ธธ ์ปจํ…Œ์ด๋„ˆ (์„ธ๋กœ ๋ฐฐ์น˜)
104
+ with gr.Column(elem_classes="chat-container"):
105
+ # ์œ„์ชฝ์— Human ๋ฉ”์‹œ์ง€ (์ŠคํŠธ๋ฆฌ๋ฐ ์—…๋ฐ์ดํŠธ๋จ)
106
+ human_bubble = gr.HTML("")
107
+ # ์•„๋ž˜์ชฝ์— AI ๋ฉ”์‹œ์ง€ (๊ณ ์ •)
108
+ ai_bubble = gr.HTML(f"<div id='ai_message' class='speech-bubble ai'>{ai_message}</div>")
109
 
110
  # ํƒ€์ดํ•‘ ํšจ๊ณผ๋ฅผ ์‹œ์ž‘ํ•  ๋ฒ„ํŠผ
111
  start_button = gr.Button("Start Typing")
112
+ # ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ํ•จ์ˆ˜ ์‚ฌ์šฉ (stream=True ์—†์ด yield ๋ฐฉ์‹์œผ๋กœ ์ŠคํŠธ๋ฆฌ๋ฐ)
113
  start_button.click(fn=stream_human_message, outputs=human_bubble)
114
 
115
  demo.launch()