81 lines
3.0 KiB
Python
81 lines
3.0 KiB
Python
"""Klient pro OpenAI — Whisper přepis + Chat Completions (slučování), přes httpx."""
|
|
import httpx
|
|
|
|
from ..config import OPENAI_BASE_URL, UPSTREAM_TIMEOUT_SECONDS
|
|
from ..errors import UpstreamError, raise_for_upstream
|
|
from ..logging_config import get_logger
|
|
|
|
log = get_logger("audio-transcription.openai")
|
|
|
|
|
|
async def transcribe(
|
|
*,
|
|
api_key: str,
|
|
audio: bytes,
|
|
filename: str,
|
|
content_type: str,
|
|
model: str,
|
|
language: str | None = None,
|
|
) -> str:
|
|
"""Přepíše audio přes OpenAI Whisper (/audio/transcriptions) a vrátí text."""
|
|
headers = {"Authorization": f"Bearer {api_key}"}
|
|
files = {"file": (filename or "audio.mp3", audio, content_type or "application/octet-stream")}
|
|
# temperature=0 => deterministický přepis, méně halucinací na tichu/šumu.
|
|
form = {"model": model, "temperature": "0"}
|
|
if language:
|
|
form["language"] = language
|
|
url = f"{OPENAI_BASE_URL}/audio/transcriptions"
|
|
|
|
try:
|
|
async with httpx.AsyncClient(timeout=UPSTREAM_TIMEOUT_SECONDS) as client:
|
|
resp = await client.post(url, headers=headers, data=form, files=files)
|
|
except httpx.HTTPError as exc:
|
|
log.error("OpenAI transcription request failed: %s", exc)
|
|
raise UpstreamError(f"OpenAI Whisper request se nezdařil: {exc}") from exc
|
|
|
|
if resp.status_code >= 400:
|
|
log.warning("OpenAI transcription returned %s: %s", resp.status_code, resp.text[:500])
|
|
raise_for_upstream("OpenAI Whisper", resp.status_code, resp.text)
|
|
|
|
data = resp.json()
|
|
return data.get("text", "") or ""
|
|
|
|
|
|
async def merge_transcripts(
|
|
*,
|
|
api_key: str,
|
|
model: str,
|
|
system_prompt: str,
|
|
text_deepgram: str,
|
|
text_whisper: str,
|
|
) -> str:
|
|
"""Sloučí dva přepisy do jednoho přes Chat Completions dle system promptu."""
|
|
headers = {"Authorization": f"Bearer {api_key}"}
|
|
payload = {
|
|
"model": model,
|
|
"messages": [
|
|
{"role": "system", "content": system_prompt},
|
|
{"role": "user", "content": f"Text z Deepgram: {text_deepgram}"},
|
|
{"role": "user", "content": f"Text z OpenAI Whisper: {text_whisper}"},
|
|
],
|
|
}
|
|
url = f"{OPENAI_BASE_URL}/chat/completions"
|
|
|
|
try:
|
|
async with httpx.AsyncClient(timeout=UPSTREAM_TIMEOUT_SECONDS) as client:
|
|
resp = await client.post(url, headers=headers, json=payload)
|
|
except httpx.HTTPError as exc:
|
|
log.error("OpenAI chat request failed: %s", exc)
|
|
raise UpstreamError(f"OpenAI chat (merge) request se nezdařil: {exc}") from exc
|
|
|
|
if resp.status_code >= 400:
|
|
log.warning("OpenAI chat returned %s: %s", resp.status_code, resp.text[:500])
|
|
raise_for_upstream("OpenAI chat (merge)", resp.status_code, resp.text)
|
|
|
|
data = resp.json()
|
|
try:
|
|
return data["choices"][0]["message"]["content"] or ""
|
|
except (KeyError, IndexError, TypeError) as exc:
|
|
log.error("Unexpected OpenAI chat response shape: %s", exc)
|
|
raise UpstreamError("Neočekávaná struktura odpovědi z OpenAI chatu.") from exc
|