KashefTech commited on
Commit
e949abd
·
verified ·
1 Parent(s): 376fab5

Delete app.py

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