book-data-miner / app.py
F-allahmoradi's picture
Upload app.py
bf24aa9 verified
# app.py
# 🔍 نسخه پیشرفته - رابط Gradio تاریک و ساده - رفع مشکل نمایش نتایج
# ============================================================================
# 🔧 Import کتابخانه‌ها
# ============================================================================
import pytesseract
from pdf2image import convert_from_path
from PIL import Image, ImageEnhance, ImageFilter
import re
import json
from typing import Dict, Any, List, Tuple, Optional
import os
from datetime import datetime
import numpy as np
from transformers import pipeline, AutoTokenizer, AutoModel, AutoModelForTokenClassification
from sentence_transformers import SentenceTransformer, util
import torch
import arabic_reshaper
from bidi.algorithm import get_display
import gradio as gr
# تنظیم مسیر Tesseract (در Hugging Face این مسیر ممکن است لازم نباشد)
# pytesseract.pytesseract.tesseract_cmd = '/usr/bin/tesseract' # فقط در Colab
# ============================================================================
# 🧠 بخش ۱: مدل‌های هوش مصنوعی با دقت بالا
# ============================================================================
class HighAccuracyAIModels:
"""مدل‌های هوش مصنوعی با دقت فوق العاده"""
def __init__(self):
self.setup_high_accuracy_models()
def setup_high_accuracy_models(self):
"""بارگذاری مدل‌های با دقت بالا"""
print("🧠 در حال بارگذاری مدل‌ها...")
try:
self.ner_pipeline = pipeline(
"token-classification",
model="HooshvareLab/bert-fa-zwnj-base-ner",
aggregation_strategy="max",
device=0 if torch.cuda.is_available() else -1
)
print("✅ مدل NER بارگذاری شد")
except Exception as e:
print(f"⚠️ خطا در بارگذاری مدل NER: {e}")
self.ner_pipeline = None
try:
self.embedding_model = SentenceTransformer(
'all-MiniLM-L6-v2',
device='cuda' if torch.cuda.is_available() else 'cpu'
)
print("✅ مدل Embedding بارگذاری شد")
except Exception as e:
print(f"⚠️ خطا در بارگذاری مدل Embedding: {e}")
self.embedding_model = None
# ============================================================================
# 🔍 بخش ۲: OCR با دقت فوق العاده
# ============================================================================
class UltraAccuracyOCREngine:
"""موتور OCR با دقت فوق العاده"""
def __init__(self, ai_models):
self.ai_models = ai_models
self.setup_advanced_ocr()
def setup_advanced_ocr(self):
"""تنظیمات پیشرفته OCR"""
self.tesseract_configs = [
r'--oem 3 --psm 6 -c tessedit_char_whitelist=آابپتثجچحخدذرزژسشصضطظعغفقکگلمنوهیءةيك۰۱۲۳۴۵۶۷۸۹٠١٢٣٤٥٦٧٨٩ :.,-()',
r'--oem 3 --psm 4 -c preserve_interword_spaces=1'
]
def extract_text_ultra_accurate(self, input_file, progress_callback=None) -> Tuple[str, Dict[str, Any]]:
"""استخراج متن با دقت فوق العاده"""
if progress_callback:
progress_callback(5, "شروع استخراج متن...")
results = {
'methods': {},
'quality_metrics': {}
}
try:
if progress_callback:
progress_callback(20, "پردازش صفحات...")
tesseract_results = self._advanced_tesseract_extraction(input_file, progress_callback)
results['methods']['tesseract_advanced'] = tesseract_results
combined_text = tesseract_results['text']
results['combined_text'] = combined_text
results['quality_metrics'] = self._calculate_comprehensive_quality(combined_text)
if progress_callback:
progress_callback(80, "استخراج متن کامل شد")
return combined_text, results
except Exception as e:
print(f"❌ خطا در استخراج متن: {e}")
return "", results
def _advanced_tesseract_extraction(self, input_file, progress_callback=None) -> Dict[str, Any]:
"""استخراج پیشرفته با Tesseract"""
start_time = datetime.now()
try:
if isinstance(input_file, str) and input_file.lower().endswith('.pdf'):
images = convert_from_path(input_file, first_page=1, last_page=3, dpi=300)
all_texts = []
for i, image in enumerate(images):
if progress_callback:
progress_callback(20 + (i * 15), f"پردازش صفحه {i+1}...")
processed_image = self._preprocess_image(image)
page_texts = []
for config in self.tesseract_configs:
try:
text = pytesseract.image_to_string(
processed_image,
lang='fas+eng',
config=config
)
if text.strip():
page_texts.append(text)
except:
continue
if page_texts:
best_page_text = max(page_texts, key=lambda x: len(x))
all_texts.append(best_page_text)
final_text = '\n'.join(all_texts)
else:
if isinstance(input_file, str):
image = Image.open(input_file)
else:
image = input_file
processed_image = self._preprocess_image(image)
final_text = pytesseract.image_to_string(processed_image, lang='fas+eng')
processing_time = (datetime.now() - start_time).total_seconds()
return {
'text': final_text,
'confidence': 0.8,
'processing_time': processing_time,
'method': 'tesseract_advanced'
}
except Exception as e:
print(f"⚠️ خطا در Tesseract: {e}")
return {'text': '', 'confidence': 0, 'processing_time': 0, 'method': 'error'}
def _preprocess_image(self, image):
"""پیش‌پردازش تصویر"""
try:
if image.mode != 'L':
image = image.convert('L')
enhancer = ImageEnhance.Contrast(image)
image = enhancer.enhance(1.3)
return image
except:
return image
def _calculate_comprehensive_quality(self, text: str) -> Dict[str, float]:
"""محاسبه کیفیت جامع متن"""
lines = [line.strip() for line in text.split('\n') if line.strip()]
persian_chars = len(re.findall(r'[آ-ی]', text))
total_chars = len(text)
return {
'overall_score': min(persian_chars / max(total_chars, 1) * 2, 1.0),
'line_count': len(lines),
'persian_ratio': persian_chars / total_chars if total_chars > 0 else 0,
'total_chars': total_chars
}
# ============================================================================
# 🤖 بخش ۳: سیستم RAG ساده‌سازی شده
# ============================================================================
class SimpleRAGSystem:
"""سیستم RAG ساده‌سازی شده"""
def __init__(self):
# حذف کلید API یا استفاده از متغیر محیطی
self.api_key = os.getenv("OPENROUTER_API_KEY", "")
if not self.api_key:
print("⚠️ کلید API یافت نشد. مدل RAG غیرفعال است.")
self.setup_llm()
self.knowledge_base = None
def setup_llm(self):
"""تنظیم مدل زبانی"""
if not self.api_key:
print("❌ کلید API تنظیم نشده است.")
self.llm = None
self.embed_model = None
return
try:
from llama_index.llms.openrouter import OpenRouter
from llama_index.embeddings.huggingface import HuggingFaceEmbedding
self.llm = OpenRouter(
model="meta-llama/llama-3-70b-instruct",
temperature=0.1,
max_tokens=2000,
api_key=self.api_key
)
self.embed_model = HuggingFaceEmbedding(
model_name="sentence-transformers/all-MiniLM-L6-v2"
)
print("✅ مدل زبانی RAG تنظیم شد")
except Exception as e:
print(f"❌ خطا در تنظیم مدل RAG: {e}")
self.llm = None
self.embed_model = None
def create_knowledge_base(self, text: str):
"""ایجاد پایگاه دانش"""
if not self.llm:
return False
try:
from llama_index.core import Document, VectorStoreIndex
short_text = text[:2000]
document = Document(text=short_text)
self.knowledge_base = VectorStoreIndex.from_documents(
[document],
embed_model=self.embed_model
)
return True
except Exception as e:
print(f"❌ خطا در ایجاد پایگاه دانش: {e}")
return False
# ============================================================================
# 🚀 بخش ۴: استخراج‌کننده متادیتا
# ============================================================================
class APIEnhancedMetadataExtractor:
"""استخراج کننده متادیتا"""
def __init__(self, rag_system):
self.rag_system = rag_system
def extract_with_api_power(self, text: str, progress_callback=None) -> Dict[str, Any]:
"""استخراج متادیتا با قدرت API"""
if progress_callback:
progress_callback(85, "استخراج اطلاعات با هوش مصنوعی...")
if not self.rag_system.llm:
return self._extract_without_api(text)
try:
chunk = text[:2000]
prompt = f"""
از متن زیر اطلاعات کتاب را استخراج کن:
{chunk}
اطلاعات مورد نیاز:
- عنوان کتاب
- نویسنده/مؤلف
- مترجم (اگر وجود دارد)
- ناشر
- سال انتشار
- شابک (ISBN)
- نوبت چاپ
پاسخ را به صورت JSON برگردان.
"""
metadata = self._call_api_for_extraction(prompt)
return metadata
except Exception as e:
print(f"❌ خطا در استخراج با API: {e}")
return self._extract_without_api(text)
def _extract_without_api(self, text: str) -> Dict[str, Any]:
"""استخراج بدون API"""
metadata = {}
# استخراج عنوان
lines = [line.strip() for line in text.split('\n') if line.strip()]
for line in lines[:10]:
if (10 <= len(line) <= 150 and
len(re.findall(r'[آ-ی]', line)) >= 2 and
not any(word in line for word in ['نویسنده', 'مؤلف', 'ناشر', 'چاپ', 'شابک'])):
metadata['title'] = line
break
# استخراج سایر اطلاعات
patterns = {
'author': r'نویسنده\s*[:\-]\s*([^\n]+)',
'publisher': r'ناشر\s*[:\-]\s*([^\n]+)',
'publication_year': r'سال\s*انتشار\s*[:\-]\s*([۱۳۴۰-۹]{4})',
'isbn': r'شابک\s*[:\-]\s*([۰-۹\-–]+)',
'edition': r'چاپ\s*(\d+)',
'translator': r'مترجم\s*[:\-]\s*([^\n]+)'
}
for field, pattern in patterns.items():
match = re.search(pattern, text, re.IGNORECASE)
if match:
metadata[field] = match.group(1).strip()
return metadata
def _call_api_for_extraction(self, prompt: str) -> Dict[str, Any]:
"""فراخوانی API"""
try:
from llama_index.core import Document
doc = Document(text=prompt)
query_engine = self.rag_system.knowledge_base.as_query_engine(
llm=self.rag_system.llm,
similarity_top_k=2
)
response = query_engine.query(prompt)
response_text = str(response).strip()
# استخراج JSON از پاسخ
json_match = re.search(r'\{[^{}]*\}', response_text)
if json_match:
return json.loads(json_match.group())
return {}
except Exception as e:
print(f"⚠️ خطا در فراخوانی API: {e}")
return {}
# ============================================================================
# 📝 بخش ۵: استخراج‌کننده ساده
# ============================================================================
class SimpleBookExtractor:
"""استخراج ساده اطلاعات کتاب"""
def extract_basic_info(self, text: str) -> Dict[str, Any]:
"""استخراج اطلاعات پایه"""
results = {}
lines = text.split('\n')
# استخراج عنوان
for line in lines[:10]:
line = line.strip()
if (10 <= len(line) <= 150 and
len(re.findall(r'[آ-ی]', line)) >= 2):
results['title'] = line
break
for line in lines:
line = line.strip()
if not line:
continue
# استخراج سال
year_match = re.search(r'۱۳[۷-۹][۰-۹]|۱۴۰[۰-۴]', line)
if year_match and 'year' not in results:
results['publication_year'] = year_match.group()
# استخراج نویسنده
author_match = re.search(r'نویسنده\s*[:\-]\s*(.+)', line, re.IGNORECASE)
if author_match and 'author' not in results:
results['author'] = author_match.group(1).strip()
# استخراج ناشر
publisher_match = re.search(r'ناشر\s*[:\-]\s*(.+)', line, re.IGNORECASE)
if publisher_match and 'publisher' not in results:
results['publisher'] = publisher_match.group(1).strip()
# استخراج مترجم
translator_match = re.search(r'مترجم\s*[:\-]\s*(.+)', line, re.IGNORECASE)
if translator_match and 'translator' not in results:
results['translator'] = translator_match.group(1).strip()
# استخراج شابک
isbn_match = re.search(r'شابک\s*[:\-]\s*([۰-۹\-–]+)', line, re.IGNORECASE)
if isbn_match and 'isbn' not in results:
results['isbn'] = isbn_match.group(1).strip()
# استخراج نوبت چاپ
edition_match = re.search(r'چاپ\s*(\d+)', line, re.IGNORECASE)
if edition_match and 'edition' not in results:
results['edition'] = edition_match.group(1).strip()
return results
def extract_additional_info(self, text: str) -> Dict[str, Any]:
"""استخراج اطلاعات تکمیلی"""
results = {}
patterns = {
'publisher': r'ناشر\s*[:\-]\s*(.+)',
'isbn': r'شابک\s*[:\-]\s*([۰-۹\-–]+)',
'translator': r'مترجم\s*[:\-]\s*(.+)',
'price': r'قیمت\s*[:\-]\s*([۰-۹,]+)',
'subject': r'موضوع\s*[:\-]\s*(.+)'
}
for field, pattern in patterns.items():
match = re.search(pattern, text, re.IGNORECASE)
if match:
results[field] = match.group(1).strip()
return results
# ============================================================================
# 🔄 بخش ۶: پردازشگر اصلی
# ============================================================================
class UltraAccuracyBookProcessor:
"""پردازشگر اصلی"""
def __init__(self):
self.ai_models = HighAccuracyAIModels()
self.ocr_engine = UltraAccuracyOCREngine(self.ai_models)
self.rag_system = SimpleRAGSystem()
self.api_extractor = APIEnhancedMetadataExtractor(self.rag_system)
self.simple_extractor = SimpleBookExtractor()
def process_book_ultra_accurate(self, input_file, progress_callback=None) -> Dict[str, Any]:
"""پردازش کتاب"""
if progress_callback:
progress_callback(0, "شروع پردازش...")
start_time = datetime.now()
# استخراج متن
if progress_callback:
progress_callback(10, "استخراج متن از فایل...")
raw_text, ocr_results = self.ocr_engine.extract_text_ultra_accurate(input_file, progress_callback)
if not raw_text or len(raw_text.strip()) < 10:
return self._create_error_result("متن کافی استخراج نشد", ocr_results, start_time)
# ایجاد پایگاه دانش
if progress_callback:
progress_callback(70, "راه‌اندازی هوش مصنوعی...")
rag_ready = self.rag_system.create_knowledge_base(raw_text)
if rag_ready:
# استخراج با API
api_metadata = self.api_extractor.extract_with_api_power(raw_text, progress_callback)
backup_metadata = self._extract_backup_metadata(raw_text)
final_metadata = self._final_fusion(api_metadata, backup_metadata, raw_text)
else:
# فقط روش معمولی
if progress_callback:
progress_callback(75, "استخراج اطلاعات...")
final_metadata = self._extract_backup_metadata(raw_text)
# ایجاد نتایج نهایی
if progress_callback:
progress_callback(95, "ذخیره‌سازی نتایج...")
results = self._create_final_results(final_metadata, raw_text, ocr_results,
rag_ready, start_time, input_file)
if progress_callback:
progress_callback(100, "پردازش کامل شد!")
return results
def _extract_backup_metadata(self, text: str) -> Dict[str, Any]:
"""استخراج پشتیبان"""
basic = self.simple_extractor.extract_basic_info(text)
additional = self.simple_extractor.extract_additional_info(text)
# ترکیب اطلاعات پایه و تکمیلی
combined_basic = basic.copy()
for key, value in additional.items():
if key not in combined_basic and value:
combined_basic[key] = value
return {
'basic_info': combined_basic,
'additional_info': additional
}
def _final_fusion(self, api_metadata: Dict, backup_metadata: Dict, text: str) -> Dict[str, Any]:
"""ترکیب نهایی"""
# ابتدا اطلاعات پشتیبان را کپی می‌کنیم
final_basic = backup_metadata.get('basic_info', {}).copy()
# سپس اطلاعات API را اضافه می‌کنیم (در صورت وجود)
if api_metadata:
for field, value in api_metadata.items():
if value and value not in ['یافت نشد', '']:
final_basic[field] = value
return {
'basic_info': final_basic,
'additional_info': backup_metadata.get('additional_info', {}),
'api_enhanced': bool(api_metadata and len(api_metadata) > 0)
}
def _create_final_results(self, metadata: Dict, text: str, ocr_results: Dict,
rag_ready: bool, start_time: datetime, input_file) -> Dict[str, Any]:
return {
'basic_info': metadata.get('basic_info', {}),
'additional_info': metadata.get('additional_info', {}),
'processing_time': (datetime.now() - start_time).total_seconds(),
'ocr_analysis': ocr_results,
'rag_available': rag_ready,
'api_enhanced': metadata.get('api_enhanced', False),
'total_text_length': len(text),
'file_info': {
'file_name': os.path.basename(input_file) if isinstance(input_file, str) else 'uploaded_file',
'file_type': 'PDF' if isinstance(input_file, str) and input_file.lower().endswith('.pdf') else 'Image'
}
}
def _create_error_result(self, error: str, ocr_results: Dict, start_time: datetime):
"""ایجاد نتیجه خطا"""
return {
'error': error,
'processing_time': (datetime.now() - start_time).total_seconds(),
'ocr_analysis': ocr_results
}
# ============================================================================
# 🎨 بخش ۷: رابط Gradio تاریک و ساده - نمایش کامل نتایج
# ============================================================================
class GradioInterface:
"""رابط کاربری Gradio"""
def __init__(self):
self.processor = None
self.current_progress = 0
self.current_status = "آماده"
def initialize_processor(self):
"""راه‌اندازی پردازشگر"""
if self.processor is None:
self.processor = UltraAccuracyBookProcessor()
def update_progress(self, progress, status):
"""به‌روزرسانی پیشرفت"""
self.current_progress = progress
self.current_status = status
def process_file(self, file):
"""پردازش فایل"""
if file is None:
return "لطفاً یک فایل آپلود کنید", "", "", 0, "آماده"
try:
self.initialize_processor()
file_path = file.name
results = self.processor.process_book_ultra_accurate(
file_path,
progress_callback=self.update_progress
)
if 'error' in results:
return f"خطا: {results['error']}", "", "", 0, "خطا"
report = self._generate_complete_report(results)
download_info = self._save_results(results, file_path)
json_output = self._generate_json_output(results)
return report, download_info, json_output, 100, "پردازش کامل شد"
except Exception as e:
return f"خطا در پردازش: {str(e)}", "", "", 0, "خطا"
def _generate_complete_report(self, results: Dict[str, Any]) -> str:
"""تولید گزارش کامل"""
basic_info = results.get('basic_info', {})
additional_info = results.get('additional_info', {})
report = "📚 نتایج کامل استخراج اطلاعات کتاب\n"
report += "=" * 50 + "\n\n"
# اطلاعات اصلی کتاب
report += "📖 اطلاعات اصلی:\n"
report += "-" * 20 + "\n"
main_fields = [
('title', 'عنوان کتاب'),
('author', 'نویسنده/مؤلف'),
('translator', 'مترجم'),
('publisher', 'ناشر'),
('publication_year', 'سال انتشار'),
('isbn', 'شابک (ISBN)'),
('edition', 'نوبت چاپ')
]
for field, title in main_fields:
value = basic_info.get(field, "یافت نشد")
report += f"• {title}: {value}\n"
# اطلاعات تکمیلی
if additional_info:
report += "\n📋 اطلاعات تکمیلی:\n"
report += "-" * 20 + "\n"
for key, value in additional_info.items():
if value and value != "یافت نشد":
display_key = self._translate_key(key)
report += f"• {display_key}: {value}\n"
# اطلاعات فنی
report += "\n🔧 اطلاعات فنی:\n"
report += "-" * 15 + "\n"
report += f"• زمان پردازش: {results.get('processing_time', 0):.1f} ثانیه\n"
report += f"• طول متن استخراج شده: {results.get('total_text_length', 0)} کاراکتر\n"
report += f"• کیفیت OCR: {results.get('ocr_analysis', {}).get('quality_metrics', {}).get('overall_score', 0):.1%}\n"
report += f"• سیستم هوش مصنوعی: {'فعال' if results.get('api_enhanced') else 'غیرفعال'}\n"
# اطلاعات فایل
file_info = results.get('file_info', {})
report += f"• نام فایل: {file_info.get('file_name', 'نامشخص')}\n"
report += f"• نوع فایل: {file_info.get('file_type', 'نامشخص')}\n"
report += f"\n🕒 تاریخ پردازش: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n"
return report
def _translate_key(self, key: str) -> str:
"""ترجمه کلیدهای انگلیسی به فارسی"""
translations = {
'publisher': 'ناشر',
'isbn': 'شابک',
'price': 'قیمت',
'subject': 'موضوع',
'translator': 'مترجم',
'author': 'نویسنده',
'publication_year': 'سال انتشار',
'edition': 'نوبت چاپ',
'title': 'عنوان'
}
return translations.get(key, key)
def _save_results(self, results: Dict[str, Any], file_path: str) -> str:
"""ذخیره نتایج"""
try:
base_name = os.path.splitext(os.path.basename(file_path))[0]
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
# ذخیره JSON
json_filename = f"{base_name}_نتایج_{timestamp}.json"
with open(json_filename, 'w', encoding='utf-8') as f:
json.dump(results, f, ensure_ascii=False, indent=2)
# ذخیره گزارش متنی
txt_filename = f"{base_name}_گزارش_{timestamp}.txt"
report_content = self._generate_complete_report(results)
with open(txt_filename, 'w', encoding='utf-8') as f:
f.write(report_content)
return f"✅ فایل‌ها با موفقیت ذخیره شدند:\n📄 {json_filename}\n📝 {txt_filename}"
except Exception as e:
return f"⚠️ خطا در ذخیره‌سازی: {str(e)}"
def _generate_json_output(self, results: Dict[str, Any]) -> str:
"""تولید خروجی JSON"""
return json.dumps(results, ensure_ascii=False, indent=2)
# ============================================================================
# 🚀 راه‌اندازی رابط Gradio تاریک و ساده
# ============================================================================
def create_dark_simple_interface():
"""ایجاد رابط تاریک و ساده"""
interface = GradioInterface()
# CSS برای رابط تاریک
dark_css = """
.gradio-container {
background: #000000 !important;
color: #ffffff !important;
font-family: Arial, sans-serif !important;
}
.container {
background: #000000 !important;
}
.panel {
background: #1a1a1a !important;
border: 1px solid #333 !important;
border-radius: 5px !important;
padding: 10px !important;
margin: 5px 0 !important;
}
.progress-text {
color: #00ff00 !important;
font-weight: bold;
}
.dark-button {
background: #333 !important;
color: white !important;
border: 1px solid #555 !important;
}
.dark-button:hover {
background: #444 !important;
}
.dark-input {
background: #1a1a1a !important;
color: white !important;
border: 1px solid #333 !important;
}
.dark-slider {
background: #333 !important;
}
.success-text {
color: #00ff00 !important;
}
.error-text {
color: #ff4444 !important;
}
"""
with gr.Blocks(
title="استخراج اطلاعات کتاب",
css=dark_css
) as demo:
gr.Markdown(
"""
<div style='text-align: center; color: white;'>
<h1>📚 استخراج اطلاعات کتاب</h1>
<p>آپلود فایل کتاب (PDF یا تصویر) برای استخراج خودکار اطلاعات</p>
</div>
"""
)
with gr.Row():
with gr.Column(scale=1):
# بخش آپلود فایل
gr.Markdown("### 📁 آپلود فایل")
file_input = gr.File(
label="",
file_types=[".pdf", ".jpg", ".jpeg", ".png"],
type="filepath",
elem_classes="dark-input"
)
# دکمه پردازش
process_btn = gr.Button(
"🚀 شروع پردازش",
variant="primary",
elem_classes="dark-button",
size="lg"
)
# بخش پیشرفت
gr.Markdown("### 📊 پیشرفت")
progress_bar = gr.Slider(
minimum=0,
maximum=100,
value=0,
label="",
interactive=False,
elem_classes="dark-slider"
)
progress_text = gr.Textbox(
label="وضعیت",
value="آماده",
interactive=False,
elem_classes="dark-input"
)
with gr.Column(scale=2):
# بخش نتایج
gr.Markdown("### 📄 نتایج کامل")
output_report = gr.Textbox(
label="",
lines=12,
show_copy_button=True,
elem_classes="dark-input"
)
# بخش ذخیره‌سازی
gr.Markdown("### 💾 ذخیره‌سازی")
download_info = gr.Textbox(
label="",
lines=3,
interactive=False,
elem_classes="dark-input"
)
# بخش JSON
gr.Markdown("### 🔧 خروجی فنی (JSON)")
json_output = gr.Textbox(
label="",
lines=8,
show_copy_button=True,
elem_classes="dark-input"
)
# اتصال رویداد
process_btn.click(
fn=interface.process_file,
inputs=[file_input],
outputs=[output_report, download_info, json_output, progress_bar, progress_text]
)
gr.Markdown(
"""
<div style='text-align: center; color: #888; margin-top: 20px;'>
<p>سیستم استخراج خودکار اطلاعات کتاب - نسخه ساده و تاریک</p>
<p>📖 تمام اطلاعات کتاب به صورت کامل نمایش داده می‌شود</p>
</div>
"""
)
return demo
# این بخش را تغییر می‌دهیم تا با Hugging Face سازگار شود
def main():
demo = create_dark_simple_interface()
demo.launch(
server_name="0.0.0.0", # برای Hugging Face
server_port=int(os.environ.get("PORT", 7860)), # پورت Hugging Face
share=False # در Hugging Face نیازی به share نیست
)
if __name__ == "__main__":
main()