Skip to main content
Glama
openai_client.pyโ€ข3.65 kB
"""OpenAI API wrapper with graceful fallback.""" from __future__ import annotations import logging import os from typing import Any, Dict, List, Optional from io import BytesIO try: # pragma: no cover - import error handling from openai import AsyncOpenAI OPENAI_AVAILABLE = True except Exception: # noqa: BLE001 OPENAI_AVAILABLE = False AsyncOpenAI = None # type: ignore[assignment] logging.warning("OpenAI package not available; using stub responses") class OpenAIClient: """Simple async wrapper around the OpenAI chat API.""" def __init__(self, api_key: Optional[str] = None, model: str = "gpt-4o-mini"): self.api_key = api_key or os.getenv("OPENAI_API_KEY") self.model = model self.client: Optional[AsyncOpenAI] = None if OPENAI_AVAILABLE and self.api_key: try: self.client = AsyncOpenAI(api_key=self.api_key) except Exception as exc: # noqa: BLE001 logging.error("Failed to init OpenAI client: %s", exc) self.client = None async def chat(self, messages: List[Dict[str, str]]) -> Dict[str, Any]: """Send chat messages to the OpenAI API. Returns a dictionary with ``role`` and ``content`` keys. If the OpenAI client is unavailable, a stub response is returned. """ if not self.client: return {"role": "assistant", "content": "OpenAI not configured."} try: response = await self.client.chat.completions.create( model=self.model, messages=messages ) message = response.choices[0].message return {"role": message.role, "content": message.content or ""} except Exception as exc: # noqa: BLE001 logging.error("OpenAI request failed: %s", exc) return {"role": "assistant", "content": "Error contacting OpenAI."} async def transcribe_audio( self, audio: bytes, model: str = "gpt-4o-mini-transcribe" ) -> str: """Transcribe audio bytes to text using OpenAI's transcription API. Returns the transcribed text. If the OpenAI client is unavailable or the request fails, an empty string is returned instead. """ if not self.client: return "" try: audio_file = BytesIO(audio) response = await self.client.audio.transcriptions.create( model=model, file=audio_file ) return getattr(response, "text", "") except Exception as exc: # noqa: BLE001 logging.error("OpenAI transcription failed: %s", exc) return "" async def text_to_speech( self, text: str, voice: str = "alloy", model: str = "gpt-4o-mini-tts", format: str = "mp3", ) -> bytes: """Convert text to speech and return audio bytes. If the OpenAI client is unavailable or the request fails, an empty byte string is returned. """ if not self.client: return b"" try: response = await self.client.audio.speech.create( model=model, voice=voice, input=text, format=format ) # HttpxBinaryResponseContent provides an async read method if hasattr(response, "aread"): return await response.aread() if hasattr(response, "read"): return response.read() return b"" except Exception as exc: # noqa: BLE001 logging.error("OpenAI text-to-speech failed: %s", exc) return b""

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/consolecowboy0/race-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server