File size: 6,132 Bytes
8e78ed6
1005880
 
177c81d
1005880
 
8e78ed6
177c81d
 
 
8e78ed6
dd043f6
a6fa5c5
1005880
177c81d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8e78ed6
177c81d
 
 
8e78ed6
1005880
177c81d
 
1005880
 
177c81d
 
08487bc
177c81d
 
 
 
 
 
1005880
8e78ed6
1005880
 
08487bc
1005880
8e78ed6
dd043f6
177c81d
 
08487bc
177c81d
08487bc
177c81d
8e78ed6
177c81d
dd043f6
177c81d
1005880
08487bc
 
 
 
 
 
 
 
dd043f6
08487bc
dd043f6
08487bc
dd043f6
 
 
 
177c81d
1005880
08487bc
dd043f6
 
177c81d
 
 
 
1005880
 
177c81d
 
 
 
 
1005880
08487bc
1005880
177c81d
 
 
 
08487bc
1005880
177c81d
 
 
 
 
 
 
 
 
1005880
 
e42c0b9
177c81d
 
dd043f6
177c81d
 
 
1005880
 
177c81d
1005880
177c81d
 
1005880
177c81d
 
1005880
177c81d
 
1005880
177c81d
 
 
 
 
 
1005880
 
 
 
 
 
177c81d
 
 
 
 
 
1005880
 
177c81d
 
 
 
 
 
1005880
177c81d
 
 
 
 
 
 
 
 
 
 
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
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
import gradio as gr
import os
import sys
import json
import requests
import random

# =====================================================
# Environment variables (Hugging Face Spaces SAFE)
# =====================================================

MODEL = "gpt-4.1-mini"  # Updated to a valid model for Responses API

API_URL = os.getenv("API_URL")
if not API_URL:
    raise RuntimeError("API_URL not set in Hugging Face Secrets")

DISABLED = os.getenv("DISABLED", "False") == "True"

keys = os.getenv("OPENAI_API_KEYS")
if not keys:
    raise RuntimeError("OPENAI_API_KEYS not set in Hugging Face Secrets")

OPENAI_API_KEYS = [k.strip() for k in keys.split(",") if k.strip()]
if not OPENAI_API_KEYS:
    raise RuntimeError("OPENAI_API_KEYS is empty")

NUM_THREADS = int(os.getenv("NUM_THREADS", "2"))

print("HF Space started")
print("API_URL loaded")
print("OPENAI_API_KEYS count:", len(OPENAI_API_KEYS))
print("NUM_THREADS:", NUM_THREADS)

# =====================================================
# Exception handling
# =====================================================

def exception_handler(exception_type, exception, traceback):
    print(f"{exception_type.__name__}: {exception}")

sys.excepthook = exception_handler
sys.tracebacklimit = 0

# =====================================================
# Prediction function (Responses API compatible)
# =====================================================

def predict(inputs, top_p, temperature, chat_counter, chatbot, history, request: gr.Request):
    if not OPENAI_API_KEYS:
        raise RuntimeError("No OpenAI API keys available")

    OPENAI_API_KEY = random.choice(OPENAI_API_KEYS)

    headers = {
        "Content-Type": "application/json",
        "Authorization": f"Bearer {OPENAI_API_KEY}"
    }

    # Build payload for Responses API
    payload = {
        "model": MODEL,
        "input": inputs,
        "temperature": temperature,
        "top_p": top_p
    }

    chat_counter += 1
    history.append({"role": "user", "content": inputs})

    try:
        response = requests.post(API_URL, headers=headers, json=payload, timeout=60)
        print("Status code:", response.status_code)

        if response.status_code != 200:
            print("Response text:", response.text)
            output_text = f"Error: {response.status_code}"
        else:
            data = response.json()
            # Extract text output from Responses API
            output_text = data["output"][0]["content"][0]["text"]
            history.append({"role": "assistant", "content": output_text})

        # Convert history to Gradio 'messages' format
        messages = [{"role": msg["role"], "content": msg["content"]} for msg in history]

        yield messages, history, chat_counter, response, gr.update(interactive=True), gr.update(interactive=True)

    except Exception as e:
        print(f"API request error: {e}")
        messages = [{"role": msg["role"], "content": msg["content"]} for msg in history]
        yield messages, history, chat_counter, None, gr.update(interactive=True), gr.update(interactive=True)

# =====================================================
# UI helpers
# =====================================================

def reset_textbox():
    return gr.update(value="", interactive=False), gr.update(interactive=False)

# =====================================================
# Gradio UI
# =====================================================

title = "<h1 align='center'>Hello welcome</h1>"
if DISABLED:
    title = """<h1 align="center" style="color:red">
    This app has reached its usage limit. Please check back later.
    </h1>"""

description = "kutti."

theme = gr.themes.Default(primary_hue="green")

with gr.Blocks(
    css="""
    #col_container { margin-left: auto; margin-right: auto; }
    #chatbot { height: 520px; overflow: auto; }
    """,
    theme=theme,
) as demo:

    gr.HTML(title)
    gr.HTML("<h3 align='center'>I'm Kutti</h3>")

    with gr.Column(elem_id="col_container", visible=False) as main_block:
        chatbot = gr.Chatbot(elem_id="chatbot", type="messages")  # Fixed warning
        inputs = gr.Textbox(placeholder="Hi there!", label="Type an input and press Enter")
        state = gr.State([])

        with gr.Row():
            with gr.Column(scale=7):
                b1 = gr.Button(visible=not DISABLED)
            with gr.Column(scale=3):
                server_status_code = gr.Textbox(label="Status code")

        with gr.Accordion("Parameters", open=False):
            top_p = gr.Slider(0, 1.0, value=1.0, step=0.05, label="Top-p")
            temperature = gr.Slider(0, 5.0, value=1.0, step=0.1, label="Temperature")
            chat_counter = gr.Number(value=0, visible=False, precision=0)

    with gr.Column(elem_id="user_consent_container") as user_consent_block:
        accept_checkbox = gr.Checkbox(visible=False)
        js = "(x) => confirm('By clicking OK, you agree to data usage terms.')"

        with gr.Accordion("User Consent", open=True):
            gr.Markdown(
                "By using this app, you consent to data collection for research and security purposes."
            )
            accept_button = gr.Button("I Agree")

        def enable_inputs():
            return gr.update(visible=False), gr.update(visible=True)

    accept_button.click(None, None, accept_checkbox, js=js, queue=False)
    accept_checkbox.change(
        fn=enable_inputs,
        inputs=[],
        outputs=[user_consent_block, main_block],
        queue=False,
    )

    inputs.submit(reset_textbox, [], [inputs, b1], queue=False)
    inputs.submit(
        predict,
        [inputs, top_p, temperature, chat_counter, chatbot, state],
        [chatbot, state, chat_counter, server_status_code, inputs, b1],
    )

    b1.click(reset_textbox, [], [inputs, b1], queue=False)
    b1.click(
        predict,
        [inputs, top_p, temperature, chat_counter, chatbot, state],
        [chatbot, state, chat_counter, server_status_code, inputs, b1],
    )

    demo.queue(
        max_size=10,
        default_concurrency_limit=NUM_THREADS,
        api_open=False,
    ).launch(share=False)