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 "

داده‌ای برای نمایش یافت نشد

" except Exception as e: return f"

خطا در ایجاد نمودار: {str(e)}

" 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("""

🤖 اسکراپر پیشرفته اسناد حقوقی

سیستم هوشمند جمع‌آوری و تحلیل اسناد حقوقی با قابلیت‌های NLP

""") 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()