Spaces:
Sleeping
Sleeping
# Create updated app.py file with fixes | |
import gradio as gr | |
import os | |
import json | |
import base64 | |
from datetime import datetime | |
from openai import OpenAI | |
from tempfile import NamedTemporaryFile | |
# Global variables | |
api_key = None | |
client = None | |
chat_history = [] | |
current_response_id = None | |
current_image = None | |
def validate_api_key(key): | |
"""Validate OpenAI API key by making a simple request""" | |
try: | |
temp_client = OpenAI(api_key=key) | |
# Make a minimal request to check if the key works | |
response = temp_client.responses.create( | |
model="gpt-4o-mini", | |
input="Hello" | |
) | |
return True, "API key is valid!" | |
except Exception as e: | |
return False, f"Invalid API key: {str(e)}" | |
def set_api_key(key): | |
"""Set the OpenAI API key and initialize client""" | |
global api_key, client | |
is_valid, message = validate_api_key(key) | |
if is_valid: | |
api_key = key | |
client = OpenAI(api_key=api_key) | |
return gr.update(visible=False), gr.update(visible=True), message | |
else: | |
return gr.update(visible=True), gr.update(visible=False), message | |
def encode_image(image_path): | |
"""Encode image to base64""" | |
with open(image_path, 'rb') as image_file: | |
return base64.b64encode(image_file.read()).decode("utf-8") | |
def chat(message, chat_history): | |
"""Process chat messages with optional image""" | |
global client, current_response_id, current_image | |
if not client: | |
return chat_history + [{"role": "assistant", "content": "Please set your OpenAI API key first."}] | |
try: | |
# Add user message to history | |
chat_history.append({"role": "user", "content": message}) | |
if current_image is not None: | |
# Save the uploaded image to a temporary file | |
temp_file = NamedTemporaryFile(delete=False, suffix=".png") | |
image_path = temp_file.name | |
current_image.save(image_path) | |
# Encode the image | |
base64_image = encode_image(image_path) | |
# Create input with text and image | |
input_messages = [ | |
{ | |
"role": "user", | |
"content": [ | |
{ | |
"type": "input_text", | |
"text": message | |
}, | |
{ | |
"type": "input_image", | |
"image_url": f"data:image/png;base64,{base64_image}" | |
} | |
] | |
} | |
] | |
response = client.responses.create( | |
model="gpt-4o-mini", | |
input=input_messages, | |
previous_response_id=current_response_id | |
) | |
# Clean up the temporary file | |
os.unlink(image_path) | |
# Reset the image | |
current_image = None | |
else: | |
# Text-only message | |
response = client.responses.create( | |
model="gpt-4o-mini", | |
input=message, | |
previous_response_id=current_response_id | |
) | |
current_response_id = response.id | |
# Add assistant response to history | |
chat_history.append({"role": "assistant", "content": response.output_text}) | |
return chat_history | |
except Exception as e: | |
error_message = f"Error: {str(e)}" | |
chat_history.append({"role": "assistant", "content": error_message}) | |
return chat_history | |
def export_chat(): | |
"""Export chat history to JSON file""" | |
global chat_history | |
if not chat_history: | |
return "No chat history to export." | |
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") | |
filename = f"chat_export_{timestamp}.json" | |
with open(filename, "w") as f: | |
json.dump(chat_history, f, indent=2) | |
return f"Chat exported to {filename}" | |
def clear_chat(): | |
"""Clear chat history and reset response ID""" | |
global chat_history, current_response_id, current_image | |
chat_history = [] | |
current_response_id = None | |
current_image = None | |
return [] | |
def generate_iframe_code(request: gr.Request): | |
"""Generate iframe code for embedding the app""" | |
app_url = request.headers.get('host', 'localhost') | |
if not app_url.startswith('http'): | |
app_url = f"https://{app_url}" | |
iframe_code = f"""<iframe | |
src="{app_url}" | |
width="100%" | |
height="500px" | |
style="border: 1px solid #ddd; border-radius: 8px;" | |
allow="microphone" | |
></iframe>""" | |
return iframe_code | |
def save_image(img): | |
"""Save uploaded image to global variable""" | |
global current_image | |
current_image = img | |
return "[Image attached]" | |
def create_ui(): | |
"""Create the Gradio UI""" | |
with gr.Blocks(theme=gr.themes.Soft(), css=""" | |
.container { max-width: 900px; margin: auto; } | |
.title { text-align: center; margin-bottom: 10px; } | |
.subtitle { text-align: center; margin-bottom: 20px; color: #666; } | |
.social-links { display: flex; justify-content: center; gap: 10px; margin-bottom: 20px; } | |
.footer { text-align: center; margin-top: 20px; padding: 10px; border-top: 1px solid #eee; } | |
.tab-content { padding: 20px; } | |
""") as demo: | |
with gr.Column(elem_classes="container"): | |
gr.Markdown("# Responses API Chatbot", elem_classes="title") | |
gr.Markdown("### Created by Pejman Ebrahimi", elem_classes="subtitle") | |
with gr.Row(elem_classes="social-links"): | |
gr.HTML(""" | |
<a href="https://www.linkedin.com/in/pejman-ebrahimi-4a60151a7/" target="_blank"> | |
<img src="https://img.shields.io/badge/LinkedIn-0077B5?style=for-the-badge&logo=linkedin&logoColor=white" alt="LinkedIn"> | |
</a> | |
<a href="https://huggingface.co/arad1367" target="_blank"> | |
<img src="https://img.shields.io/badge/π€_Hugging_Face-FFD21E?style=for-the-badge" alt="HuggingFace"> | |
</a> | |
<a href="https://arad1367.github.io/pejman-ebrahimi/" target="_blank"> | |
<img src="https://img.shields.io/badge/Website-008080?style=for-the-badge&logo=About.me&logoColor=white" alt="Website"> | |
</a> | |
<a href="https://www.uni.li/pejman.ebrahimi?set_language=en" target="_blank"> | |
<img src="https://img.shields.io/badge/University-00205B?style=for-the-badge&logo=academia&logoColor=white" alt="University"> | |
</a> | |
""") | |
# API Key Input Section | |
with gr.Group(visible=True) as api_key_group: | |
with gr.Row(): | |
api_key_input = gr.Textbox( | |
label="Enter your OpenAI API Key", | |
placeholder="sk-...", | |
type="password", | |
scale=4 | |
) | |
api_key_button = gr.Button("Set API Key", scale=1) | |
api_key_message = gr.Markdown("") | |
# Main Chat Interface (hidden until API key is set) | |
with gr.Group(visible=False) as chat_interface: | |
with gr.Tabs() as tabs: | |
with gr.TabItem("Chat", elem_classes="tab-content"): | |
chatbot = gr.Chatbot(height=400, type="messages") | |
with gr.Row(): | |
with gr.Column(scale=4): | |
msg = gr.Textbox( | |
placeholder="Type your message here...", | |
show_label=False, | |
container=False | |
) | |
with gr.Column(scale=1): | |
image_btn = gr.UploadButton("π", file_types=["image"]) | |
with gr.Row(): | |
clear_btn = gr.Button("Clear Chat") | |
export_btn = gr.Button("Export Chat") | |
theme_btn = gr.Button("Toggle Theme") | |
export_message = gr.Markdown("") | |
with gr.TabItem("Embed", elem_classes="tab-content"): | |
gr.Markdown("### Embed this chatbot on your website") | |
iframe_code = gr.Code(language="html") | |
generate_iframe_btn = gr.Button("Generate Embed Code") | |
gr.Markdown("Β© 2025 Pejman Ebrahimi - All Rights Reserved", elem_classes="footer") | |
# Set up event handlers | |
api_key_button.click( | |
set_api_key, | |
inputs=[api_key_input], | |
outputs=[api_key_group, chat_interface, api_key_message] | |
) | |
# Handle image uploads | |
image_btn.upload( | |
save_image, | |
inputs=[image_btn], | |
outputs=[msg] | |
) | |
# Handle chat submission | |
msg.submit( | |
chat, | |
inputs=[msg, chatbot], | |
outputs=[chatbot] | |
).then( | |
lambda: gr.update(value=""), | |
None, | |
[msg] | |
) | |
clear_btn.click( | |
clear_chat, | |
outputs=[chatbot] | |
) | |
export_btn.click( | |
export_chat, | |
outputs=[export_message] | |
) | |
theme_btn.click( | |
None, | |
None, | |
None, | |
_js="() => {document.body.classList.toggle('dark');}" | |
) | |
generate_iframe_btn.click( | |
generate_iframe_code, | |
None, | |
iframe_code | |
) | |
return demo | |
if __name__ == "__main__": | |
demo = create_ui() | |
demo.launch() | |