import gradio as gr import logging import os from datetime import datetime from typing import Dict, List, Optional, Tuple from enhanced_legal_scraper import EnhancedLegalScraper, LegalDocument # Create log directory log_dir = '/app/logs' os.makedirs(log_dir, exist_ok=True) # Configure logging logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s', handlers=[ logging.FileHandler(os.path.join(log_dir, 'legal_scraper.log')), logging.StreamHandler() ] ) logger = logging.getLogger(__name__) class LegalScraperInterface: def __init__(self): self.scraper = EnhancedLegalScraper(delay=2.0) self.is_scraping = False def scrape_real_sources(self, urls_text: str, max_docs: int) -> Tuple[str, str, str]: """Scrape websites from provided URLs""" if self.is_scraping: return "❌ اسکراپینگ در حال انجام است", "", "" try: self.is_scraping = True urls = [url.strip() for url in urls_text.split('\n') if url.strip()] if not urls: # Use default sources if no URLs provided urls = [ "https://rc.majlis.ir", "https://dolat.ir", "https://iribnews.ir" ] documents = self.scraper.scrape_real_sources(urls, max_docs) status = f"✅ اسکراپینگ کامل شد - {len(documents)} سند جمع‌آوری شد" # Create summary summary_lines = [ f"📊 **خلاصه نتایج:**", f"- تعداد کل اسناد: {len(documents)}", f"- منابع پردازش شده: {len(urls)}", f"- زمان اسکراپینگ: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}", "", "📋 **جزئیات:**" ] for i, url in enumerate(urls): docs_from_url = [doc for doc in documents if url in doc.source_url] summary_lines.append(f"- {url}: {len(docs_from_url)} سند") summary = "\n".join(summary_lines) # Create preview 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)}" logger.error(error_msg) 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)}", "", "📈 **بر اساس نوع:**" ] type_names = { 'law': 'قوانین', 'news': 'اخبار', 'ruling': 'آرا', 'regulation': 'آیین‌نامه', 'general': 'عمومی' } for doc_type, count in stats.get('by_type', {}).items(): stats_lines.append(f"- {type_names.get(doc_type, doc_type)}: {count}") stats_text = "\n".join(stats_lines) # Create visualization viz_html = self._create_stats_visualization(stats) return stats_text, viz_html except Exception as e: error_msg = f"خطا در دریافت آمار: {str(e)}" logger.error(error_msg) return error_msg, "" def _create_stats_visualization(self, stats: Dict) -> str: """Create visualization for statistics""" try: import plotly.express as px import pandas as pd 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) -> str: """Search in collected documents""" if not query.strip(): return "لطفاً کلیدواژه‌ای برای جستجو وارد کنید" try: results = self.scraper.search_with_similarity(query, limit=10) if not results: return f"هیچ سندی با کلیدواژه '{query}' یافت نشد" result_lines = [f"🔍 **نتایج جستجو برای '{query}':** ({len(results)} مورد یافت شد)\n"] for i, result in enumerate(results, 1): result_lines.extend([ f"**{i}. {result['title']}**", f" نوع: {result['document_type']}", f" امتیاز شباهت: {result.get('similarity_score', 0):.3f}", f" منبع: {result['source_url']}", f" خلاصه: {result.get('summary', 'ندارد')[:100]}...", "---" ]) return "\n".join(result_lines) except Exception as e: error_msg = f"خطا در جستجو: {str(e)}" logger.error(error_msg) return error_msg def export_data(self) -> Tuple[str, str]: """Export collected data""" try: filename = f"/app/data/legal_documents_{datetime.now().strftime('%Y%m%d_%H%M%S')}.csv" success = self.scraper.export_to_csv(filename) if success: return f"✅ فایل با موفقیت تولید شد: {filename}", filename else: return "❌ خطا در تولید فایل", "" except Exception as e: error_msg = f"❌ خطا در export: {str(e)}" logger.error(error_msg) return error_msg, "" def create_interface(): 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 app: gr.HTML("""

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

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

""") with gr.Tab("🕷️ اسکراپینگ"): gr.Markdown("## جمع‌آوری اسناد از منابع وب") with gr.Row(): with gr.Column(scale=2): urls_input = gr.Textbox( label="📝 URL های منابع", placeholder="هر URL را در یک خط وارد کنید (اختیاری):\nhttps://example.com\nhttps://example.org", lines=5, value="https://rc.majlis.ir\nhttps://dolat.ir\nhttps://iribnews.ir" ) max_docs = gr.Slider( label="حداکثر اسناد", minimum=5, maximum=50, value=10, step=5 ) scrape_btn = gr.Button("🚀 شروع اسکراپینگ", variant="primary") with gr.Column(scale=1): status_output = gr.Textbox( label="⚡ وضعیت", interactive=False, lines=3 ) with gr.Row(): summary_output = gr.Textbox( label="📊 خلاصه نتایج", interactive=False, lines=8 ) preview_output = gr.Textbox( label="👁️ پیش‌نمایش", interactive=False, lines=8 ) scrape_btn.click( fn=interface.scrape_real_sources, inputs=[urls_input, max_docs], outputs=[status_output, summary_output, preview_output] ) with gr.Tab("🔍 جستجو"): gr.Markdown("## جستجو در اسناد جمع‌آوری شده") search_input = gr.Textbox( label="🔍 کلیدواژه جستجو", placeholder="کلیدواژه مورد نظر را وارد کنید..." ) search_btn = gr.Button("🔍 جستجو", variant="primary") search_results = gr.Textbox( label="📋 نتایج جستجو", interactive=False, lines=15 ) search_btn.click( fn=interface.search_documents, inputs=[search_input], 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=12 ) stats_plot = gr.HTML( label="📊 نمودارها" ) stats_btn.click( fn=interface.get_database_stats, outputs=[stats_text, stats_plot] ) with gr.Tab("💾 خروجی"): gr.Markdown("## ذخیره‌سازی داده‌ها") export_btn = gr.Button("💾 خروجی CSV", variant="primary") export_status = gr.Textbox( label="📝 وضعیت", interactive=False ) export_file = gr.File( label="📁 فایل خروجی", visible=False ) export_btn.click( fn=interface.export_data, outputs=[export_status, export_file] ) with gr.Tab("📚 راهنما"): gr.Markdown(""" # 🕷️ راهنمای اسکراپر اسناد حقوقی ## ویژگی‌ها - جمع‌آوری هوشمند اسناد از منابع وب - پردازش زبان طبیعی برای متون فارسی - جستجوی پیشرفته با تحلیل معنایی - آمار و نمودارهای تحلیلی - خروجی در قالب CSV ## نحوه استفاده 1. در تب "اسکراپینگ" URL منابع را وارد کنید 2. دکمه "شروع اسکراپینگ" را بزنید 3. از تب "جستجو" برای یافتن اسناد استفاده کنید 4. آمار را در تب مربوطه مشاهده کنید ## منابع پیشنهادی - مجلس شورای اسلامی - پورتال دولت - خبرگزاری‌های معتبر ⚠️ **تذکر**: این ابزار برای مقاصد آموزشی و پژوهشی ارائه شده است. """) return app def main(): """Main entry point for Hugging Face Spaces""" 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 and launch interface interface = create_interface() interface.launch( server_name="0.0.0.0", server_port=7860, share=False, show_error=True, debug=False ) if __name__ == "__main__": main()