Spaces:
Paused
Paused
import gradio as gr | |
import os | |
import sys | |
from pathlib import Path | |
# اضافه کردن مسیر فعلی به sys.path | |
sys.path.insert(0, str(Path(__file__).parent)) | |
# ایمپورت رابط اسکراپر | |
from enhanced_legal_scraper import EnhancedLegalScraper, LegalDocument | |
import pandas as pd | |
import sqlite3 | |
import json | |
from datetime import datetime | |
from typing import List, Dict, Tuple | |
import plotly.express as px | |
class LegalScraperInterface: | |
"""Gradio interface for enhanced legal scraper""" | |
def __init__(self): | |
self.scraper = EnhancedLegalScraper(delay=1.5) | |
self.is_scraping = False | |
def scrape_websites(self, urls_text: str, max_docs: int) -> Tuple[str, str, str]: | |
"""Scrape websites from provided URLs""" | |
if self.is_scraping: | |
return "❌ اسکراپینگ در حال انجام است", "", "" | |
urls = [url.strip() for url in urls_text.split('\n') if url.strip()] | |
if not urls: | |
return "❌ لطفاً URL وارد کنید", "", "" | |
try: | |
self.is_scraping = True | |
documents = self.scraper.scrape_real_sources(urls, max_docs) | |
status = f"✅ اسکراپینگ کامل شد - {len(documents)} سند جمعآوری شد" | |
summary_lines = [ | |
f"📊 **خلاصه نتایج:**", | |
f"- تعداد کل اسناد: {len(documents)}", | |
f"- منابع پردازش شده: {len(urls)}", | |
f"- زمان اسکراپینگ: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}", | |
"", | |
"📋 **جزئیات:**" | |
] | |
for i, doc in enumerate(documents[:5]): | |
summary_lines.append(f"{i+1}. {doc.title[:50]}...") | |
summary = "\n".join(summary_lines) | |
preview_lines = [] | |
for doc in documents[:3]: | |
preview_lines.extend([ | |
f"**{doc.title}**", | |
f"نوع: {doc.document_type}", | |
f"منبع: {doc.source_url}", | |
f"امتیاز اهمیت: {doc.importance_score:.2f}", | |
f"خلاصه: {doc.summary[:100]}..." if doc.summary else "بدون خلاصه", | |
"---" | |
]) | |
preview = "\n".join(preview_lines) if preview_lines else "هیچ سندی یافت نشد" | |
return status, summary, preview | |
except Exception as e: | |
error_msg = f"❌ خطا در اسکراپینگ: {str(e)}" | |
return error_msg, "", "" | |
finally: | |
self.is_scraping = False | |
def get_database_stats(self) -> Tuple[str, str]: | |
"""Get database statistics and visualizations""" | |
try: | |
stats = self.scraper.get_enhanced_statistics() | |
stats_lines = [ | |
"📊 **آمار پایگاه داده:**", | |
f"- کل اسناد: {stats.get('total_documents', 0)}", | |
"", | |
"📈 **بر اساس نوع:**" | |
] | |
for doc_type, count in stats.get('by_type', {}).items(): | |
type_name = { | |
'law': 'قوانین', | |
'news': 'اخبار', | |
'ruling': 'آرا', | |
'regulation': 'آییننامه', | |
'general': 'عمومی' | |
}.get(doc_type, doc_type) | |
stats_lines.append(f"- {type_name}: {count}") | |
stats_text = "\n".join(stats_lines) | |
viz_html = self._create_stats_visualization(stats) | |
return stats_text, viz_html | |
except Exception as e: | |
error_msg = f"خطا در دریافت آمار: {str(e)}" | |
return error_msg, "" | |
def _create_stats_visualization(self, stats: Dict) -> str: | |
"""Create visualization for statistics""" | |
try: | |
by_type = stats.get('by_type', {}) | |
if by_type and stats.get('total_documents', 0) > 0: | |
type_names = { | |
'law': 'قوانین', | |
'news': 'اخبار', | |
'ruling': 'آرا', | |
'regulation': 'آییننامه', | |
'general': 'عمومی' | |
} | |
labels = [type_names.get(k, k) for k in by_type.keys()] | |
values = list(by_type.values()) | |
fig = px.pie( | |
values=values, | |
names=labels, | |
title="توزیع اسناد بر اساس نوع" | |
) | |
fig.update_traces(textposition='inside', textinfo='percent+label') | |
return fig.to_html() | |
else: | |
return "<p>دادهای برای نمایش یافت نشد</p>" | |
except Exception as e: | |
return f"<p>خطا در ایجاد نمودار: {str(e)}</p>" | |
def search_documents(self, query: str, search_type: str) -> str: | |
"""Search in collected documents""" | |
if not query.strip(): | |
return "لطفاً کلیدواژهای برای جستجو وارد کنید" | |
try: | |
if search_type == "هوشمند": | |
results = self.scraper.search_with_similarity(query, limit=10) | |
else: | |
results = self.scraper._text_search(query, limit=10) | |
if not results: | |
return f"هیچ سندی با کلیدواژه '{query}' یافت نشد" | |
result_lines = [f"🔍 **نتایج جستجو برای '{query}':** ({len(results)} مورد یافت شد)\n"] | |
for i, result in enumerate(results): | |
result_lines.extend([ | |
f"**{i+1}. {result['title']}**", | |
f" نوع: {result['document_type']}", | |
f" منبع: {result['source_url']}", | |
f" امتیاز شباهت: {result.get('similarity_score', 0):.3f}" if 'similarity_score' in result else "", | |
f" تاریخ: {result['date_published'] or 'نامشخص'}", | |
f" خلاصه: {result['summary'][:100]}..." if result.get('summary') else "", | |
"---" | |
]) | |
return "\n".join(result_lines) | |
except Exception as e: | |
error_msg = f"خطا در جستجو: {str(e)}" | |
return error_msg | |
def create_scraper_interface(): | |
"""Create Gradio interface for legal scraper""" | |
scraper_interface = LegalScraperInterface() | |
css = """ | |
.gradio-container { | |
max-width: 1200px !important; | |
margin: auto; | |
font-family: 'Tahoma', sans-serif; | |
} | |
.header { | |
background: linear-gradient(135deg, #2c3e50, #3498db); | |
color: white; | |
padding: 20px; | |
border-radius: 10px; | |
text-align: center; | |
margin-bottom: 20px; | |
} | |
""" | |
with gr.Blocks(css=css, title="اسکراپر پیشرفته اسناد حقوقی", theme=gr.themes.Soft()) as interface: | |
gr.HTML(""" | |
<div class="header"> | |
<h1>🤖 اسکراپر پیشرفته اسناد حقوقی</h1> | |
<p>سیستم هوشمند جمعآوری و تحلیل اسناد حقوقی با قابلیتهای NLP</p> | |
</div> | |
""") | |
with gr.Tab("🕷️ اسکراپینگ"): | |
gr.Markdown("## جمعآوری اسناد از منابع حقوقی") | |
with gr.Row(): | |
with gr.Column(scale=2): | |
urls_input = gr.Textbox( | |
label="📝 URL های منابع حقوقی", | |
placeholder="هر URL را در یک خط وارد کنید:\nhttps://rc.majlis.ir\nhttps://dolat.ir", | |
lines=5, | |
value="\n".join([ | |
"https://rc.majlis.ir", | |
"https://dolat.ir", | |
"https://iribnews.ir" | |
]) | |
) | |
max_docs = gr.Slider( | |
label="حداکثر اسناد", | |
minimum=5, | |
maximum=50, | |
value=15, | |
step=5 | |
) | |
scrape_btn = gr.Button("🚀 شروع اسکراپینگ", variant="primary") | |
with gr.Column(scale=1): | |
status_output = gr.Textbox( | |
label="⚡ وضعیت", | |
interactive=False, | |
lines=2 | |
) | |
with gr.Row(): | |
summary_output = gr.Textbox( | |
label="📊 خلاصه نتایج", | |
interactive=False, | |
lines=6 | |
) | |
preview_output = gr.Textbox( | |
label="👁️ پیشنمایش اسناد", | |
interactive=False, | |
lines=6, | |
show_copy_button=True | |
) | |
scrape_btn.click( | |
fn=scraper_interface.scrape_websites, | |
inputs=[urls_input, max_docs], | |
outputs=[status_output, summary_output, preview_output] | |
) | |
with gr.Tab("🔍 جستجوی هوشمند"): | |
gr.Markdown("## جستجوی پیشرفته در اسناد") | |
with gr.Row(): | |
search_input = gr.Textbox( | |
label="🔍 کلیدواژه جستجو", | |
placeholder="موضوع یا کلیدواژه مورد نظر را وارد کنید..." | |
) | |
search_type = gr.Dropdown( | |
label="نوع جستجو", | |
choices=["هوشمند", "متنی"], | |
value="هوشمند" | |
) | |
search_btn = gr.Button("🔍 جستجو", variant="primary") | |
search_results = gr.Textbox( | |
label="📋 نتایج جستجو", | |
interactive=False, | |
lines=15, | |
show_copy_button=True | |
) | |
search_btn.click( | |
fn=scraper_interface.search_documents, | |
inputs=[search_input, search_type], | |
outputs=[search_results] | |
) | |
with gr.Tab("📊 آمار و تحلیل"): | |
gr.Markdown("## آمار پیشرفته پایگاه داده") | |
stats_btn = gr.Button("📊 بروزرسانی آمار", variant="secondary") | |
with gr.Row(): | |
stats_text = gr.Textbox( | |
label="📈 آمار متنی", | |
interactive=False, | |
lines=10 | |
) | |
stats_plot = gr.HTML( | |
label="📊 نمودارها" | |
) | |
stats_btn.click( | |
fn=scraper_interface.get_database_stats, | |
outputs=[stats_text, stats_plot] | |
) | |
with gr.Tab("📚 راهنما"): | |
gr.Markdown(""" | |
# 🤖 راهنمای اسکراپر پیشرفته | |
## ویژگیهای پیشرفته | |
### 🧠 پردازش زبان طبیعی (NLP) | |
- استخراج خودکار کلمات کلیدی | |
- تولید خلاصه متن | |
- تحلیل احساسات | |
- شناسایی موجودیتهای حقوقی | |
- جستجوی هوشمند بر اساس شباهت معنایی | |
### 📊 تحلیل پیشرفته | |
- امتیازدهی اهمیت اسناد | |
- طبقهبندی خودکار | |
- آمار و نمودارهای تحلیلی | |
- گزارشهای آماری | |
## منابع پیشنهادی | |
- **مجلس شورای اسلامی**: https://rc.majlis.ir | |
- **دولت**: https://dolat.ir | |
- **خبرگزاریها**: IRIB, IRNA, Tasnim, Mehr, Fars | |
## نکات فنی | |
- سیستم از فایل robots.txt پیروی میکند | |
- محدودیت سرعت درخواست رعایت میشود | |
- دادهها در پایگاه داده SQLite ذخیره میشوند | |
- از مدلهای هوش مصنوعی برای پردازش استفاده میشود | |
⚠️ **تذکر**: این ابزار برای مقاصد آموزشی و پژوهشی ارائه شده است. | |
""") | |
return interface | |
def main(): | |
"""Main entry point for Hugging Face Spaces""" | |
print("🚀 راه اندازی اسکراپر پیشرفته اسناد حقوقی...") | |
print("📁 ایجاد دایرکتوریهای مورد نیاز...") | |
# Create required directories | |
os.makedirs("/app/data", exist_ok=True) | |
os.makedirs("/app/logs", exist_ok=True) | |
os.makedirs("/app/cache", exist_ok=True) | |
# Create interface | |
interface = create_scraper_interface() | |
# Launch with Hugging Face optimized settings | |
interface.launch( | |
server_name="0.0.0.0", | |
server_port=7860, | |
share=False, | |
show_error=True, | |
debug=False, | |
enable_queue=True | |
) | |
if __name__ == "__main__": | |
main() |