sarvamai 0.1.13a2__tar.gz → 0.1.14__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/PKG-INFO +1 -1
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/pyproject.toml +1 -1
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/core/client_wrapper.py +2 -2
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/speech_to_text_job/client.py +143 -0
- sarvamai-0.1.14/src/sarvamai/speech_to_text_job/job.py +484 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/speech_to_text_translate_job/client.py +133 -0
- sarvamai-0.1.14/src/sarvamai/speech_to_text_translate_job/job.py +492 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/README.md +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/__init__.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/chat/__init__.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/chat/client.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/chat/raw_client.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/client.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/core/__init__.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/core/api_error.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/core/datetime_utils.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/core/events.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/core/file.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/core/force_multipart.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/core/http_client.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/core/http_response.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/core/jsonable_encoder.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/core/pydantic_utilities.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/core/query_encoder.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/core/remove_none_from_dict.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/core/request_options.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/core/serialization.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/environment.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/errors/__init__.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/errors/bad_request_error.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/errors/forbidden_error.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/errors/internal_server_error.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/errors/service_unavailable_error.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/errors/too_many_requests_error.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/errors/unprocessable_entity_error.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/play.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/py.typed +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/requests/__init__.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/requests/audio_data.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/requests/audio_message.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/requests/audio_output.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/requests/audio_output_data.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/requests/base_job_parameters.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/requests/bulk_job_callback.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/requests/bulk_job_init_response_v_1.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/requests/chat_completion_request_assistant_message.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/requests/chat_completion_request_message.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/requests/chat_completion_request_system_message.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/requests/chat_completion_request_user_message.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/requests/chat_completion_response_message.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/requests/choice.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/requests/completion_usage.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/requests/config_message.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/requests/configure_connection.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/requests/configure_connection_data.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/requests/create_chat_completion_response.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/requests/diarized_entry.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/requests/diarized_transcript.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/requests/error_data.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/requests/error_details.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/requests/error_message.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/requests/error_response.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/requests/error_response_data.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/requests/events_data.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/requests/file_signed_url_details.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/requests/files_download_response.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/requests/files_request.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/requests/files_upload_response.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/requests/flush_signal.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/requests/job_status_v_1_response.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/requests/language_identification_response.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/requests/ping_signal.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/requests/send_text.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/requests/send_text_data.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/requests/speech_to_text_job_parameters.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/requests/speech_to_text_response.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/requests/speech_to_text_response_data.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/requests/speech_to_text_streaming_response.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/requests/speech_to_text_transcription_data.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/requests/speech_to_text_translate_job_parameters.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/requests/speech_to_text_translate_response.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/requests/speech_to_text_translate_response_data.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/requests/speech_to_text_translate_streaming_response.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/requests/speech_to_text_translate_transcription_data.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/requests/stop_configuration.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/requests/task_detail_v_1.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/requests/task_file_details.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/requests/text_to_speech_response.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/requests/timestamps_model.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/requests/transcription_metrics.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/requests/translation_response.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/requests/transliteration_response.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/speech_to_text/__init__.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/speech_to_text/client.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/speech_to_text/raw_client.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/speech_to_text_job/__init__.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/speech_to_text_job/raw_client.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/speech_to_text_streaming/__init__.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/speech_to_text_streaming/client.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/speech_to_text_streaming/raw_client.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/speech_to_text_streaming/socket_client.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/speech_to_text_streaming/types/__init__.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/speech_to_text_streaming/types/speech_to_text_streaming_high_vad_sensitivity.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/speech_to_text_streaming/types/speech_to_text_streaming_language_code.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/speech_to_text_streaming/types/speech_to_text_streaming_model.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/speech_to_text_streaming/types/speech_to_text_streaming_vad_signals.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/speech_to_text_translate_job/__init__.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/speech_to_text_translate_job/raw_client.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/speech_to_text_translate_streaming/__init__.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/speech_to_text_translate_streaming/client.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/speech_to_text_translate_streaming/raw_client.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/speech_to_text_translate_streaming/socket_client.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/speech_to_text_translate_streaming/types/__init__.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/speech_to_text_translate_streaming/types/speech_to_text_translate_streaming_high_vad_sensitivity.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/speech_to_text_translate_streaming/types/speech_to_text_translate_streaming_model.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/speech_to_text_translate_streaming/types/speech_to_text_translate_streaming_vad_signals.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/text/__init__.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/text/client.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/text/raw_client.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/text_to_speech/__init__.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/text_to_speech/client.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/text_to_speech/raw_client.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/text_to_speech_streaming/__init__.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/text_to_speech_streaming/client.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/text_to_speech_streaming/raw_client.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/text_to_speech_streaming/socket_client.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/__init__.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/audio_data.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/audio_message.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/audio_output.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/audio_output_data.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/base_job_parameters.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/bulk_job_callback.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/bulk_job_init_response_v_1.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/chat_completion_request_assistant_message.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/chat_completion_request_message.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/chat_completion_request_system_message.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/chat_completion_request_user_message.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/chat_completion_response_message.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/choice.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/completion_usage.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/config_message.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/configure_connection.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/configure_connection_data.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/configure_connection_data_output_audio_bitrate.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/configure_connection_data_output_audio_codec.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/configure_connection_data_speaker.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/configure_connection_data_target_language_code.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/create_chat_completion_response.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/diarized_entry.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/diarized_transcript.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/error_code.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/error_data.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/error_details.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/error_message.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/error_response.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/error_response_data.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/events_data.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/file_signed_url_details.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/files_download_response.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/files_request.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/files_upload_response.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/finish_reason.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/flush_signal.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/job_state.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/job_status_v_1_response.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/language_identification_response.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/numerals_format.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/ping_signal.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/reasoning_effort.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/response_type.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/role.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/sarvam_model_ids.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/send_text.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/send_text_data.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/speech_sample_rate.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/speech_to_text_job_parameters.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/speech_to_text_language.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/speech_to_text_model.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/speech_to_text_response.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/speech_to_text_response_data.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/speech_to_text_streaming_response.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/speech_to_text_transcription_data.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/speech_to_text_translate_job_parameters.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/speech_to_text_translate_language.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/speech_to_text_translate_model.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/speech_to_text_translate_response.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/speech_to_text_translate_response_data.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/speech_to_text_translate_streaming_response.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/speech_to_text_translate_transcription_data.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/spoken_form_numerals_format.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/stop_configuration.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/storage_container_type.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/task_detail_v_1.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/task_file_details.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/task_state.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/text_to_speech_language.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/text_to_speech_model.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/text_to_speech_output_audio_codec.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/text_to_speech_response.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/text_to_speech_speaker.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/timestamps_model.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/transcription_metrics.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/translate_mode.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/translate_model.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/translate_source_language.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/translate_speaker_gender.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/translate_target_language.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/translation_response.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/translatiterate_target_language.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/transliterate_mode.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/transliterate_source_language.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/types/transliteration_response.py +0 -0
- {sarvamai-0.1.13a2 → sarvamai-0.1.14}/src/sarvamai/version.py +0 -0
|
@@ -23,10 +23,10 @@ class BaseClientWrapper:
|
|
|
23
23
|
|
|
24
24
|
def get_headers(self) -> typing.Dict[str, str]:
|
|
25
25
|
headers: typing.Dict[str, str] = {
|
|
26
|
-
"User-Agent": "sarvamai/0.1.
|
|
26
|
+
"User-Agent": "sarvamai/0.1.14",
|
|
27
27
|
"X-Fern-Language": "Python",
|
|
28
28
|
"X-Fern-SDK-Name": "sarvamai",
|
|
29
|
-
"X-Fern-SDK-Version": "0.1.
|
|
29
|
+
"X-Fern-SDK-Version": "0.1.14",
|
|
30
30
|
**(self.get_custom_headers() or {}),
|
|
31
31
|
}
|
|
32
32
|
headers["api-subscription-key"] = self.api_subscription_key
|
|
@@ -10,7 +10,10 @@ from ..types.bulk_job_init_response_v_1 import BulkJobInitResponseV1
|
|
|
10
10
|
from ..types.files_download_response import FilesDownloadResponse
|
|
11
11
|
from ..types.files_upload_response import FilesUploadResponse
|
|
12
12
|
from ..types.job_status_v_1_response import JobStatusV1Response
|
|
13
|
+
from ..types.speech_to_text_model import SpeechToTextModel
|
|
14
|
+
from ..types.speech_to_text_language import SpeechToTextLanguage
|
|
13
15
|
from .raw_client import AsyncRawSpeechToTextJobClient, RawSpeechToTextJobClient
|
|
16
|
+
from .job import AsyncSpeechToTextJob, SpeechToTextJob
|
|
14
17
|
|
|
15
18
|
# this is used as the default value for optional parameters
|
|
16
19
|
OMIT = typing.cast(typing.Any, ...)
|
|
@@ -215,6 +218,76 @@ class SpeechToTextJobClient:
|
|
|
215
218
|
_response = self._raw_client.get_download_links(job_id=job_id, files=files, request_options=request_options)
|
|
216
219
|
return _response.data
|
|
217
220
|
|
|
221
|
+
def create_job(
|
|
222
|
+
self,
|
|
223
|
+
model: SpeechToTextModel = "saarika:v2.5",
|
|
224
|
+
with_diarization: bool = False,
|
|
225
|
+
with_timestamps: bool = False,
|
|
226
|
+
language_code: typing.Optional[SpeechToTextLanguage] = None,
|
|
227
|
+
num_speakers: typing.Optional[int] = None,
|
|
228
|
+
callback: typing.Optional[BulkJobCallbackParams] = OMIT,
|
|
229
|
+
request_options: typing.Optional[RequestOptions] = None,
|
|
230
|
+
) -> SpeechToTextJob:
|
|
231
|
+
"""
|
|
232
|
+
Create a new Speech-to-Text bulk job.
|
|
233
|
+
|
|
234
|
+
Parameters
|
|
235
|
+
----------
|
|
236
|
+
model : SpeechToTextModel, default="saarika:v2.5"
|
|
237
|
+
The model to use for transcription.
|
|
238
|
+
|
|
239
|
+
with_diarization : typing.Optional[bool], default=False
|
|
240
|
+
Whether to enable speaker diarization (distinguishing who said what).
|
|
241
|
+
|
|
242
|
+
with_timestamps : typing.Optional[bool], default=False
|
|
243
|
+
Whether to include word-level timestamps in the transcription output.
|
|
244
|
+
|
|
245
|
+
language_code : typing.Optional[SpeechToTextLanguage], default=None
|
|
246
|
+
The language code of the input audio (e.g., "hi-IN", "bn-IN").
|
|
247
|
+
|
|
248
|
+
num_speakers : typing.Optional[int], default=None
|
|
249
|
+
The number of distinct speakers in the audio, if known.
|
|
250
|
+
|
|
251
|
+
callback : typing.Optional[BulkJobCallbackParams], default=OMIT
|
|
252
|
+
Optional callback configuration to receive job completion events.
|
|
253
|
+
|
|
254
|
+
request_options : typing.Optional[RequestOptions], default=None
|
|
255
|
+
Request-specific configuration.
|
|
256
|
+
|
|
257
|
+
Returns
|
|
258
|
+
-------
|
|
259
|
+
SpeechToTextJob
|
|
260
|
+
A handle to the newly created Speech-to-Text job.
|
|
261
|
+
"""
|
|
262
|
+
response = self.initialise(
|
|
263
|
+
job_parameters=SpeechToTextJobParametersParams(
|
|
264
|
+
language_code=language_code,
|
|
265
|
+
model=model,
|
|
266
|
+
num_speakers=num_speakers, # type: ignore[typeddict-item]
|
|
267
|
+
with_diarization=with_diarization,
|
|
268
|
+
with_timestamps=with_timestamps,
|
|
269
|
+
),
|
|
270
|
+
callback=callback,
|
|
271
|
+
request_options=request_options,
|
|
272
|
+
)
|
|
273
|
+
return SpeechToTextJob(job_id=response.job_id, client=self)
|
|
274
|
+
|
|
275
|
+
def get_job(self, job_id: str) -> SpeechToTextJob:
|
|
276
|
+
"""
|
|
277
|
+
Get an existing Speech-to-Text job handle by job ID.
|
|
278
|
+
|
|
279
|
+
Parameters
|
|
280
|
+
----------
|
|
281
|
+
job_id : str
|
|
282
|
+
The job ID of the previously created Speech-to-Text job.
|
|
283
|
+
|
|
284
|
+
Returns
|
|
285
|
+
-------
|
|
286
|
+
SpeechToTextJob
|
|
287
|
+
A job handle which can be used to check status or retrieve results.
|
|
288
|
+
"""
|
|
289
|
+
return SpeechToTextJob(job_id=job_id, client=self)
|
|
290
|
+
|
|
218
291
|
|
|
219
292
|
class AsyncSpeechToTextJobClient:
|
|
220
293
|
def __init__(self, *, client_wrapper: AsyncClientWrapper):
|
|
@@ -456,3 +529,73 @@ class AsyncSpeechToTextJobClient:
|
|
|
456
529
|
job_id=job_id, files=files, request_options=request_options
|
|
457
530
|
)
|
|
458
531
|
return _response.data
|
|
532
|
+
|
|
533
|
+
async def create_job(
|
|
534
|
+
self,
|
|
535
|
+
model: SpeechToTextModel = "saarika:v2.5",
|
|
536
|
+
with_diarization: bool = False,
|
|
537
|
+
with_timestamps: bool = False,
|
|
538
|
+
language_code: typing.Optional[SpeechToTextLanguage] = None,
|
|
539
|
+
num_speakers: typing.Optional[int] = None,
|
|
540
|
+
callback: typing.Optional[BulkJobCallbackParams] = OMIT,
|
|
541
|
+
request_options: typing.Optional[RequestOptions] = None,
|
|
542
|
+
) -> "AsyncSpeechToTextJob":
|
|
543
|
+
"""
|
|
544
|
+
Create a new Speech-to-Text bulk job.
|
|
545
|
+
|
|
546
|
+
Parameters
|
|
547
|
+
----------
|
|
548
|
+
model : SpeechToTextModel, default="saarika:v2.5"
|
|
549
|
+
The model to use for transcription.
|
|
550
|
+
|
|
551
|
+
with_diarization : typing.Optional[bool], default=False
|
|
552
|
+
Whether to enable speaker diarization (distinguishing who said what).
|
|
553
|
+
|
|
554
|
+
with_timestamps : typing.Optional[bool], default=False
|
|
555
|
+
Whether to include word-level timestamps in the transcription output.
|
|
556
|
+
|
|
557
|
+
language_code : typing.Optional[SpeechToTextLanguage], default=None
|
|
558
|
+
The language code of the input audio (e.g., "hi-IN", "bn-IN").
|
|
559
|
+
|
|
560
|
+
num_speakers : typing.Optional[int], default=None
|
|
561
|
+
The number of distinct speakers in the audio, if known.
|
|
562
|
+
|
|
563
|
+
callback : typing.Optional[BulkJobCallbackParams], default=OMIT
|
|
564
|
+
Optional callback configuration to receive job completion events.
|
|
565
|
+
|
|
566
|
+
request_options : typing.Optional[RequestOptions], default=None
|
|
567
|
+
Request-specific configuration.
|
|
568
|
+
|
|
569
|
+
Returns
|
|
570
|
+
-------
|
|
571
|
+
AsyncSpeechToTextJob
|
|
572
|
+
A handle to the newly created job.
|
|
573
|
+
"""
|
|
574
|
+
response = await self.initialise(
|
|
575
|
+
job_parameters=SpeechToTextJobParametersParams(
|
|
576
|
+
language_code=language_code,
|
|
577
|
+
model=model,
|
|
578
|
+
with_diarization=with_diarization,
|
|
579
|
+
with_timestamps=with_timestamps,
|
|
580
|
+
num_speakers=num_speakers, # type: ignore[typeddict-item]
|
|
581
|
+
),
|
|
582
|
+
callback=callback,
|
|
583
|
+
request_options=request_options,
|
|
584
|
+
)
|
|
585
|
+
return AsyncSpeechToTextJob(job_id=response.job_id, client=self)
|
|
586
|
+
|
|
587
|
+
async def get_job(self, job_id: str) -> "AsyncSpeechToTextJob":
|
|
588
|
+
"""
|
|
589
|
+
Get an existing Speech-to-Text job handle by job ID.
|
|
590
|
+
|
|
591
|
+
Parameters
|
|
592
|
+
----------
|
|
593
|
+
job_id : str
|
|
594
|
+
The job ID of the previously created speech-to-text job.
|
|
595
|
+
|
|
596
|
+
Returns
|
|
597
|
+
-------
|
|
598
|
+
AsyncSpeechToTextJob
|
|
599
|
+
A job handle which can be used to check status or retrieve results.
|
|
600
|
+
"""
|
|
601
|
+
return AsyncSpeechToTextJob(job_id=job_id, client=self)
|
|
@@ -0,0 +1,484 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import mimetypes
|
|
3
|
+
import os
|
|
4
|
+
import time
|
|
5
|
+
import typing
|
|
6
|
+
import httpx
|
|
7
|
+
|
|
8
|
+
from ..types import JobStatusV1Response
|
|
9
|
+
|
|
10
|
+
if typing.TYPE_CHECKING:
|
|
11
|
+
from .client import AsyncSpeechToTextJobClient, SpeechToTextJobClient
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class AsyncSpeechToTextJob:
|
|
15
|
+
def __init__(self, job_id: str, client: "AsyncSpeechToTextJobClient"):
|
|
16
|
+
"""
|
|
17
|
+
Initialize the asynchronous speech-to-text job.
|
|
18
|
+
|
|
19
|
+
Parameters
|
|
20
|
+
----------
|
|
21
|
+
job_id : str
|
|
22
|
+
The unique job identifier returned from a previous job initialization.
|
|
23
|
+
|
|
24
|
+
client : AsyncSpeechToTextJobClient
|
|
25
|
+
The async client instance used to create the job.
|
|
26
|
+
|
|
27
|
+
!!! important
|
|
28
|
+
This must be the **same client instance** that was used to initialize
|
|
29
|
+
the job originally, as it contains the subscription key and configuration
|
|
30
|
+
required to authenticate and manage the job.
|
|
31
|
+
|
|
32
|
+
"""
|
|
33
|
+
self._job_id = job_id
|
|
34
|
+
self._client = client
|
|
35
|
+
|
|
36
|
+
@property
|
|
37
|
+
def job_id(self) -> str:
|
|
38
|
+
"""
|
|
39
|
+
Returns the job ID associated with this job instance.
|
|
40
|
+
|
|
41
|
+
Returns
|
|
42
|
+
-------
|
|
43
|
+
str
|
|
44
|
+
"""
|
|
45
|
+
return self._job_id
|
|
46
|
+
|
|
47
|
+
async def upload_files(
|
|
48
|
+
self, file_paths: typing.Sequence[str], timeout: float = 60.0
|
|
49
|
+
) -> bool:
|
|
50
|
+
"""
|
|
51
|
+
Upload input audio files for the speech-to-text job.
|
|
52
|
+
|
|
53
|
+
Parameters
|
|
54
|
+
----------
|
|
55
|
+
file_paths : Sequence[str]
|
|
56
|
+
List of full paths to local audio files.
|
|
57
|
+
|
|
58
|
+
timeout : float, optional
|
|
59
|
+
The maximum time to wait for the upload to complete (in seconds),
|
|
60
|
+
by default 60.0
|
|
61
|
+
Returns
|
|
62
|
+
-------
|
|
63
|
+
bool
|
|
64
|
+
True if all files are uploaded successfully.
|
|
65
|
+
"""
|
|
66
|
+
upload_links = await self._client.get_upload_links(
|
|
67
|
+
job_id=self._job_id,
|
|
68
|
+
files=[os.path.basename(p) for p in file_paths],
|
|
69
|
+
)
|
|
70
|
+
client_timeout = httpx.Timeout(timeout=timeout)
|
|
71
|
+
async with httpx.AsyncClient(timeout=client_timeout) as session:
|
|
72
|
+
for path in file_paths:
|
|
73
|
+
file_name = os.path.basename(path)
|
|
74
|
+
url = upload_links.upload_urls[file_name].file_url
|
|
75
|
+
with open(path, "rb") as f:
|
|
76
|
+
content_type, _ = mimetypes.guess_type(path)
|
|
77
|
+
if content_type is None:
|
|
78
|
+
content_type = "audio/wav"
|
|
79
|
+
response = await session.put(
|
|
80
|
+
url,
|
|
81
|
+
content=f.read(),
|
|
82
|
+
headers={
|
|
83
|
+
"x-ms-blob-type": "BlockBlob",
|
|
84
|
+
"Content-Type": content_type,
|
|
85
|
+
},
|
|
86
|
+
)
|
|
87
|
+
if response.status_code != 201:
|
|
88
|
+
raise RuntimeError(
|
|
89
|
+
f"Upload failed for {file_name}: {response.status_code}"
|
|
90
|
+
)
|
|
91
|
+
return True
|
|
92
|
+
|
|
93
|
+
async def wait_until_complete(
|
|
94
|
+
self, poll_interval: int = 5, timeout: int = 600
|
|
95
|
+
) -> JobStatusV1Response:
|
|
96
|
+
"""
|
|
97
|
+
Polls job status until it completes or fails.
|
|
98
|
+
|
|
99
|
+
Parameters
|
|
100
|
+
----------
|
|
101
|
+
poll_interval : int, optional
|
|
102
|
+
Time in seconds between polling attempts (default is 5).
|
|
103
|
+
|
|
104
|
+
timeout : int, optional
|
|
105
|
+
Maximum time to wait for completion in seconds (default is 600).
|
|
106
|
+
|
|
107
|
+
Returns
|
|
108
|
+
-------
|
|
109
|
+
JobStatusV1Response
|
|
110
|
+
Final job status.
|
|
111
|
+
|
|
112
|
+
Raises
|
|
113
|
+
------
|
|
114
|
+
TimeoutError
|
|
115
|
+
If the job does not complete within the given timeout.
|
|
116
|
+
"""
|
|
117
|
+
start = asyncio.get_event_loop().time()
|
|
118
|
+
while True:
|
|
119
|
+
status = await self.get_status()
|
|
120
|
+
state = status.job_state.lower()
|
|
121
|
+
if state in {"completed", "failed"}:
|
|
122
|
+
return status
|
|
123
|
+
if asyncio.get_event_loop().time() - start > timeout:
|
|
124
|
+
raise TimeoutError(
|
|
125
|
+
f"Job {self._job_id} did not complete within {timeout} seconds."
|
|
126
|
+
)
|
|
127
|
+
await asyncio.sleep(poll_interval)
|
|
128
|
+
|
|
129
|
+
async def get_output_mappings(self) -> typing.List[typing.Dict[str, str]]:
|
|
130
|
+
"""
|
|
131
|
+
Get the mapping of input files to their corresponding output files.
|
|
132
|
+
|
|
133
|
+
Returns
|
|
134
|
+
-------
|
|
135
|
+
List[Dict[str, str]]
|
|
136
|
+
List of mappings with keys 'input_file' and 'output_file'.
|
|
137
|
+
"""
|
|
138
|
+
job_status = await self.get_status()
|
|
139
|
+
return [
|
|
140
|
+
{
|
|
141
|
+
"input_file": detail.inputs[0].file_name,
|
|
142
|
+
"output_file": detail.outputs[0].file_name,
|
|
143
|
+
}
|
|
144
|
+
for detail in (job_status.job_details or [])
|
|
145
|
+
if detail.inputs and detail.outputs
|
|
146
|
+
]
|
|
147
|
+
|
|
148
|
+
async def download_outputs(self, output_dir: str) -> bool:
|
|
149
|
+
"""
|
|
150
|
+
Download output files to the specified directory.
|
|
151
|
+
|
|
152
|
+
Parameters
|
|
153
|
+
----------
|
|
154
|
+
output_dir : str
|
|
155
|
+
Local directory where outputs will be saved.
|
|
156
|
+
|
|
157
|
+
Returns
|
|
158
|
+
-------
|
|
159
|
+
bool
|
|
160
|
+
True if all files downloaded successfully.
|
|
161
|
+
|
|
162
|
+
Raises
|
|
163
|
+
------
|
|
164
|
+
RuntimeError
|
|
165
|
+
If a file fails to download.
|
|
166
|
+
"""
|
|
167
|
+
mappings = await self.get_output_mappings()
|
|
168
|
+
file_names = [m["output_file"] for m in mappings]
|
|
169
|
+
download_links = await self._client.get_download_links(
|
|
170
|
+
job_id=self._job_id, files=file_names
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
os.makedirs(output_dir, exist_ok=True)
|
|
174
|
+
async with httpx.AsyncClient() as session:
|
|
175
|
+
for m in mappings:
|
|
176
|
+
url = download_links.download_urls[m["output_file"]].file_url
|
|
177
|
+
response = await session.get(url)
|
|
178
|
+
if response.status_code != 200:
|
|
179
|
+
raise RuntimeError(
|
|
180
|
+
f"Download failed for {m['output_file']}: {response.status_code}"
|
|
181
|
+
)
|
|
182
|
+
output_path = os.path.join(output_dir, f"{m['input_file']}.json")
|
|
183
|
+
with open(output_path, "wb") as f:
|
|
184
|
+
f.write(response.content)
|
|
185
|
+
return True
|
|
186
|
+
|
|
187
|
+
async def get_status(self) -> JobStatusV1Response:
|
|
188
|
+
"""
|
|
189
|
+
Retrieve the current status of the job.
|
|
190
|
+
|
|
191
|
+
Returns
|
|
192
|
+
-------
|
|
193
|
+
JobStatusV1Response
|
|
194
|
+
"""
|
|
195
|
+
return await self._client.get_status(self._job_id)
|
|
196
|
+
|
|
197
|
+
async def start(self) -> JobStatusV1Response:
|
|
198
|
+
"""
|
|
199
|
+
Start the speech-to-text job processing.
|
|
200
|
+
|
|
201
|
+
Returns
|
|
202
|
+
-------
|
|
203
|
+
JobStatusV1Response
|
|
204
|
+
"""
|
|
205
|
+
return await self._client.start(job_id=self._job_id)
|
|
206
|
+
|
|
207
|
+
async def exists(self) -> bool:
|
|
208
|
+
"""
|
|
209
|
+
Check if the job exists in the system.
|
|
210
|
+
|
|
211
|
+
Returns
|
|
212
|
+
-------
|
|
213
|
+
bool
|
|
214
|
+
"""
|
|
215
|
+
try:
|
|
216
|
+
await self.get_status()
|
|
217
|
+
return True
|
|
218
|
+
except httpx.HTTPStatusError:
|
|
219
|
+
return False
|
|
220
|
+
|
|
221
|
+
async def is_complete(self) -> bool:
|
|
222
|
+
"""
|
|
223
|
+
Check if the job is either completed or failed.
|
|
224
|
+
|
|
225
|
+
Returns
|
|
226
|
+
-------
|
|
227
|
+
bool
|
|
228
|
+
"""
|
|
229
|
+
state = (await self.get_status()).job_state.lower()
|
|
230
|
+
return state in {"completed", "failed"}
|
|
231
|
+
|
|
232
|
+
async def is_successful(self) -> bool:
|
|
233
|
+
"""
|
|
234
|
+
Check if the job completed successfully.
|
|
235
|
+
|
|
236
|
+
Returns
|
|
237
|
+
-------
|
|
238
|
+
bool
|
|
239
|
+
"""
|
|
240
|
+
return (await self.get_status()).job_state.lower() == "completed"
|
|
241
|
+
|
|
242
|
+
async def is_failed(self) -> bool:
|
|
243
|
+
"""
|
|
244
|
+
Check if the job has failed.
|
|
245
|
+
|
|
246
|
+
Returns
|
|
247
|
+
-------
|
|
248
|
+
bool
|
|
249
|
+
"""
|
|
250
|
+
return (await self.get_status()).job_state.lower() == "failed"
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
class SpeechToTextJob:
|
|
254
|
+
def __init__(self, job_id: str, client: "SpeechToTextJobClient"):
|
|
255
|
+
"""
|
|
256
|
+
Initialize the synchronous speech-to-text job.
|
|
257
|
+
|
|
258
|
+
Parameters
|
|
259
|
+
----------
|
|
260
|
+
job_id : str
|
|
261
|
+
The unique job identifier returned from a previous job initialization.
|
|
262
|
+
|
|
263
|
+
client : SpeechToTextJobClient
|
|
264
|
+
The client instance used to create the job.
|
|
265
|
+
|
|
266
|
+
!!! important
|
|
267
|
+
This must be the **same client instance** that was used to initialize
|
|
268
|
+
the job originally, as it contains the subscription key and configuration
|
|
269
|
+
required to authenticate and manage the job.
|
|
270
|
+
|
|
271
|
+
"""
|
|
272
|
+
self._job_id = job_id
|
|
273
|
+
self._client = client
|
|
274
|
+
|
|
275
|
+
@property
|
|
276
|
+
def job_id(self) -> str:
|
|
277
|
+
"""
|
|
278
|
+
Returns the job ID associated with this job instance.
|
|
279
|
+
|
|
280
|
+
Returns
|
|
281
|
+
-------
|
|
282
|
+
str
|
|
283
|
+
"""
|
|
284
|
+
return self._job_id
|
|
285
|
+
|
|
286
|
+
def upload_files(
|
|
287
|
+
self, file_paths: typing.Sequence[str], timeout: float = 60.0
|
|
288
|
+
) -> bool:
|
|
289
|
+
"""
|
|
290
|
+
Upload input audio files for the speech-to-text job.
|
|
291
|
+
|
|
292
|
+
Parameters
|
|
293
|
+
----------
|
|
294
|
+
file_paths : Sequence[str]
|
|
295
|
+
List of full paths to local audio files.
|
|
296
|
+
|
|
297
|
+
timeout : float, optional
|
|
298
|
+
The maximum time to wait for the upload to complete (in seconds),
|
|
299
|
+
by default 60.0
|
|
300
|
+
Returns
|
|
301
|
+
-------
|
|
302
|
+
bool
|
|
303
|
+
True if all files are uploaded successfully.
|
|
304
|
+
"""
|
|
305
|
+
upload_links = self._client.get_upload_links(
|
|
306
|
+
job_id=self._job_id, files=[os.path.basename(p) for p in file_paths]
|
|
307
|
+
)
|
|
308
|
+
client_timeout = httpx.Timeout(timeout=timeout)
|
|
309
|
+
with httpx.Client(timeout=client_timeout) as client:
|
|
310
|
+
for path in file_paths:
|
|
311
|
+
file_name = os.path.basename(path)
|
|
312
|
+
url = upload_links.upload_urls[file_name].file_url
|
|
313
|
+
with open(path, "rb") as f:
|
|
314
|
+
response = client.put(
|
|
315
|
+
url,
|
|
316
|
+
content=f,
|
|
317
|
+
headers={
|
|
318
|
+
"x-ms-blob-type": "BlockBlob",
|
|
319
|
+
"Content-Type": "audio/wav",
|
|
320
|
+
},
|
|
321
|
+
)
|
|
322
|
+
if response.status_code != 201:
|
|
323
|
+
raise RuntimeError(
|
|
324
|
+
f"Upload failed for {file_name}: {response.status_code}"
|
|
325
|
+
)
|
|
326
|
+
return True
|
|
327
|
+
|
|
328
|
+
def wait_until_complete(
|
|
329
|
+
self, poll_interval: int = 5, timeout: int = 600
|
|
330
|
+
) -> JobStatusV1Response:
|
|
331
|
+
"""
|
|
332
|
+
Polls job status until it completes or fails.
|
|
333
|
+
|
|
334
|
+
Parameters
|
|
335
|
+
----------
|
|
336
|
+
poll_interval : int, optional
|
|
337
|
+
Time in seconds between polling attempts (default is 5).
|
|
338
|
+
|
|
339
|
+
timeout : int, optional
|
|
340
|
+
Maximum time to wait for completion in seconds (default is 600).
|
|
341
|
+
|
|
342
|
+
Returns
|
|
343
|
+
-------
|
|
344
|
+
JobStatusV1Response
|
|
345
|
+
Final job status.
|
|
346
|
+
|
|
347
|
+
Raises
|
|
348
|
+
------
|
|
349
|
+
TimeoutError
|
|
350
|
+
If the job does not complete within the given timeout.
|
|
351
|
+
"""
|
|
352
|
+
start = time.monotonic()
|
|
353
|
+
while True:
|
|
354
|
+
status = self.get_status()
|
|
355
|
+
state = status.job_state.lower()
|
|
356
|
+
if state in {"completed", "failed"}:
|
|
357
|
+
return status
|
|
358
|
+
if time.monotonic() - start > timeout:
|
|
359
|
+
raise TimeoutError(
|
|
360
|
+
f"Job {self._job_id} did not complete within {timeout} seconds."
|
|
361
|
+
)
|
|
362
|
+
time.sleep(poll_interval)
|
|
363
|
+
|
|
364
|
+
def get_output_mappings(self) -> typing.List[typing.Dict[str, str]]:
|
|
365
|
+
"""
|
|
366
|
+
Get the mapping of input files to their corresponding output files.
|
|
367
|
+
|
|
368
|
+
Returns
|
|
369
|
+
-------
|
|
370
|
+
List[Dict[str, str]]
|
|
371
|
+
List of mappings with keys 'input_file' and 'output_file'.
|
|
372
|
+
"""
|
|
373
|
+
job_status = self.get_status()
|
|
374
|
+
return [
|
|
375
|
+
{
|
|
376
|
+
"input_file": detail.inputs[0].file_name,
|
|
377
|
+
"output_file": detail.outputs[0].file_name,
|
|
378
|
+
}
|
|
379
|
+
for detail in (job_status.job_details or [])
|
|
380
|
+
if detail.inputs and detail.outputs
|
|
381
|
+
]
|
|
382
|
+
|
|
383
|
+
def download_outputs(self, output_dir: str) -> bool:
|
|
384
|
+
"""
|
|
385
|
+
Download output files to the specified directory.
|
|
386
|
+
|
|
387
|
+
Parameters
|
|
388
|
+
----------
|
|
389
|
+
output_dir : str
|
|
390
|
+
Local directory where outputs will be saved.
|
|
391
|
+
|
|
392
|
+
Returns
|
|
393
|
+
-------
|
|
394
|
+
bool
|
|
395
|
+
True if all files downloaded successfully.
|
|
396
|
+
|
|
397
|
+
Raises
|
|
398
|
+
------
|
|
399
|
+
RuntimeError
|
|
400
|
+
If a file fails to download.
|
|
401
|
+
"""
|
|
402
|
+
mappings = self.get_output_mappings()
|
|
403
|
+
file_names = [m["output_file"] for m in mappings]
|
|
404
|
+
download_links = self._client.get_download_links(
|
|
405
|
+
job_id=self._job_id, files=file_names
|
|
406
|
+
)
|
|
407
|
+
|
|
408
|
+
os.makedirs(output_dir, exist_ok=True)
|
|
409
|
+
with httpx.Client() as client:
|
|
410
|
+
for m in mappings:
|
|
411
|
+
url = download_links.download_urls[m["output_file"]].file_url
|
|
412
|
+
response = client.get(url)
|
|
413
|
+
if response.status_code != 200:
|
|
414
|
+
raise RuntimeError(
|
|
415
|
+
f"Download failed for {m['output_file']}: {response.status_code}"
|
|
416
|
+
)
|
|
417
|
+
output_path = os.path.join(output_dir, f"{m['input_file']}.json")
|
|
418
|
+
with open(output_path, "wb") as f:
|
|
419
|
+
f.write(response.content)
|
|
420
|
+
return True
|
|
421
|
+
|
|
422
|
+
def get_status(self) -> JobStatusV1Response:
|
|
423
|
+
"""
|
|
424
|
+
Retrieve the current status of the job.
|
|
425
|
+
|
|
426
|
+
Returns
|
|
427
|
+
-------
|
|
428
|
+
JobStatusV1Response
|
|
429
|
+
"""
|
|
430
|
+
return self._client.get_status(self._job_id)
|
|
431
|
+
|
|
432
|
+
def start(self) -> JobStatusV1Response:
|
|
433
|
+
"""
|
|
434
|
+
Start the speech-to-text job processing.
|
|
435
|
+
|
|
436
|
+
Returns
|
|
437
|
+
-------
|
|
438
|
+
JobStatusV1Response
|
|
439
|
+
"""
|
|
440
|
+
return self._client.start(job_id=self._job_id)
|
|
441
|
+
|
|
442
|
+
def exists(self) -> bool:
|
|
443
|
+
"""
|
|
444
|
+
Check if the job exists in the system.
|
|
445
|
+
|
|
446
|
+
Returns
|
|
447
|
+
-------
|
|
448
|
+
bool
|
|
449
|
+
"""
|
|
450
|
+
try:
|
|
451
|
+
self.get_status()
|
|
452
|
+
return True
|
|
453
|
+
except httpx.HTTPStatusError:
|
|
454
|
+
return False
|
|
455
|
+
|
|
456
|
+
def is_complete(self) -> bool:
|
|
457
|
+
"""
|
|
458
|
+
Check if the job is either completed or failed.
|
|
459
|
+
|
|
460
|
+
Returns
|
|
461
|
+
-------
|
|
462
|
+
bool
|
|
463
|
+
"""
|
|
464
|
+
return self.get_status().job_state.lower() in {"completed", "failed"}
|
|
465
|
+
|
|
466
|
+
def is_successful(self) -> bool:
|
|
467
|
+
"""
|
|
468
|
+
Check if the job completed successfully.
|
|
469
|
+
|
|
470
|
+
Returns
|
|
471
|
+
-------
|
|
472
|
+
bool
|
|
473
|
+
"""
|
|
474
|
+
return self.get_status().job_state.lower() == "completed"
|
|
475
|
+
|
|
476
|
+
def is_failed(self) -> bool:
|
|
477
|
+
"""
|
|
478
|
+
Check if the job has failed.
|
|
479
|
+
|
|
480
|
+
Returns
|
|
481
|
+
-------
|
|
482
|
+
bool
|
|
483
|
+
"""
|
|
484
|
+
return self.get_status().job_state.lower() == "failed"
|