import gradio as gr import openai from openai import OpenAI import os from typing import List, Tuple # Initialize OpenAI with environment variable # Set OPENAI_API_KEY in Hugging Face secrets client = OpenAI(api_key=os.getenv("OPENAI_API_KEY")) # Global session state chat_history = [] def respond_to_message(message: str, history: List[List[str]]) -> Tuple[str, List[List[str]]]: """Handle user message and return response with updated history""" if not message.strip(): return "", history # Add user message to history history.append([message, ""]) # Add to global chat history for sidebar global chat_history chat_history.append(message) try: # Prepare messages for OpenAI API messages = [{"role": "system", "content": "You are a helpful assistant."}] # Add conversation history for user_msg, assistant_msg in history[:-1]: # Exclude the current message if user_msg and assistant_msg: messages.append({"role": "user", "content": user_msg}) messages.append({"role": "assistant", "content": assistant_msg}) # Add current user message messages.append({"role": "user", "content": message}) # Get response from OpenAI response = client.chat.completions.create( model="gpt-3.5-turbo", # You can change to gpt-4 if available messages=messages, max_tokens=1000, temperature=0.7 ) assistant_response = response.choices[0].message.content # Update the last message in history with assistant response history[-1][1] = assistant_response return "", history except Exception as e: error_message = f"Error: {str(e)}" history[-1][1] = error_message return "", history def clear_chat() -> Tuple[str, List[List[str]]]: """Clear the current chat history""" global chat_history chat_history = [] return "", [] def get_chat_history() -> List[str]: """Get chat history for sidebar""" return chat_history # Custom CSS for ChatGPT-like styling custom_css = """ .gradio-container { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; background: white !important; min-height: 100vh; } .chat-layout { display: flex; height: 100vh; max-width: 100%; margin: 0 auto; background: white; } .sidebar { width: 280px; background: #f7f7f8; color: #374151; padding: 0; display: flex; flex-direction: column; border-right: 1px solid #e5e7eb; overflow-y: auto; } .sidebar-header { padding: 16px; border-bottom: 1px solid #e5e7eb; background: white; } .history-list { flex: 1; padding: 8px; background: #f7f7f8; overflow-y: auto; } .history-item { background: transparent !important; color: #374151 !important; border: none !important; border-radius: 6px !important; padding: 8px 12px !important; font-size: 13px !important; cursor: pointer !important; transition: background-color 0.2s !important; width: 100% !important; text-align: left !important; margin-bottom: 4px !important; box-shadow: none !important; line-height: 1.4 !important; word-wrap: break-word !important; white-space: normal !important; } .history-item:hover { background: #e5e7eb !important; } .history-item.active { background: #e5e7eb !important; } .main-chat { flex: 1; display: flex; flex-direction: column; background: white; min-height: 0; } .chat-header { padding: 12px 24px; border-bottom: 1px solid #e5e7eb; color: #374151; font-size: 16px; font-weight: 600; background: white; } .chat-messages { flex: 1; overflow-y: auto; padding: 0; background: white; min-height: 0; } .chatbot { background: transparent !important; border: none !important; box-shadow: none !important; padding: 0 !important; height: 100% !important; } .chatbot .message { margin: 0 !important; padding: 16px 0 !important; border-radius: 0 !important; border-bottom: 1px solid #e5e7eb !important; } .chatbot .user-message { background: white !important; color: #374151 !important; margin: 0 !important; padding: 16px 24px !important; } .chatbot .bot-message { background: #f9fafb !important; color: #374151 !important; margin: 0 !important; padding: 16px 24px !important; } .chat-input-container { padding: 16px 24px; border-top: 1px solid #e5e7eb; background: white; position: sticky; bottom: 0; } .chat-input { background: white !important; border: 1px solid #d1d5db !important; color: #374151 !important; border-radius: 8px !important; padding: 12px 16px !important; font-size: 16px !important; resize: none !important; min-height: 48px !important; } .chat-input:focus { border-color: #3b82f6 !important; box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.2) !important; } .send-button { background: #3b82f6 !important; color: white !important; border: none !important; border-radius: 6px !important; padding: 8px 16px !important; font-size: 14px !important; font-weight: 500 !important; cursor: pointer !important; transition: background-color 0.2s !important; height: 36px !important; } .send-button:hover { background: #2563eb !important; } .clear-button { background: #6b7280 !important; color: white !important; border: none !important; border-radius: 6px !important; padding: 8px 16px !important; font-size: 14px !important; cursor: pointer !important; transition: background-color 0.2s !important; height: 36px !important; } .clear-button:hover { background: #4b5563 !important; } @media (max-width: 768px) { .chat-layout { flex-direction: column; } .sidebar { width: 100%; height: auto; max-height: 200px; } .main-chat { flex: 1; } } """ # Create the Gradio interface with gr.Blocks(css=custom_css, title="ChatGPT Clone") as demo: with gr.Row(elem_classes="chat-layout"): # Left sidebar with chat history with gr.Column(elem_classes="sidebar"): # Sidebar header with gr.Row(elem_classes="sidebar-header"): gr.Markdown("### 💬 Chat History") # Chat history list with gr.Column(elem_classes="history-list"): chat_history_display = gr.Textbox( value="", label="", elem_classes="history-item", show_label=False, interactive=False, lines=25 ) # Main chat area with gr.Column(elem_classes="main-chat"): # Chat header with gr.Row(elem_classes="chat-header"): gr.Markdown("### AI Assistant") # Chat messages chatbot = gr.Chatbot( elem_classes="chatbot", height=500, show_label=False, container=True, bubble_full_width=True ) # Chat input area with gr.Row(elem_classes="chat-input-container"): with gr.Column(scale=4): user_input = gr.Textbox( placeholder="Type your message here...", show_label=False, lines=2, max_lines=4, elem_classes="chat-input" ) with gr.Column(scale=1): send_btn = gr.Button("Send", elem_classes="send-button") clear_btn = gr.Button("Clear", elem_classes="clear-button") # Event handlers def handle_send(message, history): result = respond_to_message(message, history) # Update chat history display as list items if chat_history: history_text = "" for i, msg in enumerate(chat_history): history_text += f"• {msg}\n" else: history_text = "No chat history yet" return result[0], result[1], history_text def handle_clear(): result = clear_chat() return result[0], result[1], "No chat history yet" # Connect events send_btn.click( fn=handle_send, inputs=[user_input, chatbot], outputs=[user_input, chatbot, chat_history_display] ) user_input.submit( fn=handle_send, inputs=[user_input, chatbot], outputs=[user_input, chatbot, chat_history_display] ) clear_btn.click( fn=handle_clear, outputs=[user_input, chatbot, chat_history_display] ) # Launch the app for Hugging Face demo.launch()