Spaces:
Sleeping
Sleeping
| """ | |
| وحدة تحليل الصور | |
| - استلام صور من تيليجرام | |
| - تحليلها عبر: | |
| 1. Z.ai vision API (إذا كان ZAI_API_KEY متاح) | |
| 2. Hugging Face Inference API (بديل مجاني) | |
| """ | |
| import base64 | |
| import logging | |
| from typing import Optional | |
| import httpx | |
| from config import config | |
| logger = logging.getLogger(__name__) | |
| async def download_telegram_file(bot, file_id: str) -> bytes: | |
| """تحميل ملف من تيليجرام""" | |
| tg_file = await bot.get_file(file_id) | |
| # استخدام download_to_memory لتجنب الكتابة على القرص | |
| import io | |
| buf = io.BytesIO() | |
| await tg_file.download_to_memory(buf) | |
| return buf.getvalue() | |
| async def analyze_image_with_zai( | |
| image_bytes: bytes, | |
| prompt: str = "صف هذه الصورة بالتفصيل.", | |
| ) -> str: | |
| """ | |
| تحليل صورة عبر Z.ai vision API (glm-4v). | |
| يتطلب ZAI_API_KEY. | |
| """ | |
| if not config.api_keys_for_use: | |
| return "❌ ZAI_API_KEY غير مضبوط. لا يمكن تحليل الصورة." | |
| b64 = base64.b64encode(image_bytes).decode("utf-8") | |
| url = f"{config.ZAI_API_BASE}/chat/completions" | |
| headers = { | |
| "Authorization": f"Bearer {config.api_keys_for_use[0]}", | |
| "Content-Type": "application/json", | |
| } | |
| payload = { | |
| "model": "glm-4v-plus", | |
| "messages": [ | |
| { | |
| "role": "user", | |
| "content": [ | |
| {"type": "text", "text": prompt}, | |
| {"type": "image_url", "image_url": {"url": f"data:image/jpeg;base64,{b64}"}}, | |
| ], | |
| } | |
| ], | |
| "max_tokens": 1024, | |
| } | |
| try: | |
| async with httpx.AsyncClient(timeout=60) as client: | |
| resp = await client.post(url, headers=headers, json=payload) | |
| if resp.status_code != 200: | |
| # محاولة بنموذج بديل | |
| payload["model"] = "glm-4v" | |
| resp = await client.post(url, headers=headers, json=payload) | |
| if resp.status_code != 200: | |
| return f"❌ فشل التحليل (HTTP {resp.status_code}): {resp.text[:200]}" | |
| data = resp.json() | |
| return data.get("choices", [{}])[0].get("message", {}).get("content", "").strip() | |
| except Exception as e: | |
| logger.error(f"Z.ai vision failed: {e}", exc_info=True) | |
| return f"❌ خطأ في التحليل: {e}" | |
| async def analyze_image_with_hf( | |
| image_bytes: bytes, | |
| hf_token: str, | |
| ) -> str: | |
| """ | |
| تحليل صورة عبر Hugging Face Inference API (مجاني). | |
| يستخدم نموذج captioning مثل Salesforce/blip2-base. | |
| """ | |
| if not hf_token: | |
| return "❌ HF_TOKEN غير مضبوط." | |
| try: | |
| # تجربة نموذج captioning | |
| url = "https://api-inference.huggingface.co/models/Salesforce/blip-image-captioning-base" | |
| headers = {"Authorization": f"Bearer {hf_token}"} | |
| async with httpx.AsyncClient(timeout=60) as client: | |
| resp = await client.post(url, headers=headers, content=image_bytes) | |
| if resp.status_code != 200: | |
| return f"❌ HF inference فشل (HTTP {resp.status_code})" | |
| data = resp.json() | |
| if isinstance(data, list) and data: | |
| caption = data[0].get("generated_text", "") | |
| return f"**وصف الصورة:** {caption}" | |
| return f"```json\n{data}\n```" | |
| except Exception as e: | |
| logger.error(f"HF image analysis failed: {e}", exc_info=True) | |
| return f"❌ خطأ: {e}" | |
| async def analyze_image( | |
| image_bytes: bytes, | |
| prompt: str = "صف هذه الصورة بالتفصيل.", | |
| hf_token: str = "", | |
| ) -> str: | |
| """تحليل صورة مع fallback تلقائي""" | |
| # جرّب Z.ai أولاً (أفضل جودة) | |
| if config.ZAI_API_KEY: | |
| result = await analyze_image_with_zai(image_bytes, prompt) | |
| if not result.startswith("❌"): | |
| return result | |
| logger.warning(f"Z.ai vision failed, trying HF: {result}") | |
| # fallback إلى HF | |
| if hf_token: | |
| return await analyze_image_with_hf(image_bytes, hf_token) | |
| return "❌ لا يمكن تحليل الصورة: ZAI_API_KEY غير متاح و HF_TOKEN غير متاح." | |