openfree commited on
Commit
3db2af2
ยท
verified ยท
1 Parent(s): 467a8c5

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +248 -128
app.py CHANGED
@@ -1,9 +1,13 @@
 
 
 
 
1
  import torch
 
2
  import gradio as gr
3
  import spaces
4
  from transformers import AutoModelForCausalLM, AutoTokenizer, TextIteratorStreamer
5
 
6
- import os
7
  from threading import Thread
8
  import random
9
  from datasets import load_dataset
@@ -17,15 +21,29 @@ import pyarrow.parquet as pq
17
  import pypdf
18
  import io
19
  import pyarrow.parquet as pq
20
- from pdfminer.high_level import extract_text
21
- from pdfminer.layout import LAParams
22
- from tabulate import tabulate # tabulate ์ถ”๊ฐ€
23
  import platform
24
  import subprocess
25
  import pytesseract
26
  from pdf2image import convert_from_path
27
 
28
- # ์ „์—ญ ๋ณ€์ˆ˜ ์ถ”๊ฐ€
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
  current_file_context = None
30
 
31
  # ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ์„ค์ •
@@ -48,6 +66,7 @@ vectorizer = TfidfVectorizer(max_features=1000)
48
  question_vectors = vectorizer.fit_transform(questions)
49
  print("TF-IDF ๋ฒกํ„ฐํ™” ์™„๋ฃŒ")
50
 
 
51
  class ChatHistory:
52
  def __init__(self):
53
  self.history = []
@@ -103,19 +122,18 @@ class ChatHistory:
103
  print(f"ํžˆ์Šคํ† ๋ฆฌ ๋กœ๋“œ ์‹คํŒจ: {e}")
104
  self.history = []
105
 
 
106
  # ์ „์—ญ ChatHistory ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ
107
  chat_history = ChatHistory()
108
 
 
109
  def find_relevant_context(query, top_k=3):
110
  # ์ฟผ๋ฆฌ ๋ฒกํ„ฐํ™”
111
  query_vector = vectorizer.transform([query])
112
-
113
  # ์ฝ”์‚ฌ์ธ ์œ ์‚ฌ๋„ ๊ณ„์‚ฐ
114
  similarities = (query_vector * question_vectors.T).toarray()[0]
115
-
116
  # ๊ฐ€์žฅ ์œ ์‚ฌํ•œ ์งˆ๋ฌธ๋“ค์˜ ์ธ๋ฑ์Šค
117
  top_indices = np.argsort(similarities)[-top_k:][::-1]
118
-
119
  # ๊ด€๋ จ ์ปจํ…์ŠคํŠธ ์ถ”์ถœ
120
  relevant_contexts = []
121
  for idx in top_indices:
@@ -125,14 +143,74 @@ def find_relevant_context(query, top_k=3):
125
  'answer': wiki_dataset['train']['answer'][idx],
126
  'similarity': similarities[idx]
127
  })
128
-
129
  return relevant_contexts
130
 
 
131
  def init_msg():
132
- return "Analyzing file..."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
133
 
134
  def analyze_file_content(content, file_type):
135
- """Analyze file content and return structural summary"""
136
  if file_type in ['parquet', 'csv']:
137
  try:
138
  lines = content.split('\n')
@@ -142,115 +220,87 @@ def analyze_file_content(content, file_type):
142
  return f"๐Ÿ“Š Dataset Structure: {columns} columns, {rows} rows"
143
  except:
144
  return "โŒ Failed to analyze dataset structure"
145
-
146
  lines = content.split('\n')
147
  total_lines = len(lines)
148
  non_empty_lines = len([line for line in lines if line.strip()])
149
-
150
  if any(keyword in content.lower() for keyword in ['def ', 'class ', 'import ', 'function']):
151
  functions = len([line for line in lines if 'def ' in line])
152
  classes = len([line for line in lines if 'class ' in line])
153
  imports = len([line for line in lines if 'import ' in line or 'from ' in line])
154
  return f"๐Ÿ’ป Code Structure: {total_lines} lines (Functions: {functions}, Classes: {classes}, Imports: {imports})"
155
-
156
  paragraphs = content.count('\n\n') + 1
157
  words = len(content.split())
158
  return f"๐Ÿ“ Document Structure: {total_lines} lines, {paragraphs} paragraphs, approximately {words} words"
159
 
 
160
  def read_uploaded_file(file):
 
 
 
 
 
161
  if file is None:
162
  return "", ""
163
  try:
164
  file_ext = os.path.splitext(file.name)[1].lower()
165
-
166
- # Parquet file processing
167
  if file_ext == '.parquet':
168
  try:
169
  table = pq.read_table(file.name)
170
  df = table.to_pandas()
171
-
172
  content = f"๐Ÿ“Š Parquet File Analysis:\n\n"
173
  content += f"1. Basic Information:\n"
174
  content += f"- Total Rows: {len(df):,}\n"
175
  content += f"- Total Columns: {len(df.columns)}\n"
176
  content += f"- Memory Usage: {df.memory_usage(deep=True).sum() / 1024 / 1024:.2f} MB\n\n"
177
-
178
  content += f"2. Column Information:\n"
179
  for col in df.columns:
180
  content += f"- {col} ({df[col].dtype})\n"
181
-
182
  content += f"\n3. Data Preview:\n"
183
  content += tabulate(df.head(5), headers='keys', tablefmt='pipe', showindex=False)
184
-
185
  content += f"\n\n4. Missing Values:\n"
186
  null_counts = df.isnull().sum()
187
  for col, count in null_counts[null_counts > 0].items():
188
  content += f"- {col}: {count:,} ({count/len(df)*100:.1f}%)\n"
189
-
190
  numeric_cols = df.select_dtypes(include=['int64', 'float64']).columns
191
  if len(numeric_cols) > 0:
192
  content += f"\n5. Numeric Column Statistics:\n"
193
  stats_df = df[numeric_cols].describe()
194
  content += tabulate(stats_df, headers='keys', tablefmt='pipe')
195
-
196
  return content, "parquet"
197
  except Exception as e:
198
  return f"Error reading Parquet file: {str(e)}", "error"
199
-
200
- # PDF file processing
201
  if file_ext == '.pdf':
202
  try:
