# ui.py # Gradio Web Interface for Caramel AI import gradio as gr import json import os from program import get_response, extract_text_from_file # --- SETUP & BRANDING --- try: branding_path = os.path.join(os.path.dirname(__file__), "branding.json") with open(branding_path, "r", encoding="utf-8") as f: brand_info = json.load(f)["brand"] except FileNotFoundError: brand_info = { "organizationName": "Caramel AI", "slogan": "AI HR Manager", "logo": {"title": ""}, "colors": {"primary": "#F0E68C", "secondary": "#8B4513"}, "email": "contact@example.com", "mobile": "N/A", "website": "#", "socialMedia": {"linkedin": "#", "github": "#", "x": "#"}} primary_color = brand_info["colors"]["primary"] secondary_color = brand_info["colors"]["secondary"] # --- CSS INJECTION --- try: css_path = os.path.join(os.path.dirname(__file__), "style.css") with open(css_path, "r", encoding="utf-8") as f: css_template = f.read() final_css = f""" """ except FileNotFoundError: print("Warning: style.css not found.") final_css = "" # --- FIXED: JAVASCRIPT VARIABLE DEFINITION WAS MISSING --- js_trigger_file_click = """ () => { // Find the hidden file input element and click it document.querySelector('#file-uploader input[type="file"]').click(); } """ js_theme_toggle = """ () => { document.body.classList.toggle('dark'); const theme_btn = document.querySelector('#theme-btn button'); if (document.body.classList.contains('dark')) { theme_btn.textContent = 'โ˜€๏ธ Light Mode'; } else { theme_btn.textContent = '๐ŸŒ™ Dark Mode'; } } """ # --- GRADIO INTERFACE --- with gr.Blocks(css=final_css, title=brand_info["organizationName"]) as caramel_ai: gr.HTML(f"""""") file_context_state = gr.State("") chatbot = gr.Chatbot(height=550, label="Caramel AI Chat", type="messages") status_display = gr.Markdown("Status: Ready") file_uploader = gr.File(label="Upload File", file_count='single', file_types=['.txt', '.pdf'], elem_id="file-uploader") with gr.Row(elem_id="input-row"): with gr.Column(min_width=50, elem_id="attachment-btn-container"): attachment_btn = gr.Button("๐Ÿ“Ž") msg_box = gr.Textbox(placeholder="Ask a question or upload a file...", show_label=False, container=False, scale=8, elem_id="msg-box") send_btn = gr.Button("Ask", variant="primary", scale=1) with gr.Row(): memory_switch = gr.Checkbox(label="Remember Conversation", value=True) clear_btn = gr.Button("๐Ÿงน Clear All") theme_btn = gr.Button("๐ŸŒ™ Dark Mode", elem_id="theme-btn") # --- UI LOGIC FUNCTIONS --- def process_file(file_obj, chat_history): if not file_obj: return "Status: File upload failed.", "", chat_history extracted_text = extract_text_from_file(file_obj) if "Error:" in extracted_text: return extracted_text, None, chat_history status = f"โœ… **Processed:** `{os.path.basename(file_obj.name)}`" history = chat_history + [{"role": "assistant", "content": f"I've read '{os.path.basename(file_obj.name)}'. Ask me anything about it."}] return status, extracted_text, history def respond(message, chat_history, memory_enabled, file_context): if not message.strip(): return "", chat_history, file_context history_for_api = chat_history if memory_enabled else [] api_history = [{"role": "model" if t["role"] == "assistant" else t["role"], "parts": [t["content"]]} for t in history_for_api] context = (f"Based ONLY on the context from the document below, answer the user's question.\n\n" f"--- DOCUMENT CONTEXT ---\n{file_context}\n\n--- USER QUESTION ---\n{message}") if file_context else message bot_response = get_response(context, api_history) history = chat_history + [{"role": "user", "content": message}, {"role": "assistant", "content": bot_response}] return "", history, file_context def clear_all(): return [], "", None, "Status: Ready", None # --- EVENT LISTENERS --- attachment_btn.click(fn=None, js=js_trigger_file_click) theme_btn.click(fn=None, js=js_theme_toggle) file_uploader.upload(process_file, inputs=[file_uploader, chatbot], outputs=[status_display, file_context_state, chatbot]) send_btn.click(respond, inputs=[msg_box, chatbot, memory_switch, file_context_state], outputs=[msg_box, chatbot, file_context_state]) msg_box.submit(respond, inputs=[msg_box, chatbot, memory_switch, file_context_state], outputs=[msg_box, chatbot, file_context_state]) clear_btn.click(clear_all, inputs=[], outputs=[chatbot, msg_box, file_context_state, status_display, file_uploader]) gr.HTML(f"""""") if __name__ == "__main__": caramel_ai.launch()