Spaces:
Runtime error
Runtime error
| import os | |
| import logging | |
| import re | |
| import io | |
| from PIL import Image | |
| import gradio as gr | |
| # ✅ تعطيل SSR قبل استيراد Gradio | |
| os.environ["GRADIO_SSR_MODE"] = "False" | |
| os.environ["GRADIO_NODE_DISABLED"] = "True" | |
| logging.basicConfig( | |
| level=logging.INFO, | |
| format='%(asctime)s - %(levelname)s - %(message)s' | |
| ) | |
| logger = logging.getLogger(__name__) | |
| logger.info("بدء تشغيل DermaScan AI...") | |
| try: | |
| from rag import build_default_vectorstore | |
| from agent import ( | |
| build_agent, | |
| set_session_storage, | |
| set_current_thread_id, | |
| set_api_client, | |
| ) | |
| from api_client import DermaScanAPIClient | |
| logger.info("✅ تم استيراد جميع الوحدات بنجاح") | |
| except Exception as e: | |
| logger.error(f"❌ فشل استيراد الوحدات: {e}", exc_info=True) | |
| raise | |
| MODEL_NAME = "llama-3.1-8b-instant" | |
| TEMPERATURE = 0.25 | |
| TOP_K = 3 | |
| EXTERNAL_API_URL = "https://omarelrayes-api.hf.space" | |
| SESSIONS = {} | |
| agent = None | |
| api_client = None | |
| def get_session(thread_id: str) -> dict: | |
| if thread_id not in SESSIONS: | |
| SESSIONS[thread_id] = { | |
| "role": "patient", "last_analysis": None, "current_image": None, | |
| "_image_blobs": {}, "_session_image_names": [], "_turn_count": 0 | |
| } | |
| return SESSIONS[thread_id] | |
| def initialize_system(): | |
| global agent, api_client | |
| try: | |
| logger.info("بدء تهيئة النظام...") | |
| groq_key = os.environ.get("GROQ_API_KEY") | |
| if not groq_key: | |
| logger.warning("GROQ_API_KEY not set") | |
| else: | |
| logger.info("GROQ_API_KEY found") | |
| api_client = DermaScanAPIClient(EXTERNAL_API_URL) | |
| set_api_client(api_client) | |
| if api_client.health_check(): | |
| logger.info("External API is healthy") | |
| vectorstore = build_default_vectorstore() | |
| retriever = vectorstore.as_retriever(search_kwargs={"k": TOP_K}) if vectorstore else None | |
| if retriever is None: | |
| logger.warning("Vectorstore not available") | |
| agent = build_agent(retriever, model_name=MODEL_NAME, temperature=TEMPERATURE) | |
| logger.info("✅ Agent built successfully") | |
| logger.info("تم تهيئة النظام بنجاح!") | |
| except Exception as e: | |
| logger.error(f"فشل التهيئة: {e}", exc_info=True) | |
| raise | |
| initialize_system() | |
| def chat_with_agent(message: str, history: list) -> str: | |
| if agent is None: | |
| return "System not initialized yet." | |
| session = get_session("default") | |
| set_session_storage(SESSIONS) | |
| set_current_thread_id("default") | |
| try: | |
| last_analysis = session.get("last_analysis") | |
| analysis_ctx = f"\n\n[Analysis: {last_analysis.get('label', 'N/A')}]" if last_analysis else "" | |
| full_prompt = message + analysis_ctx | |
| config = {"configurable": {"thread_id": "default"}, "recursion_limit": 14} | |
| final_text = "" | |
| for event in agent.stream( | |
| {"messages": [("user", full_prompt)]}, | |
| config=config, | |
| stream_mode="values" | |
| ): | |
| last_msg = event["messages"][-1] | |
| if last_msg.type == "ai" and last_msg.content: | |
| final_text = last_msg.content | |
| cleaned_text = re.sub(r'\[ANALYSIS_RESULT:\{.*?\}\]', '', final_text).strip() | |
| session["_turn_count"] = session.get("_turn_count", 0) + 1 | |
| return cleaned_text if cleaned_text else "No response." | |
| except Exception as e: | |
| logger.error(f"Chat error: {e}") | |
| return f"Error: {str(e)}" | |
| def analyze_image(image, thread_id: str = "default") -> str: | |
| if api_client is None: | |
| return "API client not initialized" | |
| try: | |
| api_client.set_role(thread_id, "patient") | |
| session = get_session(thread_id) | |
| session["current_image"] = image | |
| result = api_client.upload_and_analyze_image(image, thread_id) | |
| if not result.get('ok'): | |
| return f"Error: {result.get('error', 'Unknown error')}" | |
| session["last_analysis"] = { | |
| "label": result.get("label"), | |
| "confidence_pct": result.get("confidence_pct"), | |
| "infection_pct": result.get("infection_pct") | |
| } | |
| return ( | |
| f"تم التحليل بنجاح!\n\n" | |
| f"التصنيف: {result.get('label')}\n" | |
| f"نسبة الثقة: {result.get('confidence_pct')}%\n" | |
| f"المساحة المصابة: {result.get('infection_pct')}%" | |
| ) | |
| except Exception as e: | |
| logger.error(f"Image analysis error: {e}") | |
| return f"Error: {str(e)}" | |
| logger.info("جاري بناء واجهة Gradio...") | |
| with gr.Blocks(title="DermaScan AI") as demo: | |
| gr.Markdown("# 🏥 DermaScan AI - مساعد أمراض الجلدية") | |
| with gr.Tab("📤 رفع الصورة"): | |
| image_input = gr.Image(type="pil", label="ارفع صورة الجلد") | |
| analyze_btn = gr.Button("🔍 تحليل الصورة", variant="primary") | |
| analysis_output = gr.Textbox(label="نتيجة التحليل", lines=6) | |
| analyze_btn.click(fn=analyze_image, inputs=[image_input], outputs=[analysis_output]) | |
| with gr.Tab("💬 الدردشة"): | |
| chatbot = gr.Chatbot(label="المحادثة", height=400) | |
| msg_input = gr.Textbox(label="رسالتك", placeholder="اسأل عن حالتك الجلدية...", lines=2) | |
| send_btn = gr.Button("🚀 إرسال", variant="primary") | |
| clear_btn = gr.Button("🗑️ مسح") | |
| def user_message(user_msg, history): | |
| return "", history + [[user_msg, None]] | |
| def bot_response(history): | |
| if not history: | |
| return history | |
| user_msg = history[-1][0] | |
| response = chat_with_agent(user_msg, history[:-1]) | |
| history[-1][1] = response | |
| return history | |
| send_btn.click(user_message, [msg_input, chatbot], [msg_input, chatbot]).then( | |
| bot_response, chatbot, chatbot | |
| ) | |
| msg_input.submit(user_message, [msg_input, chatbot], [msg_input, chatbot]).then( | |
| bot_response, chatbot, chatbot | |
| ) | |
| clear_btn.click(lambda: None, None, chatbot) | |
| with gr.Tab("📚 API Info"): | |
| gr.Markdown("## API شغالة! استخدم Gradio Client للاتصال.") | |
| logger.info("✅ تم بناء واجهة Gradio") | |
| logger.info("🎉 DermaScan AI جاهز!") | |
| # ✅ الحل الحقيقي: ssr_mode=False في launch() | |
| demo.launch( | |
| server_name="0.0.0.0", | |
| server_port=7860, | |
| ssr_mode=False, # ← ده اللي هيمنع Node.js SSR | |
| share=False | |
| ) |