File size: 5,289 Bytes
c541f80
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
# 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()