203
- pdf_reader = pypdf.PdfReader(file.name)
204
- total_pages = len(pdf_reader.pages)
205
-
206
- content = f"๐Ÿ“‘ PDF Document Analysis:\n\n"
207
- content += f"1. Basic Information:\n"
208
- content += f"- Total Pages: {total_pages}\n"
209
-
210
- if pdf_reader.metadata:
211
- content += "\n2. Metadata:\n"
212
- for key, value in pdf_reader.metadata.items():
213
- if value and str(key).startswith('/'):
214
- content += f"- {key[1:]}: {value}\n"
215
-
216
- try:
217
- text = extract_text(
218
- file.name,
219
- laparams=LAParams(
220
- line_margin=0.5,
221
- word_margin=0.1,
222
- char_margin=2.0,
223
- all_texts=True
224
- )
225
- )
226
- except:
227
- text = ""
228
-
229
- if not text.strip():
230
- text = extract_pdf_text_with_ocr(file.name)
231
-
232
- if text:
233
- words = text.split()
234
- lines = text.split('\n')
235
- content += f"\n3. Text Analysis:\n"
236
- content += f"- Total Words: {len(words):,}\n"
237
- content += f"- Unique Words: {len(set(words)):,}\n"
238
- content += f"- Total Lines: {len(lines):,}\n"
239
-
240
- content += f"\n4. Content Preview:\n"
241
- preview_length = min(2000, len(text))
242
- content += f"--- First {preview_length} characters ---\n"
243
- content += text[:preview_length]
244
- if len(text) > preview_length:
245
- content += f"\n... (Showing partial content of {len(text):,} characters)\n"
246
- else:
247
- content += "\nโš ๏ธ Text extraction failed"
248
-
249
  return content, "pdf"
250
  except Exception as e:
251
  return f"Error reading PDF file: {str(e)}", "error"
252
-
253
- # CSV file processing
254
  elif file_ext == '.csv':
255
  encodings = ['utf-8', 'cp949', 'euc-kr', 'latin1']
256
  for encoding in encodings:
@@ -261,44 +311,44 @@ def read_uploaded_file(file):
261
  content += f"- Total Rows: {len(df):,}\n"
262
  content += f"- Total Columns: {len(df.columns)}\n"
263
  content += f"- Memory Usage: {df.memory_usage(deep=True).sum() / 1024 / 1024:.2f} MB\n\n"
264
-
265
  content += f"2. Column Information:\n"
266
  for col in df.columns:
267
  content += f"- {col} ({df[col].dtype})\n"
268
-
269
  content += f"\n3. Data Preview:\n"
270
  content += df.head(5).to_markdown(index=False)
271
-
272
  content += f"\n\n4. Missing Values:\n"
273
  null_counts = df.isnull().sum()
274
  for col, count in null_counts[null_counts > 0].items():
275
  content += f"- {col}: {count:,} ({count/len(df)*100:.1f}%)\n"
276
-
277
  return content, "csv"
278
  except UnicodeDecodeError:
279
  continue
280
  raise UnicodeDecodeError(f"Unable to read file with supported encodings ({', '.join(encodings)})")
281
-
282
- # Text file processing
283
  else:
284
  encodings = ['utf-8', 'cp949', 'euc-kr', 'latin1']
285
  for encoding in encodings:
286
  try:
287
  with open(file.name, 'r', encoding=encoding) as f:
288
  content = f.read()
289
-
290
  lines = content.split('\n')
291
  total_lines = len(lines)
292
  non_empty_lines = len([line for line in lines if line.strip()])
293
-
294
  is_code = any(keyword in content.lower() for keyword in ['def ', 'class ', 'import ', 'function'])
295
-
296
  analysis = f"\n๐Ÿ“ File Analysis:\n"
297
  if is_code:
298
  functions = len([line for line in lines if 'def ' in line])
299
  classes = len([line for line in lines if 'class ' in line])
300
  imports = len([line for line in lines if 'import ' in line or 'from ' in line])
301
-
302
  analysis += f"- File Type: Code\n"
303
  analysis += f"- Total Lines: {total_lines:,}\n"
304
  analysis += f"- Functions: {functions}\n"
@@ -307,18 +357,18 @@ def read_uploaded_file(file):
307
  else:
308
  words = len(content.split())
309
  chars = len(content)
310
-
311
  analysis += f"- File Type: Text\n"
312
  analysis += f"- Total Lines: {total_lines:,}\n"
313
  analysis += f"- Non-empty Lines: {non_empty_lines:,}\n"
314
  analysis += f"- Word Count: {words:,}\n"
315
  analysis += f"- Character Count: {chars:,}\n"
316
-
317
  return content + analysis, "text"
318
  except UnicodeDecodeError:
319
  continue
320
  raise UnicodeDecodeError(f"Unable to read file with supported encodings ({', '.join(encodings)})")
321
-
322
  except Exception as e:
323
  return f"Error reading file: {str(e)}", "error"
324
 
@@ -461,10 +511,10 @@ body {
461
  font-size: 1.1em !important;
462
  padding: 10px 15px !important;
463
  display: flex !important;
464
- align-items: flex-start !important; /* ํ…์ŠคํŠธ ์ž…๋ ฅ ์œ„์น˜๋ฅผ ์œ„๋กœ ์กฐ์ • */
465
  }
466
  .input-textbox textarea {
467
- padding-top: 5px !important; /* ํ…์ŠคํŠธ ์ƒ๋‹จ ์—ฌ๋ฐฑ ์กฐ์ • */
468
  }
