# app.py import streamlit as st import json import os import requests import re import time from datetime import datetime from ddgs import DDGS import isbnlib from dotenv import load_dotenv from requests.exceptions import HTTPError from huggingface_hub import InferenceClient import languages # استيراد وحدة الترجمة load_dotenv() # استيراد الملفات المحلية try: from nlm_classifier import AdvancedNLMClassifier from metadata_fetcher import EnhancedMetadataFetcher from cover_fetcher import EnhancedCoverFetcher from marc_generator import ( build_marc_record, generate_marc_iso2709, generate_marcxml ) except ImportError as e: st.error(f"Error importing modules: {e}") # واجهات افتراضية في حال فشل التحميل class AdvancedNLMClassifier: def classify_with_confidence(self, title, summary="", categories=None): return {'nlm_code': 'W 1', 'confidence_level': 'Low'} class EnhancedMetadataFetcher: def fetch_metadata(self, isbn): return {'title': 'Unknown', 'published_date': '', 'publisher': ''} class EnhancedCoverFetcher: def get_cover(self, isbn, title=None): return {'url': f"https://placehold.co/400x600?text=ISBN:{isbn}", 'status': 'fallback'} def build_marc_record(data, isbn): return ["001 ## $a ISBN" + isbn] def generate_marc_iso2709(marc_fields, isbn): return {'iso2709': '', 'human_readable': '', 'fields_count': 0, 'record_length': 0} def generate_marcxml(marc_fields, isbn): return "" # --- 1. SETUP & AUTHENTICATION --- hf_token = os.getenv("HF_TOKEN") USE_AI = os.getenv("USE_AI", "true").lower() == "true" st.set_page_config( page_title="Medical AI Librarian", layout="wide", page_icon="🏥", initial_sidebar_state="collapsed" ) # تهيئة حالة اللغة if 'language' not in st.session_state: st.session_state.language = 'en' # افتراضي إنجليزي lang = st.session_state.language direction = languages.get_language_direction(lang) # تطبيق اتجاه الصفحة عبر CSS مع تصحيح الأقواس st.markdown(f""" """, unsafe_allow_html=True) # تهيئة عميل Hugging Face بنموذج مجاني if hf_token and USE_AI: try: client = InferenceClient(model="mistralai/Mistral-7B-Instruct-v0.2", token=hf_token) st.sidebar.success(languages.get_text("ai_connected", lang)) except Exception as e: st.sidebar.warning(languages.get_text("ai_error", lang).format(str(e))) client = None else: if not hf_token: st.sidebar.info(languages.get_text("no_hf_token", lang)) client = None # --- 2. CSS STYLING (باقي الأنماط) --- st.markdown(f""" """, unsafe_allow_html=True) # --- 3. FUNCTIONS --- def clean_isbn(isbn_str): """تنظيف وتصحيح ISBN""" cleaned = re.sub(r'[^0-9X]', '', isbn_str.upper()) try: if len(cleaned) == 10: if not isbnlib.is_isbn10(cleaned): return None elif len(cleaned) == 13: if not isbnlib.is_isbn13(cleaned): return None else: return None except: pass return cleaned def search_web_context(isbn, title=None): """بحث في الويب باستخدام ddgs""" queries = [] if title: queries.extend([ f"{title} medical book publication date edition", f"{title} review summary table of contents", f"{title} medical textbook target audience" ]) queries.extend([ f"ISBN {isbn} publication details", f"{isbn} medical book specifications", f"medical library catalog {isbn}" ]) all_results = [] try: with DDGS() as ddgs: for query in queries[:4]: results = list(ddgs.text(query, max_results=3)) for result in results: all_results.append({ 'title': result.get('title', ''), 'snippet': result.get('body', ''), 'url': result.get('href', '') }) except Exception as e: st.sidebar.warning(f"Web search limited: {str(e)}") return all_results if all_results else [] def enhanced_ai_librarian_analysis(isbn, meta_data, web_context): """تحليل محسن مع دقة عالية""" lang = st.session_state.language # استخدام اللغة الحالية if not client or not USE_AI: st.info(languages.get_text("local_classification_mode", lang)) return fallback_local_classification(isbn, meta_data, web_context, lang) metadata_fetcher = EnhancedMetadataFetcher() enhanced_meta = metadata_fetcher.fetch_metadata(isbn) api_title = enhanced_meta.get('title', '') summary_context = enhanced_meta.get('description', '') categories = enhanced_meta.get('categories', []) web_context_text = " ".join([r.get('snippet', '') for r in web_context[:3]]) nlm_classifier = AdvancedNLMClassifier() nlm_result = nlm_classifier.classify_with_confidence( api_title, f"{summary_context} {web_context_text}", categories ) system_prompt = """You are a Senior Medical Cataloging Expert with specialization in NLM classification. IMPORTANT GUIDELINES: 1. Analyze the book's PRIMARY subject focus, not secondary topics 2. Consider the intended audience and purpose 3. For medical textbooks, use W 18-W 20 range 4. For clinical guides, use appropriate WB-WZ codes 5. For basic sciences, use QS-QZ series 6. Provide specific, not generic, classifications 7. Include detailed reasoning for your choice ALWAYS verify the classification matches the book's main content.""" user_prompt = f"""Please provide precise cataloging information for this medical book: ISBN: {isbn} Title: {api_title} Publication Year: {enhanced_meta.get('published_date', 'Unknown')} Publisher: {enhanced_meta.get('publisher', 'Unknown')} Subjects/Categories: {', '.join(categories) if categories else 'None'} Description: {summary_context[:300]} Additional Context: {web_context_text[:300]} NLM Classification Analysis from our system: - Suggested Code: {nlm_result['nlm_code']} - Confidence: {nlm_result['confidence_level']} - Reason: {nlm_result['confidence_reason']} Please provide your professional assessment in this JSON format: {{ "title": "Complete title", "sub_title": "Subtitle if available", "authors": ["Author list"], "edition": "Edition information", "publisher": "Publisher name", "pub_year": "YYYY (extracted accurately)", "pages": "Number of pages", "isbn_10": "ISBN-10", "isbn_13": "ISBN-13", "summary": "Comprehensive 200-word summary", "contents_note": "Detailed table of contents", "audience_category": "Specific audience description", "audience_reason": "Justification", "mesh_subjects": ["Relevant MeSH terms"], "nlm_class": "YOUR PROFESSIONAL NLM CLASSIFICATION", "nlm_class_reason": "Detailed reasoning based on content analysis", "nlm_class_confidence": "High/Medium/Low", "acquisition_decision": "Highly Recommended/Recommended/Optional/Not Recommended", "acquisition_reason": "Collection development reasoning", "quality_score": "1-10 based on authority and relevance", "data_accuracy": "High/Medium/Low based on available information" }} CRITICAL: The NLM classification must be accurate and specific to the main subject.""" try: messages = [ {"role": "system", "content": system_prompt}, {"role": "user", "content": user_prompt} ] response = client.chat_completion( messages, max_tokens=2500, temperature=0.1, top_p=0.9 ) content = response.choices[0].message.content if "```json" in content: content = content.split("```json")[1].split("```")[0] elif "```" in content: content = content.split("```")[1].split("```")[0] data = json.loads(content.strip()) # دمج نتائج NLM المحلية data['nlm_class'] = nlm_result['nlm_code'] data['nlm_class_ai_reason'] = data.get('nlm_class_reason', '') data['nlm_class_local_reason'] = nlm_result['confidence_reason'] data['nlm_class_confidence'] = nlm_result['confidence_level'] data['nlm_class_score'] = nlm_result['confidence_score'] data['nlm_alternatives'] = nlm_result.get('alternative_codes', []) data['metadata_source'] = enhanced_meta.get('source', 'Multiple') data['metadata_confidence'] = enhanced_meta.get('confidence', 'Unknown') if enhanced_meta.get('published_date'): data['pub_year'] = enhanced_meta['published_date'] data['pub_year_source'] = enhanced_meta.get('source', 'API') data['pub_year_confidence'] = enhanced_meta.get('confidence', 'Unknown') if not isinstance(data.get('authors'), list): if enhanced_meta and enhanced_meta.get('authors'): data['authors'] = enhanced_meta['authors'] else: data['authors'] = [] data['illustrations_note'] = 'illustrations (chiefly color), portraits' data['series'] = 'Medical education series' if 'textbook' in data.get('title', '').lower() else '' data['institution'] = enhanced_meta.get('institution', '') if not data.get('pages') and enhanced_meta.get('page_count'): page_count = enhanced_meta['page_count'] if isinstance(page_count, int): if page_count > 100: data['pages'] = f"xvi, {page_count}" else: data['pages'] = str(page_count) return data except HTTPError as e: if e.response.status_code == 402: st.warning(languages.get_text("ai_payment_warning", lang)) else: st.error(languages.get_text("ai_unexpected_error", lang).format(e)) return fallback_local_classification(isbn, enhanced_meta, web_context, lang) except Exception as e: st.error(languages.get_text("ai_unexpected_error", lang).format(str(e))) return fallback_local_classification(isbn, enhanced_meta, web_context, lang) def fallback_local_classification(isbn, enhanced_meta, web_context, lang='en'): """تصنيف محلي متقدم مع بيانات افتراضية ذكية وقابلية للترجمة""" nlm_classifier = AdvancedNLMClassifier() nlm_result = nlm_classifier.classify_with_confidence( enhanced_meta.get('title', ''), enhanced_meta.get('description', ''), enhanced_meta.get('categories', []) ) title = enhanced_meta.get('title', 'Unknown Title') description = enhanced_meta.get('description', '') authors = enhanced_meta.get('authors', []) publisher = enhanced_meta.get('publisher', 'Unknown') pub_year = enhanced_meta.get('published_date', '') # توليد ملخص ذكي (يبقى بالإنجليزية) if description and len(description) > 20: summary = description[:500] + ('...' if len(description) > 500 else '') else: summary = f"This book, '{title}', is a medical publication focusing on {nlm_result['nlm_name']}. " \ f"It is intended for healthcare professionals and students. " \ f"Published by {publisher} in {pub_year if pub_year else 'unknown year'}. " \ f"The work covers key concepts in {nlm_result['nlm_description'].lower() if nlm_result['nlm_description'] else 'medicine'}." # توليد محتويات افتراضية بناءً على التصنيف (تبقى بالإنجليزية) main_topic = nlm_result.get('nlm_name', 'Medicine') contents_templates = { 'Textbook': [ "1. Introduction to the field", "2. Fundamental principles", "3. Clinical applications", "4. Diagnostic approaches", "5. Therapeutic interventions", "6. Case studies", "7. Emerging trends", "8. Review questions" ], 'Surgery': [ "1. Preoperative assessment", "2. Surgical anatomy", "3. Operative techniques", "4. Postoperative care", "5. Complications and management", "6. Minimally invasive surgery", "7. Surgical outcomes" ], 'Cardiology': [ "1. Cardiac anatomy and physiology", "2. Diagnostic imaging", "3. Ischemic heart disease", "4. Heart failure", "5. Arrhythmias", "6. Valvular disorders", "7. Pharmacotherapy", "8. Interventional cardiology" ], 'Neurology': [ "1. Neuroanatomy", "2. Neurological examination", "3. Stroke and cerebrovascular disease", "4. Epilepsy", "5. Neurodegenerative disorders", "6. Headache and pain", "7. Neuromuscular disorders" ], 'Pediatrics': [ "1. Growth and development", "2. Neonatal care", "3. Pediatric infectious diseases", "4. Childhood immunizations", "5. Pediatric emergencies", "6. Adolescent medicine" ] } contents_note = [] for key, template in contents_templates.items(): if key.lower() in main_topic.lower(): contents_note = template break if not contents_note: contents_note = [ "1. Introduction", "2. Core concepts", "3. Clinical relevance", "4. Diagnostic methods", "5. Treatment strategies", "6. Patient management", "7. Future directions", "8. Review and self-assessment" ] # توليد موضوعات MeSH مع ترجمة إذا وجدت mesh_mapping = { 'W 18': [ languages.get_text("mesh_education_medical", lang), languages.get_text("mesh_textbooks", lang), languages.get_text("mesh_curriculum", lang) ], 'WB 100': [ languages.get_text("mesh_clinical_medicine", lang), languages.get_text("mesh_diagnosis", lang), languages.get_text("mesh_therapeutics", lang) ], 'WB 105': [ languages.get_text("mesh_emergency_medicine", lang), languages.get_text("mesh_traumatology", lang), languages.get_text("mesh_critical_care", lang) ], 'WO 100': [ languages.get_text("mesh_general_surgery", lang), languages.get_text("mesh_surgical_procedures", lang) ], 'WS 1': [ languages.get_text("mesh_pediatrics", lang), languages.get_text("mesh_child_development", lang), languages.get_text("mesh_adolescent_medicine", lang) ], 'WG': [ languages.get_text("mesh_cardiology", lang), languages.get_text("mesh_cardiovascular_diseases", lang), languages.get_text("mesh_heart_diseases", lang) ], 'WL': [ languages.get_text("mesh_neurology", lang), languages.get_text("mesh_nervous_system_diseases", lang), languages.get_text("mesh_brain", lang) ], 'QS 1': [ languages.get_text("mesh_anatomy", lang), languages.get_text("mesh_dissection", lang), languages.get_text("mesh_embryology", lang) ], 'QV 1': [ languages.get_text("mesh_pharmacology", lang), languages.get_text("mesh_pharmaceutical_preparations", lang), languages.get_text("mesh_drug_therapy", lang) ], 'QZ 4': [ languages.get_text("mesh_pathology", lang), languages.get_text("mesh_disease", lang), languages.get_text("mesh_clinical_pathology", lang) ], 'WY 100': [ languages.get_text("mesh_nursing_care", lang), languages.get_text("mesh_nursing_process", lang), languages.get_text("mesh_clinical_nursing_research", lang) ], 'WA 1': [ languages.get_text("mesh_public_health", lang), languages.get_text("mesh_preventive_medicine", lang), languages.get_text("mesh_epidemiology", lang) ], 'WM 1': [ languages.get_text("mesh_psychiatry", lang), languages.get_text("mesh_mental_disorders", lang), languages.get_text("mesh_psychotherapy", lang) ] } nlm_code = nlm_result['nlm_code'] mesh_subjects = [] for code_prefix, subjects in mesh_mapping.items(): if nlm_code.startswith(code_prefix) or code_prefix in nlm_code: mesh_subjects = subjects break if not mesh_subjects: mesh_subjects = [ languages.get_text("mesh_medicine", lang), languages.get_text("mesh_medical_sciences", lang), languages.get_text("mesh_health_occupations", lang) ] # تحديد الجمهور المستهدف مع الترجمة if 'Textbook' in nlm_result.get('nlm_name', ''): audience_category = languages.get_text("audience_undergraduate", lang) audience_reason = languages.get_text("audience_reason_textbook", lang) elif 'Education' in nlm_result.get('nlm_name', ''): audience_category = languages.get_text("audience_educators", lang) audience_reason = languages.get_text("audience_reason_education", lang) elif 'Surgery' in nlm_result.get('nlm_name', ''): audience_category = languages.get_text("audience_surgeons", lang) audience_reason = languages.get_text("audience_reason_surgery", lang) else: audience_category = languages.get_text("audience_medical_students", lang) audience_reason = languages.get_text("audience_reason_default", lang) # قرار الشراء مع الترجمة score = nlm_result['confidence_score'] if score >= 8: acquisition_decision = languages.get_text("decision_highly_recommended", lang) acquisition_reason = languages.get_text("acquisition_reason_high", lang) elif score >= 4: acquisition_decision = languages.get_text("decision_recommended", lang) acquisition_reason = languages.get_text("acquisition_reason_medium", lang) else: acquisition_decision = languages.get_text("decision_review_required", lang) acquisition_reason = languages.get_text("acquisition_reason_low", lang) return { 'title': title, 'sub_title': '', 'authors': authors, 'edition': enhanced_meta.get('edition', ''), 'publisher': publisher, 'pub_year': pub_year, 'pages': enhanced_meta.get('page_count', 'xii, 500'), 'isbn_10': enhanced_meta.get('isbn_10', ''), 'isbn_13': enhanced_meta.get('isbn_13', isbn), 'summary': summary, 'contents_note': contents_note, 'audience_category': audience_category, 'audience_reason': audience_reason, 'mesh_subjects': mesh_subjects, 'nlm_class': nlm_code, 'nlm_class_reason': f"Local classification: {nlm_result['confidence_reason']}", 'nlm_class_confidence': nlm_result['confidence_level'], 'nlm_class_score': score, 'acquisition_decision': acquisition_decision, 'acquisition_reason': acquisition_reason, 'quality_score': score // 2 if score > 0 else 5, 'data_accuracy': 'Medium', 'illustrations_note': 'illustrations', 'metadata_source': enhanced_meta.get('source', 'Local'), 'metadata_confidence': enhanced_meta.get('confidence', 'Medium') } # --- 4. MAIN UI --- if 'analysis_data' not in st.session_state: st.session_state.analysis_data = None if 'search_history' not in st.session_state: st.session_state.search_history = [] # --- HEADER --- st.markdown(f"""
🏥 {languages.get_text('app_title', lang)}
{languages.get_text('app_subtitle', lang)}
""", unsafe_allow_html=True) # --- MAIN INPUT AREA --- col1, col2, col3 = st.columns([2, 1, 1]) with col1: st.markdown(languages.get_text("enter_isbn", lang)) isbn_input = st.text_input( label="ISBN", placeholder=languages.get_text("isbn_placeholder", lang), label_visibility="collapsed", key="isbn_input" ) with col2: st.markdown("###  ") analyze_btn = st.button( languages.get_text("analyze_button", lang), width='stretch', type="primary", key="analyze_btn" ) with col3: st.markdown("###  ") if st.button( languages.get_text("view_stats_button", lang), width='stretch', key="stats_btn" ): st.switch_page("pages/statistics.py") # --- PROCESSING --- if analyze_btn and isbn_input: isbn_clean = clean_isbn(isbn_input) if not isbn_clean: st.error(languages.get_text("invalid_isbn", lang)) else: progress_bar = st.progress(0) status_text = st.empty() with st.spinner(languages.get_text("initializing", lang)): status_text.text(languages.get_text("fetching_metadata", lang)) metadata_fetcher = EnhancedMetadataFetcher() metadata = metadata_fetcher.fetch_metadata(isbn_clean) progress_bar.progress(25) time.sleep(0.5) status_text.text(languages.get_text("retrieving_cover", lang)) cover_fetcher = EnhancedCoverFetcher() cover_result = cover_fetcher.get_cover(isbn_clean, metadata.get('title')) progress_bar.progress(40) time.sleep(0.5) status_text.text(languages.get_text("searching_context", lang)) web_context = search_web_context(isbn_clean, metadata.get('title')) progress_bar.progress(60) time.sleep(0.5) status_text.text(languages.get_text("ai_analysis", lang)) ai_result = enhanced_ai_librarian_analysis(isbn_clean, metadata, web_context) progress_bar.progress(85) time.sleep(0.5) if ai_result: st.session_state.analysis_data = { 'metadata': metadata, 'cover_result': cover_result, 'web_context': web_context, 'ai_analysis': ai_result, 'isbn': isbn_clean, 'timestamp': datetime.now().isoformat() } st.session_state.search_history.append({ 'isbn': isbn_clean, 'title': ai_result.get('title', 'Unknown'), 'timestamp': datetime.now().isoformat(), 'nlm_class': ai_result.get('nlm_class', '') }) progress_bar.progress(100) status_text.text(languages.get_text("analysis_complete", lang)) time.sleep(1) st.rerun() else: st.error(languages.get_text("analysis_failed", lang)) progress_bar.empty() status_text.empty() # --- DISPLAY RESULTS --- if st.session_state.analysis_data: data = st.session_state.analysis_data if 'progress_bar' in locals(): progress_bar.empty() status_text.empty() tab1, tab2, tab3, tab4 = st.tabs([ languages.get_text("tab_overview", lang), languages.get_text("tab_details", lang), languages.get_text("tab_cataloging", lang), languages.get_text("tab_ai_insights", lang) ]) with tab1: col1, col2 = st.columns([1, 2]) with col1: st.markdown('
', unsafe_allow_html=True) st.image(data['cover_result']['url'], width='stretch') st.markdown('
', unsafe_allow_html=True) if data['cover_result'].get('source'): st.caption(f"Cover source: {data['cover_result']['source']}") st.markdown('
', unsafe_allow_html=True) st.markdown(f"### {languages.get_text('quick_stats', lang)}") cols = st.columns(3) with cols[0]: authors_count = len(data['ai_analysis'].get('authors', [])) st.markdown(f'
{authors_count}
', unsafe_allow_html=True) st.markdown(f'
{languages.get_text("authors_label", lang)}
', unsafe_allow_html=True) with cols[1]: quality = data['ai_analysis'].get('quality_score', 5) st.markdown(f'
{quality}/10
', unsafe_allow_html=True) st.markdown(f'
{languages.get_text("quality_label", lang)}
', unsafe_allow_html=True) with cols[2]: year = data['ai_analysis'].get('pub_year', 'N/A') st.markdown(f'
{year}
', unsafe_allow_html=True) st.markdown(f'
{languages.get_text("year_label", lang)}
', unsafe_allow_html=True) st.markdown('
', unsafe_allow_html=True) with col2: ai = data['ai_analysis'] st.markdown(f"# {ai.get('title', 'Unknown Title')}") if ai.get('sub_title'): st.markdown(f"### *{ai['sub_title']}*") authors = ai.get('authors', []) if authors: st.markdown(f"**👥 {languages.get_text('authors_label', lang)}:** {', '.join(authors)}") pub_info = [] if ai.get('publisher'): pub_info.append(ai['publisher']) if ai.get('pub_year'): pub_info.append(ai['pub_year']) if ai.get('pub_year_source'): pub_info.append(f"({ai['pub_year_source']})") if ai.get('edition'): pub_info.append(ai['edition']) if pub_info: st.markdown(f"**🏢 Publisher:** {' • '.join(pub_info)}") isbns = [] if ai.get('isbn_13'): isbns.append(f"ISBN-13: `{ai['isbn_13']}`") if ai.get('isbn_10'): isbns.append(f"ISBN-10: `{ai['isbn_10']}`") if isbns: st.markdown(f"**📋 Identifiers:** {' | '.join(isbns)}") st.markdown("---") decision = ai.get('acquisition_decision', languages.get_text("decision_recommended", lang)) if decision == languages.get_text("decision_highly_recommended", lang): pill_class = "status-high" elif decision == languages.get_text("decision_recommended", lang): pill_class = "status-medium" elif decision == languages.get_text("decision_review_required", lang) or decision == languages.get_text("decision_optional", lang): pill_class = "status-low" else: pill_class = "status-medium" st.markdown(f"### {languages.get_text('acquisition_decision', lang)}") st.markdown(f'
{decision}
', unsafe_allow_html=True) st.caption(ai.get('acquisition_reason', '')) st.markdown(f"### {languages.get_text('target_audience', lang)}") audience = ai.get('audience_category', languages.get_text("not_specified", lang)) st.markdown(f'
{audience}
', unsafe_allow_html=True) st.caption(ai.get('audience_reason', '')) with tab2: col1, col2 = st.columns(2) with col1: st.markdown('
', unsafe_allow_html=True) st.markdown(f"### {languages.get_text('summary', lang)}") st.write(ai.get('summary', languages.get_text('no_summary', lang))) st.markdown('
', unsafe_allow_html=True) st.markdown('
', unsafe_allow_html=True) st.markdown(f"### {languages.get_text('table_of_contents', lang)}") contents = ai.get('contents_note', languages.get_text('not_available', lang)) if isinstance(contents, list): for item in contents: st.write(f"• {item}") else: st.write(contents) st.markdown('
', unsafe_allow_html=True) with col2: st.markdown('
', unsafe_allow_html=True) st.markdown(f"### {languages.get_text('mesh_subjects', lang)}") mesh_terms = ai.get('mesh_subjects', []) if mesh_terms: for term in mesh_terms[:8]: st.markdown(f'
{term}
', unsafe_allow_html=True) else: st.write(languages.get_text('no_mesh', lang)) st.markdown('
', unsafe_allow_html=True) st.markdown('
', unsafe_allow_html=True) st.markdown(f"### {languages.get_text('nlm_classification', lang)}") nlm_code = ai.get('nlm_class', 'W 1') st.markdown(f'
{nlm_code}
', unsafe_allow_html=True) confidence = ai.get('nlm_class_confidence', 'Medium') if confidence == 'High': st.success(f"✅ {languages.get_text('confidence_level', lang)}: {confidence} ({languages.get_text('quality_score', lang)}: {ai.get('nlm_class_score', 0)})") elif confidence == 'Medium': st.warning(f"⚠️ {languages.get_text('confidence_level', lang)}: {confidence} ({languages.get_text('quality_score', lang)}: {ai.get('nlm_class_score', 0)})") else: st.error(f"❌ {languages.get_text('confidence_level', lang)}: {confidence} ({languages.get_text('quality_score', lang)}: {ai.get('nlm_class_score', 0)})") if ai.get('nlm_class_explanation'): st.info(f"💡 {ai['nlm_class_explanation']}") if ai.get('nlm_class_reason'): with st.expander(languages.get_text('classification_reasoning', lang)): st.write(ai['nlm_class_reason']) if ai.get('nlm_alternatives'): with st.expander(languages.get_text('alternative_classifications', lang)): for alt in ai['nlm_alternatives'][:3]: st.code(alt, language="text") st.markdown('
', unsafe_allow_html=True) with tab3: ai = data['ai_analysis'] st.markdown('
', unsafe_allow_html=True) st.markdown(f"### {languages.get_text('marc_record', lang)}") marc_lines = build_marc_record(ai, data['isbn']) marc_text = "\n".join(marc_lines) iso_record = generate_marc_iso2709(marc_lines, data['isbn']) col1, col2 = st.columns(2) with col1: st.code(marc_text, language="text") with col2: st.code(iso_record['iso2709'], language="text") st.caption(f"ISO 2709 Record - {iso_record['record_length']} bytes") marcxml_text = generate_marcxml(marc_lines, data['isbn']) col1, col2, col3, col4 = st.columns(4) with col1: st.download_button( label=languages.get_text("download_marc", lang), data=marc_text, file_name=f"{data['isbn']}.mrc", mime="text/plain", width='stretch' ) with col2: st.download_button( label=languages.get_text("download_iso", lang), data=iso_record['iso2709'].encode('utf-8'), file_name=f"{data['isbn']}_iso2709.iso", mime="application/octet-stream", width='stretch' ) with col3: st.download_button( label=languages.get_text("download_json", lang), data=json.dumps(data, indent=2, ensure_ascii=False), file_name=f"{data['isbn']}_complete.json", mime="application/json", width='stretch' ) with col4: st.download_button( label=languages.get_text("download_xml", lang), data=marcxml_text, file_name=f"{data['isbn']}.xml", mime="application/xml", width='stretch' ) st.markdown('
', unsafe_allow_html=True) with tab4: col1, col2 = st.columns(2) with col1: st.markdown('
', unsafe_allow_html=True) st.markdown(f"### {languages.get_text('ai_details', lang)}") st.metric(languages.get_text("confidence_level", lang), ai.get('confidence_level', 'Medium')) st.metric(languages.get_text("quality_score", lang), ai.get('quality_score', 'N/A')) st.metric(languages.get_text("data_sources", lang), len(data['web_context']) + (1 if data['metadata'] else 0)) if ai.get('metadata_source'): st.caption(f"{languages.get_text('metadata_source', lang)}: {ai['metadata_source']} ({ai.get('metadata_confidence', 'Unknown')})") st.markdown("---") st.markdown(f"#### {languages.get_text('nlm_analysis', lang)}") classifier = AdvancedNLMClassifier() nlm_analysis = classifier.classify_with_confidence( ai.get('title', ''), ai.get('summary', '') ) st.metric(languages.get_text("confidence_level", lang), nlm_analysis['confidence_level']) st.caption(f"{languages.get_text('code_label', lang)}: {nlm_analysis['nlm_code']}") st.caption(f"{languages.get_text('reason_label', lang)}: {nlm_analysis['confidence_reason']}") st.markdown('
', unsafe_allow_html=True) with col2: st.markdown('
', unsafe_allow_html=True) st.markdown(f"### {languages.get_text('web_context', lang)}") if data['web_context']: for i, source in enumerate(data['web_context'][:3], 1): with st.expander(f"Source {i}: {source.get('title', 'Unknown')}"): st.write(source.get('snippet', languages.get_text('no_web_context', lang))) if source.get('url'): st.caption(f"URL: {source['url']}") else: st.info(languages.get_text('no_web_context', lang)) st.markdown('
', unsafe_allow_html=True) # --- SIDEBAR --- with st.sidebar: # إضافة محدد اللغة lang_options = {'en': 'English', 'ar': 'العربية'} selected_lang = st.selectbox("Language / اللغة", options=list(lang_options.keys()), format_func=lambda x: lang_options[x], index=0 if lang=='en' else 1) if selected_lang != lang: st.session_state.language = selected_lang st.rerun() st.markdown(f"### {languages.get_text('recent_searches', lang)}") if st.session_state.search_history: for item in reversed(st.session_state.search_history[-5:]): st.caption(f"• {item['isbn']} - {item['title'][:30]}...") if item.get('nlm_class'): st.caption(f" NLM: `{item['nlm_class']}`") st.markdown("---") st.markdown(f"### {languages.get_text('settings', lang)}") if st.button(languages.get_text("clear_history", lang), key="clear_btn"): st.session_state.search_history = [] st.session_state.analysis_data = None st.rerun() st.markdown("---") st.markdown(f"### {languages.get_text('nlm_quick_guide', lang)}") with st.expander(languages.get_text("common_nlm_classifications", lang)): st.markdown(f""" {languages.get_text('medical_textbooks', lang)} {languages.get_text('clinical_medicine', lang)} {languages.get_text('basic_sciences', lang)} {languages.get_text('health_professions', lang)} {languages.get_text('common_examples', lang)} - {languages.get_text('anatomy_example', lang)} - {languages.get_text('pharmacology_example', lang)} - {languages.get_text('surgery_example', lang)} - {languages.get_text('pediatrics_example', lang)} - {languages.get_text('radiology_example', lang)} """) st.markdown("---") st.markdown(f"### {languages.get_text('stats', lang)}") st.metric(languages.get_text("total_analyses", lang), len(st.session_state.search_history)) if st.session_state.analysis_data: st.metric(languages.get_text("current_isbn", lang), st.session_state.analysis_data['isbn']) else: st.metric(languages.get_text("current_isbn", lang), languages.get_text("none", lang)) # --- FOOTER --- st.markdown(f""" """, unsafe_allow_html=True)