diff --git a/cpv3/modules/tasks/schemas.py b/cpv3/modules/tasks/schemas.py index c57d0a9..b84a711 100644 --- a/cpv3/modules/tasks/schemas.py +++ b/cpv3/modules/tasks/schemas.py @@ -83,7 +83,7 @@ class TranscriptionGenerateRequest(Schema): file_key: str = Field(..., description="Storage key of the input file") project_id: UUID | None = Field(default=None, description="Associated project ID") - engine: Literal["whisper", "google"] = Field( + engine: Literal["whisper", "google", "salutespeech"] = Field( default="whisper", description="Transcription engine to use" ) language: str | None = Field(default=None, description="Language code (e.g., 'en')") @@ -164,5 +164,5 @@ class TaskWebhookEvent(Schema): ) ) if not has_update: - raise ValueError("Webhook event must include at least one update field.") + raise ValueError("Событие вебхука должно содержать хотя бы одно обновляемое поле.") return self diff --git a/cpv3/modules/tasks/service.py b/cpv3/modules/tasks/service.py index 6f753dc..d31c420 100644 --- a/cpv3/modules/tasks/service.py +++ b/cpv3/modules/tasks/service.py @@ -88,14 +88,15 @@ ERROR_UNKNOWN_ENGINE = "Неизвестный движок транскрипц ENGINE_MAP: dict[str, str] = { "whisper": "LOCAL_WHISPER", "google": "GOOGLE_SPEECH_CLOUD", + "salutespeech": "SALUTE_SPEECH", } -MESSAGE_STARTING = "Starting" -MESSAGE_COMPLETED = "Completed" -MESSAGE_PROBING_MEDIA = "Probing media" -MESSAGE_PROCESSING = "Processing" -MESSAGE_CONVERTING = "Converting" -MESSAGE_RENDERING_CAPTIONS = "Rendering captions" +MESSAGE_STARTING = "Запуск" +MESSAGE_COMPLETED = "Завершено" +MESSAGE_PROBING_MEDIA = "Анализ медиафайла" +MESSAGE_PROCESSING = "Обработка" +MESSAGE_CONVERTING = "Конвертация" +MESSAGE_RENDERING_CAPTIONS = "Рендеринг субтитров" MESSAGE_CANCELLED = "Отменено пользователем" MESSAGE_EXTRACTING_FRAMES = "Извлечение кадров" MESSAGE_UPLOADING_FRAMES = "Загрузка кадров" @@ -560,7 +561,7 @@ def media_convert_actor( try: if output_format.lower() != "mp4": - raise ValueError(f"Unsupported format: {output_format}") + raise ValueError(f"Неподдерживаемый формат: {output_format}") storage = _get_storage_service() _send_webhook_event( @@ -612,6 +613,7 @@ def transcription_generate_actor( """Generate transcription from audio/video file.""" from cpv3.modules.transcription.service import ( transcribe_with_google_speech, + transcribe_with_salute_speech, transcribe_with_whisper, ) @@ -698,6 +700,22 @@ def transcription_generate_actor( storage, file_key=file_key, language_codes=language_codes ) ) + elif engine == "salutespeech": + audio_stream = next( + (s for s in probe.streams if s.codec_type == "audio"), None + ) + sr = int(audio_stream.sample_rate) if audio_stream and audio_stream.sample_rate else 16000 + document = _run_async( + transcribe_with_salute_speech( + storage, + file_key=file_key, + language=language, + model=model, + sample_rate=sr, + job_id=job_uuid, + on_progress=_on_whisper_progress, + ) + ) else: raise ValueError(ERROR_UNKNOWN_ENGINE.format(engine=engine)) @@ -1159,7 +1177,7 @@ class TaskService: """Apply a webhook event to the job and store a job event record.""" job = await self._job_repo.get_by_id(job_id) if job is None: - raise ValueError(f"Job {job_id} not found") + raise ValueError(f"Задача {job_id} не найдена") if job.status in (JOB_STATUS_DONE, JOB_STATUS_FAILED, JOB_STATUS_CANCELLED): logger.info("Ignoring webhook for terminal job %s (status=%s)", job_id, job.status) @@ -1644,7 +1662,7 @@ class TaskService: transcription_repo = TranscriptionRepository(self._session) transcription = await transcription_repo.get_by_id(request.transcription_id) if transcription is None: - raise ValueError(f"Transcription {request.transcription_id} not found") + raise ValueError(f"Транскрипция {request.transcription_id} не найдена") user_folder = get_user_folder(requester) resolved_folder = (