469
  .send-button {
470
  height: 70px !important;
@@ -478,73 +528,118 @@ body {
478
  }
479
  """
480
 
481
- # GPU ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ ํ•จ์ˆ˜ ์ˆ˜์ •
482
  def clear_cuda_memory():
483
  if hasattr(torch.cuda, 'empty_cache'):
484
  with torch.cuda.device('cuda'):
485
  torch.cuda.empty_cache()
486
 
487
- # ๋ชจ๋ธ ๋กœ๋“œ ํ•จ์ˆ˜ ์ˆ˜์ •
488
  @spaces.GPU
489
  def load_model():
490
  try:
491
- model = AutoModelForCausalLM.from_pretrained(
492
  MODEL_ID,
493
  torch_dtype=torch.bfloat16,
494
  device_map="auto",
495
  )
496
- return model
497
  except Exception as e:
498
  print(f"๋ชจ๋ธ ๋กœ๋“œ ์˜ค๋ฅ˜: {str(e)}")
499
  raise
500
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
501
  @spaces.GPU
502
- def stream_chat(message: str, history: list, uploaded_file, temperature: float, max_new_tokens: int, top_p: float, top_k: int, penalty: float):
 
 
 
 
 
 
 
 
 
503
  global model, current_file_context
504
-
505
  try:
506
  if model is None:
507
  model = load_model()
508
-
509
  print(f'message is - {message}')
510
  print(f'history is - {history}')
511
 
512
  # ํŒŒ์ผ ์—…๋กœ๋“œ ์ฒ˜๋ฆฌ
513
  file_context = ""
514
  if uploaded_file and message == "ํŒŒ์ผ์„ ๋ถ„์„ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค...":
 
 
515
  try:
516
  content, file_type = read_uploaded_file(uploaded_file)
517
  if content:
518
  file_analysis = analyze_file_content(content, file_type)
519
- file_context = f"\n\n๐Ÿ“„ ํŒŒ์ผ ๋ถ„์„ ๊ฒฐ๊ณผ:\n{file_analysis}\n\nํŒŒ์ผ ๋‚ด์šฉ:\n```\n{content}\n```"
 
 
 
520
  current_file_context = file_context # ํŒŒ์ผ ์ปจํ…์ŠคํŠธ ์ €์žฅ
521
  message = "์—…๋กœ๋“œ๋œ ํŒŒ์ผ์„ ๋ถ„์„ํ•ด์ฃผ์„ธ์š”."
522
  except Exception as e:
523
  print(f"ํŒŒ์ผ ๋ถ„์„ ์˜ค๋ฅ˜: {str(e)}")
524
  file_context = f"\n\nโŒ ํŒŒ์ผ ๋ถ„์„ ์ค‘ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค: {str(e)}"
525
- elif current_file_context: # ์ €์žฅ๋œ ํŒŒ์ผ ์ปจํ…์ŠคํŠธ๊ฐ€ ์žˆ์œผ๋ฉด ์‚ฌ์šฉ
 
526
  file_context = current_file_context
527
-
528
 
529
  # ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰ ๋ชจ๋‹ˆํ„ฐ๋ง
530
  if torch.cuda.is_available():
531
  print(f"CUDA ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰: {torch.cuda.memory_allocated() / 1024**2:.2f} MB")
532
 
533
  # ๋Œ€ํ™” ํžˆ์Šคํ† ๋ฆฌ๊ฐ€ ๋„ˆ๋ฌด ๊ธธ๋ฉด ์ž˜๋ผ๋‚ด๊ธฐ
534
- max_history_length = 10 # ์ตœ๋Œ€ ํžˆ์Šคํ† ๋ฆฌ ๊ธธ์ด ์„ค์ •
535
  if len(history) > max_history_length:
536
  history = history[-max_history_length:]
537
 
538
- # ๊ด€๋ จ ์ปจํ…์ŠคํŠธ ์ฐพ๊ธฐ
539
  try:
540
  relevant_contexts = find_relevant_context(message)
541
  wiki_context = "\n\n๊ด€๋ จ ์œ„ํ‚คํ”ผ๋””์•„ ์ •๋ณด:\n"
542
  for ctx in relevant_contexts:
543
- wiki_context += f"Q: {ctx['question']}\nA: {ctx['answer']}\n์œ ์‚ฌ๋„: {ctx['similarity']:.3f}\n\n"
 
 
 
 
544
  except Exception as e:
545
  print(f"์ปจํ…์ŠคํŠธ ๊ฒ€์ƒ‰ ์˜ค๋ฅ˜: {str(e)}")
546
  wiki_context = ""
547
-
548
  # ๋Œ€ํ™” ํžˆ์Šคํ† ๋ฆฌ ๊ตฌ์„ฑ
549
  conversation = []
550
  for prompt, answer in history:
@@ -557,36 +652,63 @@ def stream_chat(message: str, history: list, uploaded_file, temperature: float,
557
  final_message = file_context + wiki_context + "\nํ˜„์žฌ ์งˆ๋ฌธ: " + message
558
  conversation.append({"role": "user", "content": final_message})
559
 
560
- # ํ† ํฐ ์ˆ˜ ์ œํ•œ
561
- input_ids = tokenizer.apply_chat_template(conversation, tokenize=False, add_generation_prompt=True)
562
- max_length = 4096 # ๋˜๋Š” ๋ชจ๋ธ์˜ ์ตœ๋Œ€ ์ปจํ…์ŠคํŠธ ๊ธธ์ด
563
- if len(input_ids.split()) > max_length:
564
- # ์ปจํ…์ŠคํŠธ๊ฐ€ ๋„ˆ๋ฌด ๊ธธ๋ฉด ์ž˜๋ผ๋‚ด๊ธฐ
565
- input_ids = " ".join(input_ids.split()[-max_length:])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
566
 
567
- inputs = tokenizer(input_ids, return_tensors="pt").to("cuda")
568
-
569
- # ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰ ์ฒดํฌ
570
  if torch.cuda.is_available():
571
  print(f"์ž…๋ ฅ ํ…์„œ ์ƒ์„ฑ ํ›„ CUDA ๋ฉ”๋ชจ๋ฆฌ: {torch.cuda.memory_allocated() / 1024**2:.2f} MB")
572
 
573
- streamer = TextIteratorStreamer(tokenizer, timeout=10., skip_prompt=True, skip_special_tokens=True)
 
 
574
 
575
  generate_kwargs = dict(
576
- inputs,
577
  streamer=streamer,
578
  top_k=top_k,
579
  top_p=top_p,
580
  repetition_penalty=penalty,
581
- max_new_tokens=min(max_new_tokens, 2048), # ์ตœ๋Œ€ ํ† ํฐ ์ˆ˜ ์ œํ•œ
582
- do_sample=True,
583
  temperature=temperature,
584
- eos_token_id=[255001],
585
  )
586
-
587
  # ์ƒ์„ฑ ์‹œ์ž‘ ์ „ ๋ฉ”๋ชจ๋ฆฌ ์ •๋ฆฌ
588
  clear_cuda_memory()
589
-
590
  thread = Thread(target=model.generate, kwargs=generate_kwargs)
591
  thread.start()
592
 
@@ -601,12 +723,10 @@ def stream_chat(message: str, history: list, uploaded_file, temperature: float,
601
  except Exception as e:
602
  error_message = f"์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค: {str(e)}"
603
  print(f"Stream chat ์˜ค๋ฅ˜: {error_message}")
604
- # ์˜ค๋ฅ˜ ๋ฐœ์ƒ ์‹œ์—๋„ ๋ฉ”๋ชจ๋ฆฌ ์ •๋ฆฌ
605
  clear_cuda_memory()
606
  yield "", history + [[message, error_message]]
607
 
608
 
609
-
610
  def create_demo():
611
  with gr.Blocks(css=CSS) as demo:
612
  with gr.Column(elem_classes="markdown-style"):
@@ -615,14 +735,14 @@ def create_demo():
615
  #### ๐Ÿ“Š RAG: Upload and Analyze Files (TXT, CSV, PDF, Parquet files)
616
  Upload your files for data analysis and learning
617
  """)
