IAMTFRMZA commited on
Commit
e39a43f
·
verified ·
1 Parent(s): f652f3d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +108 -81
app.py CHANGED
@@ -3,38 +3,36 @@ from openai import OpenAI
3
  import time
4
  import os
5
  import pandas as pd
 
6
  from datetime import datetime
7
 
8
- # Load environment variables
 
 
 
 
 
 
 
 
 
 
9
  openai_key = os.getenv("openai_key")
10
  assistant_id = os.getenv("ASSISTANT_ID")
11
 
12
- # Set up transcript log
13
- transcript_file = "transcripts.xlsx"
14
- if not os.path.exists(transcript_file):
15
- df = pd.DataFrame(columns=["timestamp", "thread_id", "role", "message"])
16
- df.to_excel(transcript_file, index=False)
17
-
18
- def append_to_transcript(thread_id, role, message):
19
- df_existing = pd.read_excel(transcript_file)
20
- new_entry = pd.DataFrame({
21
- "timestamp": [datetime.now().strftime("%Y-%m-%d %H:%M:%S")],
22
- "thread_id": [thread_id],
23
- "role": [role],
24
- "message": [message]
25
- })
26
- updated_df = pd.concat([df_existing, new_entry], ignore_index=True)
27
- updated_df.to_excel(transcript_file, index=False)
28
-
29
- # Configure page
30
  st.set_page_config(page_title="Carfind.co.za AI Assistant", layout="wide")
31
 
32
- # Inject custom styling
 
 
 
 
 
 
33
  st.markdown("""
34
  <style>
35
  .block-container {padding-top: 1rem; padding-bottom: 0rem;}
36
  header {visibility: hidden;}
37
- .st-emotion-cache-18ni7ap {visibility: hidden;}
38
  .stChatMessage { max-width: 85%; border-radius: 12px; padding: 8px; margin-bottom: 10px; }
39
  .stChatMessage[data-testid="stChatMessage-user"] { background: #f0f0f0; color: #000000; }
40
  .stChatMessage[data-testid="stChatMessage-assistant"] { background: #D6E9FE; color: #000000; }
@@ -44,100 +42,129 @@ st.markdown("""
44
  font-size: 1.4rem;
45
  margin-top: 18px;
46
  }
47
-
48
- /* Logo bounce animation */
49
  @keyframes bounceIn {
50
  0% { transform: scale(0.7); opacity: 0; }
51
  60% { transform: scale(1.1); opacity: 1; }
52
  80% { transform: scale(0.95); }
53
  100% { transform: scale(1); }
54
  }
55
-
56
  .carfind-logo {
57
  animation: bounceIn 0.6s ease-out;
58
  }
59
  </style>
60
  """, unsafe_allow_html=True)
61
 
62
- # Initialize session
63
- if "thread_id" not in st.session_state:
64
- st.session_state["thread_id"] = None
65
-
66
- # Carfind logo + powered by text (animated)
67
- st.markdown(
68
- """
69
  <div style='text-align: center; margin-top: 20px; margin-bottom: -10px;'>
70
  <span style='display: inline-flex; align-items: center; gap: 8px;'>
71
  <img src='https://www.carfind.co.za/images/Carfind-Icon.svg' width='30' class='carfind-logo'/>
72
  <span style='font-size: 14px; color: gray;'>Powered by Carfind</span>
73
  </span>
74
  </div>
