Spaces:
Sleeping
Sleeping
File size: 6,650 Bytes
2b609ac |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 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 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 |
import traceback
import gradio as gr
import requests
import time
import os
import re
from typing import Dict, Tuple, Optional, Union
# Read from environment variables with default values if not set
LETTERCAST_API_BASE = os.environ.get("LETTERCAST_API_BASE", "https://app.lettercast.ai/v1")
WAIT_TIME_S = 20
DEFAULT_API_TOKEN = os.environ.get("LETTERCAST_DEFAULT_API_TOKEN") # Replace with your default token
def is_valid_url(url: str) -> bool:
url_pattern = re.compile(
r'^https?://' # http:// or https://
r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+[A-Z]{2,6}\.?|' # domain...
r'localhost|' # localhost...
r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})' # ...or ip
r'(?::\d+)?' # optional port
r'(?:/?|[/?]\S+)$', re.IGNORECASE)
return url_pattern.match(url) is not None
def create_pod(url: Optional[str], file: Optional[str],
html_content: Optional[str], detail_level: str, create_video: bool,
progress: gr.Progress = gr.Progress()) -> Tuple[Dict, str, Optional[str], Optional[str]]:
# Validate that only one input method is provided
input_count = sum(bool(x) for x in (url, file, html_content))
if input_count != 1:
return {"error": "Please provide exactly one of: URL, PDF file, or HTML content."}, "Error", None, None
if url and not is_valid_url(url):
return {"error": "Invalid URL format. Please enter a valid URL."}, "Error", None, None
token = DEFAULT_API_TOKEN
headers = {"Authorization": f"Bearer {token}"}
data = {
"detail_level": detail_level,
"create_video": create_video,
}
if url:
data["url"] = url
elif html_content:
data["html_content"] = html_content
endpoint_url = f"{LETTERCAST_API_BASE}/pods"
try:
if file is not None:
with open(file, "rb") as f:
files = {"file": (os.path.basename(file), f, "application/pdf")}
response = requests.post(endpoint_url, headers=headers, data=data, files=files)
else:
headers["Content-Type"] = "application/json"
response = requests.post(endpoint_url, headers=headers, json=data)
if response.status_code == 200:
resp_data = response.json()
pod_id = resp_data.get("pod_id")
if pod_id:
# Trigger the status check immediately if we have a valid pod_id
status, _, audio_file, video_file = check_pod_status(pod_id, progress)
return resp_data, status, audio_file, video_file
else:
return resp_data, "Pod created, but no pod_id received.", None, None
else:
error_message = f"Error {response.status_code}: {response.text}"
return {"error": error_message}, "Pod creation failed", None, None
except Exception as e:
error_message = f"Error creating pod: {str(e)}"
return {"error": error_message}, "Error", None, None
def check_pod_status(pod_id: str,
progress: gr.Progress = gr.Progress()) -> Tuple[str, Optional[str], Optional[str], Optional[str]]:
token = DEFAULT_API_TOKEN
headers = {"Authorization": f"Bearer {token}"}
max_retries = 30 # Max wait time of 10 minutes
for i in range(max_retries):
time.sleep(WAIT_TIME_S)
progress(i / max_retries, desc="Checking pod status...")
try:
response = requests.get(f"{LETTERCAST_API_BASE}/pods/{pod_id}", headers=headers)
if response.status_code == 200:
pod = response.json()
if pod['generation_status'] == 'done':
audio_file = download_media(pod_id, 'audio')
video_file = download_media(pod_id, 'video')
return "Pod is ready!", pod_id, audio_file, video_file
elif pod['generation_status'] == 'failed':
return "Pod creation failed.", None, None, None
else:
continue
except Exception as e:
return f"Error checking pod status: {str(e)}", None, None, None
return "Pod generation timed out.", None, None, None
def download_media(pod_id: str, media_type: str) -> Optional[str]:
token = DEFAULT_API_TOKEN
headers = {"Authorization": f"Bearer {token}"}
url = f"{LETTERCAST_API_BASE}/pods/{pod_id}/{media_type}"
response = requests.get(url, headers=headers)
if response.status_code == 200:
file_extension = 'mp3' if media_type == 'audio' else 'mp4'
file_path = f'pod_{media_type}_{pod_id}.{file_extension}'
with open(file_path, 'wb') as file:
file.write(response.content)
return file_path
else:
return None
with gr.Blocks() as demo:
gr.Markdown("## Try the [Lettercast.ai](https://lettercast.ai) API")
gr.Markdown("""
Provide exactly one of the following:
- Enter a URL
- Upload a PDF file
- Enter HTML content
The API home is at our [Developer Hub](https://developer.lettercast.ai).
""")
with gr.Row():
url = gr.Textbox(label="URL", placeholder="Enter a URL")
detail_level = gr.Dropdown(
choices=["summary_discussion", "summary_single_host"],
label="Pod Type",
value="summary_discussion"
)
with gr.Row():
file = gr.File(label="Upload a PDF file", type="filepath")
create_video = gr.Checkbox(label="Create Video (PDF only)", value=False)
with gr.Row():
html_content = gr.Textbox(label="HTML Content", placeholder="Enter HTML content", lines=5)
create_pod_btn = gr.Button("Create Pod")
output = gr.JSON(label="Response")
status_output = gr.Textbox(label="Status")
audio_player = gr.Audio(label="Generated Audio", visible=False, autoplay=True)
video_player = gr.Video(label="Generated Video", visible=False)
def update_ui(result, status, audio_file, video_file):
audio_visible = audio_file is not None
video_visible = video_file is not None
return (
result,
status,
audio_file,
gr.update(visible=audio_visible),
video_file,
gr.update(visible=video_visible)
)
create_pod_btn.click(
fn=lambda *args: update_ui(*create_pod(*args)),
inputs=[url, file, html_content, detail_level, create_video],
outputs=[output, status_output, audio_player, audio_player, video_player, video_player],
show_progress="full",
show_api=False
)
demo.launch() |