618
-
619
  chatbot = gr.Chatbot(
620
  value=[],
621
  height=600,
622
  label="GiniGEN AI Assistant",
623
  elem_classes="chat-container"
624
  )
625
-
626
  with gr.Row(elem_classes="input-container"):
627
  with gr.Column(scale=1, min_width=70):
628
  file_upload = gr.File(
@@ -633,7 +753,7 @@ def create_demo():
633
  interactive=True,
634
  show_label=False
635
  )
636
-
637
  with gr.Column(scale=3):
638
  msg = gr.Textbox(
639
  show_label=False,
@@ -642,21 +762,21 @@ def create_demo():
642
  elem_classes="input-textbox",
643
  scale=1
644
  )
645
-
646
  with gr.Column(scale=1, min_width=70):
647
  send = gr.Button(
648
  "Send",
649
  elem_classes="send-button custom-button",
650
  scale=1
651
  )
652
-
653
  with gr.Column(scale=1, min_width=70):
654
  clear = gr.Button(
655
  "Clear",
656
  elem_classes="clear-button custom-button",
657
  scale=1
658
  )
659
-
660
  with gr.Accordion("๐ŸŽฎ Advanced Settings", open=False):
661
  with gr.Row():
662
  with gr.Column(scale=1):
@@ -697,7 +817,7 @@ def create_demo():
697
  current_file_context = None
698
  return [], None, "Start a new conversation..."
699
 
700
- # Event bindings
701
  msg.submit(
702
  stream_chat,
703
  inputs=[msg, chatbot, file_upload, temperature, max_new_tokens, top_p, top_k, penalty],
@@ -721,7 +841,6 @@ def create_demo():
721
  queue=True
722
  )
723
 
724
- # Clear button event binding
725
  clear.click(
726
  fn=clear_conversation,
727
  outputs=[chatbot, file_upload, msg],
@@ -730,6 +849,7 @@ def create_demo():
730
 
731
  return demo
732
 
 
733
  if __name__ == "__main__":
734
  demo = create_demo()
735
- demo.launch()
 
1
+ import os
2
+ # Dynamo ์™„์ „ ๋น„ํ™œ์„ฑํ™”
3
+ os.environ["TORCH_DYNAMO_DISABLE"] = "1"
4
+
5
  import torch
6
+ import torch._dynamo
7
  import gradio as gr
8
  import spaces
9
  from transformers import AutoModelForCausalLM, AutoTokenizer, TextIteratorStreamer
10
 
 
11
  from threading import Thread
12
  import random
13
  from datasets import load_dataset
 
21
  import pypdf
22
  import io
23
  import pyarrow.parquet as pq
24
+ from tabulate import tabulate
 
 
25
  import platform
26
  import subprocess
27
  import pytesseract
28
  from pdf2image import convert_from_path
29
 
30
+ # -------------------- ์ถ”๊ฐ€: PDF to Markdown ๋ณ€ํ™˜ ๊ด€๋ จ import --------------------
31
+ import re
32
+ import requests
33
+ from bs4 import BeautifulSoup
34
+ import urllib.request
35
+ import ocrmypdf
36
+ import pytz
37
+ import urllib.parse
38
+ from pypdf import PdfReader
39
+ # ---------------------------------------------------------------------------
40
+
41
+ # --------------------
42
+ # 1) Dynamo suppress_errors ์˜ต์…˜ ์‚ฌ์šฉ (์˜ค๋ฅ˜ ์‹œ eager๋กœ fallback)
43
+ # --------------------
44
+ torch._dynamo.config.suppress_errors = True
45
+
46
+ # ์ „์—ญ ๋ณ€์ˆ˜
47
  current_file_context = None
48
 
49
  # ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ์„ค์ •
 
66
  question_vectors = vectorizer.fit_transform(questions)
67
  print("TF-IDF ๋ฒกํ„ฐํ™” ์™„๋ฃŒ")
68
 
69
+
70
  class ChatHistory:
71
  def __init__(self):
72
  self.history = []
 
122
  print(f"ํžˆ์Šคํ† ๋ฆฌ ๋กœ๋“œ ์‹คํŒจ: {e}")
123
  self.history = []
124
 
125
+
126
  # ์ „์—ญ ChatHistory ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ
127
  chat_history = ChatHistory()
128
 
129
+
130
  def find_relevant_context(query, top_k=3):
131
  # ์ฟผ๋ฆฌ ๋ฒกํ„ฐํ™”
132
  query_vector = vectorizer.transform([query])
 
133
  # ์ฝ”์‚ฌ์ธ ์œ ์‚ฌ๋„ ๊ณ„์‚ฐ
134
  similarities = (query_vector * question_vectors.T).toarray()[0]
 
135
  # ๊ฐ€์žฅ ์œ ์‚ฌํ•œ ์งˆ๋ฌธ๋“ค์˜ ์ธ๋ฑ์Šค
136
  top_indices = np.argsort(similarities)[-top_k:][::-1]
 
137
  # ๊ด€๋ จ ์ปจํ…์ŠคํŠธ ์ถ”์ถœ
138
  relevant_contexts = []
139
  for idx in top_indices:
 
143
  'answer': wiki_dataset['train']['answer'][idx],
144
  'similarity': similarities[idx]
145
  })
 
146
  return relevant_contexts
147
 
148
+
149
  def init_msg():