75
- """,
76
- unsafe_allow_html=True
77
- )
78
 
79
- # Chat input + inline clear button
80
  input_col, clear_col = st.columns([9, 1])
81
-
82
  with input_col:
83
  user_input = st.chat_input("Type your message here...")
84
 
85
  with clear_col:
86
  if st.button("🗑️", key="clear-chat", help="Clear Chat"):
87
- st.session_state["thread_id"] = None
88
- st.rerun()
 
 
 
 
 
 
 
 
 
 
89
 
90
- # Chat logic
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
91
  if openai_key and assistant_id:
92
  client = OpenAI(api_key=openai_key)
 
93
 
94
- if user_input:
95
- if not st.session_state["thread_id"]:
96
- thread = client.beta.threads.create()
97
- st.session_state["thread_id"] = thread.id
98
 
 
99
  client.beta.threads.messages.create(
100
- thread_id=st.session_state["thread_id"], role="user", content=user_input
101
  )
102
- append_to_transcript(st.session_state["thread_id"], "user", user_input)
103
 
104
- try:
105
- with st.spinner("Thinking and typing... 💭"):
106
- run = client.beta.threads.runs.create(
107
- thread_id=st.session_state["thread_id"], assistant_id=assistant_id
108
- )
109
- while True:
110
- run_status = client.beta.threads.runs.retrieve(
111
- thread_id=st.session_state["thread_id"], run_id=run.id
112
- )
113
- if run_status.status == "completed":
114
- break
115
- time.sleep(1)
116
-
117
- messages_response = client.beta.threads.messages.list(
118
- thread_id=st.session_state["thread_id"]
119
  )
 
 
 
 
 
 
 
 
120
 
121
- assistant_icon_html = "<img src='https://www.carfind.co.za/images/Carfind-Icon.svg' width='22' style='vertical-align:middle;'/>"
122
- messages_sorted = sorted(messages_response.data, key=lambda x: x.created_at, reverse=True)
123
-
124
- for msg in messages_sorted:
125
- if msg.role == "user":
126
- st.markdown(
127
- f"<div class='stChatMessage' data-testid='stChatMessage-user'>"
128
- f"👤 <strong>You:</strong> {msg.content[0].text.value}</div>",
129
- unsafe_allow_html=True
130
- )
131
- else:
132
- response_text = msg.content[0].text.value
133
- append_to_transcript(st.session_state["thread_id"], "assistant", response_text)
134
- st.markdown(
135
- f"<div class='stChatMessage' data-testid='stChatMessage-assistant'>"
136
- f"{assistant_icon_html} <strong>Carfind Assistant:</strong> {response_text}</div>",
137
- unsafe_allow_html=True
138
- )
139
 
140
- except Exception as e:
141
- st.error(f"❌ An error occurred: {str(e)}")
142
  else:
143
- st.error("⚠️ OpenAI key or Assistant ID not found. Please ensure both are set as Hugging Face secrets.")
 
3
  import time
4
  import os
5
  import pandas as pd
6
+ import uuid
7
  from datetime import datetime
8
 
9
+ # Firebase setup
10
+ import firebase_admin
11
+ from firebase_admin import credentials, firestore
12
+
13
+ if not firebase_admin._apps:
14
+ cred = credentials.Certificate("firebase-service-account.json")
15
+ firebase_admin.initialize_app(cred)
16
+
17
+ db = firestore.client()
18
+
19
+ # OpenAI setup
20
  openai_key = os.getenv("openai_key")
21
  assistant_id = os.getenv("ASSISTANT_ID")
22
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  st.set_page_config(page_title="Carfind.co.za AI Assistant", layout="wide")
24
 
25
+ # Session + Firebase user ID
26
+ if "user_id" not in st.session_state:
27
+ st.session_state["user_id"] = str(uuid.uuid4())
28
+
29
+ user_id = st.session_state["user_id"]
30
+
31
+ # Styling + Branding
32
  st.markdown("""
33
  <style>
34
  .block-container {padding-top: 1rem; padding-bottom: 0rem;}
35
  header {visibility: hidden;}
 
36
  .stChatMessage { max-width: 85%; border-radius: 12px; padding: 8px; margin-bottom: 10px; }
