from __future__ import annotations import logging import re from yuxi.channel.extensions.feishu.utils import safe_filename, recover_latin1_filename logger = logging.getLogger(__name__) def detect_file_type(filename: str) -> str: ext = filename.rsplit(".", 1)[-1].lower() if "." in filename else "" type_map = { "opus": "opus", "ogg": "opus", "mp4": "mp4", "mov": "mp4", "avi": "mp4", "pdf": "pdf", "doc": "doc", "docx": "doc", "xls": "xls", "xlsx": "xls", "ppt": "ppt", "pptx": "ppt", } return type_map.get(ext, "stream") def resolve_outbound_media_kind(filename: str, content_type: str = "") -> dict: ext = filename.rsplit(".", 1)[-1].lower() if "." in filename else "" image_exts = {"png", "jpg", "jpeg", "gif", "bmp", "webp", "tiff"} opus_exts = {"opus", "ogg"} video_exts = {"mp4", "mov", "avi", "mkv", "webm"} if ext in image_exts or (content_type and content_type.startswith("image/")): return {"msg_type": "image", "file_type": "image"} if ext in opus_exts or content_type in ("audio/ogg", "audio/opus"): return {"msg_type": "audio", "file_type": "opus"} if ext in video_exts or (content_type and content_type.startswith("video/")): return {"msg_type": "media", "file_type": "mp4"} return {"msg_type": "file", "file_type": detect_file_type(filename)} async def upload_image( app_id: str, app_secret: str, domain: str, file_path: str, http_timeout_ms: int = 30000, ) -> dict: try: from yuxi.channel.extensions.feishu.client import get_client client = get_client(app_id, app_secret, domain, http_timeout_ms) import lark_oapi with open(file_path, "rb") as f: req = lark_oapi.im.v1.CreateImageRequest( request_body=lark_oapi.im.v1.CreateImageRequestBody( image_type="message", image=f, ), ) resp = await client.im.v1.image.create_async(req) if resp.success(): return {"success": True, "image_key": getattr(resp.data, "image_key", "")} else: return {"success": False, "error": getattr(resp, "msg", "")} except ImportError: return {"success": False, "error": "lark-oapi SDK not installed"} except Exception: logger.exception("Feishu upload_image error") return {"success": False, "error": "Internal error"} async def upload_file( app_id: str, app_secret: str, domain: str, file_path: str, file_type: str = "stream", filename: str = "", http_timeout_ms: int = 30000, ) -> dict: try: from yuxi.channel.extensions.feishu.client import get_client client = get_client(app_id, app_secret, domain, http_timeout_ms) import lark_oapi with open(file_path, "rb") as f: req = lark_oapi.im.v1.CreateFileRequest( request_body=lark_oapi.im.v1.CreateFileRequestBody( file_type=file_type, file_name=filename or safe_filename(file_path), file=f, ), ) resp = await client.im.v1.file.create_async(req) if resp.success(): return {"success": True, "file_key": getattr(resp.data, "file_key", "")} else: return {"success": False, "error": getattr(resp, "msg", "")} except ImportError: return {"success": False, "error": "lark-oapi SDK not installed"} except Exception: logger.exception("Feishu upload_file error") return {"success": False, "error": "Internal error"} async def download_image( app_id: str, app_secret: str, domain: str, image_key: str, http_timeout_ms: int = 30000, ) -> dict: try: from yuxi.channel.extensions.feishu.client import get_client client = get_client(app_id, app_secret, domain, http_timeout_ms) import lark_oapi req = lark_oapi.im.v1.GetImageRequest(image_key=image_key) resp = await client.im.v1.image.get_async(req) if resp.success(): return { "success": True, "content_type": resp.file.content_type if resp.file else "", } else: return {"success": False, "error": getattr(resp, "msg", "")} except ImportError: return {"success": False, "error": "lark-oapi SDK not installed"} except Exception: logger.exception("Feishu download_image error") return {"success": False, "error": "Internal error"}