150
+ return "ํŒŒ์ผ์„ ๋ถ„์„ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค..."
151
+
152
+
153
+ # -------------------- PDF ํŒŒ์ผ์„ Markdown์œผ๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ์œ ํ‹ธ ํ•จ์ˆ˜๋“ค --------------------
154
+ def extract_text_from_pdf(reader: PdfReader) -> str:
155
+ """
156
+ PyPDF๋ฅผ ์‚ฌ์šฉํ•ด ๋ชจ๋“  ํŽ˜์ด์ง€ ํ…์ŠคํŠธ๋ฅผ ์ถ”์ถœ.
157
+ ๋งŒ์•ฝ ํ…์ŠคํŠธ๊ฐ€ ์—†์œผ๋ฉด ๋นˆ ๋ฌธ์ž์—ด ๋ฐ˜ํ™˜.
158
+ """
159
+ full_text = ""
160
+ for idx, page in enumerate(reader.pages):
161
+ text = page.extract_text() or ""
162
+ if len(text) > 0:
163
+ full_text += f"---- Page {idx+1} ----\n" + text + "\n\n"
164
+ return full_text.strip()
165
+
166
+
167
+ def convert_pdf_to_markdown(pdf_file: str):
168
+ """
169
+ PDF ํŒŒ์ผ์„ ์ฝ๊ณ  ํ…์ŠคํŠธ๋ฅผ ์ถ”์ถœํ•œ ๋’ค,
170
+ ์ด๋ฏธ์ง€๊ฐ€ ๋งŽ๊ณ  ํ…์ŠคํŠธ๊ฐ€ ์ ์€ ๊ฒฝ์šฐ์—๋Š” OCR์„ ์‹œ๋„ํ•œ๋‹ค.
171
+ ์ตœ์ข…์ ์œผ๋กœ Markdown ํ˜•์‹์œผ๋กœ ๋ณ€ํ™˜ ๊ฐ€๋Šฅํ•œ ํ…์ŠคํŠธ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
172
+ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋„ ํ•จ๊ป˜ ๋ฐ˜ํ™˜.
173
+ """
174
+ try:
175
+ reader = PdfReader(pdf_file)
176
+ except Exception as e:
177
+ return f"PDF ํŒŒ์ผ์„ ์ฝ๋Š” ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {e}", None, None
178
+
179
+ # Extract metadata
180
+ raw_meta = reader.metadata
181
+ metadata = {
182
+ "author": raw_meta.author if raw_meta else None,
183
+ "creator": raw_meta.creator if raw_meta else None,
184
+ "producer": raw_meta.producer if raw_meta else None,
185
+ "subject": raw_meta.subject if raw_meta else None,
186
+ "title": raw_meta.title if raw_meta else None,
187
+ }
188
+
189
+ # Extract text
190
+ full_text = extract_text_from_pdf(reader)
191
+
192
+ # ์ด๋ฏธ์ง€๊ฐ€ ๋งŽ๊ณ  ํ…์ŠคํŠธ๊ฐ€ ๋„ˆ๋ฌด ์งง์œผ๋ฉด OCR ์‹œ๋„
193
+ image_count = 0
194
+ for page in reader.pages:
195
+ image_count += len(page.images)
196
+
197
+ if image_count > 0 and len(full_text) < 1000:
198
+ try:
199
+ out_pdf_file = pdf_file.replace(".pdf", "_ocr.pdf")
200
+ ocrmypdf.ocr(pdf_file, out_pdf_file, force_ocr=True)
201
+ # Re-extract text from OCR-processed PDF
202
+ reader_ocr = PdfReader(out_pdf_file)
203
+ full_text = extract_text_from_pdf(reader_ocr)
204
+ except Exception as e:
205
+ full_text = f"OCR ์ฒ˜๋ฆฌ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {e}\n\n์›๋ณธ PDF ํ…์ŠคํŠธ:\n\n" + full_text
206
+
207
+ return full_text, metadata, pdf_file
208
+
209
+
210
+ # ---------------------------------------------------------------------------
211
 
212
  def analyze_file_content(content, file_type):
213
+ """ํŒŒ์ผ ๋‚ด์šฉ์„ ๊ฐ„๋‹จํžˆ ๋ถ„์„ํ•œ ํ›„ ๊ตฌ์กฐ ์š”์•ฝ์„ ๋ฐ˜ํ™˜."""
214
  if file_type in ['parquet', 'csv']:
215
  try:
216
  lines = content.split('\n')
 
220
  return f"๐Ÿ“Š Dataset Structure: {columns} columns, {rows} rows"
221
  except:
222
  return "โŒ Failed to analyze dataset structure"
223
+
224
  lines = content.split('\n')
225
  total_lines = len(lines)
226
  non_empty_lines = len([line for line in lines if line.strip()])
227
+
228
  if any(keyword in content.lower() for keyword in ['def ', 'class ', 'import ', 'function']):
229
  functions = len([line for line in lines if 'def ' in line])
230
  classes = len([line for line in lines if 'class ' in line])
231
  imports = len([line for line in lines if 'import ' in line or 'from ' in line])
232
  return f"๐Ÿ’ป Code Structure: {total_lines} lines (Functions: {functions}, Classes: {classes}, Imports: {imports})"
233
+
234
  paragraphs = content.count('\n\n') + 1
235
  words = len(content.split())
236
  return f"๐Ÿ“ Document Structure: {total_lines} lines, {paragraphs} paragraphs, approximately {words} words"
237
 
238
+
239
  def read_uploaded_file(file):
240
+ """
241
+ ์—…๋กœ๋“œ๋œ ํŒŒ์ผ์„ ์ฒ˜๋ฆฌํ•˜์—ฌ
242
+ 1) ํŒŒ์ผ ํƒ€์ž…๋ณ„๋กœ ๋‚ด์šฉ์„ ์ฝ๊ณ 
243
+ 2) ๋ถ„์„ ๊ฒฐ๊ณผ์™€ ํ•จ๊ป˜ ๋ฐ˜ํ™˜
244
+ """
245
  if file is None:
246
  return "", ""
247
  try:
248
  file_ext = os.path.splitext(file.name)[1].lower()
249
+
250
+ # Parquet
251
  if file_ext == '.parquet':
252
  try:
253
  table = pq.read_table(file.name)
254
  df = table.to_pandas()
255
+
256
  content = f"๐Ÿ“Š Parquet File Analysis:\n\n"
257
  content += f"1. Basic Information:\n"
258
  content += f"- Total Rows: {len(df):,}\n"
259
  content += f"- Total Columns: {len(df.columns)}\n"
260
  content += f"- Memory Usage: {df.memory_usage(deep=True).sum() / 1024 / 1024:.2f} MB\n\n"
261
+
262
  content += f"2. Column Information:\n"
263
  for col in df.columns:
264
  content += f"- {col} ({df[col].dtype})\n"
265
+
266
  content += f"\n3. Data Preview:\n"
267
  content += tabulate(df.head(5), headers='keys', tablefmt='pipe', showindex=False)
268
+
269
  content += f"\n\n4. Missing Values:\n"
270
  null_counts = df.isnull().sum()
271
  for col, count in null_counts[null_counts > 0].items():
272
  content += f"- {col}: {count:,} ({count/len(df)*100:.1f}%)\n"
273
+
274
  numeric_cols = df.select_dtypes(include=['int64', 'float64']).columns
275
  if len(numeric_cols) > 0:
276
  content += f"\n5. Numeric Column Statistics:\n"
277
  stats_df = df[numeric_cols].describe()
