leilaghomashchi commited on
Commit
440ba32
·
verified ·
1 Parent(s): 72a098e

Delete app.py

Browse files
Files changed (1) hide show
  1. app.py +0 -390
app.py DELETED
@@ -1,390 +0,0 @@
1
- import json
2
- import gradio as gr
3
- from typing import Dict, Any
4
- import os
5
- from dataclasses import dataclass
6
- import re
7
- import requests
8
-
9
- @dataclass
10
- class QwenConfig:
11
- """تنظیمات Qwen 2.5-32B via HF Inference API"""
12
- model_id: str = "Qwen/Qwen2.5-32B-Instruct"
13
- api_url: str = "https://api-inference.huggingface.co/models/Qwen/Qwen2.5-32B-Instruct"
14
- max_tokens: int = 1024
15
- temperature: float = 0.3
16
- top_p: float = 0.8
17
-
18
- class QwenAnonymizer:
19
- """سیستم ناشناس‌سازی متون مالی فارسی"""
20
-
21
- def __init__(self, hf_token: str = None):
22
- self.config = QwenConfig()
23
- self.hf_token = hf_token or os.getenv("HF_TOKEN")
24
- self.model_loaded = bool(self.hf_token)
25
-
26
- def anonymize_text(self, text: str) -> Dict[str, Any]:
27
- """ناشناس‌سازی متن"""
28
- if not self.hf_token:
29
- return {"success": False, "error": "HF_TOKEN یافت نشد"}
30
-
31
- if not text.strip():
32
- return {"success": False, "error": "متن ورودی خالی است"}
33
-
34
- try:
35
- print(f"⏳ پردازش متن...")
36
-
37
- system_prompt = self._create_system_prompt()
38
-
39
- # ایجاد payload
40
- payload = {
41
- "inputs": f"""[INST] {system_prompt}
42
-
43
- متن ورودی:
44
- {text}
45
-
46
- فقط متن ناشناس‌سازی شده را برگردان: [/INST]""",
47
- "parameters": {
48
- "max_new_tokens": self.config.max_tokens,
49
- "temperature": self.config.temperature,
50
- "top_p": self.config.top_p,
51
- "do_sample": True,
52
- "return_full_text": False,
53
- }
54
- }
55
-
56
- # درخواست API
57
- headers = {"Authorization": f"Bearer {self.hf_token}"}
58
- response = requests.post(
59
- self.config.api_url,
60
- headers=headers,
61
- json=payload,
62
- timeout=120
63
- )
64
-
65
- if response.status_code != 200:
66
- return {
67
- "success": False,
68
- "error": f"خطا از API: {response.status_code} - {response.text}"
69
- }
70
-
71
- result = response.json()
72
-
73
- if isinstance(result, list) and len(result) > 0:
74
- content = result[0].get("generated_text", "").strip()
75
- else:
76
- content = str(result).strip()
77
-
78
- # پاک‌سازی
79
- content = self._clean_explanations(content)
80
- content = content.strip()
81
-
82
- analysis = self._analyze_anonymized_text(content)
83
-
84
- return {
85
- "success": True,
86
- "anonymized_text": content,
87
- "entities": analysis["entities"],
88
- "statistics": analysis["statistics"],
89
- "detailed_analysis": analysis["detailed_analysis"],
90
- "quality_check": self._validate_anonymized_text(content)
91
- }
92
-
93
- except requests.exceptions.Timeout:
94
- return {"success": False, "error": "⏱️ مدل درحال بارگذاری است (۳۰-۶۰ ثانیه صبر کنید)"}
95
- except Exception as e:
96
- return {"success": False, "error": f"خطا: {str(e)}"}
97
-
98
- def _create_system_prompt(self) -> str:
99
- """دستورالعمل سیستمی"""
100
- return """شما یک سیستم ناشناس‌سازی متون مالی فارسی هستید.
101
-
102
- قوانین اندیس‌گذاری:
103
- 1. ترتیب پیوسته: company-01, company-02, ... | person-01, person-02, ... | amount-01, amount-02, ... | percent-01, percent-02, ...
104
- 2. ثبات: اگر "همراه اول" → company-01 شد، در تمام متن همان باشد
105
-
106
- انواع موجودیت:
107
- - company-XX: شرکت‌ها، بانک‌ها، سازمان‌ها
108
- - person-XX: نام و نام خانوادگی اشخاص
109
- - amount-XX: مبالغ - واحد را حفظ کن
110
- - percent-XX: درصدها
111
-
112
- مثال:
113
- ورودی: ایران خودرو در اسفند 1402 حدود 23 هزار میلیارد درآمد کسب کرد که 4.58 درصد افزایش داشت.
114
- خروجی: company-01 در اسفند 1402 حدود amount-01 درآمد کسب کرد که percent-01 افزایش داشت."""
115
-
116
- def _clean_explanations(self, content: str) -> str:
117
- """حذف توضیحات اضافی"""
118
- lines = content.split('\n')
119
- clean_lines = []
120
- for line in lines:
121
- if any(word in line.lower() for word in
122
- ['okay', 'let me', 'here is', 'خروجی', 'نتیجه', 'پاسخ:', 'assistant']):
123
- continue
124
- clean_lines.append(line)
125
- return '\n'.join(clean_lines).strip()
126
-
127
- def _analyze_anonymized_text(self, text: str) -> Dict[str, Any]:
128
- companies = re.findall(r'company-(\d+)', text)
129
- persons = re.findall(r'person-(\d+)', text)
130
- amounts = re.findall(r'amount-(\d+)', text)
131
- percents = re.findall(r'percent-(\d+)', text)
132
-
133
- statistics = {
134
- "company": len(set(companies)),
135
- "person": len(set(persons)),
136
- "amount": len(set(amounts)),
137
- "percent": len(set(percents)),
138
- "total": len(companies) + len(persons) + len(amounts) + len(percents)
139
- }
140
-
141
- entities = {
142
- "companies": sorted(list(set(companies)), key=lambda x: int(x)),
143
- "persons": sorted(list(set(persons)), key=lambda x: int(x)),
144
- "amounts": sorted(list(set(amounts)), key=lambda x: int(x)),
145
- "percents": sorted(list(set(percents)), key=lambda x: int(x))
146
- }
147
-
148
- detailed_analysis = {
149
- "preserved_dates": len(re.findall(r'\d{4}/\d{1,2}/\d{1,2}|\d{1,2}\s+\w+\s+\d{4}', text)),
150
- "financial_indicators": len(re.findall(r'\b(EPS|P/E|ARPU|NPL|ROE|ROA)\b', text)),
151
- "units_preserved": len(re.findall(r'(میلیارد|میلیون|هزار|تومان|ریال|درهم|دلار)', text))
152
- }
153
-
154
- return {
155
- "statistics": statistics,
156
- "entities": entities,
157
- "detailed_analysis": detailed_analysis
158
- }
159
-
160
- def _validate_anonymized_text(self, text: str) -> Dict[str, Any]:
161
- companies = re.findall(r'company-(\d+)', text)
162
- persons = re.findall(r'person-(\d+)', text)
163
- amounts = re.findall(r'amount-(\d+)', text)
164
- percents = re.findall(r'percent-(\d+)', text)
165
-
166
- validation_issues = []
167
-
168
- for entity_type, indices in [("company", companies), ("person", persons),
169
- ("amount", amounts), ("percent", percents)]:
170
- if indices:
171
- unique_indices = sorted(list(set([int(x) for x in indices])))
172
- if unique_indices[0] != 1:
173
- validation_issues.append(f"⚠️ {entity_type} از 01 شروع نشده")
174
-
175
- return {
176
- "is_valid": len(validation_issues) == 0,
177
- "issues": validation_issues
178
- }
179
-
180
- # ========== رابط کاربری ==========
181
-
182
- anonymizer = None
183
-
184
- def create_interface():
185
- global anonymizer
186
-
187
- custom_css = """
188
- .gradio-container {
189
- font-family: 'Tahoma', 'Arial', sans-serif !important;
190
- direction: rtl;
191
- max-width: 1200px;
192
- margin: 0 auto;
193
- }
194
- .info-box {
195
- background-color: #e3f2fd;
196
- border: 2px solid #2196F3;
197
- border-radius: 12px;
198
- padding: 15px;
199
- color: #0d47a1;
200
- margin: 10px 0;
201
- }
202
- .success-box {
203
- background-color: #e8f5e9;
204
- border: 2px solid #4caf50;
205
- border-radius: 12px;
206
- padding: 15px;
207
- color: #1b5e20;
208
- margin: 10px 0;
209
- }
210
- .warning-box {
211
- background-color: #fff3cd;
212
- border: 2px solid #ffc107;
213
- border-radius: 12px;
214
- padding: 15px;
215
- color: #856404;
216
- margin: 10px 0;
217
- }
218
- .result-box {
219
- background-color: #f8f9fa;
220
- border: 2px solid #e9ecef;
221
- border-radius: 12px;
222
- padding: 20px;
223
- }
224
- """
225
-
226
- with gr.Blocks(css=custom_css, title="ناشناس‌ساز Qwen2.5", theme=gr.themes.Soft()) as interface:
227
-
228
- gr.Markdown("""
229
- # 🔒 سیستم ناشناس‌سازی متون مالی فارسی
230
- ### 🚀 Qwen 2.5-32B (HuggingFace Inference API)
231
- """)
232
-
233
- hf_token_input = gr.Textbox(
234
- label="🔑 HuggingFace API Token",
235
- placeholder="hf_...",
236
- type="password",
237
- info="از https://huggingface.co/settings/tokens بگیرید"
238
- )
239
-
240
- gr.Markdown("""
241
- <div class="info-box">
242
- 📊 <strong>مدل:</strong> Qwen2.5-32B-Instruct<br>
243
- 🌐 <strong>منبع:</strong> HuggingFace Inference API<br>
244
- ✅ <strong>مزیت:</strong> بدون نیاز به نصب • سریع • رایگان<br>
245
- ⚡ <strong>وضعیت:</strong> آماده برای استفاده فوری
246
- </div>
247
- """)
248
-
249
- status_box = gr.Textbox(label="📋 وضعیت", interactive=False, value="✅ آماده")
250
-
251
- with gr.Row():
252
- with gr.Column(scale=1):
253
- input_text = gr.Textbox(
254
- label="📝 متن ورودی",
255
- placeholder="متن خود را اینجا وارد کنید...",
256
- lines=10,
257
- max_lines=20
258
- )
259
-
260
- with gr.Row():
261
- anonymize_btn = gr.Button("🔒 ناشناس‌سازی", variant="primary", size="lg")
262
- clear_btn = gr.Button("🗑️ پاک کردن", variant="secondary")
263
-
264
- with gr.Column(scale=1):
265
- output_text = gr.Textbox(
266
- label="🎯 متن ناشناس‌سازی شده",
267
- lines=10,
268
- max_lines=20,
269
- elem_classes=["result-box"]
270
- )
271
-
272
- with gr.Row():
273
- with gr.Column():
274
- statistics_output = gr.Markdown(label="📊 آمار")
275
- with gr.Column():
276
- quality_output = gr.Markdown(label="✅ کیفیت")
277
-
278
- with gr.Row():
279
- entities_output = gr.Markdown(label="🏷️ موجودیت‌ها")
280
- detailed_output = gr.Markdown(label="🔍 تحلیل")
281
-
282
- def process_text(text, token):
283
- """پردازش متن"""
284
- global anonymizer
285
-
286
- if not token or not token.strip():
287
- return ("", "❌ HF Token الزامی است", "", "", "", "")
288
-
289
- if not text.strip():
290
- return ("", "❌ متن خالی است", "", "", "", "")
291
-
292
- # ایجاد anonymizer با token
293
- anonymizer = QwenAnonymizer(hf_token=token.strip())
294
-
295
- result = anonymizer.anonymize_text(text)
296
-
297
- if not result["success"]:
298
- return ("", f"❌ {result['error']}", "", "", "", "")
299
-
300
- stats = result.get("statistics", {})
301
- stats_md = f"""📊 **آمار:**
302
- 🏢 شرکت: {stats.get('company', 0)}
303
- 👤 اشخاص: {stats.get('person', 0)}
304
- 💰 مبالغ: {stats.get('amount', 0)}
305
- 📊 درصدها: {stats.get('percent', 0)}
306
- 🔢 کل: {stats.get('total', 0)}"""
307
-
308
- quality = result.get("quality_check", {})
309
- quality_md = f"""✅ **کنترل کیفیت:**
310
-
311
- {'✅ موفق' if quality.get('is_valid') else '⚠️ هشدار'}
312
- """
313
- if quality.get("issues"):
314
- quality_md += "\n**نکات:**\n"
315
- for issue in quality["issues"]:
316
- quality_md += f"• {issue}\n"
317
-
318
- entities = result.get("entities", {})
319
- entities_md = "🏷️ **موجودیت‌ها:**\n"
320
- if entities.get("companies"):
321
- entities_md += f"\n🏢 company-{', company-'.join(entities['companies'])}"
322
- if entities.get("persons"):
323
- entities_md += f"\n👤 person-{', person-'.join(entities['persons'])}"
324
- if entities.get("amounts"):
325
- entities_md += f"\n💰 amount-{', amount-'.join(entities['amounts'])}"
326
- if entities.get("percents"):
327
- entities_md += f"\n📊 percent-{', percent-'.join(entities['percents'])}"
328
-
329
- detailed = result.get("detailed_analysis", {})
330
- detailed_md = f"""🔍 **تحلیل:**
331
- 📅 تاریخ: {detailed.get('preserved_dates', 0)}
332
- 📈 شاخص: {detailed.get('financial_indicators', 0)}
333
- 📏 واحد: {detailed.get('units_preserved', 0)}"""
334
-
335
- return (
336
- result["anonymized_text"],
337
- stats_md,
338
- quality_md,
339
- entities_md,
340
- detailed_md,
341
- "✅ موفق"
342
- )
343
-
344
- def clear_all():
345
- return "", "", "", "", "", ""
346
-
347
- anonymize_btn.click(
348
- fn=process_text,
349
- inputs=[input_text, hf_token_input],
350
- outputs=[output_text, statistics_output, quality_output, entities_output, detailed_output, status_box]
351
- )
352
-
353
- clear_btn.click(
354
- fn=clear_all,
355
- outputs=[input_text, output_text, statistics_output, quality_output, entities_output, detailed_output]
356
- )
357
-
358
- gr.Examples(
359
- examples=[
360
- ["ایران خودرو در اسفندماه حدود 23 هزار میلیارد تومان درآمد کسب کرد که 4.58 درصد افزایش داشت."],
361
- ["بانک ملی ایران و حسن روحانی در جلسه امروز بحث کردند."],
362
- ],
363
- inputs=input_text,
364
- label="📚 مثال‌ها"
365
- )
366
-
367
- with gr.Accordion("📖 راهنما", open=False):
368
- gr.Markdown("""
369
- ## 🔑 چگونه HF Token بگیرید:
370
-
371
- 1. به https://huggingface.co/settings/tokens بروید
372
- 2. **New token** کلیک کنید
373
- 3. نام انتخاب کنید (مثلاً: qwen-anonymizer)
374
- 4. **Type: Read** انتخاب کنید
375
- 5. **Generate** کلیک کنید
376
- 6. Token رو کپی کنید
377
-
378
- ## 🚀 چگونه استفاده کنید:
379
-
380
- 1. Token را در بالا وارد کنید
381
- 2. متن خود را در جعبه "متن ورودی" بنویسید
382
- 3. دکمه "🔒 ناشناس‌سازی" را کلیک کنید
383
- 4. نتیجه در جعبه "متن ناشناس‌سازی شده" نمایش داده می‌شود
384
- """)
385
-
386
- return interface
387
-
388
- if __name__ == "__main__":
389
- interface = create_interface()
390
- interface.launch()