leilaghomashchi commited on
Commit
397284d
·
verified ·
1 Parent(s): fa6a660

Delete app.py

Browse files
Files changed (1) hide show
  1. app.py +0 -720
app.py DELETED
@@ -1,720 +0,0 @@
1
- import gradio as gr
2
- import re
3
- import os
4
- import requests
5
- import json
6
- import logging
7
- import time
8
- from typing import Dict, List, Tuple, Optional
9
- from chatgpt_sender import ChatGPTSender
10
-
11
- logging.basicConfig(level=logging.INFO)
12
- logger = logging.getLogger(__name__)
13
-
14
- class MultiModelSender:
15
- """کلاس واحد برای ارسال به مدل‌های مختلف با retry mechanism"""
16
-
17
- def __init__(self):
18
- # دریافت API Keys از environment و trim کردن آنها
19
- self.openai_key = os.getenv("OPENAI_API_KEY", "").strip() if os.getenv("OPENAI_API_KEY") else None
20
- self.grok_key = os.getenv("XAI_API_KEY", "").strip() if os.getenv("XAI_API_KEY") else None
21
- self.gemini_key = os.getenv("GEMINI_API_KEY", "").strip() if os.getenv("GEMINI_API_KEY") else None
22
- self.deepseek_key = os.getenv("DEEPSEEK_API_KEY", "").strip() if os.getenv("DEEPSEEK_API_KEY") else None
23
-
24
- # ایجاد instance از ChatGPTSender
25
- self.chatgpt_sender = ChatGPTSender(api_key=self.openai_key, model="gpt-4o-mini")
26
-
27
- logger.info("✅ MultiModelSender مقداردهی شد")
28
-
29
- def send_to_chatgpt(self, text: str, system_msg: Optional[str] = None) -> str:
30
- """
31
- ارسال به ChatGPT با استفاده از ماژول پیشرفته
32
- """
33
- try:
34
- if system_msg:
35
- return self.chatgpt_sender.send(
36
- text=text,
37
- system_msg=system_msg,
38
- max_tokens=4096,
39
- temperature=0.1,
40
- lang='fa',
41
- retry_count=3
42
- )
43
- else:
44
- return self.chatgpt_sender.send_simple(text, lang='fa')
45
- except Exception as e:
46
- logger.error(f"❌ ChatGPT Error: {e}")
47
- return f"❌ خطا در ChatGPT: {str(e)}"
48
-
49
- def send_to_grok(self, text: str, system_msg: Optional[str] = None, retry_count: int = 3) -> str:
50
- """ارسال به Grok (xAI) با retry mechanism"""
51
- if not self.grok_key:
52
- return "❌ XAI_API_KEY (Grok) موجود نیست"
53
-
54
- messages = []
55
- if system_msg:
56
- messages.append({"role": "system", "content": system_msg})
57
- messages.append({"role": "user", "content": text})
58
-
59
- for attempt in range(retry_count):
60
- try:
61
- logger.info(f"📤 ارسال به Grok (تلاش {attempt + 1}/{retry_count})...")
62
-
63
- response = requests.post(
64
- "https://api.x.ai/v1/chat/completions",
65
- headers={
66
- "Authorization": f"Bearer {self.grok_key}",
67
- "Content-Type": "application/json"
68
- },
69
- json={
70
- "model": "grok-beta",
71
- "messages": messages,
72
- "temperature": 0.1,
73
- "max_tokens": 4096
74
- },
75
- timeout=60
76
- )
77
-
78
- if response.status_code == 200:
79
- logger.info("✅ Grok: پاسخ دریافت شد")
80
- return response.json()['choices'][0]['message']['content'].strip()
81
-
82
- elif response.status_code == 429:
83
- wait_time = 5 * (attempt + 1)
84
- logger.warning(f"⚠️ Grok Rate limit | صبر: {wait_time} ثانیه")
85
- if attempt < retry_count - 1:
86
- time.sleep(wait_time)
87
- continue
88
- else:
89
- return "❌ سهمیه Grok تمام شده است"
90
-
91
- elif response.status_code == 401:
92
- return "❌ کلید API Grok نامعتبر است!"
93
-
94
- elif response.status_code in [502, 503, 504]:
95
- wait_time = 2 * (attempt + 1)
96
- logger.warning(f"⚠️ Grok Server error | صبر: {wait_time} ثانیه")
97
- if attempt < retry_count - 1:
98
- time.sleep(wait_time)
99
- continue
100
- else:
101
- return f"❌ خطای سرور Grok: {response.status_code}"
102
-
103
- else:
104
- error_msg = response.text
105
- logger.error(f"❌ Grok API Error: {error_msg}")
106
- return f"❌ Grok API Error: {response.status_code}"
107
-
108
- except requests.exceptions.Timeout:
109
- logger.warning("⚠️ Grok Timeout | تلاش مجدد...")
110
- if attempt < retry_count - 1:
111
- time.sleep(3)
112
- continue
113
- else:
114
- return "❌ خطای اتصال به Grok: timeout"
115
-
116
- except Exception as e:
117
- logger.error(f"❌ Grok Exception: {e}")
118
- if attempt < retry_count - 1:
119
- time.sleep(2)
120
- continue
121
- else:
122
- return f"❌ خطا در Grok: {str(e)}"
123
-
124
- return "❌ خطای ناشناخته در Grok"
125
-
126
- def send_to_gemini(self, text: str, system_msg: Optional[str] = None, retry_count: int = 3) -> str:
127
- """ارسال به Google Gemini با retry mechanism"""
128
- if not self.gemini_key:
129
- return "❌ GEMINI_API_KEY موجود نیست"
130
-
131
- # ترکیب system message و text
132
- full_prompt = f"{system_msg}\n\n{text}" if system_msg else text
133
-
134
- for attempt in range(retry_count):
135
- try:
136
- logger.info(f"📤 ارسال به Gemini (تلاش {attempt + 1}/{retry_count})...")
137
-
138
- response = requests.post(
139
- f"https://generativelanguage.googleapis.com/v1beta/models/gemini-flash-latest:generateContent",
140
- headers={
141
- "Content-Type": "application/json"
142
- },
143
- json={
144
- "contents": [{
145
- "parts": [{"text": full_prompt}]
146
- }],
147
- "generationConfig": {
148
- "temperature": 0.1,
149
- "maxOutputTokens": 4096
150
- }
151
- },
152
- timeout=60
153
- )
154
-
155
- if response.status_code == 200:
156
- result = response.json()
157
- logger.info("✅ Gemini: پاسخ دریافت شد")
158
- return result['candidates'][0]['content']['parts'][0]['text'].strip()
159
-
160
- elif response.status_code == 429:
161
- wait_time = 5 * (attempt + 1)
162
- logger.warning(f"⚠️ Gemini Rate limit | صبر: {wait_time} ثانیه")
163
- if attempt < retry_count - 1:
164
- time.sleep(wait_time)
165
- continue
166
- else:
167
- return "❌ سهمیه Gemini تمام شده است"
168
-
169
- elif response.status_code == 400:
170
- error_data = response.json()
171
- error_msg = error_data.get('error', {}).get('message', 'خطای نامعتبر')
172
- return f"❌ خطای Gemini: {error_msg}"
173
-
174
- elif response.status_code in [502, 503, 504]:
175
- wait_time = 2 * (attempt + 1)
176
- logger.warning(f"⚠️ Gemini Server error | صبر: {wait_time} ثانیه")
177
- if attempt < retry_count - 1:
178
- time.sleep(wait_time)
179
- continue
180
- else:
181
- return f"❌ خطای سرور Gemini: {response.status_code}"
182
-
183
- else:
184
- error_msg = response.text
185
- logger.error(f"❌ Gemini API Error: {error_msg}")
186
- return f"❌ Gemini API Error: {response.status_code}"
187
-
188
- except requests.exceptions.Timeout:
189
- logger.warning("⚠️ Gemini Timeout | تلاش مجدد...")
190
- if attempt < retry_count - 1:
191
- time.sleep(3)
192
- continue
193
- else:
194
- return "❌ خطای اتصال به Gemini: timeout"
195
-
196
- except Exception as e:
197
- logger.error(f"❌ Gemini Exception: {e}")
198
- if attempt < retry_count - 1:
199
- time.sleep(2)
200
- continue
201
- else:
202
- return f"❌ خطا در Gemini: {str(e)}"
203
-
204
- return "❌ خطای ناشناخته در Gemini"
205
-
206
- def send_to_deepseek(self, text: str, system_msg: Optional[str] = None, retry_count: int = 3) -> str:
207
- """ارسال به DeepSeek با retry mechanism"""
208
- if not self.deepseek_key:
209
- return "❌ DEEPSEEK_API_KEY موجود نیست"
210
-
211
- messages = []
212
- if system_msg:
213
- messages.append({"role": "system", "content": system_msg})
214
- messages.append({"role": "user", "content": text})
215
-
216
- for attempt in range(retry_count):
217
- try:
218
- logger.info(f"📤 ارسال به DeepSeek (تلاش {attempt + 1}/{retry_count})...")
219
-
220
- response = requests.post(
221
- "https://api.deepseek.com/v1/chat/completions",
222
- headers={
223
- "Authorization": f"Bearer {self.deepseek_key}",
224
- "Content-Type": "application/json"
225
- },
226
- json={
227
- "model": "deepseek-chat",
228
- "messages": messages,
229
- "temperature": 0.1,
230
- "max_tokens": 4096
231
- },
232
- timeout=60
233
- )
234
-
235
- if response.status_code == 200:
236
- logger.info("✅ DeepSeek: پاسخ دریافت شد")
237
- return response.json()['choices'][0]['message']['content'].strip()
238
-
239
- elif response.status_code == 429:
240
- wait_time = 5 * (attempt + 1)
241
- logger.warning(f"⚠️ DeepSeek Rate limit | صبر: {wait_time} ثانیه")
242
- if attempt < retry_count - 1:
243
- time.sleep(wait_time)
244
- continue
245
- else:
246
- return "❌ سهمیه DeepSeek تمام شده است"
247
-
248
- elif response.status_code == 401:
249
- return "❌ کلید API DeepSeek نامعتبر است!"
250
-
251
- elif response.status_code in [502, 503, 504]:
252
- wait_time = 2 * (attempt + 1)
253
- logger.warning(f"⚠️ DeepSeek Server error | صبر: {wait_time} ثانیه")
254
- if attempt < retry_count - 1:
255
- time.sleep(wait_time)
256
- continue
257
- else:
258
- return f"❌ خطای سرور DeepSeek: {response.status_code}"
259
-
260
- else:
261
- error_msg = response.text
262
- logger.error(f"❌ DeepSeek API Error: {error_msg}")
263
- return f"❌ DeepSeek API Error: {response.status_code}"
264
-
265
- except requests.exceptions.Timeout:
266
- logger.warning("⚠️ DeepSeek Timeout | تلاش مجدد...")
267
- if attempt < retry_count - 1:
268
- time.sleep(3)
269
- continue
270
- else:
271
- return "❌ خطای اتصال به DeepSeek: timeout"
272
-
273
- except Exception as e:
274
- logger.error(f"❌ DeepSeek Exception: {e}")
275
- if attempt < retry_count - 1:
276
- time.sleep(2)
277
- continue
278
- else:
279
- return f"❌ خطا در DeepSeek: {str(e)}"
280
-
281
- return "❌ خطای ناشناخته در DeepSeek"
282
-
283
- def send_message(self, text: str, model_name: str, system_msg: Optional[str] = None) -> str:
284
- """
285
- ارسال پیام به مدل انتخاب شده
286
-
287
- Args:
288
- text: متن ارسالی
289
- model_name: نام مدل
290
- system_msg: پیام سیستم (اختیاری)
291
-
292
- Returns:
293
- پاسخ مدل
294
- """
295
- logger.info(f"🤖 ارسال به {model_name}...")
296
-
297
- if model_name == "ChatGPT-4o-mini":
298
- return self.send_to_chatgpt(text, system_msg)
299
- elif model_name == "Grok":
300
- return self.send_to_grok(text, system_msg)
301
- elif model_name == "Gemini":
302
- return self.send_to_gemini(text, system_msg)
303
- elif model_name == "DeepSeek":
304
- return self.send_to_deepseek(text, system_msg)
305
- else:
306
- return f"❌ مدل نامعتبر: {model_name}"
307
-
308
-
309
- class AnonymizerAdvanced:
310
- """ناشناس‌ساز پیشرفته با Cerebras"""
311
-
312
- def __init__(self, cerebras_key: str = None):
313
- self.cerebras_key = cerebras_key or os.getenv("CEREBRAS_API_KEY")
314
- self.mapping_table = {}
315
- self.reverse_mapping = {}
316
-
317
- # ایجاد instance از MultiModelSender
318
- self.model_sender = MultiModelSender()
319
-
320
- logger.info("✅ Anonymizer Advanced مقداردهی شد")
321
-
322
- def anonymize_with_cerebras(self, text: str) -> Tuple[str, Dict]:
323
- """ناشناس‌سازی با Cerebras - دریافت mapping از مدل"""
324
- logger.info("🧠 روش Cerebras...")
325
-
326
- if not self.cerebras_key:
327
- logger.error("❌ Cerebras API Key موجود نیست")
328
- raise ValueError("Cerebras API Key مورد نیاز است")
329
-
330
- try:
331
- # مرحله 1: ناشناس‌سازی متن
332
- prompt1 = f"""متن زیر را ناشناس کنید. قوانین:
333
- 1. اسامی اشخاص → person-01, person-02, ...
334
- 2. نام شرکت‌ها/سازمان‌ها → company-01, company-02, ...
335
- 3. مقادیر پولی → amount-01, amount-02, ...
336
- 4. درصدها → percent-01, percent-02, ...
337
- 5. فقط این توکن‌ها استفاده کنید
338
- 6. شماره‌های نسخه را درست حفظ کنید
339
- 7. اگر موجودیت تکرار شود از شماره قدیمی استفاده کنید
340
-
341
- متن:
342
- {text}
343
-
344
- خروجی: فقط متن ناشناس شده"""
345
-
346
- response1 = requests.post(
347
- "https://api.cerebras.ai/v1/chat/completions",
348
- headers={
349
- "Authorization": f"Bearer {self.cerebras_key}",
350
- "Content-Type": "application/json"
351
- },
352
- json={
353
- "model": "llama-3.3-70b",
354
- "messages": [{"role": "user", "content": prompt1}],
355
- "max_tokens": 4096,
356
- "temperature": 0.1
357
- },
358
- timeout=60
359
- )
360
-
361
- if response1.status_code != 200:
362
- logger.error(f"❌ Cerebras Error: {response1.status_code}")
363
- raise Exception(f"Cerebras API Error: {response1.status_code}")
364
-
365
- anonymized_text = response1.json()['choices'][0]['message']['content'].strip()
366
- logger.info("✅ Cerebras: ناشناس‌سازی موفق")
367
-
368
- # مرحله 2: استخراج mapping از مدل
369
- prompt2 = f"""متن اصلی:
370
- {text}
371
-
372
- متن ناشناس شده:
373
- {anonymized_text}
374
-
375
- لطفاً یک جدول mapping برای همه توکن‌های ناشناس ایجاد کن.
376
- برای هر توکن، متن اصلی کامل آن را مشخص کن.
377
-
378
- **مهم:**
379
- - برای person-XX: نام کامل شخص (مثلاً "علی احمدی")
380
- - برای company-XX: نام کامل شرکت/سازمان (مثلاً "شرکت پتروشیمی")
381
- - برای amount-XX: عدد + واحد (مثلاً "80 هزار تومان" یا "50 میلیارد ریال")
382
- - برای percent-XX: عدد + کلمه "درصد" (مثلاً "40 درصد" نه فقط "40")
383
-
384
- خروجی را به این فرمت JSON بده (فقط JSON، بدون توضیح اضافی):
385
- {{
386
- "person-01": "متن اصلی کامل",
387
- "company-01": "متن اصلی کامل",
388
- "amount-01": "متن اصلی کامل با واحد",
389
- "percent-01": "عدد + درصد",
390
- ...
391
- }}"""
392
-
393
- response2 = requests.post(
394
- "https://api.cerebras.ai/v1/chat/completions",
395
- headers={
396
- "Authorization": f"Bearer {self.cerebras_key}",
397
- "Content-Type": "application/json"
398
- },
399
- json={
400
- "model": "llama-3.3-70b",
401
- "messages": [{"role": "user", "content": prompt2}],
402
- "max_tokens": 2048,
403
- "temperature": 0.1
404
- },
405
- timeout=60
406
- )
407
-
408
- if response2.status_code == 200:
409
- mapping_text = response2.json()['choices'][0]['message']['content'].strip()
410
- mapping_text = mapping_text.replace('```json', '').replace('```', '').strip()
411
-
412
- try:
413
- self.mapping_table = json.loads(mapping_text)
414
- self._fix_percent_mapping()
415
- self.reverse_mapping = {v: k for k, v in self.mapping_table.items()}
416
- logger.info(f"✅ Mapping استخراج شد: {len(self.mapping_table)} موجودیت")
417
- except json.JSONDecodeError:
418
- logger.warning("⚠️ خطا در parse کردن JSON mapping - استفاده از روش fallback")
419
- self._extract_mapping_from_text(text, anonymized_text)
420
- else:
421
- logger.warning("⚠️ خطا در دریافت mapping - استفاده از روش fallback")
422
- self._extract_mapping_from_text(text, anonymized_text)
423
-
424
- return anonymized_text, self.mapping_table
425
-
426
- except Exception as e:
427
- logger.error(f"❌ Cerebras Exception: {e}")
428
- raise
429
-
430
- def _fix_percent_mapping(self):
431
- """اصلاح mapping برای درصدها و مقادیر"""
432
- for token, value in self.mapping_table.items():
433
- value_str = str(value).strip()
434
-
435
- if token.startswith('percent-'):
436
- if not re.search(r'(درصد|%|درصدی)', value_str):
437
- self.mapping_table[token] = f"{value_str} درصد"
438
- logger.info(f"✅ اصلاح {token}: '{value_str}' → '{value_str} درصد'")
439
-
440
- elif token.startswith('amount-'):
441
- if not re.search(r'(میلیارد|میلیون|هزار|تومان|ریال|دلار|یورو|تن)', value_str):
442
- logger.warning(f"⚠️ {token}: فقط عدد '{value_str}' - واحد مشخص نیست")
443
-
444
- def _extract_mapping_from_text(self, original: str, anonymized: str):
445
- """استخراج mapping از متن‌های اصلی و ناشناس شده"""
446
- all_tokens = []
447
- for entity_type in ['person', 'company', 'amount', 'percent']:
448
- tokens = re.findall(f'{entity_type}-\\d+', anonymized)
449
- all_tokens.extend([(t, entity_type) for t in tokens])
450
-
451
- all_tokens = sorted(set(all_tokens), key=lambda x: (x[1], int(x[0].split('-')[1])))
452
-
453
- patterns = {
454
- 'person': r'\b[ء-ي]+\s+[ء-ي]+(?:\s+[ء-ي]+)*\b',
455
- 'company': r'(?:شرکت|بانک|سازمان|گروه|هلدینگ)\s+[ء-ي]+(?:\s+[ء-ي]+)*',
456
- 'amount': r'\d+(?:\.\d+)?\s*(?:میلیارد|میلیون|هزار|تومان|ریال|دلار|یورو|تن)',
457
- 'percent': r'\d+(?:\.\d+)?\s*(?:درصد|%|درصدی)',
458
- }
459
-
460
- original_entities = {}
461
- for entity_type, pattern in patterns.items():
462
- matches = list(re.finditer(pattern, original))
463
- original_entities[entity_type] = [m.group().strip() for m in matches]
464
-
465
- for token, entity_type in all_tokens:
466
- if entity_type in original_entities and original_entities[entity_type]:
467
- token_num = int(token.split('-')[1]) - 1
468
-
469
- if token_num < len(original_entities[entity_type]):
470
- original_text = original_entities[entity_type][token_num]
471
- self.mapping_table[token] = original_text
472
- self.reverse_mapping[original_text] = token
473
- else:
474
- original_text = original_entities[entity_type][-1]
475
- if token not in self.mapping_table:
476
- self.mapping_table[token] = original_text
477
- self.reverse_mapping[original_text] = token
478
-
479
- def analyze_with_model(self, anonymized_text: str, analysis_prompt: str, model_name: str) -> str:
480
- """
481
- اجرای پرامپت‌های درون متن ناشناس‌سازی شده با مدل انتخابی
482
- """
483
- logger.info(f"🤖 {model_name} اجرای پرامپت...")
484
-
485
- if not analysis_prompt or not analysis_prompt.strip():
486
- logger.info("⚠️ پرامپتی وارد نشده - متن ناشناس‌سازی شده برگردانده می‌شود")
487
- return anonymized_text
488
-
489
- try:
490
- # ساخت system message
491
- system_msg = """شما یک تحلیلگر مالی حرفه‌ای هستید. متن حاوی کدهای ناشناس است (person-XX، company-XX، amount-XX، percent-XX).
492
- به سوالات و درخواست‌ها با دقت پاسخ دهید و این کدها را در پاسخ خود حفظ کنید."""
493
-
494
- # ساخت پیام کامل
495
- full_text = f"""{analysis_prompt}
496
-
497
- متن برای تحلیل:
498
- {anonymized_text}"""
499
-
500
- # ارسال به مدل انتخابی
501
- response = self.model_sender.send_message(full_text, model_name, system_msg)
502
-
503
- logger.info(f"✅ {model_name} پاسخ داد: {len(response)} کاراکتر")
504
- return response
505
-
506
- except Exception as e:
507
- logger.error(f"❌ {model_name} Exception: {e}")
508
- return f"❌ خطا در {model_name}: {str(e)}"
509
-
510
- def restore_text(self, anonymized_text: str) -> str:
511
- """بازگردانی متن ناشناس‌سازی شده به متن اصلی"""
512
- logger.info("🔄 بازگردانی متن...")
513
-
514
- if not self.mapping_table:
515
- logger.warning("⚠️ جدول نگاشت خالی است")
516
- return anonymized_text
517
-
518
- restored = anonymized_text
519
- for placeholder, original in sorted(self.mapping_table.items()):
520
- restored = restored.replace(placeholder, original)
521
-
522
- logger.info("✅ بازگردانی کامل")
523
- return restored
524
-
525
- def get_mapping_table_md(self) -> str:
526
- """تبدیل جدول نگاشت به Markdown"""
527
- if not self.mapping_table:
528
- return "### 📋 جدول نگاشت\n\nهیچ موجودیتی شناسایی نشد"
529
-
530
- table = "### 📋 جدول نگاشت\n\n"
531
- table += "| شناسه | متن اصلی |\n"
532
- table += "|-------|----------|\n"
533
-
534
- for token, original in sorted(self.mapping_table.items()):
535
- table += f"| **{token}** | {original} |\n"
536
-
537
- return table
538
-
539
- # متغیر سراسری
540
- anonymizer = None
541
-
542
- def process(input_text: str, analysis_prompt: str, model_choice: str):
543
- """پردازش متن - 4 مرحله"""
544
- global anonymizer
545
-
546
- if not input_text.strip():
547
- return "", "", "", ""
548
-
549
- cerebras_key = os.getenv("CEREBRAS_API_KEY")
550
-
551
- if not anonymizer:
552
- anonymizer = AnonymizerAdvanced(cerebras_key)
553
- else:
554
- anonymizer.mapping_table = {}
555
- anonymizer.reverse_mapping = {}
556
-
557
- try:
558
- logger.info("=" * 70)
559
- logger.info(f"🚀 شروع پردازش - مدل تحلیل: {model_choice}")
560
- logger.info("=" * 70)
561
-
562
- # مرحله 1: ناشناس‌سازی
563
- logger.info("📝 مرحله 1: ناشناس‌سازی...")
564
- anonymized_text, _ = anonymizer.anonymize_with_cerebras(input_text)
565
- logger.info(f"✅ ناشناس‌سازی: {len(anonymized_text)} کاراکتر")
566
-
567
- # مرحله 2: مدل انتخابی
568
- logger.info(f"🤖 مرحله 2: {model_choice}...")
569
- model_response = anonymizer.analyze_with_model(anonymized_text, analysis_prompt, model_choice)
570
- logger.info(f"✅ {model_choice}: {len(model_response)} کاراکتر")
571
-
572
- # مرحله 3: بازگردانی
573
- logger.info("🔄 مرحله 3: بازگردانی...")
574
- restored_text = anonymizer.restore_text(model_response)
575
- logger.info("✅ بازگردانی کامل")
576
-
577
- # مرحله 4: جدول نگاشت
578
- logger.info("📋 مرحله 4: جدول نگاشت...")
579
- mapping_str = anonymizer.get_mapping_table_md()
580
- logger.info(f"✅ {len(anonymizer.mapping_table)} موجودیت")
581
-
582
- logger.info("=" * 70)
583
- logger.info("✅ تمام مراحل کامل!")
584
- logger.info("=" * 70)
585
-
586
- return restored_text, model_response, anonymized_text, mapping_str
587
-
588
- except Exception as e:
589
- logger.error(f"❌ خطا: {str(e)}", exc_info=True)
590
- return "", f"❌ خطا: {str(e)}", "", ""
591
-
592
- def clear_all():
593
- """پاک کردن همه"""
594
- return "", "", "", "", "", ""
595
-
596
- # Gradio Interface
597
- css_rtl = """
598
- .input-box { direction: rtl; text-align: right; }
599
- .textbox textarea { direction: rtl; text-align: right; font-family: 'Tahoma', serif; }
600
- """
601
-
602
- with gr.Blocks(title="سیستم ناشناس‌سازی متون", theme=gr.themes.Soft(), css=css_rtl) as app:
603
-
604
- gr.Markdown("# 🔐 سیستم ناشناس‌سازی متون مالی فارسی (چند مدل)", elem_classes="input-box")
605
- gr.Markdown("### با قابلیت Retry و مدیریت خطای پیشرفته", elem_classes="input-box")
606
-
607
- with gr.Row():
608
- with gr.Column(scale=1):
609
- # منوی انتخاب مدل
610
- model_dropdown = gr.Dropdown(
611
- choices=["ChatGPT-4o-mini", "Grok", "Gemini", "DeepSeek"],
612
- value="ChatGPT-4o-mini",
613
- label="🤖 انتخاب مدل تحلیل",
614
- info="هر مدل دارای Retry و Error Handling است",
615
- interactive=True
616
- )
617
-
618
- analysis_prompt = gr.Textbox(
619
- lines=8,
620
- placeholder="مثال: این متن را خلاصه کن\nمثال: نقاط قوت و ضعف را استخراج کن",
621
- label="📋 دستورات تحلیل (اختیاری)",
622
- elem_classes="textbox"
623
- )
624
-
625
- gr.Markdown("---")
626
-
627
- with gr.Column():
628
- process_btn = gr.Button(
629
- "▶️ پردازش",
630
- variant="primary",
631
- size="lg"
632
- )
633
-
634
- clear_btn = gr.Button(
635
- "🗑️ پاک کردن",
636
- variant="stop",
637
- size="lg"
638
- )
639
-
640
- with gr.Column(scale=3):
641
- input_text = gr.Textbox(
642
- lines=14,
643
- placeholder="متن مالی/خبری فارسی را وارد کنید...",
644
- label="📝 متن ورودی",
645
- elem_classes="textbox"
646
- )
647
-
648
- gr.Markdown("---")
649
- gr.Markdown("## 📊 نتایج پردازش", elem_classes="input-box")
650
-
651
- with gr.Row():
652
- with gr.Column(scale=1):
653
- restored_text = gr.Textbox(
654
- lines=12,
655
- label="✅ متن بازگردانی شده",
656
- interactive=False,
657
- elem_classes="textbox"
658
- )
659
-
660
- with gr.Column(scale=1):
661
- model_analysis = gr.Textbox(
662
- lines=12,
663
- label="🤖 تحلیل مدل (ناشناس)",
664
- interactive=False,
665
- elem_classes="textbox"
666
- )
667
-
668
- with gr.Column(scale=1):
669
- anonymized_text = gr.Textbox(
670
- lines=12,
671
- label="🔒 متن ناشناس‌شده",
672
- interactive=False,
673
- elem_classes="textbox"
674
- )
675
-
676
- gr.Markdown("---")
677
-
678
- mapping_table = gr.Markdown(
679
- value="### 📋 جدول نگاشت\n\nهنوز پردازشی انجام نشده",
680
- label="📋 جدول نگاشت",
681
- elem_classes="input-box"
682
- )
683
-
684
- # Event Handlers
685
- process_btn.click(
686
- fn=process,
687
- inputs=[input_text, analysis_prompt, model_dropdown],
688
- outputs=[restored_text, model_analysis, anonymized_text, mapping_table]
689
- )
690
-
691
- clear_btn.click(
692
- fn=clear_all,
693
- outputs=[input_text, analysis_prompt, restored_text, model_analysis, anonymized_text, mapping_table]
694
- )
695
-
696
- if __name__ == "__main__":
697
- print("=" * 70)
698
- print("🚀 سیستم ناشناس‌سازی متون در حال راه‌اندازی...")
699
- print("=" * 70)
700
- print("\n📋 API Keys مورد نیاز:\n")
701
- print(" ✅ CEREBRAS_API_KEY (برای ناشناس‌سازی)")
702
- print(" ✅ OPENAI_API_KEY (برای ChatGPT)")
703
- print(" ✅ XAI_API_KEY (برای Grok)")
704
- print(" ✅ GEMINI_API_KEY (برای Gemini)")
705
- print(" ✅ DEEPSEEK_API_KEY (برای DeepSeek)")
706
- print("\n⚡ ویژگی‌های جدید:\n")
707
- print(" 🔄 Retry mechanism برای همه مدل‌ها")
708
- print(" ⚠️ مدیریت خطاهای Rate limiting")
709
- print(" 🛡️ Error handling پیشرفته")
710
- print(" ⏱️ Timeout handling با تلاش مجدد")
711
- print("\n🎯 روش ناشناس‌سازی: Cerebras (Llama 3.3-70B)")
712
- print("🤖 مدل‌های تحلیل: ChatGPT, Grok, Gemini, DeepSeek")
713
- print("=" * 70 + "\n")
714
-
715
- app.launch(
716
- server_name="0.0.0.0",
717
- server_port=7860,
718
- share=False,
719
- show_error=True
720
- )