# =====================================
# فایل: 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/
"""