Hoghoghi / app /enhanced_legal_scraper.py
Really-amin's picture
Upload 2 files
91a893c verified
raw
history blame
14.1 kB
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()