We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/ryoooo/nijivoice-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server
import os
import httpx
import logging
from typing import List, Optional, Union, BinaryIO
import base64
from .models import VoiceActor, VoiceGenerationRequest, Balance
from .exceptions import NijiVoiceAPIError
# ロガーの設定
logger = logging.getLogger('nijivoice_mcp.api')
class NijiVoiceClient:
"""にじボイスAPIクライアント"""
BASE_URL = "https://api.nijivoice.com/api/platform/v1"
def __init__(self, api_key: Optional[str] = None, timeout: Optional[float] = 30.0):
"""
初期化
Args:
api_key: APIキー。指定しない場合は環境変数 NIJIVOICE_API_KEY から読み込みます。
timeout: HTTPリクエストのタイムアウト時間(秒)
"""
self.api_key = api_key or os.environ.get("NIJIVOICE_API_KEY")
if not self.api_key:
raise ValueError("APIキーが指定されていません。引数で指定するか、NIJIVOICE_API_KEY 環境変数を設定してください。")
self.timeout = timeout
self.headers = {
"x-api-key": self.api_key,
"Accept": "application/json",
}
async def get_voice_actors(self) -> List[VoiceActor]:
"""
利用可能なVoice Actorの一覧を取得します。
Returns:
Voice Actorのリスト
Raises:
NijiVoiceAPIError: API呼び出しに失敗した場合
"""
try:
async with httpx.AsyncClient(timeout=self.timeout) as client:
response = await client.get(f"{self.BASE_URL}/voice-actors", headers=self.headers)
if response.status_code != 200:
raise NijiVoiceAPIError(
f"Voice Actor一覧の取得に失敗しました: {response.text}",
status_code=response.status_code
)
data = response.json()
# APIがvoiceActorsキーの中に配列を返す場合の対応
if isinstance(data, dict):
actors_data = data.get("voiceActors", data)
else:
actors_data = data
if not isinstance(actors_data, list):
# データがリストでない場合は空リストを返す
logger.warning(f"予期しないデータ形式です: {data}")
return []
return [VoiceActor.model_validate(actor) for actor in actors_data]
except TimeoutError:
raise NijiVoiceAPIError("APIリクエストがタイムアウトしました", status_code=408)
except NijiVoiceAPIError:
raise
except Exception as e:
raise NijiVoiceAPIError(f"API呼び出し中にエラーが発生しました: {str(e)}", status_code=500)
async def generate_voice(
self,
request: VoiceGenerationRequest,
) -> dict:
"""
指定されたVoice Actorの声で音声を生成します。
Args:
voice_actor_id: Voice Actor ID
request: 音声生成リクエスト
Returns:
APIレスポンス
"""
url = f"{self.BASE_URL}/voice-actors/{request.id}/generate-voice"
# リクエストデータを準備(None値のフィールドは除外)
request_data = request.model_dump(by_alias=True)
logger.debug("Sending request data to API: %s", request_data)
async with httpx.AsyncClient(timeout=self.timeout) as client:
response = await client.post(
url,
headers=self.headers,
json=request_data,
)
if response.status_code != 200:
raise NijiVoiceAPIError(f"音声生成に失敗しました: {response.text}", status_code=response.status_code)
data = response.json()
logger.debug("generate_voice API response: %s", data)
return data
async def get_balance(self) -> Balance:
"""
クレジット残高を取得します。
Returns:
クレジット残高
"""
async with httpx.AsyncClient(timeout=self.timeout) as client:
response = await client.get(f"{self.BASE_URL}/balances", headers=self.headers)
if response.status_code != 200:
raise NijiVoiceAPIError(f"クレジット残高の取得に失敗しました: {response.text}", status_code=response.status_code)
data = response.json()
# APIレスポンスの構造をログに出力
logger.debug(f"Balance API response: {data}")
# モデル検証
balance = Balance.model_validate(data)
return balance