from __future__ import annotations from typing import Any from yuxi.channels.models import ChannelMessage from yuxi.utils.logging_config import logger async def analyze_image( bridge: Any, image_url: str, prompt: str = "Describe this image in detail.", ) -> dict[str, Any]: try: resp = await bridge.post( "/vision/analyze", json={ "image_url": image_url, "prompt": prompt, }, ) return resp.json() except Exception as e: logger.warning(f"[ZaloUser] Vision analysis failed: {e}") return {"error": str(e)} async def analyze_media( bridge: Any, media_url: str, media_type: str = "image", prompt: str = "", ) -> dict[str, Any]: if media_type == "image": default_prompt = "Describe this image in detail." elif media_type == "video": default_prompt = "Describe this video content." else: default_prompt = "Analyze this media content." return await analyze_image(bridge, media_url, prompt or default_prompt) def has_vision_support(config: dict[str, Any]) -> bool: return config.get("vision", {}).get("enabled", False) async def augment_message_with_vision( bridge: Any, message: ChannelMessage, config: dict[str, Any], ) -> ChannelMessage: if not has_vision_support(config): return message image_attachments = [a for a in message.attachments if a.type == "image"] if not image_attachments: return message descriptions: list[str] = [] for att in image_attachments: if not att.url: continue try: result = await analyze_image(bridge, att.url) if result.get("description"): descriptions.append(f"[Image: {result['description']}]") elif result.get("text"): descriptions.append(f"[Image OCR: {result['text']}]") except Exception: pass if descriptions: vision_text = "\n".join(descriptions) if message.content: message.content = f"{message.content}\n{vision_text}" else: message.content = vision_text return message