Spaces:
Sleeping
Sleeping
| # 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""" | |
| <style> | |
| :root {{ | |
| --brand-primary: {primary_color}; | |
| --brand-secondary: {secondary_color}; | |
| }} | |
| {css_template} | |
| </style> | |
| """ | |
| 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"""<div id="header"><img src="{brand_info['logo']['title']}" alt="Logo"><h2>{brand_info['organizationName']}</h2><p>{brand_info['slogan']}</p></div>""") | |
| 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"""<div id="footer">...</div>""") | |
| if __name__ == "__main__": | |
| caramel_ai.launch() |