Spaces:
Sleeping
Sleeping
File size: 8,699 Bytes
b5d2247 0e4d60e b5d2247 d2c8d11 b5d2247 0e4d60e 7fc2127 d2c8d11 879871c 7fc2127 879871c 7fc2127 0e4d60e 7fc2127 879871c b5d2247 c6e5231 afe102c b5d2247 7fc2127 b5d2247 7fc2127 b5d2247 7fc2127 9809102 7fc2127 9809102 7fc2127 9809102 7fc2127 b5d2247 7fc2127 b5d2247 0e4d60e 7fc2127 0e4d60e 7fc2127 0e4d60e 7fc2127 0e4d60e 7fc2127 0e4d60e 7fc2127 b5d2247 0e4d60e b5d2247 9809102 e055921 8f9b0f3 e055921 |
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 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 |
import streamlit as st
import os
import re
from query_chat import GeminiQanA
from pathlib import Path
def extract_text_from_txt(file_path):
# In a real scenario, handle FileNotFoundError
try:
with open(file_path, "r", encoding="utf-8") as file:
return " ".join([line.strip() for line in file.readlines() if line.strip()])
except FileNotFoundError:
st.warning(f"File not found: {file_path}. Using placeholder text.")
return f"Placeholder text for {os.path.basename(file_path)}"
def load_css(file_name):
"""Loads a CSS file and injects it into the Streamlit app."""
try:
css_path = Path(__file__).parent / file_name
with open(css_path) as f:
st.markdown(f'<style>{f.read()}</style>', unsafe_allow_html=True)
# st.info(f"Loaded CSS: {file_name}") # Optional: uncomment for debugging
except FileNotFoundError:
st.error(f"CSS file not found: {file_name}. Make sure it's in the same directory as app.py.")
except Exception as e:
st.error(f"Error loading CSS file {file_name}: {e}")
@st.cache_resource()
def load_chatbot():
print("Attempting to load chatbot...") # Add print statement
with st.spinner("Loading project information..."):
# Use dummy paths if Files/ directory doesn't exist or is empty
doc1_text = extract_text_from_txt("Files/brochure_1.txt")
doc2_text = extract_text_from_txt("Files/brochure_2.txt")
chatbot_instance = GeminiQanA(doc1_text, doc2_text)
print("Chatbot loaded.") # Add print statement
return chatbot_instance
# Streamlit App Configuration
st.set_page_config(page_title="Zega AI Sales Agent", page_icon="🤖", layout="centered")
st.markdown("""
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter+Tight:ital,wght@0,100..900;1,100..900&family=Space+Grotesk:wght@300..700&display=swap" rel="stylesheet">
""", unsafe_allow_html=True)
load_css("style.css")
st.sidebar.markdown("### Welcome to Zega AI Sales Agent!")
st.sidebar.markdown("Ask anything about our team's capabilities and projects.")
# Load API key safely (using dummy key for this example if not set)
if "GOOGLE_API_KEY" in st.secrets:
os.environ["GOOGLE_API_KEY"] = st.secrets["GOOGLE_API_KEY"]
else:
# For local testing without secrets, you might uncomment the next line
# os.environ["GOOGLE_API_KEY"] = "YOUR_DUMMY_OR_REAL_API_KEY"
st.sidebar.warning("Google API key not found in Streamlit secrets. Using demo mode.")
# --- Initialize Chatbot ---
# Ensure chatbot is loaded before defining callbacks that use it
try:
chatbot = load_chatbot()
except Exception as e:
st.error(f"Failed to load chatbot: {e}")
st.stop() # Stop execution if chatbot fails to load
# --- Initialize Session State ---
if "messages" not in st.session_state:
st.session_state.messages = []
# Initialize the input field state (important!)
if "question_input" not in st.session_state:
st.session_state.question_input = ""
# --- Initialize session state if not already present ---
if "asked_ai" not in st.session_state:
st.session_state.asked_ai = False
def handle_ask_ai():
"""Callback function for the 'Ask AI' button."""
question = st.session_state.question_input # Get question from state
if question:
st.session_state.messages.append({"role": "user", "content": question})
try:
answer = chatbot.answer_question(question)
st.session_state.messages.append({"role": "assistant", "content": answer})
except Exception as e:
st.error(f"Error getting answer from chatbot: {e}")
st.session_state.question_input = "" # Clear input after processing
def handle_clear_chat():
"""Callback function for the 'Clear Chat' button."""
st.session_state.messages = []
chatbot.clear_conv_history()
st.session_state.question_input = "" # Clear the input field state as well
# No explicit st.rerun() needed here, on_click handles the rerun
# --- Chat UI ---
st.title("📄 Zega AI Sales Agent")
# Function to display messages and replace image tags with actual images
def display_message(role, content):
with st.chat_message(role):
# Find all image tags in the response (Corrected regex)
image_tags = re.findall(r"\[(.*?\.png)\]", content) # Find content inside brackets ending with .png
# Split response by image tags and process separately
parts = re.split(r"(\[.*?\.png\])", content) # Keep the delimiters
for part in parts:
if not part: # Skip empty strings from split
continue
match = re.match(r"\[(.*?\.png)\]", part) # Check if the part IS an image tag
if match:
image_filename = match.group(1)
# Assuming images are in a subfolder relative to the script
# Make sure the ZegaPos folder exists or handle the error
image_folder = "ZegaPos"
if not os.path.isdir(image_folder):
st.warning(f"Image folder '{image_folder}' not found.")
st.markdown(f"_{image_filename}_") # Display filename as text fallback
continue # Skip trying to display the image
image_path = os.path.join(image_folder, image_filename)
if os.path.exists(image_path):
st.image(image_path, use_container_width=True)
else:
st.markdown(f"⚠️ Image `{image_filename}` not found at `{image_path}`.")
else:
# Otherwise, display text
st.markdown(part)
# --- Display Chat History ---
# This loop runs on every rerun, displaying the current state of messages
for message in st.session_state.messages:
display_message(message["role"], message["content"])
# --- Chat Input using st.chat_input (Handles Enter automatically) ---
prompt = st.chat_input("Ask a question about Zega AI:")
if prompt:
# 1. Add user message to chat history immediately
st.session_state.messages.append({"role": "user", "content": prompt})
# 2. Display the user message (using your existing function)
display_message("user", prompt)
# 3. Get and display AI response
try:
with st.spinner("Thinking..."): # Optional: Add spinner for feedback
answer = chatbot.answer_question(prompt)
st.session_state.messages.append({"role": "assistant", "content": answer})
# Display the assistant message immediately after getting it
display_message("assistant", answer)
except Exception as e:
st.error(f"Error getting answer from chatbot: {e}")
# Optionally add an error message to the chat history
# st.session_state.messages.append({"role": "assistant", "content": f"Sorry, an error occurred: {e}"})
# display_message("assistant", f"Sorry, an error occurred: {e}")
# No need to manually clear st.session_state.question_input
# st.chat_input handles its state internally upon submission.
# Streamlit automatically reruns after processing the input block.
# --- Clear Chat Button (Keep this separate) ---
# Place it where you want it, maybe in the sidebar or below the chat input
st.markdown("""
<style>
.stButton > button {
color: white !important;
background-color: #ff4b4b; /* optional: red background for the trash button */
}
</style>
""", unsafe_allow_html=True)
if st.sidebar.button("🗑️ Clear Chat"):
st.session_state.messages = []
if 'chatbot' in globals() and hasattr(chatbot, 'clear_conv_history'):
chatbot.clear_conv_history()
# st.session_state.question_input is no longer used, so no need to clear it
st.rerun() # Rerun to reflect the cleared chat visually
import streamlit.components.v1 as components
components.html(
"""
<script>
function sendHeightWhenReady() {
const el = window.parent.document.getElementsByClassName('stMain')[0];
if (el) {
const height = el.scrollHeight;
console.log("Sending height to parent:", height);
window.parent.parent.postMessage({ type: 'setHeight', height: height }, '*');
} else {
// Retry in 100ms until the element appears
setTimeout(sendHeightWhenReady, 1000);
}
}
window.onload = sendHeightWhenReady;
window.addEventListener('resize', sendHeightWhenReady);
setInterval(sendHeightWhenReady, 1000);
</script>
"""
) |