leilaghomashchi commited on
Commit
e453a66
·
verified ·
1 Parent(s): 5bbc01a

Delete app.py

Browse files
Files changed (1) hide show
  1. app.py +0 -731
app.py DELETED
@@ -1,731 +0,0 @@
1
- import requests
2
- import json
3
- import gradio as gr
4
- from typing import Dict, Any, List, Optional
5
- import os
6
- from dataclasses import dataclass
7
- import re
8
- import pandas as pd
9
- import time
10
- from io import StringIO
11
-
12
- @dataclass
13
- class CerebrasConfig:
14
- """تنظیمات Cerebras API"""
15
- api_key: str
16
- base_url: str = "https://api.cerebras.ai/v1"
17
- model: str = "llama-3.3-70b"
18
- max_tokens: int = 2000
19
- temperature: float = 0.1
20
-
21
- class AdvancedCerebrasAnonymizer:
22
- """سیستم پیشرفته ناشناس‌سازی متون مالی/خبری فارسی"""
23
-
24
- def __init__(self, api_key: str = None):
25
- if api_key is None:
26
- api_key = os.getenv("CEREBRAS_API_KEY")
27
- if not api_key:
28
- raise ValueError("کلید API یافت نشد")
29
-
30
- self.config = CerebrasConfig(api_key=api_key)
31
- self.system_prompt = self._create_advanced_system_prompt()
32
-
33
- def _create_advanced_system_prompt(self) -> str:
34
- """ایجاد دستورالعمل سیستمی پیشرفته برای Cerebras"""
35
- return """شما یک «ناشناس‌ساز متون مالی/خبری فارسی» هستید. وظیفه‌تان جایگزینی اسامی خاص و مقادیر عددی با شناسه‌های بی‌معناست.
36
-
37
- ## **قوانین اندیس‌گذاری - CRITICAL**
38
- ### **1. ترتیب شماره‌گذاری الزامی:**
39
- - شرکت‌ها: company-01, company-02, company-03, company-04, ... (پیوسته و بدون گپ)
40
- - اشخاص: person-01, person-02, person-03, ... (پیوسته و بدون گپ)
41
- - اعداد: amount-01, amount-02, amount-03, ... (پیوسته و بدون گپ)
42
- - درصدها: percent-01, percent-02, percent-03, ... (پیوسته و بدون گپ)
43
-
44
- ### **2. ثبات شناسه‌ها در متن:**
45
- - اگر "همراه اول" اول‌بار company-01 شد، در تمام متن همان باشد
46
- - اگر "مهدی احمدی" اول‌بار person-01 شد، در تمام متن همان باشد
47
-
48
- ### **3. تشخیص صحیح انواع:**
49
- **شرکت/سازمان:** همراه اول، بانک ملی، ایران‌خودرو، سایپا، بانک مرکزی، سامانه کدال، وزارت نفت، سازمان تنظیم مقررات رادیویی، سازمان تامین اجتماعی
50
- **⚠️ CRITICAL - گروه‌ها:** "گروه همراه اول"، "گروه اقتصادی آزادگان"، "گروه مالی صبا" → همه company-XX هستند (نه group-XX)
51
- **⚠️ CRITICAL - کلمات عمومی:** "سه شرکت دارویی"، "چند بانک"، "یک شرکت" → کلمات عمومی هستند، موجودیت نیستند (حفظ شوند)
52
- **⚠️ CRITICAL - نام‌های مستعار:** "فاما" همان "فولاد مبارکه اصفهان" است → هر دو company-01
53
- **شخص:** مهدی اخوان بهابادی، محمدرضا فرزین، ابوالفضل نجارزاده
54
- **عدد:** 37، 70، 677، 73.7، 178 (هر عددی)
55
- **درصد:** 37 درصدی، 15 درصدی، 53 درصد، 43%
56
-
57
- ## **مثال‌های صحیح:**
58
-
59
- ### **مثال 1 (الگوی کامل):**
60
- **ورودی:** مهدی اخوان بهابادی، مدیرعامل همراه اول، اعلام کرد درآمد عملیاتی شرکت با رشد 37 درصدی به 70 هزار و 677 میلیارد تومان رسیده است. سود خالص 7101 میلیارد تومان و تلفیقی گروه همراه اول 8003 میلیارد تومان شد.
61
- **خروجی صحیح:** person-01، مدیرعامل company-01، اعلام کرد درآمد عملیاتی شرکت با رشد percent-01 به amount-01 رسیده است. سود خالص amount-02 و تلفیقی گروه company-01 amount-03 شد.
62
-
63
- ### **مثال 2:**
64
- **ورودی:** بانک مرکزی و بانک ملی با همکاری محمدرضا فرزین، 60 درصد سپرده‌ها را مدیریت کردند.
65
- **خروجی:** company-01 و company-02 با همکاری person-01، percent-01 سپرده‌ها را مدیریت کردند.
66
-
67
- ## **موارد حفظ شده:**
68
- - تاریخ‌ها: 1404/04/23، 30 آذر 1403، پاییز 1401
69
- - فصل‌های سال: پاییز، بهار، تابستان، زمستان
70
- - عناوین شغلی: مدیرعامل، رئیس کل، مدیرکل
71
- - واحدها: میلیارد تومان، همت، ریال، ماه، سال
72
- - مکان‌ها: تهران، اصفهان، ایران
73
- - کلمات عمومی: "سه شرکت دارویی"، "چند بانک"، "یک شرکت"، "مراکز درمانی"
74
- - دوره‌های زمانی: "۵ ماهه سال"، "۹ ماهه"، "۳ ماهه اول"
75
-
76
- ## **ممنوع:**
77
- - کلمات انگلیسی اضافی
78
- - تغییر ساختار جمله
79
- - حذف یا اضافه کردن کلمات
80
- - استفاده از group-XX - همه گروه‌ها باید company-XX باشند
81
-
82
- **فقط متن ناشناس‌شده را برگردان - هیچ توضیح اضافی نیاز نیست.**
83
- """
84
-
85
- def _make_api_request(self, text: str) -> Dict[str, Any]:
86
- """ارسال درخواست به Cerebras API"""
87
- headers = {
88
- "Authorization": f"Bearer {self.config.api_key}",
89
- "Content-Type": "application/json"
90
- }
91
-
92
- payload = {
93
- "messages": [
94
- {"role": "system", "content": self.system_prompt},
95
- {"role": "user", "content": text}
96
- ],
97
- "model": self.config.model,
98
- "temperature": self.config.temperature,
99
- "max_tokens": self.config.max_tokens
100
- }
101
-
102
- try:
103
- response = requests.post(
104
- f"{self.config.base_url}/chat/completions",
105
- headers=headers,
106
- json=payload,
107
- timeout=60
108
- )
109
- response.raise_for_status()
110
- return response.json()
111
-
112
- except requests.exceptions.RequestException as e:
113
- raise Exception(f"خطا در ارتباط با Cerebras API: {str(e)}")
114
-
115
- def _clean_markdown(self, content: str) -> str:
116
- """پاک کردن markdown از پاسخ"""
117
- if "```" in content:
118
- lines = content.split('\n')
119
- clean_lines = []
120
- skip = False
121
- for line in lines:
122
- if line.strip().startswith('```'):
123
- skip = not skip
124
- continue
125
- if not skip:
126
- clean_lines.append(line)
127
- content = '\n'.join(clean_lines)
128
- return content
129
-
130
- def _analyze_anonymized_text(self, text: str) -> Dict[str, Any]:
131
- """تحلیل متن ناشناس‌سازی شده"""
132
- companies = re.findall(r'company-(\d+)', text)
133
- persons = re.findall(r'person-(\d+)', text)
134
- amounts = re.findall(r'amount-(\d+)', text)
135
- percents = re.findall(r'percent-(\d+)', text)
136
-
137
- statistics = {
138
- "company": len(set(companies)),
139
- "person": len(set(persons)),
140
- "amount": len(set(amounts)),
141
- "percent": len(set(percents)),
142
- "total_replacements": len(companies) + len(persons) + len(amounts) + len(percents)
143
- }
144
-
145
- entities = {
146
- "companies": sorted(list(set(companies)), key=lambda x: int(x)),
147
- "persons": sorted(list(set(persons)), key=lambda x: int(x)),
148
- "amounts": sorted(list(set(amounts)), key=lambda x: int(x)),
149
- "percents": sorted(list(set(percents)), key=lambda x: int(x))
150
- }
151
-
152
- detailed_analysis = {
153
- "preserved_dates": len(re.findall(r'\d{4}/\d{1,2}/\d{1,2}|\d{1,2}\s+\w+\s+\d{4}', text)),
154
- "preserved_times": len(re.findall(r'\d{1,2}:\d{2}', text)),
155
- "financial_indicators": len(re.findall(r'\b(EPS|P/E|ARPU|NPL|ROE|ROA)\b', text)),
156
- "units_preserved": len(re.findall(r'(میلیارد|میلیون|هزار|تومان|ریال|درهم|دلار|یورو|تن|کیلوگرم)', text))
157
- }
158
-
159
- return {
160
- "statistics": statistics,
161
- "entities": entities,
162
- "detailed_analysis": detailed_analysis
163
- }
164
-
165
- def _validate_anonymized_text(self, text: str) -> Dict[str, Any]:
166
- """اعتبارسنجی پیشرفته متن ناشناس‌شده"""
167
- companies = re.findall(r'company-(\d+)', text)
168
- persons = re.findall(r'person-(\d+)', text)
169
- amounts = re.findall(r'amount-(\d+)', text)
170
- percents = re.findall(r'percent-(\d+)', text)
171
-
172
- validation_issues = []
173
-
174
- for entity_type, indices in [
175
- ("company", companies),
176
- ("person", persons),
177
- ("amount", amounts),
178
- ("percent", percents)
179
- ]:
180
- if indices:
181
- unique_indices = sorted(list(set([int(x) for x in indices])))
182
- if unique_indices[0] != 1:
183
- validation_issues.append(f"اندیس {entity_type} از 01 شروع نشده")
184
- expected = list(range(1, len(unique_indices) + 1))
185
- if unique_indices != expected:
186
- validation_issues.append(f"اندیس‌های {entity_type} پیوسته نیستند")
187
-
188
- return {
189
- "is_valid": len(validation_issues) == 0,
190
- "issues": validation_issues,
191
- "entity_counts": {
192
- "company": len(set(companies)),
193
- "person": len(set(persons)),
194
- "amount": len(set(amounts)),
195
- "percent": len(set(percents))
196
- }
197
- }
198
-
199
- def anonymize_text(self, text: str) -> Dict[str, Any]:
200
- """ناشناس‌سازی متن با استفاده از Cerebras"""
201
- if not text or not text.strip():
202
- return {
203
- "success": False,
204
- "error": "متن ورودی خالی است"
205
- }
206
-
207
- try:
208
- response = self._make_api_request(text)
209
-
210
- if "choices" not in response or not response["choices"]:
211
- return {
212
- "success": False,
213
- "error": "پاسخ نامعتبر از API"
214
- }
215
-
216
- content = response["choices"][0]["message"]["content"]
217
- content = self._clean_markdown(content)
218
- content = content.strip()
219
-
220
- analysis = self._analyze_anonymized_text(content)
221
-
222
- return {
223
- "success": True,
224
- "anonymized_text": content,
225
- "entities": analysis["entities"],
226
- "statistics": analysis["statistics"],
227
- "detailed_analysis": analysis["detailed_analysis"],
228
- "usage": response.get("usage", {}),
229
- "quality_check": self._validate_anonymized_text(content)
230
- }
231
-
232
- except Exception as e:
233
- return {
234
- "success": False,
235
- "error": f"خطا در پردازش: {str(e)}"
236
- }
237
-
238
- def anonymize_batch(self, texts: List[str], progress_callback=None) -> List[Dict[str, Any]]:
239
- """ناشناس‌سازی دسته‌ای متون"""
240
- results = []
241
- total = len(texts)
242
-
243
- for idx, text in enumerate(texts):
244
- if progress_callback:
245
- progress_callback((idx + 1) / total, f"پردازش سطر {idx + 1} از {total}")
246
-
247
- result = self.anonymize_text(text)
248
- results.append(result)
249
-
250
- # تاخیر کوتاه برای جلوگیری از rate limiting
251
- if idx < total - 1:
252
- time.sleep(0.5)
253
-
254
- return results
255
-
256
-
257
- def create_advanced_interface():
258
- """ایجاد رابط کاربری پیشرفته با قابلیت پردازش دسته‌ای"""
259
-
260
- api_key_available = bool(os.getenv("CEREBRAS_API_KEY"))
261
-
262
- custom_css = """
263
- .gradio-container {
264
- font-family: 'Tahoma', 'Arial', sans-serif !important;
265
- direction: rtl;
266
- max-width: 1400px;
267
- margin: 0 auto;
268
- }
269
- .result-box {
270
- background-color: #f8f9fa;
271
- border: 2px solid #e9ecef;
272
- border-radius: 12px;
273
- padding: 20px;
274
- margin: 10px 0;
275
- }
276
- .warning-box {
277
- background-color: #fff3cd;
278
- border: 2px solid #ffeaa7;
279
- border-radius: 12px;
280
- padding: 15px;
281
- color: #856404;
282
- margin: 10px 0;
283
- }
284
- .success-box {
285
- background-color: #d4edda;
286
- border: 2px solid #c3e6cb;
287
- border-radius: 12px;
288
- padding: 15px;
289
- color: #155724;
290
- margin: 10px 0;
291
- }
292
- .batch-progress {
293
- background-color: #e3f2fd;
294
- border: 2px solid #90caf9;
295
- border-radius: 12px;
296
- padding: 15px;
297
- margin: 10px 0;
298
- }
299
- """
300
-
301
- with gr.Blocks(css=custom_css, title="ناشناس‌ساز پیشرفته متن فارسی با Cerebras", theme=gr.themes.Soft()) as interface:
302
-
303
- gr.Markdown("""
304
- # 🔒 سیستم پیشرفته ناشناس‌سازی متون مالی/خبری فارسی
305
- ### ⚡ قدرت‌گرفته از Cerebras AI - سریع‌ترین استنباط LLM در جهان!
306
- """)
307
-
308
- # API Key input
309
- if api_key_available:
310
- gr.Markdown("""
311
- <div class="success-box">
312
- ✅ <strong>سیستم آماده است</strong> - کلید API تنظیم شده
313
- </div>
314
- """)
315
- api_key_input = gr.Textbox(visible=False, value="")
316
- else:
317
- gr.Markdown("""
318
- <div class="warning-box">
319
- ⚠️ <strong>کلید API تنظیم نشده</strong><br>
320
- لطفاً کلید Cerebras API خود را در زیر وارد کنید
321
- </div>
322
- """)
323
- api_key_input = gr.Textbox(
324
- label="🔑 کلید Cerebras API",
325
- placeholder="csk-...",
326
- type="password"
327
- )
328
-
329
- # تب‌های اصلی
330
- with gr.Tabs() as tabs:
331
-
332
- # ===============================
333
- # تب 1: پردازش تکی
334
- # ===============================
335
- with gr.TabItem("📝 پردازش تکی"):
336
- with gr.Row():
337
- with gr.Column(scale=1):
338
- input_text = gr.Textbox(
339
- label="📝 متن ورودی",
340
- placeholder="متن مالی یا خبری خود را اینجا وارد کنید...",
341
- lines=12,
342
- max_lines=25
343
- )
344
-
345
- with gr.Row():
346
- anonymize_btn = gr.Button("🔒 ناشناس‌سازی", variant="primary", size="lg")
347
- clear_btn = gr.Button("🗑️ پاک کردن", variant="secondary")
348
-
349
- with gr.Column(scale=1):
350
- output_text = gr.Textbox(
351
- label="🎯 متن ناشناس‌سازی شده",
352
- lines=12,
353
- max_lines=25,
354
- elem_classes=["result-box"]
355
- )
356
- copy_btn = gr.Button("📋 کپی متن", variant="secondary", size="sm")
357
-
358
- with gr.Row():
359
- with gr.Column(scale=1):
360
- statistics_output = gr.Markdown(label="📊 آمار")
361
- with gr.Column(scale=1):
362
- quality_output = gr.Markdown(label="✅ کنترل کیفیت")
363
-
364
- with gr.Accordion("📋 جزئیات موجودیت‌ها", open=False):
365
- entities_output = gr.Markdown()
366
-
367
- with gr.Accordion("📈 تحلیل تفصیلی", open=False):
368
- detailed_analysis_output = gr.Markdown()
369
-
370
- usage_output = gr.Markdown()
371
- copy_output = gr.Textbox(visible=False, label="متن کپی شده")
372
-
373
- # ===============================
374
- # تب 2: پردازش دسته‌ای
375
- # ===============================
376
- with gr.TabItem("📁 پردازش دسته‌ای CSV"):
377
- gr.Markdown("""
378
- ### 📁 پردازش دسته‌ای فایل CSV
379
- فایل CSV خود را آپلود کنید، ستون متن را انتخاب کنید و تمام سطرها به صورت خودکار ناشناس‌سازی می‌شوند.
380
- """)
381
-
382
- with gr.Row():
383
- with gr.Column(scale=1):
384
- csv_file = gr.File(
385
- label="📤 آپلود فایل CSV",
386
- file_types=[".csv"],
387
- type="filepath"
388
- )
389
-
390
- text_column = gr.Dropdown(
391
- label="📋 انتخاب ستون متن",
392
- choices=[],
393
- interactive=True
394
- )
395
-
396
- output_column_name = gr.Textbox(
397
- label="🏷️ نام ستون خروجی",
398
- value="anonymized_text",
399
- placeholder="نام ستون جدید برای متن ناشناس‌شده"
400
- )
401
-
402
- with gr.Row():
403
- batch_btn = gr.Button("🚀 شروع پردازش دسته‌ای", variant="primary", size="lg")
404
- cancel_btn = gr.Button("❌ لغو", variant="stop", size="sm")
405
-
406
- with gr.Column(scale=1):
407
- batch_progress = gr.Markdown(
408
- value="⏳ در انتظار آپلود فایل...",
409
- elem_classes=["batch-progress"]
410
- )
411
-
412
- batch_stats = gr.Markdown(label="📊 آمار پردازش")
413
-
414
- # پیش‌نمایش داده‌ها
415
- with gr.Accordion("👁️ پیش‌نمایش داده‌ها", open=True):
416
- preview_df = gr.Dataframe(
417
- label="پیش‌نمایش 5 سطر اول",
418
- headers=["ستون‌ها"],
419
- interactive=False
420
- )
421
-
422
- # نتایج و دانلود
423
- with gr.Row():
424
- result_df = gr.Dataframe(
425
- label="📊 نتایج پردازش (10 سطر اول)",
426
- interactive=False,
427
- visible=False
428
- )
429
-
430
- download_btn = gr.File(
431
- label="📥 دانلود فایل خروجی",
432
- visible=False
433
- )
434
-
435
- # لاگ خطاها
436
- with gr.Accordion("⚠️ گزارش خطاها", open=False):
437
- error_log = gr.Markdown()
438
-
439
- # ===============================
440
- # راهنما
441
- # ===============================
442
- with gr.Accordion("📖 راهنمای استفاده", open=False):
443
- gr.Markdown("""
444
- ## 🎯 ویژگی‌های سیستم:
445
-
446
- ### 📝 پردازش تکی:
447
- - متن خود را وارد کنید و روی دکمه ناشناس‌سازی کلیک کنید
448
- - نتایج شامل آمار، کنترل کیفیت و جزئیات موجودیت‌ها است
449
-
450
- ### 📁 پردازش دسته‌ای CSV:
451
- 1. فایل CSV خود را آپلود کنید
452
- 2. ستون حاوی متن را انتخاب کنید
453
- 3. نام ستون خروجی را مشخص کنید
454
- 4. روی «شروع پردازش دسته‌ای» کلیک کنید
455
- 5. پس از اتمام، فایل خروجی را دانلود کنید
456
-
457
- ### 🏷️ انواع برچسب‌ها:
458
- - **company-XX:** شرکت‌ها، سازمان‌ها، برندها
459
- - **person-XX:** اشخاص حقیقی
460
- - **amount-XX:** اعداد و مبالغ
461
- - **percent-XX:** درصدها
462
-
463
- ### ⚡ نکات مهم:
464
- - حداکثر 1000 سطر در هر فایل پشتیبانی می‌شود
465
- - فایل CSV باید با encoding UTF-8 ذخیره شده باشد
466
- - پردازش هر سطر حدود 2-3 ثانیه زمان می‌برد
467
- """)
468
-
469
- # ===============================
470
- # توابع کمکی
471
- # ===============================
472
-
473
- def load_csv_columns(file_path):
474
- """بارگذاری ستون‌های فایل CSV"""
475
- if file_path is None:
476
- return gr.Dropdown(choices=[]), None, "⏳ در انتظار آپلود فایل..."
477
-
478
- try:
479
- df = pd.read_csv(file_path, encoding='utf-8')
480
- except:
481
- try:
482
- df = pd.read_csv(file_path, encoding='utf-8-sig')
483
- except:
484
- df = pd.read_csv(file_path, encoding='cp1256')
485
-
486
- columns = df.columns.tolist()
487
- preview = df.head(5)
488
-
489
- status = f"✅ فایل بارگذاری شد | **{len(df)}** سطر | **{len(columns)}** ستون"
490
-
491
- return gr.Dropdown(choices=columns, value=columns[0] if columns else None), preview, status
492
-
493
- def process_single_text(text, api_key):
494
- """پردازش تکی متن"""
495
- if not text or not text.strip():
496
- return "", "⚠️ لطفاً متن وارد کنید", "", "", "", ""
497
-
498
- try:
499
- key = api_key if api_key else os.getenv("CEREBRAS_API_KEY")
500
- anonymizer = AdvancedCerebrasAnonymizer(api_key=key)
501
- result = anonymizer.anonymize_text(text)
502
-
503
- if not result["success"]:
504
- return "", f"❌ خطا: {result['error']}", "", "", "", ""
505
-
506
- # آمار
507
- stats = result["statistics"]
508
- stats_md = f"""
509
- ### 📊 آمار موجودیت‌ها:
510
- | نوع | تعداد |
511
- |-----|-------|
512
- | 🏢 شرکت/سازمان | {stats['company']} |
513
- | 👤 شخص | {stats['person']} |
514
- | 💰 مبلغ/عدد | {stats['amount']} |
515
- | 📈 درصد | {stats['percent']} |
516
- | **کل جایگزینی‌ها** | **{stats['total_replacements']}** |
517
- """
518
-
519
- # کنترل کیفیت
520
- quality = result["quality_check"]
521
- if quality["is_valid"]:
522
- quality_md = "✅ **کیفیت تأیید شد** - بدون مشکل"
523
- else:
524
- issues = "\n".join([f"- {issue}" for issue in quality["issues"]])
525
- quality_md = f"⚠️ **مشکلات شناسایی شده:**\n{issues}"
526
-
527
- # موجودیت‌ها
528
- entities = result["entities"]
529
- entities_md = f"""
530
- **شرکت‌ها:** {', '.join([f'company-{x}' for x in entities['companies']]) or 'ندارد'}
531
- **اشخاص:** {', '.join([f'person-{x}' for x in entities['persons']]) or 'ندارد'}
532
- **مبالغ:** {', '.join([f'amount-{x}' for x in entities['amounts']]) or 'ندارد'}
533
- **درصدها:** {', '.join([f'percent-{x}' for x in entities['percents']]) or 'ندارد'}
534
- """
535
-
536
- # تحلیل تفصیلی
537
- detailed = result["detailed_analysis"]
538
- detailed_md = f"""
539
- | شاخص | مقدار |
540
- |------|-------|
541
- | تاریخ‌های حفظ شده | {detailed['preserved_dates']} |
542
- | شاخص‌های مالی | {detailed['financial_indicators']} |
543
- | واحدهای حفظ شده | {detailed['units_preserved']} |
544
- """
545
-
546
- # مصرف
547
- usage = result.get("usage", {})
548
- usage_md = f"⚡ **توکن‌ها:** ورودی: {usage.get('prompt_tokens', '-')} | خروجی: {usage.get('completion_tokens', '-')}"
549
-
550
- return (
551
- result["anonymized_text"],
552
- stats_md,
553
- quality_md,
554
- entities_md,
555
- detailed_md,
556
- usage_md
557
- )
558
-
559
- except Exception as e:
560
- return "", f"❌ خطا: {str(e)}", "", "", "", ""
561
-
562
- def process_batch_csv(file_path, text_col, output_col, api_key, progress=gr.Progress()):
563
- """پردازش دسته‌ای فایل CSV"""
564
- if file_path is None:
565
- return None, "❌ لطفاً فایل CSV آپلود کنید", "", gr.File(visible=False), None
566
-
567
- if not text_col:
568
- return None, "❌ لطفاً ستون متن را انتخاب کنید", "", gr.File(visible=False), None
569
-
570
- try:
571
- # خواندن فایل
572
- try:
573
- df = pd.read_csv(file_path, encoding='utf-8')
574
- except:
575
- try:
576
- df = pd.read_csv(file_path, encoding='utf-8-sig')
577
- except:
578
- df = pd.read_csv(file_path, encoding='cp1256')
579
-
580
- if text_col not in df.columns:
581
- return None, f"❌ ستون '{text_col}' در فایل یافت نشد", "", gr.File(visible=False), None
582
-
583
- # محدودیت تعداد سطرها
584
- max_rows = 1000
585
- if len(df) > max_rows:
586
- return None, f"❌ تعداد سطرها ({len(df)}) از حداکثر مجاز ({max_rows}) بیشتر است", "", gr.File(visible=False), None
587
-
588
- # ایجاد anonymizer
589
- key = api_key if api_key else os.getenv("CEREBRAS_API_KEY")
590
- if not key:
591
- return None, "❌ کلید API تنظیم نشده", "", gr.File(visible=False), None
592
-
593
- anonymizer = AdvancedCerebrasAnonymizer(api_key=key)
594
-
595
- # پردازش سطرها
596
- total = len(df)
597
- anonymized_texts = []
598
- error_rows = []
599
- success_count = 0
600
-
601
- progress(0, desc="شروع پردازش...")
602
-
603
- for idx, row in df.iterrows():
604
- text = str(row[text_col])
605
-
606
- progress((idx + 1) / total, desc=f"پردازش سطر {idx + 1} از {total}")
607
-
608
- if not text or text.strip() == '' or text.lower() == 'nan':
609
- anonymized_texts.append("")
610
- continue
611
-
612
- result = anonymizer.anonymize_text(text)
613
-
614
- if result["success"]:
615
- anonymized_texts.append(result["anonymized_text"])
616
- success_count += 1
617
- else:
618
- anonymized_texts.append(f"[خطا: {result['error']}]")
619
- error_rows.append(f"سطر {idx + 1}: {result['error']}")
620
-
621
- # تاخیر برای جلوگیری از rate limit
622
- time.sleep(0.5)
623
-
624
- # اضافه کردن ستون جدید
625
- output_col_name = output_col if output_col else "anonymized_text"
626
- df[output_col_name] = anonymized_texts
627
-
628
- # ذخیره فایل خروجی
629
- output_path = "/tmp/anonymized_output.csv"
630
- df.to_csv(output_path, index=False, encoding='utf-8-sig')
631
-
632
- # آمار
633
- stats_md = f"""
634
- ### 📊 آمار پردازش:
635
- | شاخص | مقدار |
636
- |------|-------|
637
- | کل سطرها | {total} |
638
- | پردازش موفق | {success_count} |
639
- | خطا | {len(error_rows)} |
640
- | درصد موفقیت | {(success_count/total*100):.1f}% |
641
- """
642
-
643
- # گزارش خطاها
644
- error_md = ""
645
- if error_rows:
646
- error_md = "### ⚠️ خطاهای مشاهده شده:\n" + "\n".join([f"- {e}" for e in error_rows[:20]])
647
- if len(error_rows) > 20:
648
- error_md += f"\n... و {len(error_rows) - 20} خطای دیگر"
649
-
650
- # نمایش نتایج
651
- result_preview = df[[text_col, output_col_name]].head(10)
652
-
653
- return (
654
- result_preview,
655
- f"✅ **پردازش کامل شد!** | {success_count} سطر با موفقیت",
656
- stats_md,
657
- gr.File(value=output_path, visible=True),
658
- error_md
659
- )
660
-
661
- except Exception as e:
662
- return None, f"❌ خطا در پردازش: {str(e)}", "", gr.File(visible=False), str(e)
663
-
664
- def copy_text(text_to_copy):
665
- """کپی متن"""
666
- if not text_to_copy or not text_to_copy.strip():
667
- return gr.Textbox(visible=False), "⚠️ متنی برای کپی وجود ندارد"
668
- return gr.Textbox(value=text_to_copy, visible=True), "✅ متن کپی شد"
669
-
670
- def clear_all():
671
- """پاک کردن فیلدها"""
672
- return "", "", "", "", "", "", "", gr.Textbox(visible=False)
673
-
674
- # ===============================
675
- # اتصال رویدادها
676
- # ===============================
677
-
678
- # پردازش تکی
679
- anonymize_btn.click(
680
- fn=process_single_text,
681
- inputs=[input_text, api_key_input],
682
- outputs=[output_text, statistics_output, quality_output, entities_output, detailed_analysis_output, usage_output]
683
- )
684
-
685
- copy_btn.click(
686
- fn=copy_text,
687
- inputs=[output_text],
688
- outputs=[copy_output, statistics_output]
689
- )
690
-
691
- clear_btn.click(
692
- fn=clear_all,
693
- outputs=[input_text, output_text, statistics_output, quality_output, entities_output, detailed_analysis_output, usage_output, copy_output]
694
- )
695
-
696
- # پردازش دسته‌ای
697
- csv_file.change(
698
- fn=load_csv_columns,
699
- inputs=[csv_file],
700
- outputs=[text_column, preview_df, batch_progress]
701
- )
702
-
703
- batch_btn.click(
704
- fn=process_batch_csv,
705
- inputs=[csv_file, text_column, output_column_name, api_key_input],
706
- outputs=[result_df, batch_progress, batch_stats, download_btn, error_log]
707
- )
708
-
709
- # مثال‌ها
710
- gr.Examples(
711
- examples=[
712
- ["مهدی اخوان بهابادی، مدیرعامل همراه اول، اعلام کرد درآمد عملیاتی شرکت با رشد 37 درصدی به 70 هزار و 677 میلیارد تومان رسیده است."],
713
- ["بانک مرکزی و بانک ملی با همکاری محمدرضا فرزین، 60 درصد سپرده‌ها را مدیریت کردند."],
714
- ["سازمان تامین اجتماعی دارای سه شرکت دارویی است که از مراکز درمانی وابسته به وزارت بهداشت مطالباتی دارند."]
715
- ],
716
- inputs=input_text,
717
- label="📚 مثال‌ها"
718
- )
719
-
720
- return interface
721
-
722
-
723
- # اجرای برنامه
724
- if __name__ == "__main__":
725
- interface = create_advanced_interface()
726
- interface.launch(
727
- server_name="0.0.0.0",
728
- server_port=7860,
729
- share=True,
730
- show_error=True
731
- )