"""MiniMax 适配器 -- 支持 chat / image / voice / video""" from __future__ import annotations import json from typing import Any, AsyncGenerator import httpx from app.providers.base import BaseProvider, Capability, QuotaInfo class MiniMaxProvider(BaseProvider): name = "minimax" display_name = "MiniMax" capabilities = [Capability.CHAT, Capability.IMAGE, Capability.VOICE, Capability.VIDEO] async def chat( self, messages: list[dict], model: str, plan: dict, stream: bool = True, **kwargs, ) -> AsyncGenerator[str, None]: url = f"{self._base_url(plan)}/text/chatcompletion_v2" body: dict[str, Any] = { "model": model, "messages": messages, "stream": stream, **kwargs, } headers = self._build_headers(plan) async with httpx.AsyncClient(timeout=120) as client: if stream: async with client.stream("POST", url, json=body, headers=headers) as resp: resp.raise_for_status() async for line in resp.aiter_lines(): if line.startswith("data: "): yield line + "\n\n" else: resp = await client.post(url, json=body, headers=headers) resp.raise_for_status() yield json.dumps(resp.json()) async def generate_image(self, prompt: str, plan: dict, **kwargs) -> dict[str, Any]: url = f"{self._base_url(plan)}/image/generation" body = {"model": kwargs.get("model", "image-01"), "prompt": prompt, **kwargs} headers = self._build_headers(plan) async with httpx.AsyncClient(timeout=120) as client: resp = await client.post(url, json=body, headers=headers) resp.raise_for_status() return resp.json() async def generate_voice(self, text: str, plan: dict, **kwargs) -> bytes: url = f"{self._base_url(plan)}/tts/generation" body = {"text": text, "model": kwargs.get("model", "speech-02"), **kwargs} headers = self._build_headers(plan) async with httpx.AsyncClient(timeout=120) as client: resp = await client.post(url, json=body, headers=headers) resp.raise_for_status() return resp.content async def generate_video(self, prompt: str, plan: dict, **kwargs) -> dict[str, Any]: url = f"{self._base_url(plan)}/video/generation" body = {"model": kwargs.get("model", "video-01"), "prompt": prompt, **kwargs} headers = self._build_headers(plan) async with httpx.AsyncClient(timeout=120) as client: resp = await client.post(url, json=body, headers=headers) resp.raise_for_status() return resp.json() async def query_quota(self, plan: dict) -> QuotaInfo | None: """MiniMax 余额查询""" try: url = f"{self._base_url(plan)}/account/balance" headers = self._build_headers(plan) async with httpx.AsyncClient(timeout=30) as client: resp = await client.get(url, headers=headers) resp.raise_for_status() data = resp.json() return QuotaInfo( quota_remaining=data.get("balance", 0), raw=data, ) except Exception: return None