KashefTech commited on
Commit
90436dd
·
verified ·
1 Parent(s): a56c42a

Delete app.py

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