leilaghomashchi commited on
Commit
f058f91
·
verified ·
1 Parent(s): 27a2a97

Delete app.py

Browse files
Files changed (1) hide show
  1. app.py +0 -408
app.py DELETED
@@ -1,408 +0,0 @@
1
- import gradio as gr
2
- import re
3
- import os
4
- import requests
5
- import logging
6
- from typing import Dict, List, Tuple
7
- from chatgpt_sender import ChatGPTSender # ✅ import ماژول جدید
8
-
9
- logging.basicConfig(level=logging.INFO)
10
- logger = logging.getLogger(__name__)
11
-
12
- class AnonymizerAdvanced:
13
- """ناشناس‌ساز پیشرفته با روش‌های متعدد"""
14
-
15
- def __init__(self, cerebras_key: str = None, gpt_key: str = None):
16
- self.cerebras_key = cerebras_key or os.getenv("CEREBRAS_API_KEY")
17
- self.gpt_key = gpt_key or os.getenv("OPENAI_API_KEY")
18
- self.mapping_table = {} # {placeholder: original_text}
19
- self.reverse_mapping = {} # {original_text: placeholder}
20
-
21
- # ✅ ایجاد instance از ChatGPTSender
22
- self.gpt_sender = ChatGPTSender(api_key=self.gpt_key, model="gpt-4o-mini")
23
-
24
- logger.info("✅ Anonymizer Advanced مقداردهی شد")
25
-
26
-
27
- def anonymize_with_cerebras(self, text: str) -> Tuple[str, Dict]:
28
- """ناشناس‌سازی با Cerebras"""
29
- logger.info("🧠 روش Cerebras...")
30
-
31
- if not self.cerebras_key:
32
- logger.error("❌ Cerebras API Key موجود نیست")
33
- raise ValueError("Cerebras API Key مورد نیاز است")
34
-
35
- try:
36
- prompt = f"""متن زیر را ناشناس کنید. قوانین:
37
- 1. اسامی اشخاص → person-01, person-02, ...
38
- 2. نام شرکت‌ها/سازمان‌ها → company-01, company-02, ...
39
- 3. مقادیر پولی → amount-01, amount-02, ...
40
- 4. درصدها → percent-01, percent-02, ...
41
- 5. فقط این توکن‌ها استفاده کنید
42
- 6. شماره‌های نسخه را درست حفظ کنید
43
- 7. اگر موجودیت تکرار شود از شماره قدیمی استفاده کنید
44
-
45
- متن:
46
- {text}
47
-
48
- خروجی: فقط متن ناشناس شده"""
49
-
50
- response = requests.post(
51
- "https://api.cerebras.ai/v1/chat/completions",
52
- headers={
53
- "Authorization": f"Bearer {self.cerebras_key}",
54
- "Content-Type": "application/json"
55
- },
56
- json={
57
- "model": "llama-3.3-70b",
58
- "messages": [{"role": "user", "content": prompt}],
59
- "max_tokens": 4096,
60
- "temperature": 0.1
61
- },
62
- timeout=60
63
- )
64
-
65
- if response.status_code == 200:
66
- anonymized_text = response.json()['choices'][0]['message']['content'].strip()
67
- logger.info("✅ Cerebras: موفق")
68
-
69
- # استخراج mapping از متن
70
- self._extract_mapping_from_text(text, anonymized_text)
71
- return anonymized_text, self.mapping_table
72
- else:
73
- logger.error(f"❌ Cerebras Error: {response.status_code}")
74
- raise Exception(f"Cerebras API Error: {response.status_code}")
75
-
76
- except Exception as e:
77
- logger.error(f"❌ Cerebras Exception: {e}")
78
- raise
79
-
80
-
81
- def _extract_mapping_from_text(self, original: str, anonymized: str):
82
- """استخراج mapping از متن‌های اصلی و ناشناس شده - نسخه بهبود یافته"""
83
-
84
- # استخراج همه توکن‌های ناشناس از متن ناشناس‌سازی شده
85
- all_tokens = []
86
- for entity_type in ['person', 'company', 'amount', 'percent']:
87
- tokens = re.findall(f'{entity_type}-\\d+', anonymized)
88
- all_tokens.extend([(t, entity_type) for t in tokens])
89
-
90
- # حذف تکراری‌ها و مرتب‌سازی
91
- all_tokens = sorted(set(all_tokens), key=lambda x: (x[1], int(x[0].split('-')[1])))
92
-
93
- # الگوهای موجودیت در متن اصلی
94
- patterns = {
95
- 'person': r'\b[ء-ي]+\s+[ء-ي]+(?:\s+[ء-ي]+)*\b',
96
- 'company': r'(?:شرکت|بانک|سازمان|گروه|هلدینگ)\s+[ء-ي]+(?:\s+[ء-ي]+)*',
97
- 'amount': r'\d+(?:\.\d+)?\s*(?:میلیارد|میلیون|هزار|تومان|ریال|دلار|یورو|تن)',
98
- 'percent': r'\d+(?:\.\d+)?\s*(?:درصد|%|درصدی)',
99
- }
100
-
101
- # استخراج موجودیت‌های اصلی
102
- original_entities = {}
103
- for entity_type, pattern in patterns.items():
104
- matches = list(re.finditer(pattern, original))
105
- original_entities[entity_type] = [m.group().strip() for m in matches]
106
-
107
- # نگاشت توکن‌ها به موجودیت‌های اصلی
108
- for token, entity_type in all_tokens:
109
- if entity_type in original_entities and original_entities[entity_type]:
110
- # گرفتن شماره توکن (مثلاً از person-01 عدد 1 رو میگیریم)
111
- token_num = int(token.split('-')[1]) - 1
112
-
113
- if token_num < len(original_entities[entity_type]):
114
- original_text = original_entities[entity_type][token_num]
115
- self.mapping_table[token] = original_text
116
- self.reverse_mapping[original_text] = token
117
- else:
118
- # اگر شماره توکن بیشتر از تعداد موجودیت‌ها بود
119
- # از آخرین موجودیت استفاده کن
120
- original_text = original_entities[entity_type][-1]
121
- if token not in self.mapping_table:
122
- self.mapping_table[token] = original_text
123
- self.reverse_mapping[original_text] = token
124
-
125
- def analyze_with_gpt(self, anonymized_text: str, analysis_prompt: str = None) -> str:
126
- """
127
- ✅ اصلاح شده - استفاده از ماژول ChatGPTSender
128
- اجرای پرامپت‌های درون متن ناشناس‌سازی شده با ChatGPT
129
- """
130
- logger.info("🤖 ChatGPT اجرای پرامپت...")
131
-
132
- # ✅ اگر پرامپتی نیست، فقط متن ناشناس‌سازی شده برگردان
133
- if not analysis_prompt or analysis_prompt.strip() == "":
134
- logger.info("📝 بدون دستورات - فقط متن ناشناس‌سازی شده برگردانده می‌شود")
135
- return anonymized_text
136
-
137
- if not self.gpt_key:
138
- logger.warning("⚠️ GPT API Key نیست")
139
- return "❌ API Key موجود نیست"
140
-
141
- try:
142
- # متن ارسالی شامل متن ناشناس‌سازی شده + دستورات کاربر
143
- user_message = f"""متن ناشناس‌سازی شده:
144
- ---
145
- {anonymized_text}
146
- ---
147
-
148
- دستورات:
149
- {analysis_prompt}
150
-
151
- توکن‌های ناشناس را حتماً حفظ کن. فقط نتیجه اجرای دستورات را برگردان."""
152
-
153
- logger.info(f"📋 متن ارسالی به ChatGPT:\n{user_message}\n")
154
-
155
- # ✅ استفاده از ChatGPTSender به جای requests.post
156
- system_msg = """شما دستیار اجرای دستورات روی متون ناشناس‌سازی شده‌اید.
157
- توکن‌های ناشناس (person-01, company-01, amount-01, percent-01) را حتماً حفظ کن.
158
- فقط دستورات دادشده را اجرا کن."""
159
-
160
- gpt_response = self.gpt_sender.send(
161
- text=user_message,
162
- system_msg=system_msg,
163
- max_tokens=4096,
164
- temperature=0.3,
165
- lang='fa'
166
- )
167
-
168
- # بررسی برای خطاهای API
169
- if gpt_response.startswith("❌"):
170
- logger.error(f"❌ GPT Error: {gpt_response}")
171
- return gpt_response
172
-
173
- logger.info("✅ ChatGPT: دستورات اجرا شدند")
174
- logger.info(f"📤 پاسخ ChatGPT:\n{gpt_response}\n")
175
- return gpt_response
176
-
177
- except Exception as e:
178
- logger.error(f"❌ GPT Exception: {e}")
179
- return f"❌ خطا: {str(e)}"
180
-
181
- def restore_text(self, anonymized_text: str) -> str:
182
- """بازگردانی متن اصلی"""
183
- logger.info("🔄 بازگردانی...")
184
-
185
- restored = anonymized_text
186
- for placeholder, original in sorted(self.mapping_table.items()):
187
- restored = restored.replace(placeholder, original)
188
-
189
- logger.info("✅ بازگردانی کامل")
190
- return restored
191
-
192
- def get_mapping_table_md(self) -> str:
193
- """تبدیل جدول نگاشت به Markdown"""
194
- if not self.mapping_table:
195
- return "### 📋 جدول نگاشت\n\nهیچ موجودیتی شناسایی نشد"
196
-
197
- table = "### 📋 جدول نگاشت\n\n"
198
- table += "| شناسه | متن اصلی |\n"
199
- table += "|-------|----------|\n"
200
-
201
- for token, original in sorted(self.mapping_table.items()):
202
- table += f"| **{token}** | {original} |\n"
203
-
204
- return table
205
-
206
- # متغیر سراسری
207
- anonymizer = None
208
-
209
- def process(input_text: str, analysis_prompt: str = None):
210
- """پردازش متن - 4 مرحله"""
211
- global anonymizer
212
-
213
- if not input_text.strip():
214
- return "", "", "", ""
215
-
216
- cerebras_key = os.getenv("CEREBRAS_API_KEY")
217
- gpt_key = os.getenv("OPENAI_API_KEY")
218
-
219
- if not anonymizer:
220
- anonymizer = AnonymizerAdvanced(cerebras_key, gpt_key)
221
- else:
222
- anonymizer.mapping_table = {}
223
- anonymizer.reverse_mapping = {}
224
-
225
- try:
226
- logger.info("=" * 70)
227
- logger.info(f"🚀 شروع پردازش - روش: Cerebras")
228
- logger.info("=" * 70)
229
-
230
- # ============================================
231
- # مرحله 1: ناشناس‌سازی
232
- # ============================================
233
- logger.info("📝 مرحله 1: ناشناس‌سازی...")
234
-
235
- anonymized_text, _ = anonymizer.anonymize_with_cerebras(input_text)
236
-
237
- logger.info(f"✅ ناشناس‌سازی: {len(anonymized_text)} کاراکتر")
238
-
239
- # ============================================
240
- # مرحله 2: ChatGPT با متن ناشناس‌سازی شده + دستورات
241
- # ============================================
242
- logger.info("🤖 مرحله 2: ChatGPT...")
243
- gpt_response = anonymizer.analyze_with_gpt(anonymized_text, analysis_prompt)
244
- logger.info(f"✅ ChatGPT: {len(gpt_response)} کاراکتر")
245
-
246
- # ============================================
247
- # مرحله 3: بازگردانی پاسخ ChatGPT
248
- # ============================================
249
- logger.info("🔄 مرحله 3: بازگردانی...")
250
- restored_text = anonymizer.restore_text(gpt_response)
251
- logger.info("✅ بازگردانی کامل")
252
-
253
- # ============================================
254
- # مرحله 4: جدول نگاشت
255
- # ============================================
256
- logger.info("📋 مرحله 4: جدول نگاشت...")
257
- mapping_str = anonymizer.get_mapping_table_md()
258
- logger.info(f"✅ {len(anonymizer.mapping_table)} موجودیت")
259
-
260
- logger.info("=" * 70)
261
- logger.info("✅ تمام مراحل کامل!")
262
- logger.info("=" * 70)
263
-
264
- return restored_text, gpt_response, anonymized_text, mapping_str
265
-
266
- except Exception as e:
267
- logger.error(f"❌ خطا: {str(e)}", exc_info=True)
268
- return "", f"❌ خطا: {str(e)}", "", ""
269
-
270
- def clear_all():
271
- """پاک کردن همه"""
272
- return "", "", "", "", "", ""
273
-
274
- # Gradio Interface
275
- css_rtl = """
276
- .input-box { direction: rtl; text-align: right; }
277
- .textbox textarea { direction: rtl; text-align: right; font-family: 'Tahoma', serif; }
278
- """
279
-
280
- with gr.Blocks(title="سیستم ناشناس‌سازی متون", theme=gr.themes.Soft(), css=css_rtl) as app:
281
-
282
- gr.Markdown("# 🔐 سیستم ناشناس‌سازی متون مالی فارسی", elem_classes="input-box")
283
- gr.Markdown("#### استخراج و ناشناس‌سازی موجودیت‌های حساس", elem_classes="input-box")
284
- gr.Markdown("""
285
- **نحوه استفاده:**
286
- 1. متن مالی را در باکس ورودی وارد کنید
287
- 2. (اختیاری) دستورات تحلیلی برای ChatGPT بنویسید
288
- 3. دکمه "پردازش" را کلیک کنید
289
-
290
- **نکته:** اگر دستوری وارد نکنید، فقط متن ناشناس‌سازی شده نمایش داده می‌شود
291
- """, elem_classes="input-box")
292
-
293
- # ============================================
294
- # صفحه اول: دکمه‌ها (راست) + ورودی (چپ)
295
- # ============================================
296
- with gr.Row():
297
- # سمت راست: دکمه‌ها و دستورات
298
- with gr.Column(scale=1):
299
- gr.Markdown("### ⚙️ تنظیمات", elem_classes="input-box")
300
-
301
- analysis_prompt = gr.Textbox(
302
- lines=8,
303
- placeholder="دستورات را وارد کنید (مثال: خلاصه سازی\nشناسایی شرکت‌ها\nلیست افراد)\n\nاگر خالی بگذارید فقط متن ناشناس برگردانده می‌شود.",
304
- label="📋 دستورات ChatGPT (اختیاری)",
305
- elem_classes="textbox"
306
- )
307
-
308
- gr.Markdown("---")
309
-
310
- with gr.Column():
311
- process_btn = gr.Button(
312
- "▶️ پردازش",
313
- variant="primary",
314
- size="lg"
315
- )
316
-
317
- clear_btn = gr.Button(
318
- "🗑️ پاک کردن",
319
- variant="stop",
320
- size="lg"
321
- )
322
-
323
- # سمت چپ: متن ورودی (بزرگ‌تر)
324
- with gr.Column(scale=3):
325
- input_text = gr.Textbox(
326
- lines=14,
327
- placeholder="متن مالی/خبری را وارد کنید...",
328
- label="📝 متن ورودی",
329
- elem_classes="textbox"
330
- )
331
-
332
- # ============================================
333
- # صفحه دوم: 3 باکس نتایج (وسط)
334
- # ============================================
335
- gr.Markdown("---")
336
- gr.Markdown("## 📊 نتایج پردازش", elem_classes="input-box")
337
-
338
- with gr.Row():
339
- # باکس 1: متن بازگردانی شده (راست)
340
- with gr.Column(scale=1):
341
- restored_text = gr.Textbox(
342
- lines=12,
343
- label="✅ متن بازگردانی شده",
344
- interactive=False,
345
- elem_classes="textbox"
346
- )
347
-
348
- # باکس 2: تحلیل ChatGPT (وسط)
349
- with gr.Column(scale=1):
350
- gpt_analysis = gr.Textbox(
351
- lines=12,
352
- label="🤖 تحلیل ChatGPT",
353
- interactive=False,
354
- elem_classes="textbox"
355
- )
356
-
357
- # باکس 3: متن ناشناس‌شده (چپ)
358
- with gr.Column(scale=1):
359
- anonymized_text = gr.Textbox(
360
- lines=12,
361
- label="🔒 متن ناشناس‌شده",
362
- interactive=False,
363
- elem_classes="textbox"
364
- )
365
-
366
- # ============================================
367
- # پایین: جدول نگاشت (Markdown)
368
- # ============================================
369
- gr.Markdown("---")
370
-
371
- mapping_table = gr.Markdown(
372
- value="### 📋 جدول نگاشت\n\nهنوز پردازشی انجام نشده",
373
- label="📋 جدول نگاشت",
374
- elem_classes="input-box"
375
- )
376
-
377
- # ============================================
378
- # Event Handlers
379
- # ============================================
380
- process_btn.click(
381
- fn=process,
382
- inputs=[input_text, analysis_prompt],
383
- outputs=[restored_text, gpt_analysis, anonymized_text, mapping_table]
384
- )
385
-
386
- clear_btn.click(
387
- fn=clear_all,
388
- outputs=[input_text, analysis_prompt, restored_text, gpt_analysis, anonymized_text, mapping_table]
389
- )
390
-
391
- if __name__ == "__main__":
392
- print("=" * 70)
393
- print("🚀 سیستم ناشناس‌سازی متون در حال راه‌اندازی...")
394
- print("=" * 70)
395
- print("\n📋 نحوه استفاده:\n")
396
- print("1. CEREBRAS_API_KEY و OPENAI_API_KEY را تنظیم کنید")
397
- print("2. http://localhost:7860 را باز کنید")
398
- print("3. متن را وارد کنید")
399
- print("4. 'پردازش' را کلیک کنید\n")
400
- print("روش استفاده شده: Cerebras (Llama 3.3-70B)")
401
- print("=" * 70 + "\n")
402
-
403
- app.launch(
404
- server_name="0.0.0.0",
405
- server_port=7860,
406
- share=False,
407
- show_error=True
408
- )