-
Notifications
You must be signed in to change notification settings - Fork 980
Implement Runpod API integration for transcription and add webhook ha… #192
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Implement Runpod API integration for transcription and add webhook ha… #192
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR implements Runpod API integration as an alternative to local Whisper processing for media transcription, adding support for async processing via webhooks. The integration provides a configurable fallback mechanism where translation tasks use local Whisper while transcription can use either Runpod or local processing based on configuration.
- Adds Runpod API client with support for both sync and async processing
- Implements webhook handling for async Runpod job results
- Updates transcription services to conditionally use Runpod or local Whisper based on configuration
Reviewed Changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| services/runpod_whisper.py | New Runpod API client with transcription, polling, and webhook support |
| routes/webhook.py | New webhook endpoint for handling async Runpod transcription results |
| services/v1/media/media_transcribe.py | Updated to support Runpod integration with fallback to local Whisper |
| services/transcription.py | Modified to use Runpod when configured, otherwise local Whisper |
| services/ass_toolkit.py | Added Runpod support for transcription generation |
| routes/v1/media/media_transcribe.py | Added initial_prompt parameter support |
| config.py | Added Runpod configuration variables |
| .env.example | Added Runpod API key example |
| Dictionary containing transcription results in Whisper format | ||
| or job information if webhook is provided | ||
| """ | ||
| return runpod_client.transcribe_audio(audio_url, model, language, webhook_url, initial_prompt="") |
Copilot
AI
Aug 8, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The initial_prompt parameter is being hardcoded to an empty string instead of using the passed initial_prompt parameter. This should be initial_prompt=initial_prompt.
| return runpod_client.transcribe_audio(audio_url, model, language, webhook_url, initial_prompt="") | |
| return runpod_client.transcribe_audio(audio_url, model, language, webhook_url, initial_prompt=initial_prompt) |
| if not self.api_key: | ||
| raise ValueError("RUNPOD_API_KEY environment variable is not set") | ||
|
|
||
| self.base_url = "https://api.runpod.ai/v2/n8j2ln49qh2n4x/run" |
Copilot
AI
Aug 8, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The endpoint ID 'n8j2ln49qh2n4x' is hardcoded. This should be configurable via environment variable to support different Runpod endpoints or deployments.
| self.base_url = "https://api.runpod.ai/v2/n8j2ln49qh2n4x/run" | |
| self.endpoint_id = os.environ.get('RUNPOD_ENDPOINT_ID') | |
| if not self.endpoint_id: | |
| raise ValueError("RUNPOD_ENDPOINT_ID environment variable is not set") | |
| self.base_url = f"https://api.runpod.ai/v2/{self.endpoint_id}/run" |
|
|
||
| logger.info(f"Polling for job completion. Job ID: {job_id}") | ||
|
|
||
| status_url = f"https://api.runpod.ai/v2/n8j2ln49qh2n4x/status/{job_id}" |
Copilot
AI
Aug 8, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The endpoint ID is hardcoded again in the status URL. This should use the same configurable base URL pattern to maintain consistency.
| status_url = f"https://api.runpod.ai/v2/n8j2ln49qh2n4x/status/{job_id}" | |
| status_url = self.base_url.rsplit('/run', 1)[0] + f"/status/{job_id}" |
| Dictionary containing job status information | ||
| """ | ||
| try: | ||
| status_url = f"https://api.runpod.ai/v2/n8j2ln49qh2n4x/status/{job_id}" |
Copilot
AI
Aug 8, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Third occurrence of the hardcoded endpoint ID. Consider extracting this to a method or configuration variable.
| status_url = f"https://api.runpod.ai/v2/n8j2ln49qh2n4x/status/{job_id}" | |
| status_url = f"https://api.runpod.ai/v2/{self.ENDPOINT_ID}/status/{job_id}" |
| input_filename = download_file(media_url, os.path.join(LOCAL_STORAGE_PATH, f"{job_id}_input")) | ||
| logger.info(f"Downloaded media to local file: {input_filename}") | ||
|
|
||
| logger.info(f"Checking Runpod configuration: USE_RUNPOD={USE_RUNPOD}, RUNPOD_API_KEY={'✅ Set' if RUNPOD_API_KEY else '❌ Not set'}") |
Copilot
AI
Aug 8, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Logging API key presence with emoji characters could cause encoding issues in some logging systems. Consider using plain text like 'SET' and 'NOT_SET'.
| logger.info(f"Checking Runpod configuration: USE_RUNPOD={USE_RUNPOD}, RUNPOD_API_KEY={'✅ Set' if RUNPOD_API_KEY else '❌ Not set'}") | |
| logger.info(f"Checking Runpod configuration: USE_RUNPOD={USE_RUNPOD}, RUNPOD_API_KEY={'SET' if RUNPOD_API_KEY else 'NOT_SET'}") |
| input_filename = download_file(media_url, os.path.join(STORAGE_PATH, 'input_media')) | ||
| logger.info(f"Downloaded media to local file: {input_filename}") | ||
|
|
||
| logger.info(f"Checking Runpod configuration: USE_RUNPOD={USE_RUNPOD}, RUNPOD_API_KEY={'✅ Set' if RUNPOD_API_KEY else '❌ Not set'}") |
Copilot
AI
Aug 8, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same emoji encoding issue as in media_transcribe.py. Use plain text for better logging compatibility.
| logger.info(f"Checking Runpod configuration: USE_RUNPOD={USE_RUNPOD}, RUNPOD_API_KEY={'✅ Set' if RUNPOD_API_KEY else '❌ Not set'}") | |
| logger.info(f"Checking Runpod configuration: USE_RUNPOD={USE_RUNPOD}, RUNPOD_API_KEY={'Set' if RUNPOD_API_KEY else 'Not set'}") |
| # In-memory storage for webhook results (in production, use Redis or database) | ||
| webhook_results = {} |
Copilot
AI
Aug 8, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using in-memory storage for webhook results will lose data on application restart. The comment mentions using Redis or database in production, but this should be implemented or at least have proper warning documentation.
| # In-memory storage for webhook results (in production, use Redis or database) | |
| webhook_results = {} | |
| # WARNING: In-memory storage for webhook results. | |
| # All webhook results will be lost on application restart or crash. | |
| # DO NOT USE THIS IN PRODUCTION. Use Redis or a persistent database instead. | |
| webhook_results = {} | |
| logging.warning( | |
| "USING IN-MEMORY STORAGE FOR WEBHOOK RESULTS. " | |
| "ALL DATA WILL BE LOST ON APPLICATION RESTART. " | |
| "DO NOT USE THIS IN PRODUCTION. Use Redis or a persistent database." | |
| ) |
| # Global instance for easy access | ||
| runpod_client = RunpodWhisperClient() | ||
|
|
Copilot
AI
Aug 8, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Creating a global instance without proper error handling. If RUNPOD_API_KEY is not set, this will raise an exception at module import time, potentially breaking the entire application even when Runpod is not being used.
| # Global instance for easy access | |
| runpod_client = RunpodWhisperClient() | |
| # Lazy singleton instance for easy access | |
| _runpod_client_instance = None | |
| def get_runpod_client(): | |
| global _runpod_client_instance | |
| if _runpod_client_instance is None: | |
| _runpod_client_instance = RunpodWhisperClient() | |
| return _runpod_client_instance |
…v.example and add docker-compose-custom-build.yml
…ndling