278
  content += tabulate(stats_df, headers='keys', tablefmt='pipe')
279
+
280
  return content, "parquet"
281
  except Exception as e:
282
  return f"Error reading Parquet file: {str(e)}", "error"
283
+
284
+ # PDF (Markdown ๋ณ€ํ™˜)
285
  if file_ext == '.pdf':
286
  try:
287
+ markdown_text, metadata, processed_pdf_path = convert_pdf_to_markdown(file.name)
288
+ if metadata is None:
289
+ return f"PDF ํŒŒ์ผ ๋ณ€ํ™˜ ์˜ค๋ฅ˜ ๋˜๋Š” ์ฝ๊ธฐ ์‹คํŒจ.\n\n์›๋ณธ ๋ฉ”์‹œ์ง€:\n{markdown_text}", "error"
290
+
291
+ content = "# PDF to Markdown Conversion\n\n"
292
+ content += "## Metadata\n"
293
+ for k, v in metadata.items():
294
+ content += f"**{k.capitalize()}**: {v}\n\n"
295
+
296
+ content += "## Extracted Text\n\n"
297
+ content += markdown_text
298
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
299
  return content, "pdf"
300
  except Exception as e:
301
  return f"Error reading PDF file: {str(e)}", "error"
302
+
303
+ # CSV
304
  elif file_ext == '.csv':
305
  encodings = ['utf-8', 'cp949', 'euc-kr', 'latin1']
306
  for encoding in encodings:
 
311
  content += f"- Total Rows: {len(df):,}\n"
312
  content += f"- Total Columns: {len(df.columns)}\n"
313
  content += f"- Memory Usage: {df.memory_usage(deep=True).sum() / 1024 / 1024:.2f} MB\n\n"
314
+
315
  content += f"2. Column Information:\n"
316
  for col in df.columns:
317
  content += f"- {col} ({df[col].dtype})\n"
318
+
319
  content += f"\n3. Data Preview:\n"
320
  content += df.head(5).to_markdown(index=False)
321
+
322
  content += f"\n\n4. Missing Values:\n"
323
  null_counts = df.isnull().sum()
324
  for col, count in null_counts[null_counts > 0].items():
325
  content += f"- {col}: {count:,} ({count/len(df)*100:.1f}%)\n"
326
+
327
  return content, "csv"
328
  except UnicodeDecodeError:
329
  continue
330
  raise UnicodeDecodeError(f"Unable to read file with supported encodings ({', '.join(encodings)})")
331
+
332
+ # ์ผ๋ฐ˜ ํ…์ŠคํŠธ ํŒŒ์ผ
333
  else:
334
  encodings = ['utf-8', 'cp949', 'euc-kr', 'latin1']
335
  for encoding in encodings:
336
  try:
337
  with open(file.name, 'r', encoding=encoding) as f:
338
  content = f.read()
339
+
340
  lines = content.split('\n')
341
  total_lines = len(lines)
342
  non_empty_lines = len([line for line in lines if line.strip()])
343
+
344
  is_code = any(keyword in content.lower() for keyword in ['def ', 'class ', 'import ', 'function'])
345
+
346
  analysis = f"\n๐Ÿ“ File Analysis:\n"
347
  if is_code:
348
  functions = len([line for line in lines if 'def ' in line])
349
  classes = len([line for line in lines if 'class ' in line])
350
  imports = len([line for line in lines if 'import ' in line or 'from ' in line])
351
+
352
  analysis += f"- File Type: Code\n"
353
  analysis += f"- Total Lines: {total_lines:,}\n"
354
  analysis += f"- Functions: {functions}\n"
 
357
  else:
358
  words = len(content.split())
359
  chars = len(content)
360
+
361
  analysis += f"- File Type: Text\n"
362
  analysis += f"- Total Lines: {total_lines:,}\n"
363
  analysis += f"- Non-empty Lines: {non_empty_lines:,}\n"
364
  analysis += f"- Word Count: {words:,}\n"
365
  analysis += f"- Character Count: {chars:,}\n"
366
+
367
  return content + analysis, "text"
368
  except UnicodeDecodeError:
369
  continue
370
  raise UnicodeDecodeError(f"Unable to read file with supported encodings ({', '.join(encodings)})")
371
+
372
  except Exception as e:
373
  return f"Error reading file: {str(e)}", "error"
374
 
 
511
  font-size: 1.1em !important;
512
  padding: 10px 15px !important;
513
  display: flex !important;
514
+ align-items: flex-start !important;
515
  }
516
  .input-textbox textarea {
517
+ padding-top: 5px !important;
518
  }
519
  .send-button {
520
  height: 70px !important;
 
528
  }
