File size: 5,517 Bytes
6704495
 
 
 
54199ed
 
6704495
 
 
 
 
 
0d9591f
 
 
479fe9d
36ce10c
0d9591f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36ce10c
0d9591f
 
 
 
 
 
 
480bcab
 
c433823
0d9591f
 
 
 
 
 
36ce10c
6704495
36ce10c
0d9591f
 
 
 
 
6704495
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36ce10c
6704495
 
 
 
 
 
 
 
 
 
 
 
296c0e9
 
 
 
 
 
6704495
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import gradio as gr
import requests
import json
import os
import time
from collections import defaultdict

BASE_URL = "https://api.jigsawstack.com/v1"
headers = {
    "x-api-key": os.getenv("JIGSAWSTACK_API_KEY")
}


# Rate limiting configuration
request_times = defaultdict(list)
MAX_REQUESTS = 20  # Maximum requests per time window
TIME_WINDOW = 3600   # Time window in seconds (1 hour)

def get_real_ip(request: gr.Request):
    """Extract real IP address using x-forwarded-for header or fallback"""
    if not request:
        return "unknown"
    
    forwarded = request.headers.get("x-forwarded-for")
    if forwarded:
        ip = forwarded.split(",")[0].strip()  # First IP in the list is the client's
    else:
        ip = request.client.host  # fallback
    return ip

def check_rate_limit(request: gr.Request):
    """Check if the current request exceeds rate limits"""
    if not request:
        return True, "Rate limit check failed - no request info"
    
    ip = get_real_ip(request)
    now = time.time()

    # Clean up old timestamps outside the time window
    request_times[ip] = [t for t in request_times[ip] if now - t < TIME_WINDOW]
    

    # Check if rate limit exceeded
    if len(request_times[ip]) >= MAX_REQUESTS:
        time_remaining = int(TIME_WINDOW - (now - request_times[ip][0]))
        time_remaining_minutes = round(time_remaining / 60, 1)      
        time_window_minutes = round(TIME_WINDOW / 60, 1)
        return False, f"Rate limit exceeded. You can make {MAX_REQUESTS} requests per {time_window_minutes} minutes. Try again in {time_remaining_minutes} minutes."
    
    # Add current request timestamp
    request_times[ip].append(now)
    return True, ""


def transcribe_audio(input_type, audio_url, file_store_key, language, request: gr.Request):
    """Transcribe audio using JigsawStack Speech-to-Text API"""
    
    # Check rate limit first
    rate_limit_ok, rate_limit_msg = check_rate_limit(request)
    if not rate_limit_ok:
        return rate_limit_msg, ""
    
    if input_type == "Audio URL" and not audio_url:
        return "Error: Please provide an audio URL.", ""
    if input_type == "File Store Key" and not file_store_key:
        return "Error: Please provide a file store key.", ""
    try:
        payload = {}
        if input_type == "Audio URL":
            payload["url"] = audio_url.strip()
        if input_type == "File Store Key":
            payload["file_store_key"] = file_store_key.strip()
        if language:
            payload["language"] = language
        response = requests.post(
            f"{BASE_URL}/ai/transcribe",
            headers=headers,
            json=payload
        )
        response.raise_for_status()
        result = response.json()
        
        if not result.get("success"):
            error_msg = f"Error: API call failed - {result.get('message', 'Unknown error')}"
            return error_msg, ""
        transcribed_text = result.get("text", "")
        return "Transcription completed successfully!", transcribed_text
    except requests.exceptions.RequestException as e:
        return f"Request failed: {str(e)}", ""
    except Exception as e:
        return f"An unexpected error occurred: {str(e)}", ""

with gr.Blocks() as demo:
    gr.Markdown("""
    <div style='text-align: center; margin-bottom: 24px;'>
        <h1 style='font-size:2.2em; margin-bottom: 0.2em;'>🧩 Speech-to-Text Transcription</h1>
        <p style='font-size:1.2em; margin-top: 0;'>Convert speech to text with ease.</p>
        <p style='font-size:1em; margin-top: 0.5em;'>For more details and API usage, see the <a href='https://jigsawstack.com/docs/api-reference/ai/speech-to-text' target='_blank'>documentation</a>.</p>
    </div>
    """)
    with gr.Row():
        with gr.Column():
            gr.Markdown("#### Audio Input")
            input_type = gr.Radio([
                "Audio URL",
                "File Store Key"
            ], value="Audio URL", label="Select Input Type")
            audio_url = gr.Textbox(
                label="Audio URL",
                placeholder="Enter the URL of the audio/video file...",
                visible=True
            )
            file_store_key = gr.Textbox(
                label="File Store Key",
                placeholder="Enter the file store key from JigsawStack File Storage...",
                visible=False
            )
            language = gr.Textbox(
                label="Language (optional)",
                placeholder="e.g., en, es, fr, de, ja, zh... (leave empty for auto-detect)"
            )
            transcribe_btn = gr.Button("Start Transcription", variant="primary")
        with gr.Column():
            gr.Markdown("#### Transcription Result")
            status_message = gr.Textbox(label="Status", interactive=False)
            transcribed_text = gr.Textbox(
                label="Transcribed Text",
                interactive=False,
                lines=10,
                max_lines=20
            )
    def toggle_inputs(selected):
        if selected == "Audio URL":
            return gr.update(visible=True), gr.update(visible=False)
        else:
            return gr.update(visible=False), gr.update(visible=True)
    input_type.change(toggle_inputs, inputs=[input_type], outputs=[audio_url, file_store_key])
    transcribe_btn.click(
        transcribe_audio,
        inputs=[input_type, audio_url, file_store_key, language],
        outputs=[status_message, transcribed_text]
    )

demo.launch()