File size: 5,833 Bytes
2def93d
4060393
 
c645389
1c2dc95
e39a43f
4ef479c
4060393
e39a43f
 
 
 
 
 
 
 
 
 
 
c645389
e69869b
b1e9ba4
c0332bf
4060393
e39a43f
 
 
 
 
 
 
e69869b
 
98f2c4f
 
691e8b4
5c03320
 
691e8b4
 
 
 
 
 
d4828d9
 
 
 
 
 
 
 
 
e69869b
 
 
e39a43f
db82163
d4828d9
 
 
 
db82163
e39a43f
db82163
e39a43f
691e8b4
fa08413
691e8b4
1b961be
fa08413
691e8b4
e39a43f
 
 
 
 
 
 
 
 
 
 
 
fa08413
e39a43f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4867300
17e4a36
e39a43f
fa08413
e39a43f
fa08413
e39a43f
4867300
e39a43f
4867300
e39a43f
17e4a36
e39a43f
 
 
 
4867300
e39a43f
 
 
 
 
 
 
 
17e4a36
e39a43f
 
 
 
4867300
e39a43f
 
4867300
e39a43f
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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
import streamlit as st
from openai import OpenAI
import time
import os
import pandas as pd
import uuid
from datetime import datetime

# Firebase setup
import firebase_admin
from firebase_admin import credentials, firestore

if not firebase_admin._apps:
    cred = credentials.Certificate("firebase-service-account.json")
    firebase_admin.initialize_app(cred)

db = firestore.client()

# OpenAI setup
openai_key = os.getenv("openai_key")
assistant_id = os.getenv("ASSISTANT_ID")

st.set_page_config(page_title="Carfind.co.za AI Assistant", layout="wide")

# Session + Firebase user ID
if "user_id" not in st.session_state:
    st.session_state["user_id"] = str(uuid.uuid4())

user_id = st.session_state["user_id"]

# Styling + Branding
st.markdown("""
    <style>
    .block-container {padding-top: 1rem; padding-bottom: 0rem;}
    header {visibility: hidden;}
    .stChatMessage { max-width: 85%; border-radius: 12px; padding: 8px; margin-bottom: 10px; }
    .stChatMessage[data-testid="stChatMessage-user"] { background: #f0f0f0; color: #000000; }
    .stChatMessage[data-testid="stChatMessage-assistant"] { background: #D6E9FE; color: #000000; }
    div[data-testid="column"] button {
        border: none;
        background-color: transparent;
        font-size: 1.4rem;
        margin-top: 18px;
    }
    @keyframes bounceIn {
        0%   { transform: scale(0.7); opacity: 0; }
        60%  { transform: scale(1.1); opacity: 1; }
        80%  { transform: scale(0.95); }
        100% { transform: scale(1); }
    }
    .carfind-logo {
        animation: bounceIn 0.6s ease-out;
    }
    </style>
""", unsafe_allow_html=True)

st.markdown("""
    <div style='text-align: center; margin-top: 20px; margin-bottom: -10px;'>
        <span style='display: inline-flex; align-items: center; gap: 8px;'>
            <img src='https://www.carfind.co.za/images/Carfind-Icon.svg' width='30' class='carfind-logo'/>
            <span style='font-size: 14px; color: gray;'>Powered by Carfind</span>
        </span>
    </div>
""", unsafe_allow_html=True)

# Chat input + Clear Chat button
input_col, clear_col = st.columns([9, 1])
with input_col:
    user_input = st.chat_input("Type your message here...")

with clear_col:
    if st.button("🗑️", key="clear-chat", help="Clear Chat"):
        try:
            # Delete messages
            user_doc_ref = db.collection("users").document(user_id)
            message_collection = user_doc_ref.collection("messages").stream()
            for msg in message_collection:
                msg.reference.delete()
            # Delete user doc
            user_doc_ref.delete()

            # Clear session and rerun
            st.session_state.clear()
            st.rerun()

        except Exception as e:
            st.error(f"Failed to clear chat: {e}")

# Create or load thread ID from Firebase
def get_or_create_thread_id():
    doc_ref = db.collection("users").document(user_id)
    doc = doc_ref.get()
    if doc.exists:
        return doc.to_dict()["thread_id"]
    else:
        client = OpenAI(api_key=openai_key)
        thread = client.beta.threads.create()
        doc_ref.set({
            "thread_id": thread.id,
            "created_at": firestore.SERVER_TIMESTAMP
        })
        return thread.id

# Save message to Firestore
def save_message(role, content):
    db.collection("users").document(user_id).collection("messages").add({
        "role": role,
        "content": content,
        "timestamp": firestore.SERVER_TIMESTAMP
    })

# Display past chat messages (latest at the top)
def display_chat_history():
    messages = db.collection("users").document(user_id).collection("messages") \
        .order_by("timestamp").stream()

    messages_list = list(messages)[::-1]  # Reverse to show latest first

    assistant_icon_html = "<img src='https://www.carfind.co.za/images/Carfind-Icon.svg' width='22' style='vertical-align:middle;'/>"

    for msg in messages_list:
        data = msg.to_dict()
        if data["role"] == "user":
            st.markdown(
                f"<div class='stChatMessage' data-testid='stChatMessage-user'>"
                f"👤 <strong>You:</strong> {data['content']}</div>", unsafe_allow_html=True
            )
        else:
            st.markdown(
                f"<div class='stChatMessage' data-testid='stChatMessage-assistant'>"
                f"{assistant_icon_html} <strong>Carfind Assistant:</strong> {data['content']}</div>",
                unsafe_allow_html=True
            )

# OpenAI assistant interaction
if openai_key and assistant_id:
    client = OpenAI(api_key=openai_key)
    thread_id = get_or_create_thread_id()

    display_chat_history()

    if user_input:
        client.beta.threads.messages.create(
            thread_id=thread_id, role="user", content=user_input
        )
        save_message("user", user_input)

        with st.spinner("Thinking and typing... 💭"):
            run = client.beta.threads.runs.create(
                thread_id=thread_id,
                assistant_id=assistant_id
            )
            while True:
                run_status = client.beta.threads.runs.retrieve(
                    thread_id=thread_id,
                    run_id=run.id
                )
                if run_status.status == "completed":
                    break
                time.sleep(1)

        messages_response = client.beta.threads.messages.list(thread_id=thread_id)
        latest_response = sorted(messages_response.data, key=lambda x: x.created_at)[-1]
        assistant_message = latest_response.content[0].text.value
        save_message("assistant", assistant_message)

        time.sleep(0.5)  # Ensure Firestore timestamps sort properly
        st.rerun()
else:
    st.error("⚠️ OpenAI key or Assistant ID not found. Please set them as Hugging Face secrets.")