Spaces:
Sleeping
Sleeping
Commit
Β·
38822a8
1
Parent(s):
ca042ba
Fix: use /tmp for audio generation to avoid permission errors
Browse files- .gitignore +4 -1
- app/api/v1/audio.py +8 -22
- app/services/audio_service.py +8 -29
- auto_test_endpoints.py +93 -73
.gitignore
CHANGED
|
@@ -41,4 +41,7 @@ __pycache__/
|
|
| 41 |
outputs/
|
| 42 |
generated/
|
| 43 |
*.pyc
|
| 44 |
-
*.log
|
|
|
|
|
|
|
|
|
|
|
|
| 41 |
outputs/
|
| 42 |
generated/
|
| 43 |
*.pyc
|
| 44 |
+
*.log
|
| 45 |
+
|
| 46 |
+
#adding tmp files
|
| 47 |
+
/tmp/hf_cache
|
app/api/v1/audio.py
CHANGED
|
@@ -1,9 +1,9 @@
|
|
| 1 |
-
|
| 2 |
-
from fastapi
|
|
|
|
| 3 |
from pydantic import BaseModel
|
| 4 |
-
from
|
| 5 |
-
|
| 6 |
-
import os
|
| 7 |
router = APIRouter()
|
| 8 |
|
| 9 |
class AudioRequest(BaseModel):
|
|
@@ -12,23 +12,9 @@ class AudioRequest(BaseModel):
|
|
| 12 |
language: str = "en"
|
| 13 |
|
| 14 |
@router.post("/generate")
|
| 15 |
-
def
|
| 16 |
try:
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
folder = "generated/audio"
|
| 20 |
-
os.makedirs("generated_audio", exist_ok=True)
|
| 21 |
-
file_path = f"generated_audio/{filename}" # β
match your video & image folders
|
| 22 |
-
|
| 23 |
-
# β
Generate TTS audio
|
| 24 |
-
tts = gTTS(text=payload.text, lang=payload.language)
|
| 25 |
-
tts.save(file_path)
|
| 26 |
-
|
| 27 |
-
# β
Return audio bytes for inline Streamlit playback
|
| 28 |
-
with open(file_path, "rb") as f:
|
| 29 |
-
audio_bytes = f.read()
|
| 30 |
-
|
| 31 |
-
return Response(content=audio_bytes, media_type="audio/mpeg")
|
| 32 |
-
|
| 33 |
except Exception as e:
|
| 34 |
raise HTTPException(status_code=500, detail=str(e))
|
|
|
|
| 1 |
+
# app/api/v1/audio.py
|
| 2 |
+
from fastapi import APIRouter, HTTPException
|
| 3 |
+
from fastapi.responses import FileResponse
|
| 4 |
from pydantic import BaseModel
|
| 5 |
+
from app.services.audio_service import generate_audio_file
|
| 6 |
+
|
|
|
|
| 7 |
router = APIRouter()
|
| 8 |
|
| 9 |
class AudioRequest(BaseModel):
|
|
|
|
| 12 |
language: str = "en"
|
| 13 |
|
| 14 |
@router.post("/generate")
|
| 15 |
+
def generate_audio(payload: AudioRequest):
|
| 16 |
try:
|
| 17 |
+
file_path = generate_audio_file(payload.text, payload.language)
|
| 18 |
+
return FileResponse(file_path, media_type="audio/mpeg", filename="output.mp3")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 19 |
except Exception as e:
|
| 20 |
raise HTTPException(status_code=500, detail=str(e))
|
app/services/audio_service.py
CHANGED
|
@@ -1,39 +1,18 @@
|
|
| 1 |
# app/services/audio_service.py
|
| 2 |
from gtts import gTTS
|
| 3 |
-
import os
|
| 4 |
-
|
| 5 |
-
from app.db import SessionLocal
|
| 6 |
-
from app.models import MediaGeneration
|
| 7 |
-
import logging
|
| 8 |
logger = logging.getLogger(__name__)
|
| 9 |
-
import uuid
|
| 10 |
|
| 11 |
-
def generate_audio_file(text: str,
|
|
|
|
| 12 |
try:
|
|
|
|
|
|
|
| 13 |
tts = gTTS(text=text, lang=language, slow=False)
|
| 14 |
-
timestamp = datetime.now().strftime("%Y%m%d%H%M%S")
|
| 15 |
-
filename = f"audio_{timestamp}.mp3"
|
| 16 |
-
output_dir = "generated/audio"
|
| 17 |
-
os.makedirs(output_dir, exist_ok=True)
|
| 18 |
-
file_path = os.path.join(output_dir, filename)
|
| 19 |
tts.save(file_path)
|
| 20 |
-
logger.info(f"Generated Audio: {
|
| 21 |
return file_path
|
| 22 |
-
except:
|
| 23 |
logger.error(f"Audio Generation Failed: {str(e)}")
|
| 24 |
raise
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
from app.db import SessionLocal
|
| 28 |
-
from app.models import MediaGeneration
|
| 29 |
-
|
| 30 |
-
def save_metadata(media_type, prompt, file_path):
|
| 31 |
-
db = SessionLocal()
|
| 32 |
-
record = MediaGeneration(
|
| 33 |
-
media_type=media_type,
|
| 34 |
-
prompt=prompt,
|
| 35 |
-
file_path=file_path,
|
| 36 |
-
)
|
| 37 |
-
db.add(record)
|
| 38 |
-
db.commit()
|
| 39 |
-
db.close()
|
|
|
|
| 1 |
# app/services/audio_service.py
|
| 2 |
from gtts import gTTS
|
| 3 |
+
import os, uuid, logging
|
| 4 |
+
|
|
|
|
|
|
|
|
|
|
| 5 |
logger = logging.getLogger(__name__)
|
|
|
|
| 6 |
|
| 7 |
+
def generate_audio_file(text: str, language: str = "en") -> str:
|
| 8 |
+
"""Generate an MP3 file in Hugging Face writable /tmp directory."""
|
| 9 |
try:
|
| 10 |
+
os.makedirs("/tmp", exist_ok=True)
|
| 11 |
+
file_path = os.path.join("/tmp", f"audio_{uuid.uuid4().hex}.mp3")
|
| 12 |
tts = gTTS(text=text, lang=language, slow=False)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 13 |
tts.save(file_path)
|
| 14 |
+
logger.info(f"Generated Audio: {file_path}")
|
| 15 |
return file_path
|
| 16 |
+
except Exception as e:
|
| 17 |
logger.error(f"Audio Generation Failed: {str(e)}")
|
| 18 |
raise
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
auto_test_endpoints.py
CHANGED
|
@@ -1,83 +1,103 @@
|
|
| 1 |
import requests
|
| 2 |
import json
|
| 3 |
import os
|
|
|
|
|
|
|
| 4 |
|
| 5 |
BASE_URL = "https://osnarayana-media-gen-api.hf.space"
|
| 6 |
-
TOKEN = "my_secure_token_123"
|
| 7 |
-
|
| 8 |
-
headers = {
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
if "
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 23 |
return {"prompt": "A cute cat in watercolor style"}
|
| 24 |
-
|
| 25 |
-
return {
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 29 |
return {"reference": "hello world", "candidate": "hello"}
|
| 30 |
-
|
| 31 |
return {"reference": "a photo of a cat", "candidate": "an image of a cute cat"}
|
| 32 |
-
# fallback
|
| 33 |
return {}
|
| 34 |
|
| 35 |
-
|
| 36 |
-
def
|
| 37 |
-
""
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
import requests
|
| 2 |
import json
|
| 3 |
import os
|
| 4 |
+
import time
|
| 5 |
+
from datetime import datetime
|
| 6 |
|
| 7 |
BASE_URL = "https://osnarayana-media-gen-api.hf.space"
|
| 8 |
+
TOKEN = "my_secure_token_123" # must match your auth.py
|
| 9 |
+
|
| 10 |
+
headers = {
|
| 11 |
+
"Authorization": f"Bearer {TOKEN}",
|
| 12 |
+
"Content-Type": "application/json"
|
| 13 |
+
}
|
| 14 |
+
|
| 15 |
+
# Directory for saving media files
|
| 16 |
+
os.makedirs("outputs", exist_ok=True)
|
| 17 |
+
|
| 18 |
+
def unique_filename(prefix, ext):
|
| 19 |
+
ts = datetime.now().strftime("%Y%m%d_%H%M%S_%f")
|
| 20 |
+
return os.path.join("outputs", f"{prefix}_{ts}.{ext}")
|
| 21 |
+
|
| 22 |
+
# Dummy payload generator
|
| 23 |
+
def get_dummy_payload(path):
|
| 24 |
+
if "audio/generate" in path:
|
| 25 |
+
return {"text": "Hello from auto test!"}
|
| 26 |
+
elif "video/generate" in path:
|
| 27 |
+
return {
|
| 28 |
+
"prompt": "A futuristic city with flying cars",
|
| 29 |
+
"tone": "inspiring",
|
| 30 |
+
"domain": "sci-fi",
|
| 31 |
+
"environment": "day"
|
| 32 |
+
}
|
| 33 |
+
elif "image/generate" in path:
|
| 34 |
return {"prompt": "A cute cat in watercolor style"}
|
| 35 |
+
elif "ppt/generate" in path:
|
| 36 |
+
return {
|
| 37 |
+
"slides": [
|
| 38 |
+
{"title": "Welcome", "content": "This is auto-generated PPT"},
|
| 39 |
+
{"title": "Conclusion", "content": "Demo slide"}
|
| 40 |
+
]
|
| 41 |
+
}
|
| 42 |
+
elif "metrics/evaluate/bleu" in path:
|
| 43 |
+
# metrics currently require query params
|
| 44 |
return {"reference": "hello world", "candidate": "hello"}
|
| 45 |
+
elif "metrics/evaluate/clipscore" in path:
|
| 46 |
return {"reference": "a photo of a cat", "candidate": "an image of a cute cat"}
|
|
|
|
| 47 |
return {}
|
| 48 |
|
| 49 |
+
# Detect if endpoint expects query params
|
| 50 |
+
def use_query_params(path):
|
| 51 |
+
return "metrics/evaluate" in path # currently only metrics use query
|
| 52 |
+
|
| 53 |
+
# List of endpoints to test
|
| 54 |
+
ENDPOINTS = [
|
| 55 |
+
"/api/v1/audio/generate",
|
| 56 |
+
"/api/v1/video/generate",
|
| 57 |
+
"/api/v1/image/generate",
|
| 58 |
+
"/api/v1/ppt/generate",
|
| 59 |
+
"/api/v1/metrics/evaluate/bleu",
|
| 60 |
+
"/api/v1/metrics/evaluate/clipscore"
|
| 61 |
+
]
|
| 62 |
+
|
| 63 |
+
for endpoint in ENDPOINTS:
|
| 64 |
+
url = f"{BASE_URL}{endpoint}"
|
| 65 |
+
payload = get_dummy_payload(endpoint)
|
| 66 |
+
|
| 67 |
+
print(f"\n=== Testing POST {url} ===")
|
| 68 |
+
print("Payload:", payload)
|
| 69 |
+
|
| 70 |
+
# Decide whether to use params or json
|
| 71 |
+
if use_query_params(endpoint):
|
| 72 |
+
response = requests.post(url, headers=headers, params=payload)
|
| 73 |
+
else:
|
| 74 |
+
response = requests.post(url, headers=headers, json=payload)
|
| 75 |
+
|
| 76 |
+
status = response.status_code
|
| 77 |
+
print("Status:", status)
|
| 78 |
+
|
| 79 |
+
if status == 200:
|
| 80 |
+
# Handle media files
|
| 81 |
+
content_type = response.headers.get("content-type", "")
|
| 82 |
+
if "application/json" in content_type:
|
| 83 |
+
print("JSON Response:", response.json())
|
| 84 |
+
else:
|
| 85 |
+
# Save binary file
|
| 86 |
+
ext = "bin"
|
| 87 |
+
if "image" in content_type:
|
| 88 |
+
ext = "png"
|
| 89 |
+
elif "audio" in content_type:
|
| 90 |
+
ext = "mp3"
|
| 91 |
+
elif "video" in content_type:
|
| 92 |
+
ext = "mp4"
|
| 93 |
+
elif "presentation" in content_type or "ppt" in endpoint:
|
| 94 |
+
ext = "pptx"
|
| 95 |
+
|
| 96 |
+
filename = unique_filename(endpoint.strip("/").replace("/", "_"), ext)
|
| 97 |
+
with open(filename, "wb") as f:
|
| 98 |
+
f.write(response.content)
|
| 99 |
+
print(f"β
Saved media file: {filename}")
|
| 100 |
+
else:
|
| 101 |
+
print("Error Response:", response.text)
|
| 102 |
+
|
| 103 |
+
time.sleep(1) # small delay to avoid spamming
|