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()