ForcePilot/backend/package/yuxi/channels/adapters/imessage/media_ai.py

85 lines
3.1 KiB
Python
Raw Normal View History

from __future__ import annotations
from typing import Any
from yuxi.utils.logging_config import logger
async def describe_image(image_data: bytes, vision_api_url: str = "", vision_api_key: str = "") -> str:
"""通过外部 Vision API 描述图片内容。
如果未配置 API URL返回基本元数据描述
"""
if not vision_api_url:
return f"Image attachment ({len(image_data)} bytes)"
try:
import base64
import aiohttp
encoded = base64.b64encode(image_data).decode("utf-8")
payload = {
"model": "gpt-4o-mini",
"messages": [
{
"role": "user",
"content": [
{"type": "text", "text": "Describe this image briefly in one sentence."},
{
"type": "image_url",
"image_url": {"url": f"data:image/jpeg;base64,{encoded}"},
},
],
}
],
"max_tokens": 100,
}
headers = {"Authorization": f"Bearer {vision_api_key}"}
async with aiohttp.ClientSession() as session:
async with session.post(
vision_api_url, json=payload, headers=headers, timeout=aiohttp.ClientTimeout(total=15)
) as resp:
if resp.status == 200:
data = await resp.json()
return data["choices"][0]["message"]["content"]
return f"Image attachment ({len(image_data)} bytes)"
except Exception as e:
logger.warning(f"[iMessage/AI] Vision API failed: {e}")
return f"Image attachment ({len(image_data)} bytes)"
async def transcribe_audio(audio_data: bytes, transcription_api_url: str = "", transcription_api_key: str = "") -> str:
"""通过外部 API 转录音频内容。"""
if not transcription_api_url:
return f"Audio attachment ({len(audio_data)} bytes)"
try:
import aiohttp
from aiohttp import FormData
form = FormData()
form.add_field("file", audio_data, filename="audio.caf", content_type="audio/x-caf")
form.add_field("model", "whisper-1")
headers = {"Authorization": f"Bearer {transcription_api_key}"}
async with aiohttp.ClientSession() as session:
async with session.post(
transcription_api_url, data=form, headers=headers, timeout=aiohttp.ClientTimeout(total=30)
) as resp:
if resp.status == 200:
data = await resp.json()
return data.get("text", "")
return f"Audio attachment ({len(audio_data)} bytes)"
except Exception as e:
logger.warning(f"[iMessage/AI] Transcription API failed: {e}")
return f"Audio attachment ({len(audio_data)} bytes)"
def is_vision_configured(config: dict[str, Any]) -> bool:
return bool(config.get("vision_api_url") and config.get("vision_api_key"))
def is_transcription_configured(config: dict[str, Any]) -> bool:
return bool(config.get("transcription_api_url") and config.get("transcription_api_key"))