529
  """
530
 
 
531
  def clear_cuda_memory():
532
  if hasattr(torch.cuda, 'empty_cache'):
533
  with torch.cuda.device('cuda'):
534
  torch.cuda.empty_cache()
535
 
536
+
537
  @spaces.GPU
538
  def load_model():
539
  try:
540
+ loaded_model = AutoModelForCausalLM.from_pretrained(
541
  MODEL_ID,
542
  torch_dtype=torch.bfloat16,
543
  device_map="auto",
544
  )
545
+ return loaded_model
546
  except Exception as e:
547
  print(f"๋ชจ๋ธ ๋กœ๋“œ ์˜ค๋ฅ˜: {str(e)}")
548
  raise
549
 
550
+ def _truncate_tokens_for_context(input_ids_str: str, desired_input_length: int) -> str:
551
+ """
552
+ ์ž…๋ ฅ ๋ฌธ์ž์—ด์ด desired_input_length ํ† ํฐ์„ ๋„˜์œผ๋ฉด, ์•ž๋ถ€๋ถ„(์˜ค๋ž˜๋œ ์ปจํ…์ŠคํŠธ)์„ ์ž˜๋ผ๋‚ด๋Š” ํ•จ์ˆ˜.
553
+ """
554
+ tokens = input_ids_str.split()
555
+ if len(tokens) > desired_input_length:
556
+ # ๊ฐ€์žฅ ์˜ค๋ž˜๋œ ๋ถ€๋ถ„์„ ๋ฒ„๋ฆฌ๊ณ , ๋’ค์—์„œ desired_input_length๋งŒ ๋‚จ๊น€
557
+ tokens = tokens[-desired_input_length:]
558
+ return " ".join(tokens)
559
+
560
+
561
+ # build_prompt ํ•จ์ˆ˜: ๋Œ€ํ™” ๋‚ด์—ญ์„ ๋ฌธ์ž์—ด๋กœ ๋ณ€ํ™˜
562
+ def build_prompt(conversation: list) -> str:
563
+ """
564
+ conversation์€ ๊ฐ ํ•ญ๋ชฉ์ด {"role": "user" ๋˜๋Š” "assistant", "content": ...} ํ˜•ํƒœ์˜ ๋”•์…”๋„ˆ๋ฆฌ ๋ชฉ๋ก์ž…๋‹ˆ๋‹ค.
565
+ ์ด๋ฅผ ๋‹จ์ˆœ ํ…์ŠคํŠธ ํ”„๋กฌํ”„ํŠธ๋กœ ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
566
+ """
567
+ prompt = ""
568
+ for msg in conversation:
569
+ if msg["role"] == "user":
570
+ prompt += "User: " + msg["content"] + "\n"
571
+ elif msg["role"] == "assistant":
572
+ prompt += "Assistant: " + msg["content"] + "\n"
573
+ # ๋งˆ์ง€๋ง‰์— ์–ด์‹œ์Šคํ„ดํŠธ ์‘๋‹ต์„ ๊ธฐ๋Œ€ํ•˜๋„๋ก ์ถ”๊ฐ€
574
+ prompt += "Assistant: "
575
+ return prompt
576
+
577
+
578
  @spaces.GPU
579
+ def stream_chat(
580
+ message: str,
581
+ history: list,
582
+ uploaded_file,
583
+ temperature: float,
584
+ max_new_tokens: int,
585
+ top_p: float,
586
+ top_k: int,
587
+ penalty: float
588
+ ):
589
  global model, current_file_context
590
+
591
  try:
592
  if model is None:
593
  model = load_model()
594
+
595
  print(f'message is - {message}')
596
  print(f'history is - {history}')
597
 
598
  # ํŒŒ์ผ ์—…๋กœ๋“œ ์ฒ˜๋ฆฌ
599
  file_context = ""
600
  if uploaded_file and message == "ํŒŒ์ผ์„ ๋ถ„์„ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค...":
601
+ # ์ƒˆ๋กœ์šด ํŒŒ์ผ ์—…๋กœ๋“œ ์‹œ์—๋Š” ๊ธฐ์กด ๋ฉ”๋ชจ๋ฆฌ ์ปจํ…์ŠคํŠธ ์ดˆ๊ธฐํ™”
602
+ current_file_context = None
603
  try:
604
  content, file_type = read_uploaded_file(uploaded_file)
605
  if content:
606
  file_analysis = analyze_file_content(content, file_type)
607
+ file_context = (
608
+ f"\n\n๐Ÿ“„ ํŒŒ์ผ ๋ถ„์„ ๊ฒฐ๊ณผ:\n{file_analysis}"
609
+ f"\n\nํŒŒ์ผ ๋‚ด์šฉ:\n```\n{content}\n```"
610
+ )
611
  current_file_context = file_context # ํŒŒ์ผ ์ปจํ…์ŠคํŠธ ์ €์žฅ
612
  message = "์—…๋กœ๋“œ๋œ ํŒŒ์ผ์„ ๋ถ„์„ํ•ด์ฃผ์„ธ์š”."
613
  except Exception as e:
614
  print(f"ํŒŒ์ผ ๋ถ„์„ ์˜ค๋ฅ˜: {str(e)}")
615
  file_context = f"\n\nโŒ ํŒŒ์ผ ๋ถ„์„ ์ค‘ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค: {str(e)}"
616
+ elif current_file_context:
617
+ # ์ด๋ฏธ ์—…๋กœ๋“œ๋œ ํŒŒ์ผ ์ปจํ…์ŠคํŠธ๊ฐ€ ์žˆ๋‹ค๋ฉด ์‚ฌ์šฉ
618
  file_context = current_file_context
 
619
 
620
  # ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰ ๋ชจ๋‹ˆํ„ฐ๋ง
621
  if torch.cuda.is_available():
622
  print(f"CUDA ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰: {torch.cuda.memory_allocated() / 1024**2:.2f} MB")
623
 
624
  # ๋Œ€ํ™” ํžˆ์Šคํ† ๋ฆฌ๊ฐ€ ๋„ˆ๋ฌด ๊ธธ๋ฉด ์ž˜๋ผ๋‚ด๊ธฐ
625
+ max_history_length = 10
626
  if len(history) > max_history_length:
627
  history = history[-max_history_length:]
628
 
629
+ # ์œ„ํ‚ค ์ปจํ…์ŠคํŠธ ์ฐพ๊ธฐ
630
  try:
631
  relevant_contexts = find_relevant_context(message)
632
  wiki_context = "\n\n๊ด€๋ จ ์œ„ํ‚คํ”ผ๋””์•„ ์ •๋ณด:\n"
633
  for ctx in relevant_contexts:
634
+ wiki_context += (
635
+ f"Q: {ctx['question']}\n"
636
+ f"A: {ctx['answer']}\n"
637
+ f"์œ ์‚ฌ๋„: {ctx['similarity']:.3f}\n\n"
638
+ )
639
  except Exception as e:
640
  print(f"์ปจํ…์ŠคํŠธ ๊ฒ€์ƒ‰ ์˜ค๋ฅ˜: {str(e)}")
641
  wiki_context = ""
642
+
643
  # ๋Œ€ํ™” ํžˆ์Šคํ† ๋ฆฌ ๊ตฌ์„ฑ
644
  conversation = []
645
  for prompt, answer in history:
 
652
  final_message = file_context + wiki_context + "\nํ˜„์žฌ ์งˆ๋ฌธ: " + message
653
  conversation.append({"role": "user", "content": final_message})
654
 
655
+ # build_prompt ์‚ฌ์šฉ (๊ธฐ์กด tokenizer.apply_chat_template ๋Œ€์‹ )
656
+ input_ids_str = build_prompt(conversation)
657
+ # ๋จผ์ € 6000 ํ† ํฐ ์ด๋‚ด๋กœ ์ž˜๋ผ์ฃผ๊ธฐ (์ž„์˜์˜ ์ˆ˜์น˜, ํ•„์š”์— ๋”ฐ๋ผ ์กฐ์ • ๊ฐ€๋Šฅ)
658
+ input_ids_str = _truncate_tokens_for_context(input_ids_str, 6000)
659
+
660
+ inputs = tokenizer(input_ids_str, return_tensors="pt").to("cuda")
661
+
662
+ # ์ตœ๋Œ€ ์ปจํ…์ŠคํŠธ 8192 ๊ณ ๋ คํ•˜์—ฌ, ๋‚จ์€ ์ž๋ฆฌ๊ฐ€ ์ ์œผ๋ฉด max_new_tokens ์ค„์ด๊ธฐ
663
+ max_context = 8192
664
+ input_length = inputs["input_ids"].shape[1]
665
+ remaining = max_context - input_length
666
+
667
+ # ์ตœ์†Œ 128 ํ† ํฐ ์ •๋„๋Š” ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋งŒ๋“ค๊ณ  ์‹ถ๋‹ค๋ฉด,
668
+ # remaining์ด 128 ๋ฏธ๋งŒ์ด๋ฉด, ์ถ”๊ฐ€๋กœ input์„ ๋” ์ž˜๋ผ๋‚ธ๋‹ค.
669
+ min_generation = 128
670
+ if remaining < min_generation:
671
+ # ๋” ์ž˜๋ผ์„œ ์ถฉ๋ถ„ํ•œ ์ถœ๋ ฅ ํ† ํฐ ํ™•๋ณด
672
+ must_cut = min_generation - remaining # ๋ช‡ ํ† ํฐ๋งŒํผ ๋” ์ž๋ฅผ์ง€
673
+ new_desired_input_length = max(1, input_length - must_cut)
674
+ print(f"[์ฃผ์˜] ์ž…๋ ฅ์ด ๋„ˆ๋ฌด ๊ธธ์–ด {must_cut}ํ† ํฐ ๋” ์ œ๊ฑฐํ•˜์—ฌ, input_length={input_length} -> {new_desired_input_length} ์žฌ์กฐ์ •")
675
+ # ๋ฌธ์ž์—ด ๋‹ค์‹œ ๋งŒ๋“ค์–ด์„œ tokenizer
676
+ input_ids_str = _truncate_tokens_for_context(input_ids_str, new_desired_input_length)
677
+ inputs = tokenizer(input_ids_str, return_tensors="pt").to("cuda")
678
+ input_length = inputs["input_ids"].shape[1]
679
+ remaining = max_context - input_length
680
+
681
+ # ์ตœ์ข…์ ์œผ๋กœ (input + max_new_tokens) <= 8192 ๋˜๋„๋ก
682
+ if remaining < max_new_tokens:
683
+ print(f"[์ฃผ์˜] ์ž…๋ ฅ ํ† ํฐ์ด ๋งŽ์•„ max_new_tokens={max_new_tokens} -> {remaining}๋กœ ์กฐ์ •ํ•ฉ๋‹ˆ๋‹ค.")
684
+ max_new_tokens = remaining
685
+
686
+ if max_new_tokens < 1:
687
+ # ๊ทธ๋ž˜๋„ 1 ๋ฏธ๋งŒ์ด๋ฉด 1 ํ† ํฐ๋งŒ ์ƒ์„ฑ
688
+ max_new_tokens = 1
689
 
 
 
 
690
  if torch.cuda.is_available():
691
  print(f"์ž…๋ ฅ ํ…์„œ ์ƒ์„ฑ ํ›„ CUDA ๋ฉ”๋ชจ๋ฆฌ: {torch.cuda.memory_allocated() / 1024**2:.2f} MB")
692
 
693
+ streamer = TextIteratorStreamer(
694
+ tokenizer, timeout=10., skip_prompt=True, skip_special_tokens=True
695
+ )
696
 
697
  generate_kwargs = dict(
698
+ **inputs,
699
  streamer=streamer,
700
  top_k=top_k,
701
  top_p=top_p,
702
  repetition_penalty=penalty,
703
+ max_new_tokens=max_new_tokens,
704
+ do_sample=True,
705
  temperature=temperature,
706
+ eos_token_id=255001, # ์ˆ˜์ •: ๋ฆฌ์ŠคํŠธ ๋Œ€์‹  ์ •์ˆ˜ํ˜• ์‚ฌ์šฉ
707
  )
708
+
709
  # ์ƒ์„ฑ ์‹œ์ž‘ ์ „ ๋ฉ”๋ชจ๋ฆฌ ์ •๋ฆฌ
710
  clear_cuda_memory()
711
+
712
  thread = Thread(target=model.generate, kwargs=generate_kwargs)
713
  thread.start()
714
 
 
723
  except Exception as e:
724
  error_message = f"์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค: {str(e)}"
725
  print(f"Stream chat ์˜ค๋ฅ˜: {error_message}")
 
726
  clear_cuda_memory()
727
  yield "", history + [[message, error_message]]
728
 
729
 
 
730
  def create_demo():
731
  with gr.Blocks(css=CSS) as demo:
732
  with gr.Column(elem_classes="markdown-style"):
 
735
  #### ๐Ÿ“Š RAG: Upload and Analyze Files (TXT, CSV, PDF, Parquet files)
736
  Upload your files for data analysis and learning
737
  """)
