|
|
import requests |
|
|
import json |
|
|
import gradio as gr |
|
|
from typing import Dict, Any |
|
|
import os |
|
|
from dataclasses import dataclass |
|
|
import re |
|
|
|
|
|
@dataclass |
|
|
class CerebrasConfig: |
|
|
"""تنظیمات Cerebras API برای Qwen 3-32B""" |
|
|
api_key: str |
|
|
base_url: str = "https://api.cerebras.ai/v1" |
|
|
model: str = "qwen/qwen-3-14b:free" |
|
|
max_tokens: int = 16384 |
|
|
temperature: float = 0.3 |
|
|
top_p: float = 0.8 |
|
|
presence_penalty: float = 0.2 |
|
|
frequency_penalty: float = 0.2 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class AdvancedCerebrasAnonymizer: |
|
|
"""سیستم پیشرفته ناشناسسازی متون مالی/خبری فارسی با Qwen 3-32B""" |
|
|
|
|
|
def __init__(self, api_key: str = None): |
|
|
if api_key is None: |
|
|
api_key = os.getenv("CEREBRAS_API_KEY") |
|
|
if not api_key: |
|
|
raise ValueError("کلید API یافت نشد") |
|
|
|
|
|
self.config = CerebrasConfig(api_key=api_key) |
|
|
self.system_prompt = self._create_advanced_system_prompt() |
|
|
|
|
|
def _create_advanced_system_prompt(self) -> str: |
|
|
"""ایجاد دستورالعمل سیستمی بهینه شده""" |
|
|
return """شما یک سیستم ناشناسسازی متون مالی فارسی هستید. |
|
|
|
|
|
⚠️ CRITICAL: در پاسخ نهایی خود، فقط و فقط متن ناشناسسازی شده را برگردانید، بدون هیچ توضیح، تحلیل، یا تگ اضافی. |
|
|
|
|
|
## قوانین اندیسگذاری: |
|
|
1. **ترتیب پیوسته**: company-01, company-02, ... | person-01, person-02, ... | amount-01, amount-02, ... | percent-01, percent-02, ... |
|
|
2. **ثبات**: اگر "همراه اول" → company-01 شد، در تمام متن همان باشد |
|
|
3. **نام مستعار**: "فاما" = "فولاد مبارکه" → هر دو company-01 |
|
|
4. **اشاره ضمنی**: "این شرکت" اگر به company-01 اشاره دارد → company-01 (نه company-02) |
|
|
|
|
|
## انواع موجودیت: |
|
|
- **company-XX**: شرکتها، بانکها، سازمانها، گروهها |
|
|
- **person-XX**: نام و نام خانوادگی اشخاص |
|
|
- **amount-XX**: مبالغ - واحد را حفظ کن |
|
|
- **percent-XX**: درصدها |
|
|
|
|
|
## قوانین کلیدی: |
|
|
1. بازرس = شرکت است → company-XX |
|
|
2. واحدها: "amount-01 میلیارد تومان" ✅ |
|
|
3. گروهها: "گروه X" → company-XX |
|
|
4. کلمات عمومی حفظ: "سه شرکت" → حفظ |
|
|
5. دوره زمانی حفظ: "۵ ماهه" → حفظ |
|
|
6. بازه = یک entity: "یک تا 1.5 میلیون" → amount-01 |
|
|
7.شناسایی و دستهبندی درصدها بین 50 تا 70 درصد به عنوان یک موجودیت درصد در متن |
|
|
8.شناسایی تمام ارقام موجود در متن به عنوان موجودیت amount-XX مانند "سود خالص 50 میلیارد تومان" را به مقدار amount-01 تبدیل کن. |
|
|
9.شناسایی مقدار درصد در بازه 40–60٪ به عنوان یک موجودیت درصد (percent-03مثلا). |
|
|
10.بزرگترین هلدینگ شستا در حوزه بازار سرمایه عمل میکند" را به صورت "بزرگترین هلدینگ company-03 در حوزه بازار سرمایه عمل میکند" |
|
|
11.هر جا که یک شرکت و گروه با نام یکسان ذکر شود، آن را به یک موجودیت یکسان (company-XX) تبدیل کن. |
|
|
12.سود حاصل از منابع عملیاتی ۱۰،۸۸۷،۸۶۴ میلیون ریال" را به عنوان amount-01 شناسایی کن. |
|
|
13."بانک ملی ایران" را به عنوان company-01 شناسایی کن. |
|
|
14.شرکت ارتباطات سیار ایران همراه اول" را به عنوان company-01 شناسایی کن. |
|
|
15."سپردهگذاری مرکزی اوراق بهادار و تسویه وجوه" را به عنوان company-01 شناسایی کن. |
|
|
|
|
|
## مثال: |
|
|
ورودی: ایران خودرو در اسفند 1402 حدود 23 هزار و 296 میلیارد درآمد کسب کرد که 4.58 درصد افزایش داشت. |
|
|
خروجی: company-01 در اسفند 1402 حدود amount-01 درآمد کسب کرد که percent-01 افزایش داشت. |
|
|
"این اپراتور در منطقه توانسته به پوششی 100 میلیونی دست پیدا کند" را به صورت "این اپراتور در منطقه توانسته به پوششی amount-04 دست پیدا کند". |
|
|
|
|
|
|
|
|
⚠️ یادآوری: فقط متن ناشناسشده، بدون هیچ توضیح اضافی.""" |
|
|
|
|
|
def _make_api_request(self, text: str) -> Dict[str, Any]: |
|
|
"""ارسال درخواست به Cerebras API""" |
|
|
headers = { |
|
|
"Authorization": f"Bearer {self.config.api_key}", |
|
|
"Content-Type": "application/json" |
|
|
} |
|
|
|
|
|
|
|
|
user_content = f"{text}\n\n/no_think" |
|
|
|
|
|
payload = { |
|
|
"messages": [ |
|
|
{ |
|
|
"role": "system", |
|
|
"content": self.system_prompt |
|
|
}, |
|
|
{ |
|
|
"role": "user", |
|
|
"content": user_content |
|
|
} |
|
|
], |
|
|
"model": self.config.model, |
|
|
"temperature": self.config.temperature, |
|
|
"top_p": self.config.top_p, |
|
|
"max_tokens": self.config.max_tokens |
|
|
} |
|
|
|
|
|
try: |
|
|
response = requests.post( |
|
|
f"{self.config.base_url}/chat/completions", |
|
|
headers=headers, |
|
|
json=payload, |
|
|
timeout=60 |
|
|
) |
|
|
response.raise_for_status() |
|
|
return response.json() |
|
|
|
|
|
except requests.exceptions.RequestException as e: |
|
|
raise Exception(f"خطا در ارتباط با Cerebras API: {str(e)}") |
|
|
|
|
|
def anonymize_text(self, text: str) -> Dict[str, Any]: |
|
|
"""ناشناسسازی متن با استفاده از Qwen 3-32B""" |
|
|
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"] |
|
|
|
|
|
|
|
|
content = self._remove_thinking_tags(content) |
|
|
|
|
|
|
|
|
content = self._clean_markdown(content) |
|
|
|
|
|
|
|
|
content = content.strip() |
|
|
|
|
|
|
|
|
content = self._clean_explanations(content) |
|
|
|
|
|
|
|
|
analysis = self._analyze_anonymized_text(content) |
|
|
|
|
|
return { |
|
|
"success": True, |
|
|
"anonymized_text": content, |
|
|
"entities": analysis["entities"], |
|
|
"statistics": analysis["statistics"], |
|
|
"detailed_analysis": analysis["detailed_analysis"], |
|
|
"usage": response.get("usage", {}), |
|
|
"quality_check": self._validate_anonymized_text(content) |
|
|
} |
|
|
|
|
|
except Exception as e: |
|
|
return { |
|
|
"success": False, |
|
|
"error": f"خطا در پردازش: {str(e)}" |
|
|
} |
|
|
|
|
|
def _remove_thinking_tags(self, content: str) -> str: |
|
|
"""حذف تگهای thinking از خروجی""" |
|
|
|
|
|
content = re.sub(r'<think>.*?</think>', '', content, flags=re.DOTALL) |
|
|
|
|
|
|
|
|
content = re.sub(r'</?think>', '', content) |
|
|
|
|
|
return content.strip() |
|
|
|
|
|
def _clean_markdown(self, content: str) -> str: |
|
|
"""پاک کردن 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) |
|
|
return content |
|
|
|
|
|
def _clean_explanations(self, content: str) -> str: |
|
|
"""حذف توضیحات اضافی در ابتدا یا انتها""" |
|
|
lines = content.split('\n') |
|
|
clean_lines = [] |
|
|
|
|
|
for line in lines: |
|
|
|
|
|
if any(word in line.lower() for word in ['okay', 'let me', 'here is', 'خروجی', 'نتیجه', 'پاسخ']): |
|
|
continue |
|
|
clean_lines.append(line) |
|
|
|
|
|
return '\n'.join(clean_lines).strip() |
|
|
|
|
|
def _analyze_anonymized_text(self, text: str) -> Dict[str, Any]: |
|
|
"""تحلیل متن ناشناسسازی شده""" |
|
|
import re |
|
|
|
|
|
|
|
|
companies = re.findall(r'company-(\d+)', text) |
|
|
persons = re.findall(r'person-(\d+)', text) |
|
|
amounts = re.findall(r'amount-(\d+)', text) |
|
|
percents = re.findall(r'percent-(\d+)', text) |
|
|
|
|
|
|
|
|
statistics = { |
|
|
"company": len(set(companies)), |
|
|
"person": len(set(persons)), |
|
|
"amount": len(set(amounts)), |
|
|
"percent": len(set(percents)), |
|
|
"total_replacements": len(companies) + len(persons) + len(amounts) + len(percents) |
|
|
} |
|
|
|
|
|
|
|
|
entities = { |
|
|
"companies": sorted(list(set(companies)), key=lambda x: int(x)), |
|
|
"persons": sorted(list(set(persons)), key=lambda x: int(x)), |
|
|
"amounts": sorted(list(set(amounts)), key=lambda x: int(x)), |
|
|
"percents": sorted(list(set(percents)), key=lambda x: int(x)) |
|
|
} |
|
|
|
|
|
|
|
|
detailed_analysis = { |
|
|
"preserved_dates": len(re.findall(r'\d{4}/\d{1,2}/\d{1,2}|\d{1,2}\s+\w+\s+\d{4}', text)), |
|
|
"preserved_times": len(re.findall(r'\d{1,2}:\d{2}', text)), |
|
|
"financial_indicators": len(re.findall(r'\b(EPS|P/E|ARPU|NPL|ROE|ROA)\b', text)), |
|
|
"units_preserved": len(re.findall(r'(میلیارد|میلیون|هزار|تومان|ریال|درهم|دلار|یورو|تن|کیلوگرم)', text)) |
|
|
} |
|
|
|
|
|
return { |
|
|
"statistics": statistics, |
|
|
"entities": entities, |
|
|
"detailed_analysis": detailed_analysis |
|
|
} |
|
|
|
|
|
def _validate_anonymized_text(self, text: str) -> Dict[str, Any]: |
|
|
"""اعتبارسنجی پیشرفته متن ناشناسشده""" |
|
|
import re |
|
|
|
|
|
|
|
|
companies = re.findall(r'company-(\d+)', text) |
|
|
persons = re.findall(r'person-(\d+)', text) |
|
|
amounts = re.findall(r'amount-(\d+)', text) |
|
|
percents = re.findall(r'percent-(\d+)', text) |
|
|
|
|
|
validation_issues = [] |
|
|
|
|
|
|
|
|
for entity_type, indices in [ |
|
|
("company", companies), |
|
|
("person", persons), |
|
|
("amount", amounts), |
|
|
("percent", percents) |
|
|
]: |
|
|
if indices: |
|
|
unique_indices = sorted(list(set([int(x) for x in indices]))) |
|
|
|
|
|
if unique_indices[0] != 1: |
|
|
validation_issues.append(f"اندیس {entity_type} از 01 شروع نشده (شروع: {unique_indices[0]:02d})") |
|
|
|
|
|
|
|
|
expected = list(range(1, len(unique_indices) + 1)) |
|
|
if unique_indices != expected: |
|
|
validation_issues.append(f"اندیسهای {entity_type} پیوسته نیستند: {[f'{x:02d}' for x in unique_indices]}") |
|
|
|
|
|
|
|
|
english_words = re.findall(r'\b[a-zA-Z]+\b', text) |
|
|
unwanted_english = [word for word in english_words if word.lower() not in ['eps', 'p/e', 'arpu', 'npl', 'roe', 'roa']] |
|
|
if unwanted_english: |
|
|
validation_issues.append(f"کلمات انگلیسی غیرضروری: {unwanted_english}") |
|
|
|
|
|
return { |
|
|
"is_valid": len(validation_issues) == 0, |
|
|
"issues": validation_issues, |
|
|
"entity_counts": { |
|
|
"company": len(set(companies)), |
|
|
"person": len(set(persons)), |
|
|
"amount": len(set(amounts)), |
|
|
"percent": len(set(percents)) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def create_advanced_interface(): |
|
|
"""ایجاد رابط کاربری پیشرفته""" |
|
|
|
|
|
api_key_available = bool(os.getenv("CEREBRAS_API_KEY")) |
|
|
|
|
|
custom_css = """ |
|
|
.gradio-container { |
|
|
font-family: 'Tahoma', 'Arial', sans-serif !important; |
|
|
direction: rtl; |
|
|
max-width: 1400px; |
|
|
margin: 0 auto; |
|
|
} |
|
|
.result-box { |
|
|
background-color: #f8f9fa; |
|
|
border: 2px solid #e9ecef; |
|
|
border-radius: 12px; |
|
|
padding: 20px; |
|
|
margin: 10px 0; |
|
|
} |
|
|
.warning-box { |
|
|
background-color: #fff3cd; |
|
|
border: 2px solid #ffeaa7; |
|
|
border-radius: 12px; |
|
|
padding: 15px; |
|
|
color: #856404; |
|
|
margin: 10px 0; |
|
|
} |
|
|
.success-box { |
|
|
background-color: #d4edda; |
|
|
border: 2px solid #c3e6cb; |
|
|
border-radius: 12px; |
|
|
padding: 15px; |
|
|
color: #155724; |
|
|
margin: 10px 0; |
|
|
} |
|
|
.qwen-box { |
|
|
background-color: #e7f3ff; |
|
|
border: 2px solid #2196F3; |
|
|
border-radius: 12px; |
|
|
padding: 15px; |
|
|
color: #0d47a1; |
|
|
margin: 10px 0; |
|
|
} |
|
|
.stats-grid { |
|
|
display: grid; |
|
|
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); |
|
|
gap: 15px; |
|
|
margin: 15px 0; |
|
|
} |
|
|
.stat-card { |
|
|
background-color: #ffffff; |
|
|
border: 1px solid #dee2e6; |
|
|
border-radius: 8px; |
|
|
padding: 15px; |
|
|
text-align: center; |
|
|
box-shadow: 0 2px 4px rgba(0,0,0,0.1); |
|
|
} |
|
|
.quality-badge { |
|
|
display: inline-block; |
|
|
padding: 5px 10px; |
|
|
border-radius: 20px; |
|
|
font-weight: bold; |
|
|
margin: 5px; |
|
|
} |
|
|
.quality-pass { |
|
|
background-color: #28a745; |
|
|
color: white; |
|
|
} |
|
|
.quality-fail { |
|
|
background-color: #dc3545; |
|
|
color: white; |
|
|
} |
|
|
""" |
|
|
|
|
|
with gr.Blocks(css=custom_css, title="ناشناسساز پیشرفته با Qwen 3-32B", theme=gr.themes.Soft()) as interface: |
|
|
|
|
|
gr.Markdown(""" |
|
|
# 🔒 سیستم پیشرفته ناشناسسازی متون مالی/خبری فارسی |
|
|
### ⚡ قدرتگرفته از Cerebras AI + Alibaba Qwen 3-32B |
|
|
""") |
|
|
|
|
|
gr.Markdown(""" |
|
|
<div class="qwen-box"> |
|
|
🚀 <strong>مدل: Alibaba Qwen 3-32B (اصلاح شده)</strong><br> |
|
|
⚡ سرعت: 2,400 توکن/ثانیه | 🧠 32B پارامتر | 💰 $0.40/$0.80<br> |
|
|
✅ <strong>بهینهسازی شده:</strong> Thinking Mode غیرفعال برای خروجی مستقیم |
|
|
</div> |
|
|
""") |
|
|
|
|
|
if api_key_available: |
|
|
gr.Markdown(""" |
|
|
<div class="success-box"> |
|
|
✅ <strong>سیستم آماده است</strong> - کلید API تنظیم شده |
|
|
</div> |
|
|
""") |
|
|
api_key_input = gr.Textbox(visible=False, value="") |
|
|
else: |
|
|
gr.Markdown(""" |
|
|
<div class="warning-box"> |
|
|
⚠️ <strong>کلید API تنظیم نشده</strong><br> |
|
|
لطفاً کلید Cerebras API خود را وارد کنید |
|
|
</div> |
|
|
""") |
|
|
api_key_input = gr.Textbox( |
|
|
label="🔑 کلید Cerebras API", |
|
|
placeholder="csk-...", |
|
|
type="password" |
|
|
) |
|
|
|
|
|
with gr.Row(): |
|
|
with gr.Column(scale=1): |
|
|
input_text = gr.Textbox( |
|
|
label="📝 متن ورودی", |
|
|
placeholder="متن مالی یا خبری خود را اینجا وارد کنید...", |
|
|
lines=12, |
|
|
max_lines=25 |
|
|
) |
|
|
|
|
|
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=12, |
|
|
max_lines=25, |
|
|
elem_classes=["result-box"] |
|
|
) |
|
|
|
|
|
copy_btn = gr.Button( |
|
|
"📋 کپی متن", |
|
|
variant="secondary", |
|
|
size="sm" |
|
|
) |
|
|
|
|
|
copy_output = gr.Textbox( |
|
|
label="📋 متن برای کپی", |
|
|
lines=3, |
|
|
visible=False, |
|
|
interactive=True |
|
|
) |
|
|
|
|
|
with gr.Row(): |
|
|
with gr.Column(): |
|
|
statistics_output = gr.Markdown(label="📊 آمار کلی") |
|
|
with gr.Column(): |
|
|
quality_output = gr.Markdown(label="✅ کنترل کیفیت") |
|
|
|
|
|
with gr.Row(): |
|
|
with gr.Column(): |
|
|
entities_output = gr.Markdown(label="🏷️ موجودیتها") |
|
|
with gr.Column(): |
|
|
detailed_analysis_output = gr.Markdown(label="🔍 تحلیل دقیق") |
|
|
|
|
|
usage_output = gr.Markdown(label="⚡ اطلاعات پردازش") |
|
|
|
|
|
def process_advanced_text(text: str, api_key_manual: str = ""): |
|
|
"""پردازش متن""" |
|
|
if api_key_manual is None: |
|
|
api_key_manual = "" |
|
|
|
|
|
final_api_key = "" |
|
|
if api_key_manual and api_key_manual.strip(): |
|
|
final_api_key = api_key_manual.strip() |
|
|
elif os.getenv("CEREBRAS_API_KEY"): |
|
|
final_api_key = os.getenv("CEREBRAS_API_KEY") |
|
|
|
|
|
if not final_api_key: |
|
|
return ("", "❌ کلید API وارد نشده است", "", "", "", "") |
|
|
|
|
|
if not text or not text.strip(): |
|
|
return ("", "❌ لطفاً متن ورودی را وارد کنید", "", "", "", "") |
|
|
|
|
|
try: |
|
|
anonymizer = AdvancedCerebrasAnonymizer(api_key=final_api_key) |
|
|
result = anonymizer.anonymize_text(text) |
|
|
|
|
|
if not result["success"]: |
|
|
return ("", f"❌ خطا: {result['error']}", "", "", "", "") |
|
|
|
|
|
stats = result.get("statistics", {}) |
|
|
stats_md = f"""📊 **آمار کلی:** |
|
|
|
|
|
<div class="stats-grid"> |
|
|
<div class="stat-card"><h3>🏢 شرکتها</h3><h2>{stats.get('company', 0)}</h2></div> |
|
|
<div class="stat-card"><h3>👤 اشخاص</h3><h2>{stats.get('person', 0)}</h2></div> |
|
|
<div class="stat-card"><h3>💰 مبالغ</h3><h2>{stats.get('amount', 0)}</h2></div> |
|
|
<div class="stat-card"><h3>📊 درصدها</h3><h2>{stats.get('percent', 0)}</h2></div> |
|
|
<div class="stat-card"><h3>🔢 کل</h3><h2>{stats.get('total_replacements', 0)}</h2></div> |
|
|
</div> |
|
|
""" |
|
|
|
|
|
quality = result.get("quality_check", {}) |
|
|
quality_md = "✅ **کنترل کیفیت:**\n\n" |
|
|
|
|
|
if quality.get("is_valid", False): |
|
|
quality_md += '<span class="quality-badge quality-pass">✅ موفق</span>\n\n' |
|
|
else: |
|
|
quality_md += '<span class="quality-badge quality-fail">❌ مشکل</span>\n\n' |
|
|
issues = quality.get("issues", []) |
|
|
if issues: |
|
|
quality_md += "**مشکلات:**\n" |
|
|
for issue in issues: |
|
|
quality_md += f"• {issue}\n" |
|
|
|
|
|
entities = result.get("entities", {}) |
|
|
entities_md = "🏷️ **موجودیتها:**\n\n" |
|
|
|
|
|
if entities.get("companies"): |
|
|
entities_md += f"🏢 company-{', company-'.join(entities['companies'])}\n\n" |
|
|
if entities.get("persons"): |
|
|
entities_md += f"👤 person-{', person-'.join(entities['persons'])}\n\n" |
|
|
if entities.get("amounts"): |
|
|
entities_md += f"💰 amount-{', amount-'.join(entities['amounts'])}\n\n" |
|
|
if entities.get("percents"): |
|
|
entities_md += f"📊 percent-{', percent-'.join(entities['percents'])}\n\n" |
|
|
|
|
|
detailed = result.get("detailed_analysis", {}) |
|
|
detailed_md = f"""🔍 **تحلیل:** |
|
|
|
|
|
📅 تاریخ: {detailed.get('preserved_dates', 0)} |
|
|
📈 شاخصها: {detailed.get('financial_indicators', 0)} |
|
|
📏 واحدها: {detailed.get('units_preserved', 0)} |
|
|
""" |
|
|
|
|
|
usage = result.get("usage", {}) |
|
|
usage_md = f"""⚡ **Qwen 3-32B:** |
|
|
|
|
|
🤖 مدل: {anonymizer.config.model} |
|
|
🌡️ Temperature: {anonymizer.config.temperature} |
|
|
📥 Input: {usage.get('prompt_tokens', '?')} |
|
|
📤 Output: {usage.get('completion_tokens', '?')} |
|
|
📊 Total: {usage.get('total_tokens', '?')} |
|
|
""" |
|
|
|
|
|
return ( |
|
|
result["anonymized_text"], |
|
|
stats_md, |
|
|
quality_md, |
|
|
entities_md, |
|
|
detailed_md, |
|
|
usage_md |
|
|
) |
|
|
|
|
|
except Exception as e: |
|
|
return ("", f"❌ خطا: {str(e)}", "", "", "", "") |
|
|
|
|
|
def copy_text(text_to_copy): |
|
|
if not text_to_copy or not text_to_copy.strip(): |
|
|
return gr.Textbox(visible=False), "⚠️ متن خالی" |
|
|
return gr.Textbox(value=text_to_copy, visible=True), "✅ آماده کپی" |
|
|
|
|
|
def clear_all(): |
|
|
return "", "", "", "", "", "", "", gr.Textbox(visible=False) |
|
|
|
|
|
anonymize_btn.click( |
|
|
fn=process_advanced_text, |
|
|
inputs=[input_text, api_key_input], |
|
|
outputs=[output_text, statistics_output, quality_output, entities_output, detailed_analysis_output, usage_output] |
|
|
) |
|
|
|
|
|
copy_btn.click( |
|
|
fn=copy_text, |
|
|
inputs=[output_text], |
|
|
outputs=[copy_output, statistics_output] |
|
|
) |
|
|
|
|
|
clear_btn.click( |
|
|
fn=clear_all, |
|
|
outputs=[input_text, output_text, statistics_output, quality_output, entities_output, detailed_analysis_output, usage_output, copy_output] |
|
|
) |
|
|
|
|
|
gr.Examples( |
|
|
examples=[ |
|
|
["ایران خودرو در اسفندماه سال 1402 حدود 23 هزار و 296 میلیارد تومان درآمد کسب کرد که در مقایسه با بهمن 4.58 درصد افزایش داشت."], |
|
|
["مجمع پتروشیمی بوعلی سینا برگزار شد. وانیا نیک تدبیر را بازرس قانونی انتخاب کردند."], |
|
|
["شرکت فولاد مبارکه اصفهان با ملی نفت قرارداد امضا کرد. فاما سرمایه را از 8700 به 12500 میلیارد افزایش میدهد."] |
|
|
], |
|
|
inputs=input_text, |
|
|
label="📚 مثالها" |
|
|
) |
|
|
|
|
|
with gr.Accordion("📖 راهنما", open=False): |
|
|
gr.Markdown(""" |
|
|
## 🔧 اصلاحات انجام شده: |
|
|
|
|
|
### ✅ مشکل حل شده: |
|
|
- غیرفعال کردن Thinking Mode با `/no_think` |
|
|
- حذف خودکار تگهای `<think>` |
|
|
- پاکسازی توضیحات اضافی |
|
|
- کاهش Temperature به 0.3 برای دقت بیشتر |
|
|
|
|
|
### 🎯 چگونه کار میکند: |
|
|
1. پرامپت بهینه شده برای خروجی مستقیم |
|
|
2. اضافه کردن `/no_think` به انتهای درخواست |
|
|
3. پردازش و پاکسازی خودکار خروجی |
|
|
4. حذف تمام توضیحات و تگهای اضافی |
|
|
""") |
|
|
|
|
|
return interface |
|
|
|
|
|
if __name__ == "__main__": |
|
|
interface = create_advanced_interface() |
|
|
interface.launch( |
|
|
show_error=True, |
|
|
ssr_mode=False |
|
|
) |