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