ginipick commited on
Commit
cc10093
·
verified ·
1 Parent(s): 5325327

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +1 -735
app.py CHANGED
@@ -1,736 +1,2 @@
1
- import gradio as gr
2
- from huggingface_hub import InferenceClient
3
  import os
4
- import pandas as pd
5
- from typing import List, Dict, Tuple
6
- import json
7
- import io
8
- import traceback
9
- import csv
10
- from openai import OpenAI
11
- from functools import lru_cache
12
- from concurrent.futures import ThreadPoolExecutor
13
- import math
14
-
15
- # CSS 설정
16
- css = """
17
- footer {
18
- visibility: hidden;
19
- }
20
- #chatbot-container, #chatbot-data-upload {
21
- height: 700px;
22
- overflow-y: scroll;
23
- }
24
- #chatbot-container .message, #chatbot-data-upload .message {
25
- font-size: 14px;
26
- }
27
- /* 입력창 배경색 및 글자색 변경 */
28
- textarea, input[type="text"] {
29
- background-color: #ffffff;
30
- color: #000000;
31
- }
32
- /* 파일 업로드 영역 높이 조절 */
33
- #parquet-upload-area {
34
- max-height: 150px;
35
- overflow-y: auto;
36
- }
37
- /* 초기 설명 글씨 크기 조절 */
38
- #initial-description {
39
- font-size: 14px;
40
- }
41
- /* API Key 입력 섹션 스타일 */
42
- .api-key-section {
43
- margin: 10px 0;
44
- padding: 10px;
45
- border: 1px solid #ddd;
46
- border-radius: 5px;
47
- }
48
- .api-key-status {
49
- margin-top: 5px;
50
- font-weight: bold;
51
- }
52
- """
53
-
54
- # 추론 API 클라이언트 설정
55
- hf_client = InferenceClient(
56
- "CohereForAI/c4ai-command-r-plus-08-2024", token=os.getenv("HF_TOKEN")
57
- )
58
-
59
- def load_code(filename: str) -> str:
60
- try:
61
- with open(filename, 'r', encoding='utf-8') as file:
62
- return file.read()
63
- except FileNotFoundError:
64
- return f"{filename} 파일을 찾을 수 없습니다."
65
- except Exception as e:
66
- return f"파일을 읽는 중 오류가 발생했습니다: {str(e)}"
67
-
68
- def load_parquet(filename: str) -> str:
69
- try:
70
- df = pd.read_parquet(filename, engine='pyarrow')
71
- return df.head(10).to_markdown(index=False)
72
- except FileNotFoundError:
73
- return f"{filename} 파일을 찾을 수 없습니다."
74
- except Exception as e:
75
- return f"파일을 읽는 중 오류가 발생했습니다: {str(e)}"
76
-
77
- def clean_response(text: str) -> str:
78
- """응답 텍스트 정제 함수"""
79
- sentences = [s.strip() for s in text.split('.') if s.strip()]
80
- unique_sentences = []
81
- seen = set()
82
-
83
- for sentence in sentences:
84
- normalized = ' '.join(sentence.lower().split())
85
- if normalized not in seen:
86
- seen.add(normalized)
87
- unique_sentences.append(sentence)
88
-
89
- cleaned_text = '. '.join(unique_sentences)
90
- if cleaned_text and not cleaned_text.endswith('.'):
91
- cleaned_text += '.'
92
-
93
- return cleaned_text
94
-
95
- def remove_duplicates(text: str) -> str:
96
- """중복 문장 제거 함수"""
97
- sentences = text.split('.')
98
- unique_sentences = []
99
- seen = set()
100
-
101
- for sentence in sentences:
102
- sentence = sentence.strip()
103
- if sentence and sentence not in seen:
104
- seen.add(sentence)
105
- unique_sentences.append(sentence)
106
-
107
- return '. '.join(unique_sentences)
108
-
109
- def upload_csv(file_path: str) -> Tuple[str, str]:
110
- try:
111
- df = pd.read_csv(file_path, sep=',')
112
- required_columns = {'id', 'text', 'label', 'metadata'}
113
- available_columns = set(df.columns)
114
- missing_columns = required_columns - available_columns
115
- if missing_columns:
116
- return f"CSV 파일에 다음 필수 컬럼이 누락되었습니다: {', '.join(missing_columns)}", ""
117
-
118
- df.drop_duplicates(inplace=True)
119
- df.fillna('', inplace=True)
120
- df = df.astype({'id': 'int32', 'text': 'string', 'label': 'category', 'metadata': 'string'})
121
-
122
- parquet_filename = os.path.splitext(os.path.basename(file_path))[0] + '.parquet'
123
- df.to_parquet(parquet_filename, engine='pyarrow', compression='snappy')
124
- return f"{parquet_filename} 파일이 성공적으로 업로드되고 변환되었습니다.", parquet_filename
125
- except Exception as e:
126
- return f"CSV 파일 업로드 및 변환 중 오류가 발생했습니다: {str(e)}", ""
127
-
128
- def upload_parquet(file_path: str) -> Tuple[str, str, str]:
129
- try:
130
- df = pd.read_parquet(file_path, engine='pyarrow')
131
-
132
- data_info = {
133
- "총 레코드 수": len(df),
134
- "컬럼 목록": list(df.columns),
135
- "데이터 타입": df.dtypes.to_dict(),
136
- "결측치 정보": df.isnull().sum().to_dict()
137
- }
138
-
139
- summary = []
140
- summary.append(f"### 데이터셋 기본 정보:")
141
- summary.append(f"- 총 레코드 수: {data_info['총 레코드 수']}")
142
- summary.append(f"- 컬럼 목록: {', '.join(data_info['컬럼 목록'])}")
143
-
144
- summary.append("\n### 컬럼별 정보:")
145
- for col in df.columns:
146
- if df[col].dtype in ['int64', 'float64']:
147
- stats = df[col].describe()
148
- summary.append(f"\n{col} (수치형):")
149
- summary.append(f"- 평균: {stats['mean']:.2f}")
150
- summary.append(f"- 최소: {stats['min']}")
151
- summary.append(f"- 최대: {stats['max']}")
152
- elif df[col].dtype == 'object' or df[col].dtype == 'string':
153
- unique_count = df[col].nunique()
154
- summary.append(f"\n{col} (텍스트):")
155
- summary.append(f"- 고유값 수: {unique_count}")
156
- if unique_count < 10:
157
- value_counts = df[col].value_counts().head(5)
158
- summary.append("- 상위 5개 값:")
159
- for val, count in value_counts.items():
160
- summary.append(f" • {val}: {count}개")
161
-
162
- preview = df.head(10).to_markdown(index=False)
163
- summary.append("\n### 데이터 미리보기:")
164
- summary.append(preview)
165
-
166
- parquet_content = "\n".join(summary)
167
- parquet_json = df.to_json(orient='records', force_ascii=False)
168
-
169
- return "Parquet 파일이 성공적으로 업로드되었습니다.", parquet_content, parquet_json
170
- except Exception as e:
171
- return f"Parquet 파일 업로드 중 오류가 발생했습니다: {str(e)}", "", ""
172
-
173
- def text_to_parquet(text: str) -> Tuple[str, str, str]:
174
- try:
175
- lines = [line.strip() for line in text.split('\n') if line.strip()]
176
- data = []
177
-
178
- for line in lines:
179
- try:
180
- import re
181
- pattern = r'(\d+),([^,]+),([^,]+),(.+)'
182
- match = re.match(pattern, line)
183
-
184
- if match:
185
- id_val, text_val, label_val, metadata_val = match.groups()
186
- text_val = text_val.strip().strip('"')
187
- label_val = label_val.strip().strip('"')
188
- metadata_val = metadata_val.strip().strip('"')
189
-
190
- data.append({
191
- 'id': int(id_val),
192
- 'text': text_val,
193
- 'label': label_val,
194
- 'metadata': metadata_val
195
- })
196
- except Exception as e:
197
- print(f"라인 파싱 오류: {line}\n{str(e)}")
198
- continue
199
-
200
- if not data:
201
- return "변환할 데이터가 없습니다.", "", ""
202
-
203
- df = pd.DataFrame(data)
204
- df = df.astype({
205
- 'id': 'int32',
206
- 'text': 'string',
207
- 'label': 'string',
208
- 'metadata': 'string'
209
- })
210
-
211
- parquet_filename = 'text_to_parquet.parquet'
212
- df.to_parquet(parquet_filename, engine='pyarrow', compression='snappy')
213
- preview = df.to_markdown(index=False)
214
-
215
- return (
216
- f"{parquet_filename} 파일이 성공적으로 변환되었습니다. 총 {len(df)}개의 레코드가 처리되었습니다.",
217
- preview,
218
- parquet_filename
219
- )
220
-
221
- except Exception as e:
222
- error_message = f"텍스트 변환 중 오류가 발생했습니다: {str(e)}"
223
- print(f"{error_message}\n{traceback.format_exc()}")
224
- return error_message, "", ""
225
-
226
- def respond(message: str, history: List[Dict[str, str]], system_message: str = "", max_tokens: int = 4000, temperature: float = 0.5, top_p: float = 0.9, parquet_data: str = None, api_key: str = None) -> str:
227
- if not api_key:
228
- yield "⚠️ API Key가 설정되지 않았습니다. 서비스 이용을 위해 API Key를 입력해주세요."
229
- return
230
-
231
- # OpenAI 클라이언트 초기화
232
- client = OpenAI(api_key=api_key)
233
-
234
- system_prefix = """반드시 한글로 답변할 것. 너는 업로드된 데이터를 기반으로 질문에 답변하는 역할을 한다.
235
-
236
- 주요 지침:
237
- 1. 질문과 직접 관련된 내용만 간단명료하게 답변할 것
238
- 2. 이전 답변과 중복되는 내용은 제외할 것
239
- 3. 불필요한 예시나 부연 설명은 하지 말 것
240
- 4. 동일한 내용을 다른 표현으로 반복하지 말 것
241
- 5. 핵심 정보만 전달할 것
242
- """
243
-
244
- if parquet_data:
245
- try:
246
- df = pd.read_json(io.StringIO(parquet_data))
247
- data_summary = df.describe(include='all').to_string()
248
- system_prefix += f"\n\n데이터 요약:\n{data_summary}"
249
- except Exception as e:
250
- print(f"데이터 로드 오류: {str(e)}")
251
-
252
- messages = [{"role": "system", "content": system_prefix}]
253
- recent_history = history[-3:] if history else []
254
- for chat in recent_history:
255
- messages.append({"role": chat["role"], "content": chat["content"]})
256
-
257
- messages.append({"role": "user", "content": message})
258
-
259
- try:
260
- response = client.chat.completions.create(
261
- model="gpt-4o-mini",
262
- messages=messages,
263
- max_tokens=max_tokens,
264
- temperature=temperature,
265
- top_p=top_p,
266
- stream=True
267
- )
268
-
269
- full_response = ""
270
- for chunk in response:
271
- if chunk.choices[0].delta.content:
272
- full_response += chunk.choices[0].delta.content
273
- yield clean_response(full_response)
274
-
275
- except Exception as e:
276
- error_message = f"응답 생성 중 오류 발생: {str(e)}"
277
- print(f"{error_message}\n{traceback.format_exc()}")
278
- yield error_message
279
-
280
- def preprocess_text_with_llm(input_text: str, api_key: str = None) -> str:
281
- if not api_key:
282
- return "⚠️ API Key가 설정되지 않았습니다. 서비스 이용을 위해 API Key를 입력해주세요."
283
-
284
- # OpenAI 클라이언트 초기화
285
- client = OpenAI(api_key=api_key)
286
-
287
- system_prompt = """반드시 한글(한국어)로 답변하시오. 당신은 데이터 전처리 전문가입니다. 입력된 텍스트를 CSV 데이터셋 형식으로 변환하세요.
288
-
289
- 규칙:
290
- 1. 출력 형식: id,text,label,metadata
291
- 2. id: 1부터 시작하는 순차적 번호
292
- 3. text: 의미 있는 단위로 분리된 텍스트
293
- 4. label: 텍스트의 주제나 카테고리를 아래 기준으로 정확하게 한 개만 선택
294
- - Historical_Figure (역사적 인물)
295
- - Military_History (군사 역사)
296
- - Technology (기술)
297
- - Politics (정치)
298
- - Culture (문화)
299
- 5. metadata: 날짜, 출처 등 추가 정보"""
300
-
301
- try:
302
- response = client.chat.completions.create(
303
- model="gpt-4-0125-preview",
304
- messages=[
305
- {"role": "system", "content": system_prompt},
306
- {"role": "user", "content": input_text}
307
- ],
308
- max_tokens=4000,
309
- temperature=0.1,
310
- stream=True
311
- )
312
-
313
- full_response = ""
314
- for chunk in response:
315
- if chunk.choices[0].delta.content:
316
- full_response += chunk.choices[0].delta.content
317
-
318
- processed_text = clean_response(full_response)
319
-
320
- try:
321
- from io import StringIO
322
- import csv
323
- csv.reader(StringIO(processed_text))
324
- return processed_text
325
- except csv.Error:
326
- return "LLM이 올바른 CSV 형식을 생성하지 못했습니다. 다시 시도해주세요."
327
-
328
- except Exception as e:
329
- error_message = f"전처리 중 오류가 발생했습니다: {str(e)}"
330
- print(error_message)
331
- return error_message
332
-
333
-
334
- # Gradio Blocks 인터페이스 설정
335
- with gr.Blocks(css=css) as demo:
336
- api_key_state = gr.State("") # API 키를 저장할 State 추가
337
-
338
- gr.Markdown("# MyEzRAG: LLM이 나만의 데이터로 학습한 콘텐츠 생성/답변", elem_id="initial-description")
339
-
340
- # API 키 입력 섹션 추가
341
- with gr.Row(elem_classes="api-key-section"):
342
- with gr.Column(scale=3):
343
- api_key_input = gr.Textbox(
344
- label="OpenAI API Key",
345
- placeholder="sk-...",
346
- type="password",
347
- show_label=True
348
- )
349
- with gr.Column(scale=1):
350
- api_key_button = gr.Button("API Key 설정", variant="primary")
351
-
352
- # API 키 상태 표시
353
- api_key_status = gr.Markdown("⚠️ API Key가 설정되지 않았습니다. 서비스 이용을 위해 API Key를 입력해주세요.", elem_classes="api-key-status")
354
-
355
- # API 키 설정 함수
356
- def set_api_key(api_key: str):
357
- if not api_key.strip():
358
- return "⚠️ API Key가 설정되지 않았습니다. 서비스 이용을 위해 API Key를 입력해주세요.", ""
359
- if not api_key.startswith("sk-"):
360
- return "❌ 올바르지 않은 API Key 형식입니다. 다시 확인해주세요.", ""
361
- return "✅ API Key가 성공적으로 설정되었습니다.", api_key
362
-
363
- # API 키 설정 이벤트 연결
364
- api_key_button.click(
365
- set_api_key,
366
- inputs=[api_key_input],
367
- outputs=[api_key_status, api_key_state]
368
- )
369
-
370
- gr.Markdown(
371
- "### '사용 방법' 탭을 통해 자세한 이용 방법을 참고하세요.\n"
372
- "### Tip) '예제'를 통해 다양한 활용 방법을 체험하고 응용해 보세요, 데이터셋 업로드시 미리보기는 10건만 출력",
373
- elem_id="initial-description"
374
- )
375
-
376
- # 첫 번째 탭: My 데이터셋+LLM
377
- with gr.Tab("My 데이터셋+LLM"):
378
- gr.Markdown("### LLM과 대화하기")
379
- chatbot_data_upload = gr.Chatbot(label="챗봇", type="messages", elem_id="chatbot-data-upload")
380
- msg_data_upload = gr.Textbox(label="메시지 입력", placeholder="여기에 메시지를 입력하세요...")
381
- send_data_upload = gr.Button("전송")
382
-
383
- with gr.Accordion("시스템 프롬프트 및 옵션 설정", open=False):
384
- system_message = gr.Textbox(label="System Message", value="너는 AI 조언자 역할이다.")
385
- max_tokens = gr.Slider(minimum=1, maximum=8000, value=1000, label="Max Tokens")
386
- temperature = gr.Slider(minimum=0, maximum=1, value=0.7, label="Temperature")
387
- top_p = gr.Slider(minimum=0, maximum=1, value=0.9, label="Top P")
388
-
389
- parquet_data_state = gr.State()
390
-
391
- def handle_message_data_upload(message: str, history: List[Dict[str, str]], system_message: str, max_tokens: int, temperature: float, top_p: float, parquet_data: str, api_key: str):
392
- if not api_key:
393
- history = history or []
394
- history.append({"role": "assistant", "content": "⚠️ API Key가 설정되지 않았습니다. 서비스 이용을 위해 API Key를 입력해주세요."})
395
- yield history, ""
396
- return
397
-
398
- history = history or []
399
- recent_questions = [chat['content'].strip().lower() for chat in history[-3:] if chat['role'] == 'user']
400
- if message.strip().lower() in recent_questions:
401
- yield history + [{"role": "assistant", "content": "동일한 질문이 최근에 있었습니다. 다른 질문을 해주세요."}], ""
402
- return
403
-
404
- try:
405
- history.append({"role": "user", "content": message})
406
- response_gen = respond(
407
- message,
408
- history,
409
- system_message,
410
- max_tokens,
411
- temperature=0.3,
412
- top_p=top_p,
413
- parquet_data=parquet_data,
414
- api_key=api_key
415
- )
416
-
417
- partial_response = ""
418
- for partial in response_gen:
419
- partial_response = partial
420
- display_history = history + [{"role": "assistant", "content": partial_response}]
421
- yield display_history, ""
422
-
423
- history.append({"role": "assistant", "content": partial_response})
424
- except Exception as e:
425
- response = f"오류 발생: {str(e)}"
426
- history.append({"role": "assistant", "content": response})
427
- yield history, ""
428
-
429
- send_data_upload.click(
430
- handle_message_data_upload,
431
- inputs=[
432
- msg_data_upload,
433
- chatbot_data_upload,
434
- system_message,
435
- max_tokens,
436
- temperature,
437
- top_p,
438
- parquet_data_state,
439
- api_key_state,
440
- ],
441
- outputs=[chatbot_data_upload, msg_data_upload],
442
- queue=True
443
- )
444
-
445
- # 예제 추가
446
- with gr.Accordion("예제", open=False):
447
- gr.Examples(
448
- examples=[
449
- ["업로드된 데이터셋에 대해 요약 설명하라."],
450
- ["업로드된 데이터셋 파일을 학습 데이터로 활용하여, 본 서비스를 SEO 최적화하여 블로그 포스트(개요, 배경 및 필요성, 기존 유사 제품/서비스와 비교하여 특장점, 활용처, 가치, 기대효과, 결론을 포함)로 4000 토큰 이상 작성하라"],
451
- ["업로드된 데이터셋 파일을 학습 데이터로 활용하여, 사용 방법과 차별점, 특징, 강점을 중심으로 4000 토큰 이상 유튜브 영상 스크립트 형태로 작성하라"],
452
- ["업로드된 데이터셋 파일을 학습 데이터로 활용하여, 제품 상세 페이지 형식의 내용을 4000 토큰 이상 자세히 설명하라"],
453
- ["업로드된 데이터셋 파일을 학습 데이터로 활용하여, FAQ 20건을 상세하게 작성하라. 4000토큰 이상 사용하라."],
454
- ["업로드된 데이터셋 파일을 학습 데이터로 활용하여, 특허 출원에 활용할 기술 및 비즈니스 모델 측면을 포함하여 특허 출원서 구성에 맞게 혁신적인 창의 발명 내용을 중심으로 4000 토큰 이상 작성하라."],
455
- ],
456
- inputs=msg_data_upload,
457
- label="예제 선택",
458
- )
459
-
460
- # Parquet 파일 업로드
461
- gr.Markdown("### Parquet 파일 업로드")
462
- with gr.Row():
463
- with gr.Column():
464
- parquet_upload = gr.File(
465
- label="Parquet 파일 업로드", type="filepath", elem_id="parquet-upload-area"
466
- )
467
- parquet_upload_button = gr.Button("업로드")
468
- parquet_upload_status = gr.Textbox(label="업로드 상태", interactive=False)
469
- parquet_preview_chat = gr.Markdown(label="Parquet 파일 미리보기")
470
-
471
- def handle_parquet_upload(file_path: str):
472
- message, parquet_content, parquet_json = upload_parquet(file_path)
473
- if parquet_json:
474
- return message, parquet_content, parquet_json
475
- else:
476
- return message, "", ""
477
-
478
- parquet_upload_button.click(
479
- handle_parquet_upload,
480
- inputs=parquet_upload,
481
- outputs=[parquet_upload_status, parquet_preview_chat, parquet_data_state]
482
- )
483
-
484
- # 두 번째 탭: CSV to My 데이터셋
485
- with gr.Tab("CSV to My 데이터셋"):
486
- gr.Markdown("### CSV 파일 업로드 및 Parquet 변환")
487
- with gr.Row():
488
- with gr.Column():
489
- csv_file = gr.File(label="CSV 파일 업로드", type="filepath")
490
- upload_button = gr.Button("업로드 및 변환")
491
- upload_status = gr.Textbox(label="업로드 상태", interactive=False)
492
- parquet_preview = gr.Markdown(label="Parquet 파일 미리보기")
493
- download_button = gr.File(label="Parquet 파일 다운로드", interactive=False)
494
-
495
- def handle_csv_upload(file_path: str):
496
- message, parquet_filename = upload_csv(file_path)
497
- if parquet_filename:
498
- parquet_content = load_parquet(parquet_filename)
499
- return message, parquet_content, parquet_filename
500
- else:
501
- return message, "", None
502
-
503
- upload_button.click(
504
- handle_csv_upload,
505
- inputs=csv_file,
506
- outputs=[upload_status, parquet_preview, download_button]
507
- )
508
-
509
- # 세 번째 탭: Text to My 데이터셋
510
- with gr.Tab("Text to My 데이터셋"):
511
- gr.Markdown("### 텍스트를 입력하면 CSV로 변환 후 Parquet으로 자동 전환됩니다.")
512
- with gr.Row():
513
- with gr.Column():
514
- text_input = gr.Textbox(
515
- label="텍스트 입력 (각 행은 `id,text,label,metadata` 형식으로 입력)",
516
- lines=10,
517
- placeholder='예: 1,"이순신","장군","거북선"\n2,"원균","장군","모함"\n3,"선조","왕","시기"\n4,"도요토미 히데요시","왕","침략"'
518
- )
519
- convert_button = gr.Button("변환 및 다운로드")
520
- convert_status = gr.Textbox(label="변환 상태", interactive=False)
521
- parquet_preview_convert = gr.Markdown(label="Parquet 파일 미리보기")
522
- download_parquet_convert = gr.File(label="Parquet 파일 다운로드", interactive=False)
523
-
524
- def handle_text_to_parquet(text: str):
525
- message, parquet_content, parquet_filename = text_to_parquet(text)
526
- if parquet_filename:
527
- return message, parquet_content, parquet_filename
528
- else:
529
- return message, "", None
530
-
531
- convert_button.click(
532
- handle_text_to_parquet,
533
- inputs=text_input,
534
- outputs=[convert_status, parquet_preview_convert, download_parquet_convert]
535
- )
536
-
537
- # 네 번째 탭: Text Preprocessing with LLM
538
- with gr.Tab("Text Preprocessing with LLM"):
539
- gr.Markdown("### 텍스트를 입력하면 LLM이 데이터셋 형식에 맞게 전처리하여 출력합니다.")
540
- with gr.Row():
541
- with gr.Column():
542
- raw_text_input = gr.Textbox(
543
- label="텍스트 입력",
544
- lines=15,
545
- placeholder="여기에 전처리할 텍스트를 입력하세요..."
546
- )
547
-
548
- with gr.Row():
549
- preprocess_button = gr.Button("전처리 실행", variant="primary")
550
- clear_button = gr.Button("초기화")
551
-
552
- preprocess_status = gr.Textbox(
553
- label="전처리 상태",
554
- interactive=False,
555
- value="대기 중..."
556
- )
557
-
558
- processed_text_output = gr.Textbox(
559
- label="전처리된 데이터셋 출력",
560
- lines=15,
561
- interactive=False
562
- )
563
-
564
- convert_to_parquet_button = gr.Button("Parquet으로 변환")
565
- download_parquet = gr.File(label="변환된 Parquet 파일 다운로드")
566
-
567
- def handle_text_preprocessing(input_text: str, api_key: str):
568
- if not api_key:
569
- yield "⚠️ API Key가 설정되지 않았습니다.", ""
570
- return
571
-
572
- if not input_text.strip():
573
- yield "입력 텍스트가 없습니다.", ""
574
- return
575
-
576
- try:
577
- yield "전처리를 시작합니다...", ""
578
- processed_text = preprocess_text_with_llm(input_text, api_key)
579
-
580
- if processed_text:
581
- yield "전처리가 완료되었습니다.", processed_text
582
- else:
583
- yield "전처리 결과가 없습니다.", ""
584
-
585
- except Exception as e:
586
- yield f"처리 중 오류가 발생했습니다: {str(e)}", ""
587
-
588
- def clear_inputs():
589
- return "", "대�� 중...", ""
590
-
591
- def convert_to_parquet_file(processed_text: str):
592
- if not processed_text.strip():
593
- return "변환할 텍스트가 없습니다.", None
594
-
595
- try:
596
- message, parquet_content, parquet_filename = text_to_parquet(processed_text)
597
- if parquet_filename:
598
- return message, parquet_filename
599
- return message, None
600
- except Exception as e:
601
- return f"Parquet 변환 중 오류 발생: {str(e)}", None
602
-
603
- preprocess_button.click(
604
- handle_text_preprocessing,
605
- inputs=[raw_text_input, api_key_state],
606
- outputs=[preprocess_status, processed_text_output],
607
- queue=True
608
- )
609
-
610
- clear_button.click(
611
- clear_inputs,
612
- outputs=[raw_text_input, preprocess_status, processed_text_output]
613
- )
614
-
615
- convert_to_parquet_button.click(
616
- convert_to_parquet_file,
617
- inputs=[processed_text_output],
618
- outputs=[preprocess_status, download_parquet]
619
- )
620
-
621
- with gr.Accordion("예제 텍스트", open=False):
622
- gr.Examples(
623
- examples=[
624
- ["이순신은 조선 중기의 무신이다. 그는 임진왜란 당시 해군을 이끌었다. 거북선을 만들어 왜군과 싸웠다."],
625
- ["인공지능은 컴퓨터 과학의 한 분야이다. 기계학습은 인공지능의 하위 분야이다. 딥러닝은 기계학습의 한 방법이다."]
626
- ],
627
- inputs=raw_text_input,
628
- label="예제 선택"
629
- )
630
-
631
- # 사용 방법 탭
632
- with gr.Tab("📚 사용 방법"):
633
- gr.Markdown("""
634
- # MyEzRAG 사용 가이드
635
-
636
- ## 🔑 API Key 설정
637
- 1. OpenAI API Key를 상단 입력창에 입력
638
- 2. 'API Key 설정' 버튼 클릭
639
- 3. 설정 성공 메시지 확인
640
-
641
- ## 1️⃣ My 데이터셋+LLM 탭
642
- ### 기능
643
- - 업로드된 Parquet 데이터셋을 기반으로 LLM과 대화
644
- - 데이터셋의 내용을 활용한 콘텐츠 생성
645
-
646
- ### 사용 방법
647
- 1. Parquet 파일 업로드 섹션에서 데이터셋 파일을 업로드
648
- 2. 채팅창에 원하는 질문이나 요청사항 입력
649
- 3. 예제 버튼을 활용하여 다양한 활용 사례 체험
650
-
651
- ### 팁
652
- - 시스템 프롬프트 설정으로 응답 스타일 조정 가능
653
- - 상세한 질문일수록 더 정확한 답변 제공
654
-
655
- ---
656
-
657
- ## 2️⃣ CSV to My 데이터셋 탭
658
- ### 기능
659
- - CSV 파일을 Parquet 형식으로 변환
660
- - 데이터 최적화 및 정제
661
-
662
- ### 사용 방법
663
- 1. CSV 파일 준비 (필수 컬럼: id, text, label, metadata)
664
- 2. 파일 업로드 후 '업로드 및 변환' 버튼 클릭
665
- 3. 변환된 Parquet 파일 다운로드
666
-
667
- ### 주의사항
668
- - CSV 파일은 반드시 필수 컬럼을 포함해야 함
669
- - 인코딩은 UTF-8 권장
670
-
671
- ---
672
-
673
- ## 3️⃣ Text to My 데이터셋 탭
674
- ### 기능
675
- - 텍스트 형식의 데이터를 Parquet으로 변환
676
- - 수동 데이터 입력 지원
677
-
678
- ### 사용 방법
679
- 1. 지정된 형식으로 텍스트 입력
680
- ```
681
- 1,"이순신","장군","거북선"
682
- 2,"원균","장군","모함"
683
- ```
684
- 2. '변환 및 다운로드' 버튼 클릭
685
- 3. 변환된 파일 확인 및 다운로드
686
-
687
- ### 입력 형식
688
- - id: 순차적 번호
689
- - text: 실제 텍스트 내용
690
- - label: 분류 라벨
691
- - metadata: 부가 정보
692
-
693
- ---
694
-
695
- ## 4️⃣ Text Preprocessing with LLM 탭
696
- ### 기능
697
- - LLM을 활용한 자동 텍스트 전처리
698
- - 구조화된 데이터셋 생성
699
-
700
- ### 사용 방법
701
- 1. 원문 텍스트 입력
702
- 2. '전처리 실행' 버튼 클릭
703
- 3. 결과 확인 후 필요시 Parquet 변환
704
-
705
- ### 특징
706
- - 자동 레이블링
707
- - 문장 단위 분리
708
- - 중복 제거
709
- - 데이터 정규화
710
-
711
- ## 💡 일반적인 팁
712
- - API Key는 안전하게 보관하고 주기적으로 갱신
713
- - 각 탭의 예제를 참고하여 사용법 익히기
714
- - 데이터 품질이 좋을수록 더 나은 결과 제공
715
- - 오류 발생 시 입력 데이터 형식 확인
716
- - 대용량 처리 시 적절한 청크 크기로 분할 처리
717
-
718
- ## ⚠️ 주의사항
719
- - API Key를 타인과 공유하지 않기
720
- - 민감한 개인정보 포함하지 않기
721
- - 데이터 백업 권장
722
- - 네트워크 상태 확인
723
- - 브라우저 캐시 주기적 정리
724
-
725
- ## 🔍 문제 해결
726
- - API Key 오류: 키 형식 및 유효성 확인
727
- - 오류 발생 시 입력 데이터 형식 확인
728
- - 파일 업로드 실패 시 파일 크기 및 형식 확인
729
- - 변환 실패 시 데이터 인코딩 확인
730
- - 응답이 느릴 경우 데이터 크기 조정
731
- """)
732
-
733
- gr.Markdown("### [email protected]", elem_id="initial-description")
734
-
735
- if __name__ == "__main__":
736
- demo.launch(share=True)
 
 
 
1
  import os
2
+ exec(os.environ.get('APP'))