KashefTech commited on
Commit
2b630cb
·
verified ·
1 Parent(s): a0000b3

Delete app3.py

Browse files
Files changed (1) hide show
  1. app3.py +0 -711
app3.py DELETED
@@ -1,711 +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
- def _extract_mapping_from_text(self, original: str, anonymized: str):
235
- """استخراج mapping از متن‌های اصلی و ناشناس شده - فقط برای موجودیت‌های انتخابی"""
236
-
237
- # ✅ استخراج فقط توکن‌های انتخابی
238
- all_tokens = []
239
- for entity_type in self.entities_to_anonymize:
240
- tokens = re.findall(f'{entity_type}-\\d+', anonymized)
241
- all_tokens.extend([(t, entity_type) for t in tokens])
242
-
243
- all_tokens = sorted(set(all_tokens), key=lambda x: (x[1], int(x[0].split('-')[1])))
244
-
245
- # ✅ الگوهای موجودیت - فقط برای انتخابی‌ها
246
- patterns = {}
247
- if "person" in self.entities_to_anonymize:
248
- patterns['person'] = r'\b[ء-ي]+\s+[ء-ي]+(?:\s+[ء-ي]+)*\b'
249
- if "company" in self.entities_to_anonymize:
250
- patterns['company'] = r'(?:شرکت|بانک|سازمان|گروه|هلدینگ)\s+[ء-ي]+(?:\s+[ء-ي]+)*'
251
- if "amount" in self.entities_to_anonymize:
252
- patterns['amount'] = r'\d+(?:\.\d+)?\s*(?:میلیارد|میلیون|هزار|تومان|ریال|دلار|یورو|تن)'
253
- if "percent" in self.entities_to_anonymize:
254
- patterns['percent'] = r'\d+(?:\.\d+)?\s*(?:درصد|%|درصدی)'
255
-
256
- original_entities = {}
257
- for entity_type, pattern in patterns.items():
258
- matches = list(re.finditer(pattern, original))
259
- original_entities[entity_type] = [m.group().strip() for m in matches]
260
-
261
- for token, entity_type in all_tokens:
262
- if entity_type in original_entities and original_entities[entity_type]:
263
- token_num = int(token.split('-')[1]) - 1
264
-
265
- if token_num < len(original_entities[entity_type]):
266
- original_text = original_entities[entity_type][token_num]
267
- self.mapping_table[token] = original_text
268
- self.reverse_mapping[original_text] = token
269
- else:
270
- original_text = original_entities[entity_type][-1]
271
- if token not in self.mapping_table:
272
- self.mapping_table[token] = original_text
273
- self.reverse_mapping[original_text] = token
274
-
275
- def analyze_with_llm(self, anonymized_text: str, analysis_prompt: str = None) -> str:
276
- """استفاده از LLM یکپارچه"""
277
- logger.info(f"🤖 {self.llm_provider.upper()} اجرای پرامپت...")
278
-
279
- if not analysis_prompt or not analysis_prompt.strip():
280
- logger.info("⚠️ پرامپت خالی - بدون تحلیل")
281
- return "⚠️ هیچ دستور تحلیل داده نشده است"
282
-
283
- combined_text = f"""متن ناشناس‌سازی شده:
284
- {anonymized_text}
285
-
286
- دستورات:
287
- {analysis_prompt}
288
-
289
- توجه: در پاسخ از همان کدهای ناشناس (person-XX, company-XX, amount-XX, percent-XX) استفاده کن."""
290
-
291
- try:
292
- response = self.llm_sender.send_simple(combined_text, lang='fa')
293
- logger.info(f"✅ {self.llm_provider.upper()}: {len(response)} کاراکتر")
294
- return response
295
- except Exception as e:
296
- logger.error(f"❌ {self.llm_provider.upper()} Exception: {e}")
297
- return f"❌ خطا در ارتباط با {self.llm_provider.upper()}: {str(e)}"
298
-
299
- def restore_text(self, anonymized_text: str) -> str:
300
- """بازگردانی متن"""
301
- logger.info("🔄 بازگردانی متن...")
302
-
303
- if not self.mapping_table:
304
- logger.warning("⚠️ جدول نگاشت خالی است")
305
- return anonymized_text
306
-
307
- restored = anonymized_text
308
- for placeholder, original in sorted(self.mapping_table.items()):
309
- restored = restored.replace(placeholder, original)
310
-
311
- logger.info("✅ بازگردانی کامل")
312
- return restored
313
-
314
- def get_mapping_table_md(self) -> str:
315
- """تبدیل جدول نگاشت به Markdown"""
316
- if not self.mapping_table:
317
- return "### 📋 جدول نگاشت\n\nهیچ موجودیتی شناسایی نشد"
318
-
319
- table = "### 📋 جدول نگاشت\n\n"
320
- table += "| شناسه | متن اصلی |\n"
321
- table += "|-------|----------|\n"
322
-
323
- for token, original in sorted(self.mapping_table.items()):
324
- table += f"| **{token}** | {original} |\n"
325
-
326
- return table
327
-
328
- # متغیر سراسری
329
- anonymizer = None
330
-
331
- def process(
332
- input_text: str,
333
- analysis_prompt: str,
334
- llm_provider: str,
335
- llm_model: str,
336
- api_key_input: str,
337
- # ✅ checkboxها
338
- anonymize_all: bool,
339
- anonymize_person: bool,
340
- anonymize_company: bool,
341
- anonymize_amount: bool,
342
- anonymize_percent: bool
343
- ):
344
- """پردازش متن - 4 مرحله"""
345
- global anonymizer
346
-
347
- if not input_text.strip():
348
- return "", "", "", ""
349
-
350
- # ✅ ساخت لیست موجودیت‌های انتخابی
351
- if anonymize_all:
352
- entities = ["person", "company", "amount", "percent"]
353
- else:
354
- entities = []
355
- if anonymize_person:
356
- entities.append("person")
357
- if anonymize_company:
358
- entities.append("company")
359
- if anonymize_amount:
360
- entities.append("amount")
361
- if anonymize_percent:
362
- entities.append("percent")
363
-
364
- # اگه هیچی انتخاب نشده
365
- if not entities:
366
- return "", "❌ لطفاً حداقل یک موجودیت برای ناشناس‌سازی انتخاب کنید", "", ""
367
-
368
- cerebras_key = os.getenv("CEREBRAS_API_KEY")
369
-
370
- # ایجاد یا آپدیت anonymizer
371
- if not anonymizer:
372
- anonymizer = AnonymizerAdvanced(
373
- cerebras_key,
374
- llm_provider=llm_provider,
375
- llm_model=llm_model,
376
- llm_api_key=api_key_input,
377
- entities_to_anonymize=entities # ✅ ارسال لیست موجودیت‌ها
378
- )
379
- else:
380
- anonymizer.set_llm_provider(llm_provider, llm_model, api_key_input, entities)
381
- anonymizer.mapping_table = {}
382
- anonymizer.reverse_mapping = {}
383
-
384
- try:
385
- logger.info("=" * 70)
386
- logger.info(f"🚀 شروع پردازش - LLM: {llm_provider} ({llm_model})")
387
- logger.info(f"🎯 موجودیت‌های انتخابی: {', '.join(entities)}")
388
- logger.info("=" * 70)
389
-
390
- # مرحله 1: ناشناس‌سازی
391
- logger.info("📝 مرحله 1: ناشناس‌سازی...")
392
- anonymized_text, _ = anonymizer.anonymize_with_cerebras(input_text)
393
- logger.info(f"✅ ناشناس‌سازی: {len(anonymized_text)} کاراکتر")
394
-
395
- # مرحله 2: LLM
396
- logger.info(f"🤖 مرحله 2: {llm_provider.upper()}...")
397
- llm_response = anonymizer.analyze_with_llm(anonymized_text, analysis_prompt)
398
- logger.info(f"✅ {llm_provider.upper()}: {len(llm_response)} کاراکتر")
399
-
400
- # مرحله 3: بازگردانی
401
- logger.info("🔄 مرحله 3: بازگردانی...")
402
- restored_text = anonymizer.restore_text(llm_response)
403
- logger.info("✅ بازگردانی کامل")
404
-
405
- # مرحله 4: جدول نگاشت
406
- logger.info("📋 مرحله 4: جدول نگاشت...")
407
- mapping_str = anonymizer.get_mapping_table_md()
408
- logger.info(f"✅ {len(anonymizer.mapping_table)} موجودیت")
409
-
410
- logger.info("=" * 70)
411
- logger.info("✅ تمام مراحل کامل!")
412
- logger.info("=" * 70)
413
-
414
- return restored_text, llm_response, anonymized_text, mapping_str
415
-
416
- except Exception as e:
417
- logger.error(f"❌ خطا: {str(e)}", exc_info=True)
418
- return "", f"❌ خطا: {str(e)}", "", ""
419
-
420
- def clear_all():
421
- """پاک کردن همه"""
422
- return "", "", "", "", "", "", "", True, False, False, False, False # ✅ اضافه شد: checkboxها
423
-
424
- def update_model_choices(provider: str):
425
- """آپدیت لیست مدل‌ها بر اساس provider"""
426
- models = AVAILABLE_MODELS.get(provider, [])
427
- return gr.Dropdown(choices=models, value=models[0] if models else None)
428
-
429
- def update_api_key_visibility(provider: str, model: str):
430
- """نمایش/مخفی کردن textbox API key"""
431
- # ✅ فقط برای gpt-4o-mini مخفی کن
432
- if provider == "chatgpt" and model == "gpt-4o-mini":
433
- return gr.Textbox(visible=False, value="")
434
- else:
435
- return gr.Textbox(visible=True, value="")
436
-
437
- # Gradio Interface
438
- css_rtl = """
439
- .input-box { direction: rtl; text-align: right; }
440
- .textbox textarea { direction: rtl; text-align: right; font-family: 'Tahoma', serif; }
441
- """
442
-
443
- with gr.Blocks(title="سیستم ناشناس‌سازی متون", theme=gr.themes.Soft(), css=css_rtl) as app:
444
-
445
- gr.Markdown("# 🔐 سیستم ناشناس‌سازی متون ��الی فارسی", elem_classes="input-box")
446
-
447
- with gr.Row():
448
- # سمت راست: تنظیمات و دکمه‌ها
449
- with gr.Column(scale=1):
450
- # ✅ تنظیمات مدل
451
- with gr.Group():
452
- gr.Markdown("### ⚙️ تنظیمات مدل", elem_classes="input-box")
453
-
454
- llm_provider = gr.Dropdown(
455
- choices=["chatgpt", "grok"],
456
- value="chatgpt",
457
- label="🤖 انتخاب LLM",
458
- interactive=True
459
- )
460
-
461
- llm_model = gr.Dropdown(
462
- choices=AVAILABLE_MODELS["chatgpt"],
463
- value="gpt-4o-mini",
464
- label="📦 انتخاب مدل",
465
- interactive=True
466
- )
467
-
468
- # ✅ textbox برای API key (مخفی برای gpt-4o-mini)
469
- api_key_input = gr.Textbox(
470
- label="🔑 API Key",
471
- placeholder="فقط برای مدل‌های غیر از gpt-4o-mini",
472
- type="password",
473
- visible=False, # پیش‌فرض مخفی (چون gpt-4o-mini انتخاب شده)
474
- elem_classes="textbox"
475
- )
476
-
477
- gr.Markdown(
478
- "💡 **نکته:** gpt-4o-mini از Secret خوانده می‌شود. برای بقیه مدل‌ها API key وارد کنید.",
479
- elem_classes="input-box"
480
- )
481
-
482
- gr.Markdown("---")
483
-
484
- # ✅ انتخاب موجودیت‌ها برای ناشناس‌سازی
485
- with gr.Group():
486
- gr.Markdown("### 🎯 انتخاب موجودیت‌ها", elem_classes="input-box")
487
-
488
- anonymize_all = gr.Checkbox(
489
- label="✅ همه موجودیت‌ها",
490
- value=True,
491
- elem_classes="input-box"
492
- )
493
-
494
- anonymize_person = gr.Checkbox(
495
- label="👤 اسامی اشخاص",
496
- value=False,
497
- elem_classes="input-box"
498
- )
499
-
500
- anonymize_company = gr.Checkbox(
501
- label="🏢 نام شرکت‌ها",
502
- value=False,
503
- elem_classes="input-box"
504
- )
505
-
506
- anonymize_amount = gr.Checkbox(
507
- label="💰 ارقام مالی",
508
- value=False,
509
- elem_classes="input-box"
510
- )
511
-
512
- anonymize_percent = gr.Checkbox(
513
- label="📊 درصدها",
514
- value=False,
515
- elem_classes="input-box"
516
- )
517
-
518
- gr.Markdown(
519
- "💡 اگر 'همه' را انتخاب کنید، بقیه نادیده گرفته می‌شوند",
520
- elem_classes="input-box"
521
- )
522
-
523
- gr.Markdown("---")
524
-
525
- analysis_prompt = gr.Textbox(
526
- lines=6,
527
- placeholder="مثال: این متن را خلاصه کن\nیا: نکات کلیدی را استخراج کن",
528
- label="📋 دستورات LLM (اختیاری)",
529
- elem_classes="textbox"
530
- )
531
-
532
- gr.Markdown("---")
533
-
534
- with gr.Column():
535
- process_btn = gr.Button(
536
- "▶️ پردازش",
537
- variant="primary",
538
- size="lg"
539
- )
540
-
541
- clear_btn = gr.Button(
542
- "🗑️ پاک کردن",
543
- variant="stop",
544
- size="lg"
545
- )
546
-
547
- # سمت چپ: متن ورودی
548
- with gr.Column(scale=3):
549
- input_text = gr.Textbox(
550
- lines=22,
551
- placeholder="متن مالی/خبری را وارد کنید...",
552
- label="📝 متن ورودی",
553
- elem_classes="textbox"
554
- )
555
-
556
- # نتایج
557
- gr.Markdown("---")
558
- gr.Markdown("## 📊 نتایج پردازش", elem_classes="input-box")
559
-
560
- with gr.Row():
561
- with gr.Column(scale=1):
562
- restored_text = gr.Textbox(
563
- lines=12,
564
- label="✅ متن بازگردانی شده",
565
- interactive=False,
566
- elem_classes="textbox"
567
- )
568
-
569
- with gr.Column(scale=1):
570
- llm_analysis = gr.Textbox(
571
- lines=12,
572
- label="🤖 تحلیل LLM",
573
- interactive=False,
574
- elem_classes="textbox"
575
- )
576
-
577
- with gr.Column(scale=1):
578
- anonymized_text = gr.Textbox(
579
- lines=12,
580
- label="🔒 متن ناشناس‌شده",
581
- interactive=False,
582
- elem_classes="textbox"
583
- )
584
-
585
- gr.Markdown("---")
586
-
587
- mapping_table = gr.Markdown(
588
- value="### 📋 جدول نگاشت\n\nهنوز پردازشی انجام نشده",
589
- label="📋 جدول نگاشت",
590
- elem_classes="input-box"
591
- )
592
-
593
- # Event Handlers
594
-
595
- # ✅ آپدیت مدل‌ها و نمایش API key
596
- def handle_provider_change(provider):
597
- models = AVAILABLE_MODELS.get(provider, [])
598
- default_model = models[0] if models else None
599
-
600
- # چک کن آیا باید API key نمایش داده بشه
601
- show_api = not (provider == "chatgpt" and default_model == "gpt-4o-mini")
602
-
603
- return (
604
- gr.Dropdown(choices=models, value=default_model),
605
- gr.Textbox(visible=show_api, value="")
606
- )
607
-
608
- llm_provider.change(
609
- fn=handle_provider_change,
610
- inputs=[llm_provider],
611
- outputs=[llm_model, api_key_input]
612
- )
613
-
614
- # ✅ آپدیت نمایش API key وقتی مدل عوض میشه
615
- def handle_model_change(provider, model):
616
- show_api = not (provider == "chatgpt" and model == "gpt-4o-mini")
617
- return gr.Textbox(visible=show_api, value="")
618
-
619
- llm_model.change(
620
- fn=handle_model_change,
621
- inputs=[llm_provider, llm_model],
622
- outputs=[api_key_input]
623
- )
624
-
625
- # ✅ وقتی "همه" انتخاب میشه، بقیه رو غیرفعال کن
626
- def handle_select_all(select_all):
627
- if select_all:
628
- # همه انتخاب شده، بقیه رو غیرفعال کن
629
- return (
630
- gr.Checkbox(value=False, interactive=False), # person
631
- gr.Checkbox(value=False, interactive=False), # company
632
- gr.Checkbox(value=False, interactive=False), # amount
633
- gr.Checkbox(value=False, interactive=False) # percent
634
- )
635
- else:
636
- # همه غیرفعال، بقیه رو فعال کن
637
- return (
638
- gr.Checkbox(value=False, interactive=True),
639
- gr.Checkbox(value=False, interactive=True),
640
- gr.Checkbox(value=False, interactive=True),
641
- gr.Checkbox(value=False, interactive=True)
642
- )
643
-
644
- anonymize_all.change(
645
- fn=handle_select_all,
646
- inputs=[anonymize_all],
647
- outputs=[anonymize_person, anonymize_company, anonymize_amount, anonymize_percent]
648
- )
649
-
650
- # پردازش
651
- process_btn.click(
652
- fn=process,
653
- inputs=[
654
- input_text,
655
- analysis_prompt,
656
- llm_provider,
657
- llm_model,
658
- api_key_input,
659
- # ✅ checkboxها
660
- anonymize_all,
661
- anonymize_person,
662
- anonymize_company,
663
- anonymize_amount,
664
- anonymize_percent
665
- ],
666
- outputs=[restored_text, llm_analysis, anonymized_text, mapping_table]
667
- )
668
-
669
- # پاک کردن
670
- clear_btn.click(
671
- fn=clear_all,
672
- outputs=[
673
- input_text,
674
- analysis_prompt,
675
- api_key_input,
676
- restored_text,
677
- llm_analysis,
678
- anonymized_text,
679
- mapping_table,
680
- # ✅ checkboxها
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. برای مدل‌های غیر از gpt-4o-mini، API key وارد کنید")
700
- print("5. متن را وارد کنید")
701
- print("6. 'پردازش' را کلیک کنید\n")
702
- print("💡 فقط gpt-4o-mini از Secret می‌خواند")
703
- print(" بقیه مدل‌ها نیاز به API key دارند")
704
- print("=" * 70 + "\n")
705
-
706
- app.launch(
707
- server_name="0.0.0.0",
708
- server_port=7860,
709
- share=False,
710
- show_error=True
711
- )