37
  .stChatMessage[data-testid="stChatMessage-user"] { background: #f0f0f0; color: #000000; }
38
  .stChatMessage[data-testid="stChatMessage-assistant"] { background: #D6E9FE; color: #000000; }
 
42
  font-size: 1.4rem;
43
  margin-top: 18px;
44
  }
 
 
45
  @keyframes bounceIn {
46
  0% { transform: scale(0.7); opacity: 0; }
47
  60% { transform: scale(1.1); opacity: 1; }
48
  80% { transform: scale(0.95); }
49
  100% { transform: scale(1); }
50
  }
 
51
  .carfind-logo {
52
  animation: bounceIn 0.6s ease-out;
53
  }
54
  </style>
55
  """, unsafe_allow_html=True)
56
 
57
+ st.markdown("""
 
 
 
 
 
 
58
  <div style='text-align: center; margin-top: 20px; margin-bottom: -10px;'>
59
  <span style='display: inline-flex; align-items: center; gap: 8px;'>
60
  <img src='https://www.carfind.co.za/images/Carfind-Icon.svg' width='30' class='carfind-logo'/>
61
  <span style='font-size: 14px; color: gray;'>Powered by Carfind</span>
62
  </span>
63
  </div>
64
+ """, unsafe_allow_html=True)
 
 
65
 
66
+ # Chat input + Clear Chat button
67
  input_col, clear_col = st.columns([9, 1])
 
68
  with input_col:
69
  user_input = st.chat_input("Type your message here...")
70
 
71
  with clear_col:
72
  if st.button("🗑️", key="clear-chat", help="Clear Chat"):
73
+ try:
74
+ # Delete messages
75
+ user_doc_ref = db.collection("users").document(user_id)
76
+ message_collection = user_doc_ref.collection("messages").stream()
77
+ for msg in message_collection:
78
+ msg.reference.delete()
79
+ # Delete user doc
80
+ user_doc_ref.delete()
81
+
82
+ # Clear session and rerun
83
+ st.session_state.clear()
84
+ st.rerun()
85
 
86
+ except Exception as e:
87
+ st.error(f"Failed to clear chat: {e}")
88
+
89
+ # Create or load thread ID from Firebase
90
+ def get_or_create_thread_id():
91
+ doc_ref = db.collection("users").document(user_id)
92
+ doc = doc_ref.get()
93
+ if doc.exists:
94
+ return doc.to_dict()["thread_id"]
95
+ else:
96
+ client = OpenAI(api_key=openai_key)
97
+ thread = client.beta.threads.create()
98
+ doc_ref.set({
99
+ "thread_id": thread.id,
100
+ "created_at": firestore.SERVER_TIMESTAMP
101
+ })
102
+ return thread.id
103
+
104
+ # Save message to Firestore
105
+ def save_message(role, content):
106
+ db.collection("users").document(user_id).collection("messages").add({
107
+ "role": role,
108
+ "content": content,
109
+ "timestamp": firestore.SERVER_TIMESTAMP
110
+ })
111
+
112
+ # Display past chat messages (latest at the top)
113
+ def display_chat_history():
114
+ messages = db.collection("users").document(user_id).collection("messages") \
115
+ .order_by("timestamp").stream()
116
+
117
+ messages_list = list(messages)[::-1] # Reverse to show latest first
118
+
119
+ assistant_icon_html = "<img src='https://www.carfind.co.za/images/Carfind-Icon.svg' width='22' style='vertical-align:middle;'/>"
120
+
121
+ for msg in messages_list:
122
+ data = msg.to_dict()
123
+ if data["role"] == "user":
124
+ st.markdown(
125
+ f"<div class='stChatMessage' data-testid='stChatMessage-user'>"
126
+ f"👤 <strong>You:</strong> {data['content']}</div>", unsafe_allow_html=True
127
+ )
128
+ else:
129
+ st.markdown(
130
+ f"<div class='stChatMessage' data-testid='stChatMessage-assistant'>"
131
+ f"{assistant_icon_html} <strong>Carfind Assistant:</strong> {data['content']}</div>",
132
+ unsafe_allow_html=True
133
+ )
134
+
135
+ # OpenAI assistant interaction
136
  if openai_key and assistant_id:
137
  client = OpenAI(api_key=openai_key)
138
+ thread_id = get_or_create_thread_id()
139
 
140
+ display_chat_history()
 
 
 
141
 
142
+ if user_input:
143
  client.beta.threads.messages.create(
144
+ thread_id=thread_id, role="user", content=user_input
145
  )
146
+ save_message("user", user_input)
147
 
148
+ with st.spinner("Thinking and typing... 💭"):
149
+ run = client.beta.threads.runs.create(
150
+ thread_id=thread_id,
151
+ assistant_id=assistant_id
 
 
 
 
 
 
 
 
 
 
 
152
  )
153
+ while True:
154
+ run_status = client.beta.threads.runs.retrieve(
155
+ thread_id=thread_id,
156
+ run_id=run.id
157
+ )
158
+ if run_status.status == "completed":
159
+ break
160
+ time.sleep(1)
161
 
162
+ messages_response = client.beta.threads.messages.list(thread_id=thread_id)
163
+ latest_response = sorted(messages_response.data, key=lambda x: x.created_at)[-1]
164
+ assistant_message = latest_response.content[0].text.value
165
+ save_message("assistant", assistant_message)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
166
 
167
+ time.sleep(0.5) # Ensure Firestore timestamps sort properly
168
+ st.rerun()
169
  else:
170
+ st.error("⚠️ OpenAI key or Assistant ID not found. Please set them as Hugging Face secrets.")