cutechicken commited on
Commit
0223744
β€’
1 Parent(s): 0de5bb6

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +235 -134
app.py CHANGED
@@ -8,10 +8,15 @@ import random
8
  from datasets import load_dataset
9
  import numpy as np
10
  from sklearn.feature_extraction.text import TfidfVectorizer
 
 
 
 
11
 
12
  # GPU λ©”λͺ¨λ¦¬ 관리
13
  torch.cuda.empty_cache()
14
 
 
15
  HF_TOKEN = os.environ.get("HF_TOKEN", None)
16
  MODEL_ID = "CohereForAI/c4ai-command-r7b-12-2024"
17
  MODELS = os.environ.get("MODELS")
@@ -36,6 +41,64 @@ vectorizer = TfidfVectorizer(max_features=1000)
36
  question_vectors = vectorizer.fit_transform(questions)
37
  print("TF-IDF 벑터화 μ™„λ£Œ")
38
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
  def find_relevant_context(query, top_k=3):
40
  # 쿼리 벑터화
41
  query_vector = vectorizer.transform([query])
@@ -49,7 +112,7 @@ def find_relevant_context(query, top_k=3):
49
  # κ΄€λ ¨ μ»¨ν…μŠ€νŠΈ μΆ”μΆœ
50
  relevant_contexts = []
51
  for idx in top_indices:
