Spaces:
Running
Running
| #!/usr/bin/env python3 | |
| """ | |
| Standalone script to generate sound effects using Hugging Face API. | |
| Uses only built-in Python libraries (no external dependencies). | |
| """ | |
| import os | |
| import json | |
| import urllib.request | |
| import time | |
| from pathlib import Path | |
| # Load environment variables from .env if present | |
| env_path = Path(__file__).parent / ".env" | |
| if env_path.exists(): | |
| with open(env_path) as f: | |
| for line in f: | |
| if line.strip() and not line.startswith("#"): | |
| key, _, value = line.strip().partition("=") | |
| os.environ[key] = value | |
| # Get Hugging Face API token from environment variable | |
| HF_API_TOKEN = os.environ.get("HF_API_TOKEN") | |
| if not HF_API_TOKEN: | |
| print("Warning: HF_API_TOKEN not set in environment or .env file.") | |
| # Using your UnlimitedMusicGen Gradio Space | |
| SPACE_URL = "https://surn-unlimitedmusicgen.hf.space" | |
| GRADIO_API_URL = f"{SPACE_URL}/api/predict" | |
| GRADIO_STATUS_URL = f"{SPACE_URL}/call/predict/{{event_id}}" | |
| # Sound effects to generate | |
| EFFECT_PROMPTS = { | |
| "correct_guess": {"prompt": "A short, sharp ding sound for a correct guess", "duration": 2}, | |
| "incorrect_guess": {"prompt": "A low buzz sound for an incorrect guess", "duration": 2}, | |
| "miss": {"prompt": "A soft thud sound for a miss", "duration": 1}, | |
| "hit": {"prompt": "A bright chime sound for a hit", "duration": 1}, | |
| "congratulations": {"prompt": "A triumphant fanfare sound for congratulations", "duration": 3} | |
| } | |
| def generate_sound_effect_gradio(effect_name: str, prompt: str, duration: float, output_dir: Path) -> bool: | |
| """Generate a single sound effect using Gradio API (async call).""" | |
| print(f"\nGenerating: {effect_name}") | |
| print(f" Prompt: {prompt}") | |
| print(f" Duration: {duration}s") | |
| # Step 1: Submit generation request | |
| payload = json.dumps({ | |
| "data": [prompt, duration] | |
| }).encode('utf-8') | |
| headers = { | |
| "Content-Type": "application/json" | |
| } | |
| try: | |
| print(f" Submitting request to Gradio API...") | |
| # Submit the job | |
| req = urllib.request.Request(GRADIO_API_URL, data=payload, headers=headers, method='POST') | |
| with urllib.request.urlopen(req, timeout=30) as response: | |
| if response.status == 200: | |
| result = json.loads(response.read().decode()) | |
| event_id = result.get("event_id") | |
| if not event_id: | |
| print(f" β No event_id returned") | |
| return False | |
| print(f" Job submitted, event_id: {event_id}") | |
| # Step 2: Poll for results | |
| status_url = GRADIO_STATUS_URL.format(event_id=event_id) | |
| for poll_attempt in range(30): # Poll for up to 5 minutes | |
| time.sleep(10) | |
| print(f" Polling for results (attempt {poll_attempt + 1}/30)...") | |
| status_req = urllib.request.Request(status_url, headers=headers) | |
| try: | |
| with urllib.request.urlopen(status_req, timeout=30) as status_response: | |
| # Gradio returns streaming events, read until we get the result | |
| for line in status_response: | |
| line = line.decode('utf-8').strip() | |
| if line.startswith('data: '): | |
| event_data = json.loads(line[6:]) # Remove 'data: ' prefix | |
| if event_data.get('msg') == 'process_completed': | |
| # Get the audio file URL | |
| output_data = event_data.get('output', {}).get('data', []) | |
| if output_data and len(output_data) > 0: | |
| audio_url = output_data[0].get('url') | |
| if audio_url: | |
| # Download the audio file | |
| full_audio_url = f"https://surn-unlimitedmusicgen.hf.space{audio_url}" | |
| print(f" Downloading from: {full_audio_url}") | |
| audio_req = urllib.request.Request(full_audio_url) | |
| with urllib.request.urlopen(audio_req, timeout=30) as audio_response: | |
| audio_data = audio_response.read() | |
| # Save to file | |
| output_path = output_dir / f"{effect_name}.wav" | |
| with open(output_path, "wb") as f: | |
| f.write(audio_data) | |
| print(f" β Success! Saved to: {output_path}") | |
| print(f" File size: {len(audio_data)} bytes") | |
| return True | |
| elif event_data.get('msg') == 'process_error': | |
| print(f" β Generation error: {event_data.get('output')}") | |
| return False | |
| except Exception as poll_error: | |
| print(f" Polling error: {poll_error}") | |
| continue | |
| print(f" β Timeout waiting for generation") | |
| return False | |
| else: | |
| print(f" β Error {response.status}: {response.read().decode()}") | |
| return False | |
| except Exception as e: | |
| print(f" β Error: {e}") | |
| return False | |
| def main(): | |
| """Generate all sound effects.""" | |
| print("=" * 70) | |
| print("Sound Effects Generator for BattleWords") | |
| print("=" * 70) | |
| print(f"Using UnlimitedMusicGen Gradio API") | |
| print(f"API URL: {GRADIO_API_URL}") | |
| print(f"\nGenerating {len(EFFECT_PROMPTS)} sound effects...\n") | |
| # Create output directory | |
| output_dir = Path(__file__).parent / "assets" / "audio" | |
| output_dir.mkdir(parents=True, exist_ok=True) | |
| print(f"Output directory: {output_dir}\n") | |
| # Generate each effect | |
| success_count = 0 | |
| for effect_name, config in EFFECT_PROMPTS.items(): | |
| if generate_sound_effect_gradio( | |
| effect_name, | |
| config["prompt"], | |
| config["duration"], | |
| output_dir | |
| ): | |
| success_count += 1 | |
| # Small delay between requests | |
| if effect_name != list(EFFECT_PROMPTS.keys())[-1]: | |
| print(" Waiting 5 seconds before next request...") | |
| time.sleep(5) | |
| print("\n" + "=" * 70) | |
| print(f"Generation complete! {success_count}/{len(EFFECT_PROMPTS)} successful") | |
| print("=" * 70) | |
| if success_count == len(EFFECT_PROMPTS): | |
| print("\nβ All sound effects generated successfully!") | |
| else: | |
| print(f"\nβ {len(EFFECT_PROMPTS) - success_count} sound effects failed to generate") | |
| if __name__ == "__main__": | |
| main() | |