Files

91 lines
2.5 KiB
Python
Raw Permalink Normal View History

"""Upload voice confirmation WAV objects to MinIO (S3-compatible)."""
from __future__ import annotations
import hashlib
import io
from dataclasses import dataclass
from loguru import logger
from minio import Minio
from minio.error import S3Error
from app.config import Settings
@dataclass(frozen=True)
class StoredAudio:
object_key: str
sha256_hex: str
size_bytes: int
class MinioAudioStorageService:
"""Stores raw doctor voice WAV for audit trail."""
def __init__(self, settings: Settings) -> None:
self._s = settings
self._client: Minio | None = None
if settings.minio_configured:
endpoint = settings.minio_endpoint.strip()
self._client = Minio(
endpoint,
access_key=settings.minio_access_key.strip(),
secret_key=settings.minio_secret_key.strip(),
secure=bool(settings.minio_secure),
region=(settings.minio_region or "").strip() or None,
)
@property
def configured(self) -> bool:
return self._client is not None
def ensure_bucket(self) -> None:
if self._client is None:
return
name = self._s.minio_bucket.strip()
try:
if not self._client.bucket_exists(name):
self._client.make_bucket(name)
logger.info("MinIO bucket created: {}", name)
except S3Error as exc:
logger.warning("MinIO ensure_bucket failed: {}", exc)
raise
def upload_voice_wav(
self,
*,
surgery_id: str,
confirmation_id: str,
data: bytes,
content_type: str | None,
) -> StoredAudio:
if self._client is None:
raise RuntimeError("MinIO is not configured")
digest = hashlib.sha256(data).hexdigest()
suffix = digest[:12]
object_key = (
f"surgeries/{surgery_id}/confirmations/{confirmation_id}/{suffix}.wav"
)
bucket = self._s.minio_bucket.strip()
ct = content_type or "audio/wav"
stream = io.BytesIO(data)
try:
self._client.put_object(
bucket,
object_key,
stream,
length=len(data),
content_type=ct,
)
except S3Error as exc:
logger.warning("MinIO put_object failed: {}", exc)
raise
return StoredAudio(
object_key=object_key,
sha256_hex=digest,
size_bytes=len(data),
)