52
- if similarities[idx] > 0: # μœ μ‚¬λ„κ°€ 0보닀 큰 경우만 포함
53
  relevant_contexts.append({
54
  'question': questions[idx],
55
  'answer': wiki_dataset['train']['answer'][idx],
@@ -58,16 +121,94 @@ def find_relevant_context(query, top_k=3):
58
 
59
  return relevant_contexts
60
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61
  @spaces.GPU
62
- def stream_chat(message: str, history: list, temperature: float, max_new_tokens: int, top_p: float, top_k: int, penalty: float):
63
  print(f'message is - {message}')
64
  print(f'history is - {history}')
65
 
 
 
 
 
 
 
 
66
  # κ΄€λ ¨ μ»¨ν…μŠ€νŠΈ μ°ΎκΈ°
67
  relevant_contexts = find_relevant_context(message)
68
- context_prompt = "\n\nκ΄€λ ¨ μ°Έκ³  정보:\n"
69
  for ctx in relevant_contexts:
70
- context_prompt += f"Q: {ctx['question']}\nA: {ctx['answer']}\nμœ μ‚¬λ„: {ctx['similarity']:.3f}\n\n"
71
 
72
  # λŒ€ν™” νžˆμŠ€ν† λ¦¬ ꡬ성
73
  conversation = []
@@ -76,15 +217,13 @@ def stream_chat(message: str, history: list, temperature: float, max_new_tokens:
76
  {"role": "user", "content": prompt},
77
  {"role": "assistant", "content": answer}
78
  ])
79
-
80
 
81
- # μ»¨ν…μŠ€νŠΈλ₯Ό ν¬ν•¨ν•œ μ΅œμ’… ν”„λ‘¬ν”„νŠΈ ꡬ성
82
- final_message = context_prompt + "\nν˜„μž¬ 질문: " + message
83
  conversation.append({"role": "user", "content": final_message})
84
 
85
  input_ids = tokenizer.apply_chat_template(conversation, tokenize=False, add_generation_prompt=True)
86
  inputs = tokenizer(input_ids, return_tensors="pt").to(0)
87
-
88
 
89
  streamer = TextIteratorStreamer(tokenizer, timeout=10., skip_prompt=True, skip_special_tokens=True)
90
 
@@ -108,8 +247,6 @@ def stream_chat(message: str, history: list, temperature: float, max_new_tokens:
108
  buffer += new_text
109
  yield buffer
110
 
111
- chatbot = gr.Chatbot(height=500)
112
-
113
  CSS = """
114
  /* 전체 νŽ˜μ΄μ§€ μŠ€νƒ€μΌλ§ */
115
  body {
@@ -117,131 +254,72 @@ body {
117
  min-height: 100vh;
118
  font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
119
  }
120
- /* 메인 μ»¨ν…Œμ΄λ„ˆ */
121
- .container {
122
- max-width: 1200px;
123
- margin: 0 auto;
124
- padding: 2rem;
125
- background: rgba(255, 255, 255, 0.95);
126
- border-radius: 20px;
127
- box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
128
- backdrop-filter: blur(10px);
129
- transform: perspective(1000px) translateZ(0);
130
- transition: all 0.3s ease;
131
- }
132
- /* 제λͺ© μŠ€νƒ€μΌλ§ */
133
- h1 {
134
- color: #2d3436;
135
- font-size: 2.5rem;
136
- text-align: center;
137
- margin-bottom: 2rem;
138
- text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.1);
139
- transform: perspective(1000px) translateZ(20px);
140
- }
141
- h3 {
142
- text-align: center;
143
- color: #2d3436;
144
- font-size: 1.5rem;
145
- margin: 1rem 0;
146
- }
147
- /* μ±„νŒ…λ°•μŠ€ μŠ€νƒ€μΌλ§ */
148
- .chatbox {
149
- background: white;
150
- border-radius: 15px;
151
- box-shadow: 0 8px 32px rgba(31, 38, 135, 0.15);
152
- backdrop-filter: blur(4px);
153
- border: 1px solid rgba(255, 255, 255, 0.18);
154
- padding: 1rem;
155
- margin: 1rem 0;
156
- transform: translateZ(0);
157
- transition: all 0.3s ease;
158
- }
159
- /* λ©”μ‹œμ§€ μŠ€νƒ€μΌλ§ */
160
- .chatbox .messages .message.user {
161
- background: linear-gradient(145deg, #e1f5fe, #bbdefb);
162
- border-radius: 15px;
163
- padding: 1rem;
164
- margin: 0.5rem;
165
- box-shadow: 5px 5px 15px rgba(0, 0, 0, 0.05);
166
- transform: translateZ(10px);
167
- animation: messageIn 0.3s ease-out;
168
- }
169
- .chatbox .messages .message.bot {
170
- background: linear-gradient(145deg, #f5f5f5, #eeeeee);
171
- border-radius: 15px;
172
- padding: 1rem;
173
- margin: 0.5rem;
174
- box-shadow: 5px 5px 15px rgba(0, 0, 0, 0.05);
175
- transform: translateZ(10px);
176
- animation: messageIn 0.3s ease-out;
177
- }
178
- /* λ²„νŠΌ μŠ€νƒ€μΌλ§ */
179
- .duplicate-button {
180
- background: linear-gradient(145deg, #24292e, #1a1e22) !important;
181
- color: white !important;
182
- border-radius: 100vh !important;
183
- padding: 0.8rem 1.5rem !important;
184
- box-shadow: 3px 3px 10px rgba(0, 0, 0, 0.2) !important;
185
- transition: all 0.3s ease !important;
186
- border: none !important;
187
- cursor: pointer !important;
188
- }
189
- .duplicate-button:hover {
190
- transform: translateY(-2px) !important;
191
- box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3) !important;
192
- }
193
- /* μž…λ ₯ ν•„λ“œ μŠ€νƒ€μΌλ§ */
194
  """
195
 
196
  with gr.Blocks(css=CSS) as demo:
197
- gr.ChatInterface(
198
- fn=stream_chat,
199
- chatbot=chatbot,
200
- fill_height=True,
201
- theme="soft",
202
- additional_inputs_accordion=gr.Accordion(label="βš™οΈ μ˜΅μ…˜", open=False, render=False),
203
- additional_inputs=[
204
- gr.Slider(
205
- minimum=0,
206
- maximum=1,
207
- step=0.1,
208
- value=0.8,
209
- label="μ˜¨λ„",
210
- render=False,
211
- ),
212
- gr.Slider(
213
- minimum=128,
214
- maximum=8000,
215
- step=1,
216
- value=4000,
217
- label="μ΅œλŒ€ 토큰 수",
218
- render=False,
219
- ),
220
- gr.Slider(
221
- minimum=0.0,
222
- maximum=1.0,
223
- step=0.1,
224
- value=0.8,
225
- label="μƒμœ„ ν™•λ₯ ",
226
- render=False,
227
- ),
228
- gr.Slider(
229
- minimum=1,
230
- maximum=20,
231
- step=1,
232
- value=20,
233
- label="μƒμœ„ K",
234
- render=False,
235
- ),
236
- gr.Slider(
237
- minimum=0.0,
238
- maximum=2.0,
239
- step=0.1,
240
- value=1.0,
241
- label="반볡 νŒ¨λ„ν‹°",
242
- render=False,
243
- ),
244
- ],
 
 
 
 
 
 
 
 
 
 
 
 
 
 
245
  examples=[
246
  ["ν•œκ΅­μ˜ 전톡 μ ˆκΈ°μ™€ 24μ ˆκΈ°μ— λŒ€ν•΄ μžμ„Ένžˆ μ„€λͺ…ν•΄μ£Όμ„Έμš”."],
247
  ["μš°λ¦¬λ‚˜λΌ 전톡 μŒμ‹ 쀑 건강에 쒋은 λ°œνš¨μŒμ‹ 5가지λ₯Ό μΆ”μ²œν•˜κ³  κ·Έ 효λŠ₯을 μ„€λͺ…ν•΄μ£Όμ„Έμš”."],
@@ -256,8 +334,31 @@ with gr.Blocks(css=CSS) as demo:
256
  ["ν•œκ΅­μ˜ 전톡 의볡인 ν•œλ³΅μ˜ ꡬ쑰와 νŠΉμ§•μ„ 과학적, 미학적 κ΄€μ μ—μ„œ λΆ„μ„ν•΄μ£Όμ„Έμš”."],
257
  ["ν•œκ΅­μ˜ 전톡 κ°€μ˜₯ ꡬ쑰λ₯Ό 기후와 ν™˜κ²½ κ΄€μ μ—μ„œ λΆ„μ„ν•˜κ³ , ν˜„λŒ€ 건좕에 μ μš©ν•  수 μžˆλŠ” μš”μ†Œλ₯Ό μ œμ•ˆν•΄μ£Όμ„Έμš”."]
258
  ],
259
- cache_examples=False,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
260
  )
261
 
262
  if __name__ == "__main__":
263
- demo.launch()
 
8
  from datasets import load_dataset
9
  import numpy as np
10
  from sklearn.feature_extraction.text import TfidfVectorizer
11
+ import pandas as pd
12
+ from typing import List, Tuple
13
+ import json
14
+ from datetime import datetime
15
 
16
  # GPU λ©”λͺ¨λ¦¬ 관리
17
  torch.cuda.empty_cache()
18
 
19
+ # ν™˜κ²½ λ³€μˆ˜ μ„€μ •
20
  HF_TOKEN = os.environ.get("HF_TOKEN", None)
21
  MODEL_ID = "CohereForAI/c4ai-command-r7b-12-2024"
22
  MODELS = os.environ.get("MODELS")
 
41
  question_vectors = vectorizer.fit_transform(questions)
42
  print("TF-IDF 벑터화 μ™„λ£Œ")
43
 
44
+ class ChatHistory:
45
+ def __init__(self):
46
+ self.history = []
47
+ self.history_file = "/tmp/chat_history.json"
48
+ self.load_history()
49
+
50
+ def add_conversation(self, user_msg: str, assistant_msg: str):
51
+ conversation = {
52
+ "timestamp": datetime.now().isoformat(),
53
+ "messages": [
54
+ {"role": "user", "content": user_msg},
55
+ {"role": "assistant", "content": assistant_msg}
56
+ ]
57
+ }
58
+ self.history.append(conversation)
59
+ self.save_history()
60
+
61
+ def format_for_display(self):
62
+ formatted = []
63
+ for conv in self.history:
64
+ formatted.append([
65
+ conv["messages"][0]["content"],
66
+ conv["messages"][1]["content"]
67
+ ])
68
+ return formatted
69
+
70
+ def get_messages_for_api(self):
71
+ messages = []
72
+ for conv in self.history:
73
+ messages.extend([
74
+ {"role": "user", "content": conv["messages"][0]["content"]},
75
+ {"role": "assistant", "content": conv["messages"][1]["content"]}
76
+ ])
77
+ return messages
78
+
79
+ def clear_history(self):
80
+ self.history = []
81
+ self.save_history()
82
+
83
+ def save_history(self):
84
+ try:
85
+ with open(self.history_file, 'w', encoding='utf-8') as f:
86
+ json.dump(self.history, f, ensure_ascii=False, indent=2)
87
+ except Exception as e:
88
+ print(f"νžˆμŠ€ν† λ¦¬ μ €μž₯ μ‹€νŒ¨: {e}")
89
+
90
+ def load_history(self):
91
+ try:
92
+ if os.path.exists(self.history_file):
93
+ with open(self.history_file, 'r', encoding='utf-8') as f:
94
+ self.history = json.load(f)
95
+ except Exception as e:
96
+ print(f"νžˆμŠ€ν† λ¦¬ λ‘œλ“œ μ‹€νŒ¨: {e}")
97
+ self.history = []
98
+
99
+ # μ „μ—­ ChatHistory μΈμŠ€ν„΄μŠ€ 생성
100
+ chat_history = ChatHistory()
101
+
102
  def find_relevant_context(query, top_k=3):
103
  # 쿼리 벑터화
104
  query_vector = vectorizer.transform([query])
 
112
  # κ΄€λ ¨ μ»¨ν…μŠ€νŠΈ μΆ”μΆœ
113
  relevant_contexts = []
114
  for idx in top_indices:
115
+ if similarities[idx] > 0:
116
  relevant_contexts.append({
117
  'question': questions[idx],
118
  'answer': wiki_dataset['train']['answer'][idx],
 
121
 
122
  return relevant_contexts
123
 
124
+ def analyze_file_content(content, file_type):
125
+ """Analyze file content and return structural summary"""
126
+ if file_type in ['parquet', 'csv']:
127
+ try:
128
+ lines = content.split('\n')
129
+ header = lines[0]
130
+ columns = header.count('|') - 1
131
+ rows = len(lines) - 3
132
+ return f"πŸ“Š 데이터셋 ꡬ쑰: {columns}개 컬럼, {rows}개 데이터"
133
+ except:
134
+ return "❌ 데이터셋 ꡬ쑰 뢄석 μ‹€νŒ¨"
135
+
136
+ lines = content.split('\n')
137
+ total_lines = len(lines)
138
+ non_empty_lines = len([line for line in lines if line.strip()])
139
+
140
+ if any(keyword in content.lower() for keyword in ['def ', 'class ', 'import ', 'function']):
141
+ functions = len([line for line in lines if 'def ' in line])
142
+ classes = len([line for line in lines if 'class ' in line])
143
+ imports = len([line for line in lines if 'import ' in line or 'from ' in line])
144
+ return f"πŸ’» μ½”λ“œ ꡬ쑰: {total_lines}쀄 (ν•¨μˆ˜: {functions}, 클래슀: {classes}, μž„ν¬νŠΈ: {imports})"
145
+
146
+ paragraphs = content.count('\n\n') + 1
147
+ words = len(content.split())
148
+ return f"πŸ“ λ¬Έμ„œ ꡬ쑰: {total_lines}쀄, {paragraphs}단락, μ•½ {words}단어"
149
+
150
+ def read_uploaded_file(file):
151
+ if file is None:
152
+ return "", ""
153
+ try:
154
+ file_ext = os.path.splitext(file.name)[1].lower()
155
+
156
+ if file_ext == '.parquet':
157
+ df = pd.read_parquet(file.name, engine='pyarrow')
158
+ content = df.head(10).to_markdown(index=False)
159
+ return content, "parquet"
160
+ elif file_ext == '.csv':
161
+ encodings = ['utf-8', 'cp949', 'euc-kr', 'latin1']
162
+ for encoding in encodings:
163
+ try:
164
+ df = pd.read_csv(file.name, encoding=encoding)
165
+ content = f"πŸ“Š 데이터 미리보기:\n{df.head(10).to_markdown(index=False)}\n\n"
166
+ content += f"\nπŸ“ˆ 데이터 정보:\n"
167
+ content += f"- 전체 ν–‰ 수: {len(df)}\n"
168
+ content += f"- 전체 μ—΄ 수: {len(df.columns)}\n"
169
+ content += f"- 컬럼 λͺ©λ‘: {', '.join(df.columns)}\n"
170
+ content += f"\nπŸ“‹ 컬럼 데이터 νƒ€μž…:\n"
171
+ for col, dtype in df.dtypes.items():
172
+ content += f"- {col}: {dtype}\n"
173
+ null_counts = df.isnull().sum()
174
+ if null_counts.any():
175
+ content += f"\n⚠️ 결츑치:\n"
176
+ for col, null_count in null_counts[null_counts > 0].items():
177
+ content += f"- {col}: {null_count}개 λˆ„λ½\n"
178
+ return content, "csv"
179
+ except UnicodeDecodeError:
180
+ continue
181
+ raise UnicodeDecodeError(f"❌ μ§€μ›λ˜λŠ” μΈμ½”λ”©μœΌλ‘œ νŒŒμΌμ„ 읽을 수 μ—†μŠ΅λ‹ˆλ‹€ ({', '.join(encodings)})")
182
+ else:
183
+ encodings = ['utf-8', 'cp949', 'euc-kr', 'latin1']
184
+ for encoding in encodings:
185
+ try:
186
+ with open(file.name, 'r', encoding=encoding) as f:
187
+ content = f.read()
188
+ return content, "text"
189
+ except UnicodeDecodeError:
190
+ continue
191
+ raise UnicodeDecodeError(f"❌ μ§€μ›λ˜λŠ” μΈμ½”λ”©μœΌλ‘œ νŒŒμΌμ„ 읽을 수 μ—†μŠ΅λ‹ˆλ‹€ ({', '.join(encodings)})")
192
+ except Exception as e:
193
+ return f"❌ 파일 읽기 였λ₯˜: {str(e)}", "error"
194
+
195
  @spaces.GPU
196
+ def stream_chat(message: str, history: list, uploaded_file, temperature: float, max_new_tokens: int, top_p: float, top_k: int, penalty: float):
197
  print(f'message is - {message}')
198
  print(f'history is - {history}')
199
 
200
+ # 파일 μ—…λ‘œλ“œ 처리
201
+ file_context = ""
202
+ if uploaded_file:
203
+ content, file_type = read_uploaded_file(uploaded_file)
204
+ if content:
205
+ file_context = f"\n\nμ—…λ‘œλ“œλœ 파일 λ‚΄μš©:\n```\n{content}\n```"
206
+
207
  # κ΄€λ ¨ μ»¨ν…μŠ€νŠΈ μ°ΎκΈ°
208
  relevant_contexts = find_relevant_context(message)
209
+ wiki_context = "\n\nκ΄€λ ¨ μœ„ν‚€ν”Όλ””μ•„ 정보:\n"
210
  for ctx in relevant_contexts:
211
+ wiki_context += f"Q: {ctx['question']}\nA: {ctx['answer']}\nμœ μ‚¬λ„: {ctx['similarity']:.3f}\n\n"
212
 
213
  # λŒ€ν™” νžˆμŠ€ν† λ¦¬ ꡬ성
214
  conversation = []
 
217
  {"role": "user", "content": prompt},
218
  {"role": "assistant", "content": answer}
219
  ])
 
220
 
221
+ # μ΅œμ’… ν”„λ‘¬ν”„νŠΈ ꡬ성
222
+ final_message = file_context + wiki_context + "\nν˜„μž¬ 질문: " + message
223
  conversation.append({"role": "user", "content": final_message})
224
 
225
  input_ids = tokenizer.apply_chat_template(conversation, tokenize=False, add_generation_prompt=True)
226
  inputs = tokenizer(input_ids, return_tensors="pt").to(0)
 
227
 
228
  streamer = TextIteratorStreamer(tokenizer, timeout=10., skip_prompt=True, skip_special_tokens=True)
229
 
 
247
  buffer += new_text
248
  yield buffer
249
 
 
 
250
  CSS = """
251
  /* 전체 νŽ˜μ΄μ§€ μŠ€νƒ€μΌλ§ */
252
  body {
 
254
  min-height: 100vh;
255
  font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
256
  }
257
+ /* ... (μ΄μ „μ˜ CSS μŠ€νƒ€μΌ μœ μ§€) ... */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
258
  """
259
 
260
  with gr.Blocks(css=CSS) as demo:
261
+ with gr.Row():
262
+ with gr.Column(scale=2):
263
+ chatbot = gr.Chatbot(height=500)
264
+
265
+ msg = gr.Textbox(
266
+ label="λ©”μ‹œμ§€ μž…λ ₯",
267
+ show_label=False,
268
+ placeholder="무엇이든 λ¬Όμ–΄λ³΄μ„Έμš”... πŸ’­",
269
+ container=False
270
+ )
271
+
272
+ with gr.Row():
273
+ clear = gr.ClearButton([msg, chatbot], value="λŒ€ν™”λ‚΄μš© μ§€μš°κΈ°")
274
+ send = gr.Button("보내기 πŸ“€")
275
+
276
+ with gr.Column(scale=1):
277
+ gr.Markdown("### 파일 μ—…λ‘œλ“œ πŸ“")
278
+ file_upload = gr.File(
279
+ label="파일 선택",
280
+ file_types=["text", ".csv", ".parquet"],
281
+ type="filepath"
282
+ )
283
+
284
+ with gr.Accordion("κ³ κΈ‰ μ„€μ • βš™οΈ", open=False):
285
+ temperature = gr.Slider(
286
+ minimum=0,
287
+ maximum=1,
288
+ step=0.1,
289
+ value=0.8,
290
+ label="μ˜¨λ„",
291
+ )
292
+ max_new_tokens = gr.Slider(
293
+ minimum=128,
294
+ maximum=8000,
295
+ step=1,
296
+ value=4000,
297
+ label="μ΅œλŒ€ 토큰 수",
298
+ )
299
+ top_p = gr.Slider(
300
+ minimum=0.0,
301
+ maximum=1.0,
302
+ step=0.1,
303
+ value=0.8,
304
+ label="μƒμœ„ ν™•λ₯ ",
305
+ )
306
+ top_k = gr.Slider(
307
+ minimum=1,
308
+ maximum=20,
309
+ step=1,
310
+ value=20,
311
+ label="μƒμœ„ K",
312
+ )
313
+ penalty = gr.Slider(
314
+ minimum=0.0,
315
+ maximum=2.0,
316
+ step=0.1,
317
+ value=1.0,
318
+ label="반볡 νŒ¨λ„ν‹°",
319
+ )
320
+
321
+ # μ˜ˆμ‹œ 질문
322
+ gr.Examples(
323
  examples=[
324
  ["ν•œκ΅­μ˜ 전톡 μ ˆκΈ°μ™€ 24μ ˆκΈ°μ— λŒ€ν•΄ μžμ„Ένžˆ μ„€λͺ…ν•΄μ£Όμ„Έμš”."],
325
  ["μš°λ¦¬λ‚˜λΌ 전톡 μŒμ‹ 쀑 건강에 쒋은 λ°œνš¨μŒμ‹ 5가지λ₯Ό μΆ”μ²œν•˜κ³  κ·Έ 효λŠ₯을 μ„€λͺ…ν•΄μ£Όμ„Έμš”."],
 
334
  ["ν•œκ΅­μ˜ 전톡 의볡인 ν•œλ³΅μ˜ ꡬ쑰와 νŠΉμ§•μ„ 과학적, 미학적 κ΄€μ μ—μ„œ λΆ„μ„ν•΄μ£Όμ„Έμš”."],
335
  ["ν•œκ΅­μ˜ 전톡 κ°€μ˜₯ ꡬ쑰λ₯Ό 기후와 ν™˜κ²½ κ΄€μ μ—μ„œ λΆ„μ„ν•˜κ³ , ν˜„λŒ€ 건좕에 μ μš©ν•  수 μžˆλŠ” μš”μ†Œλ₯Ό μ œμ•ˆν•΄μ£Όμ„Έμš”."]
336
  ],
337
+ inputs=msg,
338
+ )
339
+
340
+ # 이벀트 바인딩
341
+ msg.submit(
342
+ stream_chat,
343
+ inputs=[msg, chatbot, file_upload, temperature, max_new_tokens, top_p, top_k, penalty],
344
+ outputs=[msg, chatbot]
345
+ )
346
+
347
+ send.click(
348
+ stream_chat,
349
+ inputs=[msg, chatbot, file_upload, temperature, max_new_tokens, top_p, top_k, penalty],
350
+ outputs=[msg, chatbot]
351
+ )
352
+
353
+ # 파일 μ—…λ‘œλ“œμ‹œ μžλ™ 뢄석
354
+ file_upload.change(
355
+ lambda: "파일 뢄석을 μ‹œμž‘ν•©λ‹ˆλ‹€...",
356
+ outputs=msg
357
+ ).then(
358
+ stream_chat,
359
+ inputs=[msg, chatbot, file_upload, temperature, max_new_tokens, top_p, top_k, penalty],
360
+ outputs=[msg, chatbot]
361
  )
362
 
363
  if __name__ == "__main__":
364
+ demo.launch()