# ===================================== # فایل: app.py (کد اصلی برای HF Spaces) # ===================================== import requests import json import gradio as gr from typing import Dict, Any import os from dataclasses import dataclass @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("""
⚠️ کلید API در متغیرهای محیطی یافت نشد
لطفاً کلید Groq API خود را در زیر وارد کنید یا در Settings > Secrets تنظیم کنید
""") api_key_input = gr.Textbox( label="🔑 کلید Groq API", placeholder="gsk_...", type="password", value="" ) else: gr.Markdown("""
سیستم آماده است - کلید API تنظیم شده
""") 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/ """