738
+
739
  chatbot = gr.Chatbot(
740
  value=[],
741
  height=600,
742
  label="GiniGEN AI Assistant",
743
  elem_classes="chat-container"
744
  )
745
+
746
  with gr.Row(elem_classes="input-container"):
747
  with gr.Column(scale=1, min_width=70):
748
  file_upload = gr.File(
 
753
  interactive=True,
754
  show_label=False
755
  )
756
+
757
  with gr.Column(scale=3):
758
  msg = gr.Textbox(
759
  show_label=False,
 
762
  elem_classes="input-textbox",
763
  scale=1
764
  )
765
+
766
  with gr.Column(scale=1, min_width=70):
767
  send = gr.Button(
768
  "Send",
769
  elem_classes="send-button custom-button",
770
  scale=1
771
  )
772
+
773
  with gr.Column(scale=1, min_width=70):
774
  clear = gr.Button(
775
  "Clear",
776
  elem_classes="clear-button custom-button",
777
  scale=1
778
  )
779
+
780
  with gr.Accordion("๐ŸŽฎ Advanced Settings", open=False):
781
  with gr.Row():
782
  with gr.Column(scale=1):
 
817
  current_file_context = None
818
  return [], None, "Start a new conversation..."
819
 
820
+ # ์ด๋ฒคํŠธ ์—ฐ๊ฒฐ
821
  msg.submit(
822
  stream_chat,
823
  inputs=[msg, chatbot, file_upload, temperature, max_new_tokens, top_p, top_k, penalty],
 
841
  queue=True
842
  )
843
 
 
844
  clear.click(
845
  fn=clear_conversation,
846
  outputs=[chatbot, file_upload, msg],
 
849
 
850
  return demo
851
 
852
+
853
  if __name__ == "__main__":
854
  demo = create_demo()
855
+ demo.launch()