🏛️ آرشیو هوشمند پیشرفته اسناد حقوقی ایران
سیستم جامع مجهز به هوش مصنوعی پیشرفته، کش هوشمند و کرالر خودکار
🧠 مدلهای SOTA فارسی | ⚡ کش هوشمند | 🎯 امتیازدهی پیشرفته | 🔄 کرالر خودکار
""" پلتفرم پیشرفته هوشمند اسناد حقوقی ایران - نسخه ارتقاء یافته مجهز به مدلهای SOTA فارسی، سیستم کش هوشمند و امتیازدهی پیشرفته """ import os import gc import sys import time import json import logging import hashlib import resource import requests import threading import re import random import sqlite3 import pickle from pathlib import Path from datetime import datetime, timedelta from typing import List, Dict, Any, Optional, Tuple, Union from dataclasses import dataclass, field from concurrent.futures import ThreadPoolExecutor, as_completed, ProcessPoolExecutor from urllib.parse import urljoin, urlparse import warnings import asyncio from functools import lru_cache import numpy as np import gradio as gr import pandas as pd import torch from bs4 import BeautifulSoup from transformers import ( AutoTokenizer, AutoModelForSequenceClassification, pipeline, logging as transformers_logging, AutoModel ) from sentence_transformers import SentenceTransformer, util from hazm import Normalizer, word_tokenize, Lemmatizer import faiss # === تنظیمات اولیه پیشرفته === warnings.filterwarnings('ignore') transformers_logging.set_verbosity_error() try: resource.setrlimit(resource.RLIMIT_AS, (4*1024*1024*1024, 4*1024*1024*1024)) except: pass os.environ.update({ 'TRANSFORMERS_CACHE': '/tmp/hf_cache', 'HF_HOME': '/tmp/hf_cache', 'TORCH_HOME': '/tmp/torch_cache', 'TOKENIZERS_PARALLELISM': 'false', 'CUDA_VISIBLE_DEVICES': '0' if torch.cuda.is_available() else '' }) logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') logger = logging.getLogger(__name__) # === ثابتهای سیستم === DB_PATH = "data/iranian_legal_archive_advanced.sqlite" CACHE_DB_PATH = "data/cache_system.sqlite" EMBEDDINGS_CACHE_PATH = "data/embeddings_cache.pkl" VECTOR_INDEX_PATH = "data/faiss_index.bin" SVG_ICONS = { 'search': '🔍', 'document': '📄', 'analyze': '🤖', 'export': '📊', 'settings': '⚙️', 'link': '🔗', 'success': '✅', 'error': '❌', 'warning': '⚠️', 'database': '🗄️', 'crawler': '🔄', 'brain': '🧠', 'cache': '⚡', 'score': '📈', 'classify': '🏷️', 'similarity': '🎯' } # منابع حقوقی با پیکربندی پیشرفته LEGAL_SOURCES = { "مجلس شورای اسلامی": { "base_url": "https://rc.majlis.ir", "patterns": ["/fa/law/show/", "/fa/report/show/"], "selectors": [".main-content", ".article-body", "article"], "delay_range": (2, 5), "priority": 1, "reliability_score": 0.95 }, "پورتال ملی قوانین": { "base_url": "https://www.dotic.ir", "patterns": ["/portal/law/", "/regulation/"], "selectors": [".content-area", ".law-content"], "delay_range": (1, 4), "priority": 1, "reliability_score": 0.90 }, "قوه قضاییه": { "base_url": "https://www.judiciary.ir", "patterns": ["/fa/news/", "/fa/verdict/"], "selectors": [".news-content", ".main-content"], "delay_range": (3, 6), "priority": 2, "reliability_score": 0.85 }, "وزارت دادگستری": { "base_url": "https://www.moj.ir", "patterns": ["/fa/news/", "/fa/regulation/"], "selectors": [".content-area", ".news-content"], "delay_range": (2, 4), "priority": 2, "reliability_score": 0.80 } } # واژگان تخصصی حقوقی گسترده PERSIAN_LEGAL_TERMS = { "قوانین_اساسی": ["قانون اساسی", "مجلس شورای اسلامی", "شورای نگهبان", "ولایت فقیه", "اصول قانون اساسی"], "قوانین_عادی": ["ماده", "تبصره", "فصل", "باب", "قانون مدنی", "قانون جزا", "قانون تجارت", "قانون کار"], "اصطلاحات_حقوقی": ["شخص حقیقی", "شخص حقوقی", "دعوا", "خواهان", "خوانده", "مجازات", "قرارداد", "تعهد"], "نهادهای_قضایی": ["دادگاه", "قاضی", "وکیل", "مدعیالعموم", "رای", "حکم", "دادنامه", "قرار"], "اصطلاحات_مالی": ["مالیات", "عوارض", "جریمه", "خسارت", "تأمین", "ضمانت", "وثیقه", "دیه"], "جرائم": ["جنایت", "جنحه", "تخلف", "قصاص", "دیه", "تعزیر", "حدود", "قذف"] } # مدلهای SOTA پیشنهادی AVAILABLE_MODELS = { "classification": { "fabert": "sbunlp/fabert", "parsbert": "HooshvareLab/bert-base-parsbert-uncased", "legal_roberta": "lexlms/legal-roberta-base" }, "embedding": { "maux_gte": "xmanii/maux-gte-persian", "sentence_transformer": "sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2" }, "ner": { "parsbert_ner": "HooshvareLab/bert-fa-base-uncased-ner" } } @dataclass class ProcessingResult: """نتیجه پردازش سند""" url: str title: str content: str source: str quality_score: float classification: Dict[str, float] sentiment_score: float legal_entities: List[str] embeddings: Optional[np.ndarray] processing_time: float cache_hit: bool = False @dataclass class SystemMetrics: """متریکهای عملکرد سیستم""" total_processed: int = 0 cache_hits: int = 0 classification_accuracy: float = 0.0 avg_processing_time: float = 0.0 memory_usage: float = 0.0 active_crawlers: int = 0 # === سیستم کش هوشمند === class IntelligentCacheSystem: """سیستم کش هوشمند با TTL و اولویتبندی""" def __init__(self, cache_db_path: str = CACHE_DB_PATH): self.cache_db_path = cache_db_path self.memory_cache = {} self.access_count = {} self.max_memory_items = 1000 self._init_database() def _init_database(self): """ایجاد پایگاه داده کش""" os.makedirs(os.path.dirname(self.cache_db_path), exist_ok=True) with sqlite3.connect(self.cache_db_path) as conn: conn.execute(''' CREATE TABLE IF NOT EXISTS cache_entries ( key TEXT PRIMARY KEY, value BLOB, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, access_count INTEGER DEFAULT 1, ttl_seconds INTEGER DEFAULT 3600, priority INTEGER DEFAULT 1 ) ''') conn.execute(''' CREATE INDEX IF NOT EXISTS idx_created_ttl ON cache_entries(created_at, ttl_seconds) ''') def _generate_key(self, url: str, model_type: str = "general") -> str: """تولید کلید یکتا برای کش""" content = f"{url}:{model_type}" return hashlib.md5(content.encode()).hexdigest() def get(self, url: str, model_type: str = "general") -> Optional[Dict]: """دریافت از کش با بررسی TTL""" key = self._generate_key(url, model_type) # بررسی memory cache if key in self.memory_cache: self.access_count[key] = self.access_count.get(key, 0) + 1 return self.memory_cache[key] # بررسی database cache with sqlite3.connect(self.cache_db_path) as conn: cursor = conn.execute(''' SELECT value, created_at, ttl_seconds, access_count FROM cache_entries WHERE key = ? ''', (key,)) row = cursor.fetchone() if row: value_blob, created_at, ttl_seconds, access_count = row created_time = datetime.fromisoformat(created_at) # بررسی انقضاء if datetime.now() - created_time < timedelta(seconds=ttl_seconds): # بروزرسانی شمارنده دسترسی conn.execute( 'UPDATE cache_entries SET access_count = access_count + 1 WHERE key = ?', (key,) ) # اضافه به memory cache value = pickle.loads(value_blob) self._add_to_memory_cache(key, value) return value else: # حذف entry منقضی conn.execute('DELETE FROM cache_entries WHERE key = ?', (key,)) return None def set(self, url: str, value: Dict, model_type: str = "general", ttl_seconds: int = 3600, priority: int = 1): """ذخیره در کش""" key = self._generate_key(url, model_type) # ذخیره در memory cache self._add_to_memory_cache(key, value) # ذخیره در database with sqlite3.connect(self.cache_db_path) as conn: value_blob = pickle.dumps(value) conn.execute(''' INSERT OR REPLACE INTO cache_entries (key, value, ttl_seconds, priority) VALUES (?, ?, ?, ?) ''', (key, value_blob, ttl_seconds, priority)) def _add_to_memory_cache(self, key: str, value: Dict): """اضافه کردن به memory cache با مدیریت حد""" if len(self.memory_cache) >= self.max_memory_items: # حذف کماستفادهترین item least_used_key = min(self.access_count.keys(), key=self.access_count.get) del self.memory_cache[least_used_key] del self.access_count[least_used_key] self.memory_cache[key] = value self.access_count[key] = self.access_count.get(key, 0) + 1 def cleanup_expired(self): """پاکسازی entries منقضی""" with sqlite3.connect(self.cache_db_path) as conn: conn.execute(''' DELETE FROM cache_entries WHERE datetime(created_at, '+' || ttl_seconds || ' seconds') < datetime('now') ''') def get_stats(self) -> Dict: """آمار کش""" with sqlite3.connect(self.cache_db_path) as conn: cursor = conn.execute(''' SELECT COUNT(*) as total_entries, SUM(access_count) as total_accesses, AVG(access_count) as avg_accesses FROM cache_entries ''') stats = cursor.fetchone() return { 'memory_cache_size': len(self.memory_cache), 'database_entries': stats[0] if stats[0] else 0, 'total_accesses': stats[1] if stats[1] else 0, 'average_accesses': round(stats[2], 2) if stats[2] else 0 } # === سیستم امتیازدهی پیشرفته === class AdvancedScoringSystem: """سیستم امتیازدهی پیشرفته با وزندهی چندگانه""" def __init__(self): self.weights = { 'content_length': 0.15, 'legal_terms_density': 0.25, 'source_reliability': 0.20, 'structure_quality': 0.15, 'linguistic_quality': 0.15, 'citation_count': 0.10 } self.normalizer = Normalizer() self.lemmatizer = Lemmatizer() def calculate_comprehensive_score(self, content: str, source_info: Dict, legal_entities: List[str]) -> Dict[str, float]: """محاسبه امتیاز جامع""" scores = {} # امتیاز طول محتوا scores['content_length'] = self._score_content_length(content) # تراکم اصطلاحات حقوقی scores['legal_terms_density'] = self._score_legal_terms_density(content) # قابلیت اعتماد منبع scores['source_reliability'] = source_info.get('reliability_score', 0.5) # کیفیت ساختار scores['structure_quality'] = self._score_structure_quality(content) # کیفیت زبانی scores['linguistic_quality'] = self._score_linguistic_quality(content) # تعداد ارجاعات scores['citation_count'] = self._score_citations(content, legal_entities) # محاسبه امتیاز نهایی final_score = sum( scores[factor] * self.weights[factor] for factor in scores ) scores['final_score'] = min(100, max(0, final_score * 100)) return scores def _score_content_length(self, content: str) -> float: """امتیازدهی بر اساس طول محتوا""" word_count = len(content.split()) if word_count < 50: return word_count / 50 * 0.5 elif word_count > 2000: return 1.0 else: return 0.5 + (word_count - 50) / 1950 * 0.5 def _score_legal_terms_density(self, content: str) -> float: """امتیازدهی تراکم اصطلاحات حقوقی""" total_terms = 0 content_lower = content.lower() for category, terms in PERSIAN_LEGAL_TERMS.items(): for term in terms: total_terms += content_lower.count(term.lower()) words = len(content.split()) if words == 0: return 0.0 density = total_terms / words return min(1.0, density * 20) # نرمالسازی def _score_structure_quality(self, content: str) -> float: """امتیازدهی کیفیت ساختار""" score = 0.0 # بررسی وجود ساختار مواد و تبصرهها if 'ماده' in content: score += 0.3 if 'تبصره' in content: score += 0.2 if 'فصل' in content or 'باب' in content: score += 0.2 # بررسی پاراگرافبندی paragraphs = content.split('\n') if len(paragraphs) > 2: score += 0.3 return min(1.0, score) def _score_linguistic_quality(self, content: str) -> float: """امتیازدهی کیفیت زبانی""" score = 0.0 # نسبت کاراکترهای فارسی persian_chars = sum(1 for c in content if '\u0600' <= c <= '\u06FF') persian_ratio = persian_chars / len(content) if content else 0 score += persian_ratio * 0.5 # بررسی وجود علائم نگارشی punctuation_count = sum(1 for c in content if c in '.,;:!؟') words_count = len(content.split()) if words_count > 0: punctuation_ratio = punctuation_count / words_count score += min(0.3, punctuation_ratio * 3) # بررسی طول متوسط جملات sentences = re.split(r'[.؟!]', content) if sentences: avg_sentence_length = sum(len(s.split()) for s in sentences) / len(sentences) if 10 <= avg_sentence_length <= 25: score += 0.2 return min(1.0, score) def _score_citations(self, content: str, legal_entities: List[str]) -> float: """امتیازدهی ارجاعات قانونی""" citation_patterns = [ r'ماده\s*\d+', r'تبصره\s*\d+', r'بند\s*\d+', r'فصل\s*\d+', r'قانون\s+[آ-ی\s]+', r'مصوبه\s+[آ-ی\s]+' ] total_citations = 0 for pattern in citation_patterns: total_citations += len(re.findall(pattern, content)) # اضافه کردن موجودیتهای قانونی total_citations += len(legal_entities) # نرمالسازی (هر 5 ارجاع = امتیاز کامل) return min(1.0, total_citations / 5) # === سیستم طبقهبندی هوشمند === class IntelligentClassificationSystem: """سیستم طبقهبندی هوشمند چندمرحلهای""" def __init__(self, cache_system: IntelligentCacheSystem): self.cache_system = cache_system self.models = {} self.is_ready = False # دستههای حقوقی self.legal_categories = { 'قانون': ['قانون', 'مقررات', 'آییننامه'], 'دادنامه': ['دادنامه', 'رای', 'حکم'], 'قرارداد': ['قرارداد', 'توافقنامه', 'پروتکل'], 'لایحه': ['لایحه', 'طرح', 'پیشنهاد'], 'بخشنامه': ['بخشنامه', 'دستورالعمل', 'رهنمود'], 'نظریه': ['نظریه', 'استعلام', 'پاسخ'] } def load_models(self): """بارگذاری مدلهای طبقهبندی""" try: # مدل اصلی طبقهبندی self.models['classifier'] = pipeline( "text-classification", model=AVAILABLE_MODELS['classification']['parsbert'], device=0 if torch.cuda.is_available() else -1, batch_size=8 if torch.cuda.is_available() else 2 ) # مدل تشخیص موجودیت self.models['ner'] = pipeline( "ner", model=AVAILABLE_MODELS['ner']['parsbert_ner'], device=0 if torch.cuda.is_available() else -1, aggregation_strategy="simple" ) # مدل embedding self.models['embedder'] = SentenceTransformer( AVAILABLE_MODELS['embedding']['maux_gte'] ) self.is_ready = True logger.info("تمام مدلهای طبقهبندی بارگذاری شدند") except Exception as e: logger.error(f"خطا در بارگذاری مدلها: {e}") self.is_ready = False def classify_document(self, content: str, use_cache: bool = True) -> Dict: """طبقهبندی هوشمند سند""" if not self.is_ready: return {'error': 'مدلها آماده نیستند'} # بررسی کش cache_key = hashlib.md5(content.encode()).hexdigest() if use_cache: cached = self.cache_system.get(cache_key, 'classification') if cached: cached['cache_hit'] = True return cached start_time = time.time() result = {} try: # متن نمونه برای پردازش text_sample = ' '.join(content.split()[:400]) # طبقهبندی با مدل ترنسفورمر if 'classifier' in self.models: classification = self.models['classifier'](text_sample) result['transformer_classification'] = classification[:3] # طبقهبندی بر اساس قوانین result['rule_based_classification'] = self._rule_based_classify(content) # تشخیص موجودیتها if 'ner' in self.models: entities = self.models['ner'](text_sample) result['named_entities'] = [ e for e in entities if e.get('score', 0) > 0.8 ][:10] # استخراج موجودیتهای حقوقی result['legal_entities'] = self._extract_legal_entities(content) # تولید embedding if 'embedder' in self.models: result['embedding'] = self.models['embedder'].encode(text_sample) # محاسبه اعتماد ترکیبی result['confidence_score'] = self._calculate_combined_confidence(result) result['processing_time'] = time.time() - start_time result['cache_hit'] = False # ذخیره در کش if use_cache: self.cache_system.set(cache_key, result, 'classification', ttl_seconds=7200) except Exception as e: logger.error(f"خطا در طبقهبندی: {e}") result['error'] = str(e) return result def _rule_based_classify(self, content: str) -> Dict[str, float]: """طبقهبندی بر اساس قوانین""" scores = {} content_lower = content.lower() for category, keywords in self.legal_categories.items(): score = 0.0 for keyword in keywords: count = content_lower.count(keyword.lower()) score += count * 0.1 scores[category] = min(1.0, score) # نرمالسازی امتیازها total_score = sum(scores.values()) if total_score > 0: scores = {k: v/total_score for k, v in scores.items()} return scores def _extract_legal_entities(self, content: str) -> List[str]: """استخراج موجودیتهای حقوقی""" entities = [] # الگوهای ارجاعات قانونی patterns = [ r'ماده\s*(\d+)', r'تبصره\s*(\d+)', r'بند\s*([الف-ی]|\d+)', r'فصل\s*(\d+)', r'قانون\s+([آ-ی\s]{5,50})', r'مصوبه\s+([آ-ی\s]{5,50})' ] for pattern in patterns: matches = re.findall(pattern, content) entities.extend(matches) return list(set(entities))[:20] def _calculate_combined_confidence(self, result: Dict) -> float: """محاسبه اعتماد ترکیبی""" confidence = 0.0 weights = {'transformer': 0.6, 'rule_based': 0.3, 'entities': 0.1} # اعتماد مدل ترنسفورمر if 'transformer_classification' in result: transformer_conf = result['transformer_classification'][0].get('score', 0) confidence += transformer_conf * weights['transformer'] # اعتماد طبقهبندی قانونی if 'rule_based_classification' in result: rule_conf = max(result['rule_based_classification'].values()) confidence += rule_conf * weights['rule_based'] # تعداد موجودیتهای قانونی entity_count = len(result.get('legal_entities', [])) entity_conf = min(1.0, entity_count / 5) confidence += entity_conf * weights['entities'] return round(confidence, 3) # === سیستم جستجوی معنایی پیشرفته === class SemanticSearchEngine: """موتور جستجوی معنایی با ایندکس FAISS""" def __init__(self, cache_system: IntelligentCacheSystem): self.cache_system = cache_system self.embedder = None self.faiss_index = None self.documents = [] self.document_embeddings = None self.is_ready = False def initialize(self): """مقداردهی اولیه موتور جستجو""" try: self.embedder = SentenceTransformer( AVAILABLE_MODELS['embedding']['maux_gte'] ) logger.info("مدل embedding بارگذاری شد") # بارگذاری ایندکس موجود در صورت وجود if os.path.exists(VECTOR_INDEX_PATH) and os.path.exists(EMBEDDINGS_CACHE_PATH): self._load_existing_index() self.is_ready = True except Exception as e: logger.error(f"خطا در مقداردهی موتور جستجو: {e}") def build_index(self, documents: List[Tuple], progress_callback=None): """ساخت ایندکس FAISS""" try: if not documents: return False if progress_callback: progress_callback("استخراج متون...", 0.1) self.documents = documents texts = [doc[3] for doc in documents if doc[3]] # content field if progress_callback: progress_callback(f"تولید embedding برای {len(texts)} سند...", 0.3) # تولید embeddings با batch processing batch_size = 16 all_embeddings = [] for i in range(0, len(texts), batch_size): batch = texts[i:i+batch_size] batch_embeddings = self.embedder.encode( batch, convert_to_tensor=True, show_progress_bar=False ) all_embeddings.append(batch_embeddings) if progress_callback: progress = 0.3 + (i / len(texts)) * 0.6 progress_callback(f"پردازش batch {i//batch_size + 1}...", progress) # ترکیب embeddings self.document_embeddings = torch.cat(all_embeddings, dim=0).cpu().numpy() if progress_callback: progress_callback("ساخت ایندکس FAISS...", 0.9) # ساخت ایندکس FAISS dimension = self.document_embeddings.shape[1] self.faiss_index = faiss.IndexFlatIP(dimension) # Inner Product for cosine similarity # نرمالسازی برای cosine similarity faiss.normalize_L2(self.document_embeddings) self.faiss_index.add(self.document_embeddings) # ذخیره ایندکس self._save_index() if progress_callback: progress_callback("تکمیل ایندکسسازی", 1.0) logger.info(f"ایندکس با {len(documents)} سند آماده شد") return True except Exception as e: logger.error(f"خطا در ساخت ایندکس: {e}") return False def search(self, query: str, top_k: int = 10, threshold: float = 0.3) -> List[Dict]: """جستجوی معنایی پیشرفته""" if not self.is_ready or self.faiss_index is None: return [] try: # بررسی کش cache_key = f"search:{hashlib.md5(query.encode()).hexdigest()}:{top_k}" cached = self.cache_system.get(cache_key, 'search') if cached: return cached # تولید embedding برای query query_embedding = self.embedder.encode([query], convert_to_tensor=True) query_embedding = query_embedding.cpu().numpy() faiss.normalize_L2(query_embedding) # جستجو در ایندکس similarities, indices = self.faiss_index.search(query_embedding, top_k * 2) results = [] for i, (similarity, idx) in enumerate(zip(similarities[0], indices[0])): if similarity < threshold: continue if idx < len(self.documents): doc = self.documents[idx] results.append({ 'rank': i + 1, 'document_id': doc[0], 'url': doc[1], 'title': doc[2], 'content_preview': doc[3][:300] + '...' if len(doc[3]) > 300 else doc[3], 'similarity_score': float(similarity), 'relevance_category': self._categorize_relevance(similarity) }) # مرتبسازی نهایی results = results[:top_k] # ذخیره در کش self.cache_system.set(cache_key, results, 'search', ttl_seconds=1800) return results except Exception as e: logger.error(f"خطا در جستجو: {e}") return [] def _categorize_relevance(self, similarity: float) -> str: """دستهبندی میزان ارتباط""" if similarity >= 0.8: return "بسیار مرتبط" elif similarity >= 0.6: return "مرتبط" elif similarity >= 0.4: return "نسبتاً مرتبط" else: return "کمارتباط" def _save_index(self): """ذخیره ایندکس و embeddings""" try: if self.faiss_index: faiss.write_index(self.faiss_index, VECTOR_INDEX_PATH) if self.document_embeddings is not None: with open(EMBEDDINGS_CACHE_PATH, 'wb') as f: pickle.dump({ 'embeddings': self.document_embeddings, 'documents_info': [(doc[0], doc[1], doc[2]) for doc in self.documents] }, f) logger.info("ایندکس ذخیره شد") except Exception as e: logger.error(f"خطا در ذخیره ایندکس: {e}") def _load_existing_index(self): """بارگذاری ایندکس موجود""" try: self.faiss_index = faiss.read_index(VECTOR_INDEX_PATH) with open(EMBEDDINGS_CACHE_PATH, 'rb') as f: cache_data = pickle.load(f) self.document_embeddings = cache_data['embeddings'] # بازسازی documents از اطلاعات ذخیره شده # نیاز به query از دیتابیس برای محتوای کامل logger.info("ایندکس موجود بارگذاری شد") except Exception as e: logger.error(f"خطا در بارگذاری ایندکس: {e}") # === مدیریت پایگاه داده پیشرفته === class AdvancedDatabaseManager: """مدیریت پیشرفته پایگاه داده با بهینهسازیهای جدید""" def __init__(self, db_path: str = DB_PATH): self.db_path = db_path os.makedirs(os.path.dirname(db_path), exist_ok=True) self._init_database() def _init_database(self): """ایجاد پایگاه داده با جداول پیشرفته""" with sqlite3.connect(self.db_path) as conn: # جدول اسناد اصلی conn.execute(''' CREATE TABLE IF NOT EXISTS documents ( id INTEGER PRIMARY KEY AUTOINCREMENT, url TEXT UNIQUE NOT NULL, title TEXT, source TEXT, content TEXT, word_count INTEGER, quality_scores TEXT, classification_result TEXT, legal_entities TEXT, embedding_vector BLOB, scraped_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP, processing_status TEXT DEFAULT 'pending' ) ''') # ایجاد ایندکسها برای جدول documents conn.execute('CREATE INDEX IF NOT EXISTS idx_documents_source ON documents(source)') conn.execute('CREATE INDEX IF NOT EXISTS idx_documents_scraped_at ON documents(scraped_at)') conn.execute('CREATE INDEX IF NOT EXISTS idx_documents_status ON documents(processing_status)') conn.execute('CREATE INDEX IF NOT EXISTS idx_documents_updated ON documents(last_updated)') # جدول متریکهای عملکرد conn.execute(''' CREATE TABLE IF NOT EXISTS performance_metrics ( id INTEGER PRIMARY KEY AUTOINCREMENT, metric_name TEXT, metric_value REAL, timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) ''') # ایندکسها برای جدول metrics conn.execute('CREATE INDEX IF NOT EXISTS idx_metrics_name ON performance_metrics(metric_name)') conn.execute('CREATE INDEX IF NOT EXISTS idx_metrics_timestamp ON performance_metrics(timestamp)') # جدول لاگهای پردازش conn.execute(''' CREATE TABLE IF NOT EXISTS processing_logs ( id INTEGER PRIMARY KEY AUTOINCREMENT, document_id INTEGER, operation TEXT, status TEXT, details TEXT, processing_time REAL, timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (document_id) REFERENCES documents (id) ) ''') # ایندکسها برای جدول logs conn.execute('CREATE INDEX IF NOT EXISTS idx_logs_operation ON processing_logs(operation)') conn.execute('CREATE INDEX IF NOT EXISTS idx_logs_status ON processing_logs(status)') conn.execute('CREATE INDEX IF NOT EXISTS idx_logs_timestamp ON processing_logs(timestamp)') conn.execute('CREATE INDEX IF NOT EXISTS idx_logs_document_id ON processing_logs(document_id)') def save_document_advanced(self, result: ProcessingResult) -> bool: """ذخیره پیشرفته سند""" try: with sqlite3.connect(self.db_path) as conn: # محاسبه embedding bytes embedding_blob = None if result.embeddings is not None: embedding_blob = result.embeddings.tobytes() conn.execute(''' INSERT OR REPLACE INTO documents (url, title, source, content, word_count, quality_scores, classification_result, legal_entities, embedding_vector, processing_status, last_updated) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 'completed', datetime('now')) ''', ( result.url, result.title, result.source, result.content, len(result.content.split()), json.dumps({'quality_score': result.quality_score}, ensure_ascii=False), json.dumps(result.classification, ensure_ascii=False), json.dumps(result.legal_entities, ensure_ascii=False), embedding_blob )) # ثبت لاگ document_id = conn.lastrowid conn.execute(''' INSERT INTO processing_logs (document_id, operation, status, processing_time) VALUES (?, 'save', 'success', ?) ''', (document_id, result.processing_time)) return True except Exception as e: logger.error(f"خطا در ذخیره پیشرفته: {e}") return False def get_documents_with_embeddings(self) -> List[Tuple]: """دریافت اسناد همراه با embeddings""" with sqlite3.connect(self.db_path) as conn: return conn.execute(''' SELECT id, url, title, content, embedding_vector FROM documents WHERE processing_status = 'completed' AND content IS NOT NULL ORDER BY last_updated DESC ''').fetchall() def get_advanced_stats(self) -> Dict: """آمار پیشرفته سیستم""" with sqlite3.connect(self.db_path) as conn: # آمار کلی total_docs = conn.execute("SELECT COUNT(*) FROM documents").fetchone()[0] # آمار بر اساس منبع source_stats = conn.execute(''' SELECT source, COUNT(*), AVG(word_count) FROM documents GROUP BY source ORDER BY COUNT(*) DESC ''').fetchall() # آمار عملکرد avg_processing_time = conn.execute(''' SELECT AVG(processing_time) FROM processing_logs WHERE operation = 'save' AND status = 'success' ''').fetchone()[0] or 0 # آمار وضعیت پردازش status_stats = conn.execute(''' SELECT processing_status, COUNT(*) FROM documents GROUP BY processing_status ''').fetchall() return { 'total_documents': total_docs, 'source_statistics': source_stats, 'average_processing_time': round(avg_processing_time, 2), 'status_statistics': status_stats, 'last_updated': datetime.now().isoformat() } # === کرالر خودکار پیشرفته === class AdvancedCrawlerSystem: """سیستم کرالر خودکار با قابلیتهای هوشمند""" def __init__(self, scraper, db_manager: AdvancedDatabaseManager, classification_system: IntelligentClassificationSystem): self.scraper = scraper self.db_manager = db_manager self.classification_system = classification_system self.is_active = False self.crawler_stats = SystemMetrics() self.discovered_urls = set() self.processed_urls = set() def start_intelligent_crawling(self, duration_hours: int = 24, max_docs_per_cycle: int = 10) -> None: """شروع کرالر هوشمند""" self.is_active = True self.crawler_stats.active_crawlers = 1 def crawler_worker(): end_time = time.time() + (duration_hours * 3600) cycle_count = 0 logger.info(f"کرالر هوشمند برای {duration_hours} ساعت شروع شد") while time.time() < end_time and self.is_active: cycle_count += 1 cycle_start = time.time() try: # فاز 1: کشف URLs جدید new_urls = self._discover_quality_urls() logger.info(f"چرخه {cycle_count}: {len(new_urls)} URL جدید کشف شد") # فاز 2: اولویتبندی URLs prioritized_urls = self._prioritize_urls(new_urls)[:max_docs_per_cycle] # فاز 3: پردازش هوشمند for i, url in enumerate(prioritized_urls): if not self.is_active: break try: # استخراج محتوا scraped_result = self.scraper.scrape_document(url) if scraped_result.get('status') == 'موفق': # طبقهبندی هوشمند classification = self.classification_system.classify_document( scraped_result['content'] ) # ساخت ProcessingResult processing_result = ProcessingResult( url=url, title=scraped_result.get('title', ''), content=scraped_result.get('content', ''), source=scraped_result.get('source_info', {}).get('name', ''), quality_score=scraped_result.get('quality_assessment', {}).get('overall_score', 0), classification=classification.get('rule_based_classification', {}), sentiment_score=0.5, # پیشفرض legal_entities=classification.get('legal_entities', []), embeddings=classification.get('embedding'), processing_time=classification.get('processing_time', 0) ) # ذخیره در دیتابیس if self.db_manager.save_document_advanced(processing_result): self.crawler_stats.total_processed += 1 logger.info(f"سند ذخیره شد: {processing_result.title[:50]}...") self.processed_urls.add(url) # تأخیر بین درخواستها time.sleep(random.uniform(2, 5)) except Exception as e: logger.error(f"خطا در پردازش {url}: {e}") # فاز 4: بهینهسازی و پاکسازی self._optimize_system() cycle_duration = time.time() - cycle_start logger.info(f"چرخه {cycle_count} در {cycle_duration:.1f} ثانیه تکمیل شد") # استراحت بین چرخهها if self.is_active: time.sleep(600) # 10 دقیقه except Exception as e: logger.error(f"خطا در چرخه کرالر: {e}") time.sleep(300) # 5 دقیقه در صورت خطا self.is_active = False self.crawler_stats.active_crawlers = 0 logger.info("کرالر متوقف شد") # اجرای کرالر در thread جداگانه crawler_thread = threading.Thread(target=crawler_worker, daemon=True) crawler_thread.start() def _discover_quality_urls(self) -> List[str]: """کشف URLs با کیفیت""" new_urls = [] for source_name, config in LEGAL_SOURCES.items(): if not self.is_active: break try: # درخواست صفحه اصلی response = self.scraper.session.get( config['base_url'], timeout=15, headers=self.scraper.anti_ddos.get_random_headers() ) soup = BeautifulSoup(response.content, 'html.parser') # استخراج لینکها for link in soup.find_all('a', href=True): full_url = urljoin(config['base_url'], link['href']) # فیلتر بر اساس patterns if any(pattern in full_url for pattern in config['patterns']): if (full_url not in self.processed_urls and full_url not in self.discovered_urls): new_urls.append(full_url) self.discovered_urls.add(full_url) # محدودیت تعداد URLs از هر منبع if len(new_urls) >= 50: break except Exception as e: logger.error(f"خطا در کشف URLs از {source_name}: {e}") return new_urls[:100] # محدودیت کلی def _prioritize_urls(self, urls: List[str]) -> List[str]: """اولویتبندی URLs بر اساس کیفیت احتمالی""" url_priorities = [] for url in urls: priority_score = 0.0 # امتیاز بر اساس منبع for source_name, config in LEGAL_SOURCES.items(): if config['base_url'] in url: priority_score += config.get('reliability_score', 0.5) * 0.4 priority_score += (3 - config.get('priority', 3)) * 0.2 break # امتیاز بر اساس URL pattern if '/law/' in url or '/legal/' in url: priority_score += 0.3 if '/verdict/' in url or '/judgment/' in url: priority_score += 0.2 if any(term in url.lower() for term in ['قانون', 'مقرره', 'آییننامه']): priority_score += 0.1 url_priorities.append((url, priority_score)) # مرتبسازی بر اساس اولویت url_priorities.sort(key=lambda x: x[1], reverse=True) return [url for url, score in url_priorities] def _optimize_system(self): """بهینهسازی دورهای سیستم""" try: # پاکسازی حافظه gc.collect() # پاکسازی کش منقضی if hasattr(self.scraper, 'cache_system'): self.scraper.cache_system.cleanup_expired() # محدود کردن discovered_urls if len(self.discovered_urls) > 5000: # حذف قدیمیترینها (شبیهسازی FIFO) self.discovered_urls = set(list(self.discovered_urls)[-3000:]) # آپدیت آمار حافظه self.crawler_stats.memory_usage = self._get_memory_usage() except Exception as e: logger.error(f"خطا در بهینهسازی: {e}") def _get_memory_usage(self) -> float: """دریافت میزان مصرف حافظه""" try: with open('/proc/self/status') as f: for line in f: if line.startswith('VmRSS:'): return float(line.split()[1]) / 1024 except: pass return 0.0 def stop_crawler(self): """توقف کرالر""" self.is_active = False self.crawler_stats.active_crawlers = 0 logger.info("درخواست توقف کرالر ارسال شد") def get_crawler_stats(self) -> Dict: """آمار کرالر""" return { 'is_active': self.is_active, 'total_processed': self.crawler_stats.total_processed, 'discovered_urls': len(self.discovered_urls), 'processed_urls': len(self.processed_urls), 'memory_usage': self.crawler_stats.memory_usage, 'cache_hits': self.crawler_stats.cache_hits } # === اپلیکیشن اصلی پیشرفته === class AdvancedIranianLegalArchive: """اپلیکیشن پیشرفته با تمام قابلیتهای ارتقاء یافته""" def __init__(self): # مقداردهی اجزاء سیستم self.cache_system = IntelligentCacheSystem() self.db_manager = AdvancedDatabaseManager() self.scoring_system = AdvancedScoringSystem() self.classification_system = IntelligentClassificationSystem(self.cache_system) self.search_engine = SemanticSearchEngine(self.cache_system) # مدیریت حالت سیستم self.system_ready = False self.system_metrics = SystemMetrics() # کرالر (بعد از مقداردهی scraper) self.crawler_system = None # مقداردهی سیستم self._initialize_advanced_system() def _initialize_advanced_system(self): """مقداردهی پیشرفته سیستم""" logger.info("🚀 شروع مقداردهی سیستم پیشرفته...") try: # بارگذاری مدلهای طبقهبندی self.classification_system.load_models() # مقداردهی موتور جستجو self.search_engine.initialize() # ایجاد scraper ساده from types import SimpleNamespace self.scraper = SimpleNamespace() self.scraper.cache_system = self.cache_system self.scraper.session = requests.Session() self.scraper.scrape_document = self._create_scraper_method() # مقداردهی کرالر self.crawler_system = AdvancedCrawlerSystem( self.scraper, self.db_manager, self.classification_system ) self.system_ready = True logger.info("✅ سیستم پیشرفته آماده است") # مقداردهی اولیه در صورت خالی بودن دیتابیس if self.db_manager.get_advanced_stats()['total_documents'] == 0: self._seed_with_sample_documents() except Exception as e: logger.error(f"❌ خطا در مقداردهی: {e}") self.system_ready = False def _create_scraper_method(self): """ایجاد متد scraper""" def scrape_document(url: str) -> Dict: try: # شبیهسازی scraping ساده response = self.scraper.session.get(url, timeout=30) soup = BeautifulSoup(response.content, 'html.parser') title = soup.find('title') title = title.text if title else "بدون عنوان" content = soup.get_text(strip=True)[:2000] # امتیازدهی scores = self.scoring_system.calculate_comprehensive_score( content, {'reliability_score': 0.8}, [] ) return { 'status': 'موفق', 'title': title, 'content': content, 'quality_assessment': scores, 'source_info': {'name': 'منبع نمونه'} } except Exception as e: return {'status': 'ناموفق', 'error': str(e)} return scrape_document def _seed_with_sample_documents(self): """مقداردهی نمونه""" sample_docs = [ { 'url': 'https://example.com/law/1', 'title': 'قانون نمونه شماره 1', 'content': 'ماده 1- این قانون به منظور تنظیم روابط حقوقی وضع شده است. تبصره: موارد استثنا در آییننامه اجرایی تعیین میشود.', 'source': 'منبع نمونه' }, { 'url': 'https://example.com/law/2', 'title': 'آییننامه اجرایی نمونه', 'content': 'بند الف) کلیه اشخاص حقیقی و حقوقی مشمول این مقررات هستند. بند ب) تخلفات مربوطه در دادگاه رسیدگی میشود.', 'source': 'منبع نمونه' } ] for doc in sample_docs: # طبقهبندی classification = self.classification_system.classify_document(doc['content']) # ساخت ProcessingResult result = ProcessingResult( url=doc['url'], title=doc['title'], content=doc['content'], source=doc['source'], quality_score=85.0, classification=classification.get('rule_based_classification', {}), sentiment_score=0.6, legal_entities=classification.get('legal_entities', []), embeddings=classification.get('embedding'), processing_time=0.5 ) self.db_manager.save_document_advanced(result) logger.info("مقداردهی نمونه تکمیل شد") def process_urls_intelligent(self, urls_text: str, progress=gr.Progress()) -> Tuple[str, str]: """پردازش هوشمند URLs با تمام قابلیتها""" if not urls_text or not urls_text.strip(): return "❌ لطفاً فهرست آدرسها را وارد کنید", "" urls = [url.strip() for url in urls_text.strip().split('\n') if url.strip().startswith(('http://', 'https://'))] if not urls: return "❌ آدرس معتبری یافت نشد", "" # محدودیت برای HF Spaces if len(urls) > 15: urls = urls[:15] warning = "⚠️ به دلیل محدودیتها، تنها 15 آدرس اول پردازش میشود.\n\n" else: warning = "" results = [] cache_hits = 0 total_processing_time = 0 for i, url in enumerate(urls): progress_value = (i + 1) / len(urls) progress(progress_value, desc=f"پردازش هوشمند {i+1} از {len(urls)}") start_time = time.time() try: # بررسی کش cached = self.cache_system.get(url, 'comprehensive') if cached: cache_hits += 1 results.append(cached) continue # استخراج محتوا scraped_result = self.scraper.scrape_document(url) if scraped_result.get('status') == 'موفق': # طبقهبندی هوشمند classification = self.classification_system.classify_document( scraped_result['content'] ) # امتیازدهی پیشرفته scores = self.scoring_system.calculate_comprehensive_score( scraped_result['content'], scraped_result.get('source_info', {}), classification.get('legal_entities', []) ) # ساخت نتیجه جامع processing_result = ProcessingResult( url=url, title=scraped_result.get('title', ''), content=scraped_result.get('content', ''), source=scraped_result.get('source_info', {}).get('name', ''), quality_score=scores['final_score'], classification=classification.get('rule_based_classification', {}), sentiment_score=0.5, legal_entities=classification.get('legal_entities', []), embeddings=classification.get('embedding'), processing_time=time.time() - start_time, cache_hit=False ) # ذخیره در دیتابیس self.db_manager.save_document_advanced(processing_result) # ذخیره در کش cache_data = { 'title': processing_result.title, 'quality_score': processing_result.quality_score, 'classification': processing_result.classification, 'legal_entities': processing_result.legal_entities, 'status': 'موفق' } self.cache_system.set(url, cache_data, 'comprehensive', ttl_seconds=7200) results.append(cache_data) else: results.append({'status': 'ناموفق', 'error': scraped_result.get('error', '')}) total_processing_time += time.time() - start_time except Exception as e: logger.error(f"خطا در پردازش {url}: {e}") results.append({'status': 'ناموفق', 'error': str(e)}) # تأخیر بین درخواستها time.sleep(1) # تولید گزارش جامع successful = sum(1 for r in results if r.get('status') == 'موفق') failed = len(results) - successful avg_quality = sum(r.get('quality_score', 0) for r in results if r.get('quality_score')) / max(successful, 1) summary = f"""{warning}📊 **گزارش پردازش هوشمند:** {SVG_ICONS['success']} موفق: {successful} {SVG_ICONS['error']} ناموفق: {failed} {SVG_ICONS['cache']} استفاده از کش: {cache_hits} 📈 میانگین کیفیت: {avg_quality:.1f}/100 ⏱️ زمان کل: {total_processing_time:.1f} ثانیه 📚 کل اسناد در آرشیو: {self.db_manager.get_advanced_stats()['total_documents']}""" # جزئیات نتایج details_lines = [] for i, result in enumerate(results, 1): if result.get('status') == 'موفق': title = result.get('title', 'بدون عنوان')[:50] quality = result.get('quality_score', 0) entities_count = len(result.get('legal_entities', [])) cache_icon = SVG_ICONS['cache'] if result.get('cache_hit') else '' details_lines.append( f"{i}. {cache_icon} {title}... (کیفیت: {quality:.1f}, موجودیتها: {entities_count})" ) else: error = result.get('error', 'نامشخص')[:50] details_lines.append(f"{i}. {SVG_ICONS['error']} خطا: {error}...") details = '\n'.join(details_lines) return summary, details def build_intelligent_search_index(self, progress=gr.Progress()) -> str: """ساخت ایندکس جستجوی هوشمند""" def progress_callback(message: str, value: float): progress(value, desc=message) try: documents = self.db_manager.get_documents_with_embeddings() if not documents: return "❌ سندی برای ایندکسسازی یافت نشد" success = self.search_engine.build_index(documents, progress_callback) if success: return f"✅ ایندکس هوشمند با {len(documents)} سند آماده شد" else: return "❌ خطا در ساخت ایندکس" except Exception as e: logger.error(f"خطا در ساخت ایندکس: {e}") return f"❌ خطا: {str(e)}" def intelligent_semantic_search(self, query: str, top_k: int = 10) -> Tuple[str, pd.DataFrame]: """جستجوی معنایی هوشمند""" if not query or not query.strip(): return "❌ لطفاً عبارت جستجو را وارد کنید", pd.DataFrame() if not self.search_engine.is_ready or self.search_engine.faiss_index is None: return "❌ ایندکس جستجو آماده نیست", pd.DataFrame() try: start_time = time.time() results = self.search_engine.search(query.strip(), top_k, threshold=0.2) search_time = time.time() - start_time if not results: return f"🔍 نتیجهای برای '{query}' یافت نشد", pd.DataFrame() # تبدیل به DataFrame df_data = [] for result in results: df_data.append({ 'رتبه': result['rank'], 'امتیاز شباهت': f"{result['similarity_score']:.3f}", 'درجه ارتباط': result['relevance_category'], 'عنوان': result['title'], 'خلاصه محتوا': result['content_preview'], 'آدرس': result['url'] }) df = pd.DataFrame(df_data) message = f"""🔍 **نتایج جستجوی هوشمند:** {query} 📊 {len(results)} نتیجه در {search_time:.2f} ثانیه 🎯 حد آستانه شباهت: 0.2 {SVG_ICONS['cache']} استفاده از کش سیستم""" return message, df except Exception as e: logger.error(f"خطا در جستجو: {e}") return f"❌ خطا در جستجو: {str(e)}", pd.DataFrame() def start_intelligent_crawler(self, duration_hours: int) -> str: """شروع کرالر هوشمند""" if not self.crawler_system: return "❌ سیستم کرالر آماده نیست" if self.crawler_system.is_active: return "❌ کرالر در حال حاضر فعال است" try: self.crawler_system.start_intelligent_crawling(duration_hours, max_docs_per_cycle=5) return f"🚀 کرالر هوشمند برای {duration_hours} ساعت شروع شد" except Exception as e: return f"❌ خطا در شروع کرالر: {str(e)}" def stop_intelligent_crawler(self) -> str: """توقف کرالر هوشمند""" if self.crawler_system: self.crawler_system.stop_crawler() return "🛑 کرالر متوقف شد" return "❌ کرالر یافت نشد" def get_comprehensive_system_status(self) -> str: """وضعیت جامع سیستم""" try: # آمار پایگاه داده db_stats = self.db_manager.get_advanced_stats() # آمار کش cache_stats = self.cache_system.get_stats() # آمار کرالر crawler_stats = self.crawler_system.get_crawler_stats() if self.crawler_system else {} # آمار مدلها models_ready = self.classification_system.is_ready search_ready = self.search_engine.is_ready status_parts = [ f"🏛️ **آرشیو هوشمند اسناد حقوقی ایران**", f"📊 **آمار پایگاه داده:**", f"📚 اسناد: {db_stats['total_documents']:,}", f"⏱️ میانگین زمان پردازش: {db_stats['average_processing_time']} ثانیه", "", f"{SVG_ICONS['cache']} **سیستم کش:**", f"💾 حافظه کش: {cache_stats['memory_cache_size']} آیتم", f"🗄️ کش دیتابیس: {cache_stats['database_entries']} ورودی", f"📈 کل دسترسیها: {cache_stats['total_accesses']:,}", "", f"🤖 **سیستمهای هوشمند:**", f"🏷️ طبقهبندی: {'آماده' if models_ready else 'غیرآماده'}", f"🔍 جستجوی معنایی: {'آماده' if search_ready else 'غیرآماده'}", "", f"{SVG_ICONS['crawler']} **کرالر خودکار:**", f"وضعیت: {'فعال' if crawler_stats.get('is_active') else 'غیرفعال'}", f"پردازش شده: {crawler_stats.get('total_processed', 0)}", f"کشف شده: {crawler_stats.get('discovered_urls', 0)} URL", f"مصرف حافظه: {crawler_stats.get('memory_usage', 0):.1f} MB", "", f"📈 **منابع:**" ] # اضافه کردن آمار منابع for source_data in db_stats.get('source_statistics', []): source, count, avg_words = source_data status_parts.append(f" • {source}: {count:,} سند (میانگین: {avg_words:.0f} کلمه)") return '\n'.join(status_parts) except Exception as e: logger.error(f"خطا در دریافت وضعیت: {e}") return f"❌ خطا در دریافت وضعیت: {str(e)}" def export_advanced_data(self) -> Tuple[str, str]: """صدور پیشرفته دادهها""" try: # دریافت اسناد با جزئیات کامل with sqlite3.connect(self.db_manager.db_path) as conn: docs = conn.execute(''' SELECT url, title, source, word_count, quality_scores, classification_result, legal_entities, scraped_at FROM documents WHERE processing_status = 'completed' ORDER BY scraped_at DESC ''').fetchall() if not docs: return "❌ سندی برای صدور یافت نشد", "" # تبدیل به DataFrame df_data = [] for doc in docs: quality_data = json.loads(doc[4]) if doc[4] else {} classification_data = json.loads(doc[5]) if doc[5] else {} entities_data = json.loads(doc[6]) if doc[6] else [] df_data.append({ 'آدرس': doc[0], 'عنوان': doc[1], 'منبع': doc[2], 'تعداد کلمات': doc[3], 'امتیاز کیفیت': quality_data.get('quality_score', 0), 'دستهبندی اصلی': max(classification_data.keys(), key=classification_data.get) if classification_data else 'نامشخص', 'تعداد موجودیتهای حقوقی': len(entities_data), 'تاریخ استخراج': doc[7] }) df = pd.DataFrame(df_data) # ذخیره فایل timestamp = datetime.now().strftime('%Y%m%d_%H%M%S') filename = f"iranian_legal_archive_advanced_{timestamp}.csv" filepath = f"/tmp/{filename}" df.to_csv(filepath, index=False, encoding='utf-8-sig') return f"✅ {len(docs)} سند با جزئیات کامل صادر شد", filepath except Exception as e: logger.error(f"خطا در صدور: {e}") return f"❌ خطا در صدور: {str(e)}", "" def create_advanced_interface(self): """ایجاد رابط کاربری پیشرفته""" custom_css = """ .rtl { direction: rtl; text-align: right; font-family: 'Vazirmatn', 'Tahoma', sans-serif; } .main-title { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 25px; border-radius: 15px; text-align: center; margin-bottom: 25px; box-shadow: 0 8px 32px rgba(0,0,0,0.1); } .metric-card { background: linear-gradient(45deg, #f093fb 0%, #f5576c 100%); color: white; padding: 15px; border-radius: 10px; margin: 5px; } .advanced-tab { border: 2px solid #667eea; border-radius: 10px; padding: 15px; margin: 10px; } """ with gr.Blocks( title="آرشیو هوشمند پیشرفته اسناد حقوقی ایران", theme=gr.themes.Soft(primary_hue=gr.themes.colors.purple, secondary_hue=gr.themes.colors.indigo), css=custom_css ) as interface: # عنوان اصلی پیشرفته gr.HTML(f"""
سیستم جامع مجهز به هوش مصنوعی پیشرفته، کش هوشمند و کرالر خودکار
🧠 مدلهای SOTA فارسی | ⚡ کش هوشمند | 🎯 امتیازدهی پیشرفته | 🔄 کرالر خودکار