Spaces:
Sleeping
Sleeping
| # ===================================== | |
| # فایل: app.py (کد اصلی برای HF Spaces) | |
| # ===================================== | |
| import requests | |
| import json | |
| import gradio as gr | |
| from typing import Dict, Any | |
| import os | |
| from dataclasses import dataclass | |
| class GroqConfig: | |
| """تنظیمات Groq API""" | |
| api_key: str | |
| base_url: str = "https://api.groq.com/openai/v1" | |
| model: str = "llama-3.1-8b-instant" | |
| max_tokens: int = 1000 | |
| temperature: float = 0.1 | |
| class GroqAnonymizer: | |
| """سیستم ناشناسسازی با استفاده از Groq""" | |
| def __init__(self, api_key: str = None): | |
| # در HF Spaces از متغیر محیطی کلید را بخوان | |
| if api_key is None: | |
| api_key = os.getenv("GROQ_API_KEY") | |
| if not api_key: | |
| raise ValueError("کلید API در متغیرهای محیطی یافت نشد. لطفاً GROQ_API_KEY را تنظیم کنید.") | |
| self.config = GroqConfig(api_key=api_key) | |
| self.system_prompt = self._create_system_prompt() | |
| def _create_system_prompt(self) -> str: | |
| """ایجاد دستورالعمل سیستمی برای Groq""" | |
| return """شما یک سیستم ناشناسسازی متن فارسی هستید. | |
| وظیفه: تشخیص و جایگزینی موجودیتهای حساس: | |
| 1. نام شرکتها → company-01, company-02, ... | |
| 2. نام افراد → person-01, person-02, ... | |
| 3. مبالغ و اعداد → amount-01, amount-02, ... | |
| 4. درصدها → percent-01, percent-02, ... | |
| نکات: | |
| - همان موجودیت = همان شماره | |
| - پیشوندها (دکتر، آقا) را حفظ کنید | |
| - فقط متن ناشناسسازی شده را برگردانید، بدون JSON یا توضیح اضافی | |
| مثال: | |
| ورودی: احمد رضایی مدیرعامل شرکت پارس 100 میلیون تومان درآمد دارد | |
| خروجی: person-01 مدیرعامل company-01 amount-01 درآمد دارد""" | |
| def _make_api_request(self, text: str) -> Dict[str, Any]: | |
| """ارسال درخواست به Groq API""" | |
| headers = { | |
| "Authorization": f"Bearer {self.config.api_key}", | |
| "Content-Type": "application/json" | |
| } | |
| payload = { | |
| "messages": [ | |
| { | |
| "role": "system", | |
| "content": self.system_prompt | |
| }, | |
| { | |
| "role": "user", | |
| "content": text | |
| } | |
| ], | |
| "model": self.config.model, | |
| "temperature": self.config.temperature, | |
| "max_tokens": self.config.max_tokens | |
| } | |
| try: | |
| print(f"DEBUG: Sending request to {self.config.base_url}/chat/completions") | |
| print(f"DEBUG: Model: {self.config.model}") | |
| print(f"DEBUG: Text length: {len(text)}") | |
| response = requests.post( | |
| f"{self.config.base_url}/chat/completions", | |
| headers=headers, | |
| json=payload, | |
| timeout=30 | |
| ) | |
| print(f"DEBUG: Response status: {response.status_code}") | |
| if response.status_code != 200: | |
| print(f"DEBUG: Error response: {response.text}") | |
| response.raise_for_status() | |
| return response.json() | |
| except requests.exceptions.RequestException as e: | |
| print(f"DEBUG: Request exception: {str(e)}") | |
| raise Exception(f"خطا در ارتباط با Groq API: {str(e)}") | |
| def anonymize_text(self, text: str) -> Dict[str, Any]: | |
| """ناشناسسازی متن با استفاده از Groq""" | |
| if not text.strip(): | |
| return { | |
| "success": False, | |
| "error": "متن ورودی خالی است" | |
| } | |
| try: | |
| response = self._make_api_request(text) | |
| if "choices" not in response or not response["choices"]: | |
| return { | |
| "success": False, | |
| "error": "پاسخ نامعتبر از API" | |
| } | |
| content = response["choices"][0]["message"]["content"] | |
| # پاک کردن markdown اگر وجود دارد | |
| if "```" in content: | |
| lines = content.split('\n') | |
| clean_lines = [] | |
| skip = False | |
| for line in lines: | |
| if line.strip().startswith('```'): | |
| skip = not skip | |
| continue | |
| if not skip: | |
| clean_lines.append(line) | |
| content = '\n'.join(clean_lines) | |
| # حذف خطوط اضافی و فضاهای خالی | |
| content = content.strip() | |
| return { | |
| "success": True, | |
| "anonymized_text": content, | |
| "entities": [], # در حالت ساده entities نداریم | |
| "statistics": self._count_entities(content), | |
| "usage": response.get("usage", {}) | |
| } | |
| except Exception as e: | |
| return { | |
| "success": False, | |
| "error": f"خطا در پردازش: {str(e)}" | |
| } | |
| def _count_entities(self, text: str) -> Dict[str, int]: | |
| """شمارش موجودیتها در متن ناشناسسازی شده""" | |
| import re | |
| company_count = len(re.findall(r'company-\d+', text)) | |
| person_count = len(re.findall(r'person-\d+', text)) | |
| amount_count = len(re.findall(r'amount-\d+', text)) | |
| percent_count = len(re.findall(r'percent-\d+', text)) | |
| group_count = len(re.findall(r'group-\d+', text)) | |
| return { | |
| "company": company_count, | |
| "person": person_count, | |
| "amount": amount_count, | |
| "percent": percent_count, | |
| "group": group_count | |
| } | |
| def create_interface(): | |
| """ایجاد رابط کاربری برای Hugging Face Spaces""" | |
| # بررسی وجود کلید API | |
| api_key_available = bool(os.getenv("GROQ_API_KEY")) | |
| # CSS سفارشی | |
| custom_css = """ | |
| .gradio-container { | |
| font-family: 'Tahoma', 'Arial', sans-serif !important; | |
| direction: rtl; | |
| max-width: 1200px; | |
| margin: 0 auto; | |
| } | |
| .result-box { | |
| background-color: #f0f8ff; | |
| border: 1px solid #ddd; | |
| border-radius: 8px; | |
| padding: 15px; | |
| font-family: 'Tahoma', monospace; | |
| line-height: 1.6; | |
| } | |
| .warning-box { | |
| background-color: #fff3cd; | |
| border: 1px solid #ffeaa7; | |
| border-radius: 8px; | |
| padding: 10px; | |
| color: #856404; | |
| } | |
| .success-box { | |
| background-color: #d4edda; | |
| border: 1px solid #c3e6cb; | |
| border-radius: 8px; | |
| padding: 10px; | |
| color: #155724; | |
| } | |
| """ | |
| with gr.Blocks(css=custom_css, title="ناشناسسازی متن فارسی", theme=gr.themes.Soft()) as interface: | |
| # عنوان | |
| gr.Markdown(""" | |
| # 🔒 سیستم ناشناسسازی متن فارسی | |
| ### قدرتگرفته از Groq AI برای تشخیص و حفاظت از اطلاعات حساس | |
| این سیستم قادر است نام افراد، شرکتها، مبالغ مالی و درصدها را به صورت هوشمند تشخیص و ناشناسسازی کند. | |
| """) | |
| # ورود کلید API اگر در secrets موجود نباشد | |
| if not api_key_available: | |
| gr.Markdown(""" | |
| <div class="warning-box"> | |
| ⚠️ <strong>کلید API در متغیرهای محیطی یافت نشد</strong><br> | |
| لطفاً کلید Groq API خود را در زیر وارد کنید یا در Settings > Secrets تنظیم کنید | |
| </div> | |
| """) | |
| api_key_input = gr.Textbox( | |
| label="🔑 کلید Groq API", | |
| placeholder="gsk_...", | |
| type="password", | |
| value="" | |
| ) | |
| else: | |
| gr.Markdown(""" | |
| <div class="success-box"> | |
| ✅ <strong>سیستم آماده است</strong> - کلید API تنظیم شده | |
| </div> | |
| """) | |
| api_key_input = gr.Textbox(visible=False) | |
| with gr.Row(): | |
| with gr.Column(scale=1): | |
| input_text = gr.Textbox( | |
| label="📝 متن ورودی", | |
| placeholder="متن خود را اینجا وارد کنید...", | |
| lines=10, | |
| max_lines=20 | |
| ) | |
| with gr.Row(): | |
| anonymize_btn = gr.Button( | |
| "🔒 ناشناسسازی متن", | |
| variant="primary", | |
| size="lg" | |
| ) | |
| clear_btn = gr.Button( | |
| "🗑️ پاک کردن", | |
| variant="secondary" | |
| ) | |
| with gr.Column(scale=1): | |
| output_text = gr.Textbox( | |
| label="🎯 متن ناشناسسازی شده", | |
| lines=10, | |
| max_lines=20, | |
| elem_classes=["result-box"] | |
| ) | |
| # دکمه کپی | |
| copy_btn = gr.Button( | |
| "📋 کپی متن", | |
| variant="secondary", | |
| size="sm" | |
| ) | |
| # متن برای کپی | |
| copy_output = gr.Textbox( | |
| label="📋 متن برای کپی (Ctrl+A و Ctrl+C)", | |
| lines=3, | |
| max_lines=10, | |
| visible=False, | |
| interactive=True | |
| ) | |
| with gr.Row(): | |
| with gr.Column(): | |
| statistics_output = gr.Markdown(label="📊 آمار تشخیص") | |
| with gr.Column(): | |
| usage_output = gr.Markdown(label="⚡ اطلاعات پردازش") | |
| entities_output = gr.Markdown(label="📋 جزئیات تغییرات") | |
| def process_text(text: str, api_key_manual: str = ""): | |
| """پردازش متن""" | |
| # تعیین کلید API - اولویت با manual input | |
| if api_key_manual is None: | |
| api_key_manual = "" | |
| final_api_key = api_key_manual.strip() if api_key_manual and api_key_manual.strip() else os.getenv("GROQ_API_KEY") | |
| if not final_api_key: | |
| return ( | |
| "", | |
| "❌ کلید API وارد نشده است. لطفاً در فیلد بالا وارد کنید یا در Settings تنظیم کنید.", | |
| "", | |
| "" | |
| ) | |
| if not text.strip(): | |
| return ( | |
| "", | |
| "❌ لطفاً متن ورودی را وارد کنید", | |
| "", | |
| "" | |
| ) | |
| try: | |
| anonymizer = GroqAnonymizer(api_key=final_api_key) | |
| result = anonymizer.anonymize_text(text) | |
| if not result["success"]: | |
| return ( | |
| "", | |
| f"❌ خطا: {result['error']}", | |
| "", | |
| "" | |
| ) | |
| # آمار | |
| stats = result.get("statistics", {}) | |
| stats_md = "📊 **آمار تشخیص:**\n\n" | |
| total = sum(stats.values()) if stats else 0 | |
| stats_md += f"🔢 **کل موارد:** {total}\n\n" | |
| type_names = { | |
| 'company': 'شرکتها', | |
| 'person': 'افراد', | |
| 'group': 'گروهها', | |
| 'amount': 'مبالغ', | |
| 'percent': 'درصدها' | |
| } | |
| if stats: | |
| for key, value in stats.items(): | |
| if value > 0: | |
| name = type_names.get(key, key) | |
| stats_md += f"• {name}: **{value}** مورد\n" | |
| # اطلاعات پردازش | |
| usage = result.get("usage", {}) | |
| usage_md = "⚡ **اطلاعات پردازش:**\n\n" | |
| if usage: | |
| usage_md += f"• مدل: Llama 3.1\n" | |
| usage_md += f"• Token های ورودی: {usage.get('prompt_tokens', 'نامشخص')}\n" | |
| usage_md += f"• Token های خروجی: {usage.get('completion_tokens', 'نامشخص')}\n" | |
| else: | |
| usage_md += "✅ پردازش با موفقیت انجام شد" | |
| # جزئیات موجودیتها | |
| entities = result.get("entities", []) | |
| entities_md = "📋 **جزئیات تغییرات:**\n\n" | |
| if entities: | |
| for i, entity in enumerate(entities, 1): | |
| entities_md += f"**{i}.** *{entity.get('type', 'نامشخص')}*\n" | |
| entities_md += f" • اصل: `{entity.get('original', '')}`\n" | |
| entities_md += f" • جایگزین: `{entity.get('anonymized', '')}`\n\n" | |
| else: | |
| entities_md += "هیچ تغییری انجام نشده یا جزئیات در دسترس نیست" | |
| return ( | |
| result["anonymized_text"], | |
| stats_md, | |
| usage_md, | |
| entities_md | |
| ) | |
| except Exception as e: | |
| return ( | |
| "", | |
| f"❌ خطای غیرمنتظره: {str(e)}", | |
| "", | |
| "" | |
| ) | |
| def copy_text(text_to_copy): | |
| """تابع کپی متن""" | |
| if not text_to_copy.strip(): | |
| return gr.Textbox(visible=False), "⚠️ متنی برای کپی وجود ندارد" | |
| # نمایش textbox با محتوای قابل کپی | |
| return gr.Textbox(value=text_to_copy, visible=True), "✅ متن در کادر زیر آماده کپی است (Ctrl+A سپس Ctrl+C)" | |
| def clear_all(): | |
| """پاک کردن تمام فیلدها""" | |
| return "", "", "", "", "", gr.Textbox(visible=False) | |
| # اتصال رویدادها | |
| anonymize_btn.click( | |
| fn=process_text, | |
| inputs=[input_text, api_key_input], | |
| outputs=[output_text, statistics_output, usage_output, entities_output] | |
| ) | |
| clear_btn.click( | |
| fn=clear_all, | |
| outputs=[input_text, output_text, statistics_output, usage_output, entities_output, copy_output] | |
| ) | |
| # مثالهای نمونه | |
| gr.Examples( | |
| examples=[ | |
| ["ایران خودرو در اسفندماه سال 1402 حدود 23 هزار و 296 میلیارد تومان درآمد کسب کرد که در مقایسه با بهمن 4.58 درصد افزایش داشت."], | |
| ["مهدی اخوان بهابادی، مدیرعامل همراه اول، اعلام کرد درآمد عملیاتی شرکت با رشد 37 درصدی به 70 هزار و 677 میلیارد تومان رسیده است."], | |
| ["بانک پاسارگاد با شناسایی سود خالص 155 هزار میلیارد ریالی در رده دوم سودآورترین بانکهای کشور قرار گرفت."], | |
| ["شرکت سرمایهگذاری دارویی تأمین (تیپیکو) گزارش فعالیت هیئتمدیره خود را برای سال مالی منتهی به 31 اردیبهشت 1404 منتشر کرد."] | |
| ], | |
| inputs=input_text, | |
| label="📚 مثالهای آزمایشی" | |
| ) | |
| # راهنمای استفاده | |
| gr.Markdown(""" | |
| --- | |
| ### 🎯 **ویژگیها:** | |
| - 🏢 تشخیص نام شرکتها و سازمانها | |
| - 👤 تشخیص نام افراد با پیشوندهای مختلف | |
| - 💰 تشخیص مبالغ مالی و اعداد | |
| - 📊 تشخیص درصدها با فرمتهای مختلف | |
| - 🏗️ تشخیص نام گروهها | |
| ### 📝 **نحوه کار:** | |
| 1. متن خود را در کادر ورودی وارد کنید | |
| 2. دکمه "ناشناسسازی متن" را کلیک کنید | |
| 3. نتیجه را در کادر خروجی مشاهده کنید | |
| 4. آمار و جزئیات تغییرات را بررسی کنید | |
| ### ⚠️ **توجه:** | |
| - این سیستم برای متون فارسی بهینهسازی شده است | |
| - حداکثر طول متن ورودی حدود 1000 کلمه توصیه میشود | |
| - اطلاعات شما پس از پردازش حذف میشوند | |
| """) | |
| return interface | |
| # اجرای برنامه | |
| if __name__ == "__main__": | |
| interface = create_interface() | |
| interface.launch() | |
| # ===================================== | |
| # فایل: requirements.txt | |
| # ===================================== | |
| """ | |
| gradio==4.0.0 | |
| requests==2.31.0 | |
| """ | |
| # ===================================== | |
| # فایل: README.md | |
| # ===================================== | |
| """ | |
| --- | |
| title: Persian Text Anonymizer | |
| emoji: 🔒 | |
| colorFrom: blue | |
| colorTo: purple | |
| sdk: gradio | |
| sdk_version: 4.0.0 | |
| app_file: app.py | |
| pinned: false | |
| license: mit | |
| --- | |
| # 🔒 سیستم ناشناسسازی متن فارسی | |
| سیستم هوشمند برای تشخیص و ناشناسسازی اطلاعات حساس در متون فارسی با استفاده از مدلهای زبانی پیشرفته. | |
| ## ویژگیها | |
| - 🏢 **تشخیص شرکتها**: نام شرکتها، بانکها، موسسات | |
| - 👤 **تشخیص افراد**: نام اشخاص با پیشوندهای مختلف | |
| - 💰 **تشخیص مبالغ**: اعداد، مبالغ مالی، واحدهای اندازهگیری | |
| - 📊 **تشخیص درصدها**: انواع فرمتهای درصد | |
| - 🏗️ **تشخیص گروهها**: نام گروهها و هلدینگها | |
| ## تنظیمات | |
| برای استفاده از این برنامه، نیاز به تنظیم متغیر محیطی `GROQ_API_KEY` دارید. | |
| ## مثال استفاده | |
| ```python | |
| from app import GroqAnonymizer | |
| anonymizer = GroqAnonymizer() | |
| result = anonymizer.anonymize_text("احمد رضایی مدیرعامل شرکت پارس 100 میلیون تومان درآمد دارد.") | |
| print(result["anonymized_text"]) | |
| # خروجی: "person-01 مدیرعامل company-01 amount-01 درآمد دارد." | |
| ``` | |
| ## تکنولوژی | |
| - **Groq API**: برای پردازش هوشمند متن | |
| - **Gradio**: برای رابط کاربری وب | |
| - **Llama 3.1**: مدل زبانی پیشرفته | |
| ## مجوز | |
| MIT License | |
| """ | |
| # ===================================== | |
| # فایل: .gitignore | |
| # ===================================== | |
| """ | |
| __pycache__/ | |
| *.py[cod] | |
| *$py.class | |
| *.so | |
| .Python | |
| build/ | |
| develop-eggs/ | |
| dist/ | |
| downloads/ | |
| eggs/ | |
| .eggs/ | |
| lib/ | |
| lib64/ | |
| parts/ | |
| sdist/ | |
| var/ | |
| wheels/ | |
| *.egg-info/ | |
| .installed.cfg | |
| *.egg | |
| MANIFEST | |
| .env | |
| .venv | |
| env/ | |
| venv/ | |
| ENV/ | |
| env.bak/ | |
| venv.bak/ | |
| .DS_Store | |
| .vscode/ | |
| .idea/ | |
| *.swp | |
| *.swo | |
| gradio_cached_examples/ | |
| flagged/ | |
| """ |