krinya commited on
Commit
fb4a4b8
·
1 Parent(s): 1b8e582

refactor: Update Dockerfile and README, remove unused files, and enhance agent configuration

Browse files
Dockerfile CHANGED
@@ -1,40 +1,53 @@
 
1
  FROM python:3.12-slim
2
 
3
- # Create a non-root user
 
 
 
4
  RUN useradd --create-home --shell /bin/bash app
5
 
6
- # Set working directory
7
  WORKDIR /app
8
 
9
- # Install system dependencies
10
- RUN apt-get update && apt-get install -y \
 
11
  gcc \
12
  g++ \
13
  curl \
14
  && rm -rf /var/lib/apt/lists/*
15
 
16
- # Install uv
17
- RUN pip install uv
 
 
18
 
19
- # Copy project files and change ownership
20
  COPY . .
 
 
21
  RUN chown -R app:app /app
22
 
23
- # Switch to non-root user
24
  USER app
25
 
26
- # Set uv cache directory to a writable location
 
27
  ENV UV_CACHE_DIR=/app/.uv-cache
28
 
29
- # Install dependencies using uv
 
30
  RUN uv sync --frozen
31
 
32
- # Expose the port that Gradio will run on
 
33
  EXPOSE 7860
34
 
35
- # Set environment variables for Gradio
36
  ENV GRADIO_SERVER_NAME="0.0.0.0"
37
  ENV GRADIO_SERVER_PORT=7860
38
 
39
- # Run the Gradio app
 
40
  CMD ["uv", "run", "python", "src/sales_assistant/ui_dashboard/gradio_app.py"]
 
1
+ # Start from a minimal Python image. Slim reduces size while keeping Python.
2
  FROM python:3.12-slim
3
 
4
+ # Make Python output unbuffered (better real-time logs)
5
+ ENV PYTHONUNBUFFERED=1
6
+
7
+ # Create a non-root user to run the app (security best-practice).
8
  RUN useradd --create-home --shell /bin/bash app
9
 
10
+ # Set working directory for subsequent commands and the container runtime.
11
  WORKDIR /app
12
 
13
+ # Install system dependencies needed to build Python packages and tooling.
14
+ # --no-install-recommends keeps the image smaller by avoiding extra packages.
15
+ RUN apt-get update && apt-get install -y --no-install-recommends \
16
  gcc \
17
  g++ \
18
  curl \
19
  && rm -rf /var/lib/apt/lists/*
20
 
21
+ # Upgrade pip and related build tools, and install uv (project's runtime manager).
22
+ # --no-cache-dir avoids leaving pip cache in the image.
23
+ RUN python -m pip install --upgrade pip setuptools wheel && \
24
+ pip install --no-cache-dir uv
25
 
26
+ # Copy project files into the image.
27
  COPY . .
28
+
29
+ # Ensure the non-root user owns the app directory so it can run/install files there.
30
  RUN chown -R app:app /app
31
 
32
+ # Switch to the non-root user for better security for subsequent steps.
33
  USER app
34
 
35
+ # Set uv cache dir to somewhere writable by the app user. This avoids permission errors
36
+ # when uv manages its own cache during `uv sync` or runtime.
37
  ENV UV_CACHE_DIR=/app/.uv-cache
38
 
39
+ # Install application dependencies using uv. Running this as the non-root `app` user
40
+ # keeps the image consistent with runtime permissions. `--frozen` ensures deterministic installs.
41
  RUN uv sync --frozen
42
 
43
+ # Expose the port Gradio uses (default in the project). This is informational and
44
+ # useful for container orchestration and documentation.
45
  EXPOSE 7860
46
 
47
+ # Set Gradio environment variables so the app binds to all interfaces in containers.
48
  ENV GRADIO_SERVER_NAME="0.0.0.0"
49
  ENV GRADIO_SERVER_PORT=7860
50
 
51
+ # Default command: run the Gradio app via uv. Using uv run keeps the environment consistent
52
+ # with development workflows that rely on uv.
53
  CMD ["uv", "run", "python", "src/sales_assistant/ui_dashboard/gradio_app.py"]
README.md CHANGED
@@ -10,15 +10,16 @@ license: mit
10
 
11
  # StreamNet Sales Assistant 🤖
12
 
13
- A sophisticated AI-powered sales assistant that helps customers explore products, get pricing information, and generate professional quotes. Built with LangGraph, LangChain, and Gradio.
14
 
15
  ## Features
16
 
17
  - 🔍 **Product Search**: Advanced search across our product database
18
  - 📊 **Data Analysis**: Statistical insights and product comparisons
19
- - 💰 **Quote Generation**: Professional quote creation with current exchange rates
20
  - 🌍 **Exchange Rates**: Real-time currency conversion
21
- - **Natural Language**: Chat naturally about products and services
 
 
22
 
23
  ## How to Use
24
 
@@ -35,7 +36,6 @@ Simply start a conversation with the assistant! You can:
35
  - **Language Model**: GPT-5-mini
36
  - **Database**: MySQL with SQLAlchemy
37
  - **UI**: Gradio
38
- - **Validation**: Pydantic
39
 
40
  ## Repository
41
 
 
10
 
11
  # StreamNet Sales Assistant 🤖
12
 
13
+ AI-powered sales assistant that helps the sales department with e.g.: get pricing information, and generate professional quotes.
14
 
15
  ## Features
16
 
17
  - 🔍 **Product Search**: Advanced search across our product database
18
  - 📊 **Data Analysis**: Statistical insights and product comparisons
 
19
  - 🌍 **Exchange Rates**: Real-time currency conversion
20
+ - 🌐 **Web Search with Tavaily**: Instantly search the web for up-to-date product information
21
+ - 💰 **Quote Generation**: Professional quote creation with current exchange rates
22
+
23
 
24
  ## How to Use
25
 
 
36
  - **Language Model**: GPT-5-mini
37
  - **Database**: MySQL with SQLAlchemy
38
  - **UI**: Gradio
 
39
 
40
  ## Repository
41
 
README_HF.md DELETED
@@ -1,42 +0,0 @@
1
- ---
2
- title: StreamNet Sales Assistant
3
- emoji: 🤖
4
- colorFrom: blue
5
- colorTo: purple
6
- sdk: docker
7
- pinned: false
8
- license: mit
9
- ---
10
-
11
- # StreamNet Sales Assistant 🤖
12
-
13
- A sophisticated AI-powered sales assistant that helps customers explore products, get pricing information, and generate professional quotes. Built with LangGraph, LangChain, and Gradio.
14
-
15
- ## Features
16
-
17
- - 🔍 **Product Search**: Advanced search across our product database
18
- - 📊 **Data Analysis**: Statistical insights and product comparisons
19
- - 💰 **Quote Generation**: Professional quote creation with current exchange rates
20
- - 🌍 **Exchange Rates**: Real-time currency conversion
21
- - ❓ **Natural Language**: Chat naturally about products and services
22
-
23
- ## How to Use
24
-
25
- Simply start a conversation with the assistant! You can:
26
-
27
- - Ask about specific products: "Can you give me a price for a Saber 4k+?"
28
- - Request quotes: "I need a 55 inch Samsung TV, what are my options?"
29
- - Get exchange rates: "What are the current exchange rates?"
30
- - Explore categories: "What categories of Samsung products do you have?"
31
-
32
- ## Technology Stack
33
-
34
- - **AI Framework**: LangGraph + LangChain
35
- - **Language Model**: GPT-4
36
- - **Database**: MySQL with SQLAlchemy
37
- - **UI**: Gradio
38
- - **Validation**: Pydantic
39
-
40
- ## Repository
41
-
42
- Full source code is available at: [https://github.com/krinya/sales_assistant_with_quote](https://github.com/krinya/sales_assistant_with_quote)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
docs/HUGGINGFACE_DEPLOYMENT.md DELETED
@@ -1,148 +0,0 @@
1
- # Hugging Face Deployment Guide
2
-
3
- This guide explains how to deploy your sales assistant application on Hugging Face Spaces with secure SSH key management.
4
-
5
- ## Setting Up Secrets in Hugging Face
6
-
7
- 1. **Go to your Hugging Face Space settings**
8
- - Navigate to your space on Hugging Face
9
- - Click on "Settings" tab
10
- - Go to "Repository secrets"
11
-
12
- 2. **Add the following secrets:**
13
-
14
- ### Required Database Secrets
15
- ```
16
- SSH_HOSTNAME=your.ssh.hostname.com
17
- SSH_PORT=22
18
- SSH_USERNAME=your-ssh-username
19
- SSH_PEM_CONTENT=-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEA...\n-----END RSA PRIVATE KEY-----
20
- MYSQL_HOST=your.mysql.hostname.com
21
- MYSQL_PORT=3306
22
- MYSQL_USER=your-mysql-user
23
- MYSQL_PASSWORD=your-mysql-password
24
- MYSQL_DB=your-database-name
25
- ```
26
-
27
- ### Required API Keys
28
- ```
29
- OPENAI_API_KEY=your-openai-api-key
30
- HUGGINGFACE_API_KEY=your-hf-api-key
31
- TAVILY_API_KEY=your-tavily-api-key
32
- BREVO_API_KEY=your-brevo-api-key
33
- COMPANY_EMAIL=your-company@email.com
34
- ```
35
-
36
- ### Optional Configuration
37
- ```
38
- MODEL_NAME=gpt-5-mini
39
- MODEL_PROVIDER=openai
40
- LANGSMITH_API_KEY=your-langsmith-key
41
- LANGSMITH_TRACING_V2=true
42
- LANGSMITH_ENDPOINT=https://api.smith.langchain.com
43
- LANGSMITH_PROJECT=your-project-name
44
- ```
45
-
46
- ## SSH PEM Content Format
47
-
48
- When adding your SSH private key as `SSH_PEM_CONTENT`, use this format:
49
-
50
- ```
51
- -----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEA0dtZotnwrz2jVSz2X3cZ...\n-----END RSA PRIVATE KEY-----
52
- ```
53
-
54
- **Important Notes:**
55
- - Replace actual line breaks with `\n`
56
- - Don't include quotes around the content
57
- - Keep the BEGIN/END lines intact
58
- - Include the `\n` characters exactly as shown
59
-
60
- ## How It Works
61
-
62
- Our implementation now uses **paramiko directly** instead of temporary files:
63
-
64
- ### ✅ Advantages of Current Implementation
65
- - **No temporary files**: PEM content is parsed directly in memory
66
- - **Hugging Face friendly**: Works seamlessly with HF secrets
67
- - **More secure**: No files written to disk
68
- - **Cloud native**: Perfect for containerized environments
69
- - **Fallback support**: Still works with file-based keys if needed
70
-
71
- ### 🔄 Process Flow
72
- 1. **Load environment variables** from HF secrets
73
- 2. **Parse PEM content** directly using paramiko
74
- 3. **Create SSH tunnel** using the parsed key object
75
- 4. **Connect to database** through the secure tunnel
76
- 5. **Clean shutdown** with no temporary files to clean up
77
-
78
- ## Testing Locally
79
-
80
- To test your HF deployment locally:
81
-
82
- 1. **Copy your secrets** to a local `.env` file (temporarily)
83
- 2. **Run the test**: `uv run python test_files/db_test.py`
84
- 3. **Verify output**: Look for "✅ Successfully created SSH key from PEM content"
85
- 4. **Delete local .env**: Don't commit secrets to git!
86
-
87
- ## Deployment Files for HF
88
-
89
- Make sure your Hugging Face space includes:
90
-
91
- - `app.py` (or your main application file)
92
- - `requirements.txt` (or `pyproject.toml`)
93
- - `README.md`
94
-
95
- Example `app.py` for Gradio:
96
- ```python
97
- import gradio as gr
98
- from src.sales_assistant.ui_dashboard.gradio_app import create_app
99
-
100
- if __name__ == "__main__":
101
- app = create_app()
102
- app.launch()
103
- ```
104
-
105
- ## Troubleshooting
106
-
107
- ### Common Issues:
108
-
109
- 1. **"No SSH key available"**
110
- - Check that `SSH_PEM_CONTENT` is properly set in HF secrets
111
- - Verify the PEM format includes `\n` characters
112
-
113
- 2. **"Could not parse PEM content"**
114
- - Ensure the PEM content is properly formatted
115
- - Check that the private key is valid
116
-
117
- 3. **Connection timeout**
118
- - Verify SSH hostname and port
119
- - Check that the SSH server allows connections from HF infrastructure
120
-
121
- 4. **MySQL connection failed**
122
- - Verify MySQL credentials
123
- - Check that MySQL server allows connections from your SSH server
124
-
125
- ### Debug Mode
126
-
127
- Add this to your app for debugging:
128
- ```python
129
- import os
130
- print(f"SSH_PEM_CONTENT loaded: {bool(os.getenv('SSH_PEM_CONTENT'))}")
131
- print(f"SSH_HOSTNAME: {os.getenv('SSH_HOSTNAME')}")
132
- ```
133
-
134
- ## Security Best Practices
135
-
136
- 1. **Never commit secrets** to your git repository
137
- 2. **Use HF secrets** for all sensitive information
138
- 3. **Rotate SSH keys** periodically
139
- 4. **Monitor access logs** on your SSH and database servers
140
- 5. **Use strong passwords** for database accounts
141
- 6. **Consider IP whitelisting** if possible
142
-
143
- ## Performance Tips
144
-
145
- 1. **Connection pooling**: The implementation reuses connections efficiently
146
- 2. **Query optimization**: Use indexed columns for faster queries
147
- 3. **Caching**: Consider caching frequently accessed data
148
- 4. **Monitoring**: Set up monitoring for your database and SSH server
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
docs/SSH_KEY_MANAGEMENT.md DELETED
File without changes
scripts/setup_hf_secrets.py DELETED
File without changes
src/sales_assistant/agent_main/agent_runner.py CHANGED
@@ -16,7 +16,7 @@ class ConversationConfig(BaseModel):
16
  """Enhanced configuration with validation for GPT-5-mini conversations."""
17
  session_id: str = Field(default_factory=lambda: str(uuid.uuid4()))
18
  user_id: str = Field(default="default_user")
19
- langsmith_project: str = Field(default_factory=lambda: os.getenv("LANGSMITH_PROJECT", "sales-assistant-gpt5"))
20
  enable_langsmith: bool = Field(default=True)
21
  model_name: str = Field(default_factory=lambda: os.getenv("MODEL_NAME", "gpt-5-mini"))
22
  model_provider: str = Field(default_factory=lambda: os.getenv("MODEL_PROVIDER", "openai"))
@@ -235,7 +235,6 @@ def clear_conversation_history(compiled_graph, thread_id: str) -> None:
235
  try:
236
  config = {"configurable": {"thread_id": thread_id}}
237
  # Note: LangGraph's MemorySaver doesn't have a direct clear method
238
- # You would need to implement this based on your specific checkpointer
239
  print(f"Note: To clear history, restart with a new thread_id")
240
  except Exception as e:
241
  print(f"Error clearing conversation history: {e}")
 
16
  """Enhanced configuration with validation for GPT-5-mini conversations."""
17
  session_id: str = Field(default_factory=lambda: str(uuid.uuid4()))
18
  user_id: str = Field(default="default_user")
19
+ langsmith_project: str = Field(default_factory=lambda: os.getenv("LANGSMITH_PROJECT", "sales-assistant"))
20
  enable_langsmith: bool = Field(default=True)
21
  model_name: str = Field(default_factory=lambda: os.getenv("MODEL_NAME", "gpt-5-mini"))
22
  model_provider: str = Field(default_factory=lambda: os.getenv("MODEL_PROVIDER", "openai"))
 
235
  try:
236
  config = {"configurable": {"thread_id": thread_id}}
237
  # Note: LangGraph's MemorySaver doesn't have a direct clear method
 
238
  print(f"Note: To clear history, restart with a new thread_id")
239
  except Exception as e:
240
  print(f"Error clearing conversation history: {e}")
src/sales_assistant/agent_tools/get_exchange_rates.py CHANGED
@@ -3,6 +3,7 @@ from langchain_core.tools import tool
3
  from .tool_schemas import CurrencyConversionInput, CurrencyConversionOutput, ErrorOutput
4
 
5
  # Fixed exchange rates relative to HUF (kept simple and deterministic)
 
6
  _EXCHANGE_RATES = {
7
  "HUF": 1.0,
8
  "EUR": 400.0,
 
3
  from .tool_schemas import CurrencyConversionInput, CurrencyConversionOutput, ErrorOutput
4
 
5
  # Fixed exchange rates relative to HUF (kept simple and deterministic)
6
+ ## This will be replaced with a real API call in a production scenario now for testing it is hardcoded to see tool functionality
7
  _EXCHANGE_RATES = {
8
  "HUF": 1.0,
9
  "EUR": 400.0,
src/sales_assistant/ui_dashboard/gradio_app.py CHANGED
@@ -9,10 +9,8 @@ import gradio as gr
9
  from typing import List, Tuple, Dict
10
  from datetime import datetime
11
  import glob
12
- import threading
13
- import time
14
  import logging
15
- import io
16
 
17
  # Add the src directory to the path
18
  sys.path.insert(0, os.path.join(os.path.dirname(__file__), '../..'))
 
9
  from typing import List, Tuple, Dict
10
  from datetime import datetime
11
  import glob
 
 
12
  import logging
13
+
14
 
15
  # Add the src directory to the path
16
  sys.path.insert(0, os.path.join(os.path.dirname(__file__), '../..'))
src/sales_assistant/ui_dashboard/streamlit_app.py DELETED
@@ -1,273 +0,0 @@
1
- """
2
- Streamlit Chat UI for Sales Assistant
3
-
4
- This module provides a simple Streamlit-based chat interface for the sales assistant.
5
- """
6
- import os
7
- import sys
8
- import streamlit as st
9
- from typing import Dict, Any, List
10
-
11
- # Add the src directory to the path
12
- sys.path.insert(0, os.path.join(os.path.dirname(__file__), '../..'))
13
-
14
- from sales_assistant.main import (
15
- check_environment_setup,
16
- create_custom_config
17
- )
18
- from sales_assistant.agent_main.agent_runner import (
19
- create_agent_runner,
20
- run_conversation_turn
21
- )
22
-
23
-
24
- # Page configuration
25
- st.set_page_config(
26
- page_title="Sales Assistant with Quote Generation",
27
- page_icon="🤖",
28
- layout="wide",
29
- initial_sidebar_state="expanded"
30
- )
31
-
32
-
33
- def initialize_session_state():
34
- """Initialize Streamlit session state variables."""
35
- if "messages" not in st.session_state:
36
- st.session_state.messages = []
37
-
38
- if "compiled_graph" not in st.session_state:
39
- st.session_state.compiled_graph = None
40
-
41
- if "checkpointer" not in st.session_state:
42
- st.session_state.checkpointer = None
43
-
44
- if "langsmith_client" not in st.session_state:
45
- st.session_state.langsmith_client = None
46
-
47
- if "thread_id" not in st.session_state:
48
- st.session_state.thread_id = None
49
-
50
- if "agent_initialized" not in st.session_state:
51
- st.session_state.agent_initialized = False
52
-
53
-
54
- def initialize_agent():
55
- """Initialize the sales assistant agent."""
56
- if st.session_state.agent_initialized:
57
- return True
58
-
59
- try:
60
- with st.spinner("Initializing Sales Assistant..."):
61
- # Check environment setup
62
- if not check_environment_setup():
63
- st.error("❌ Environment setup failed. Please check your configuration.")
64
- return False
65
-
66
- # Create configuration
67
- config = create_custom_config(
68
- session_id="streamlit_session",
69
- user_id="streamlit_user",
70
- enable_langsmith=True
71
- )
72
-
73
- # Create agent runner
74
- compiled_graph, checkpointer, langsmith_client, thread_id = create_agent_runner(config)
75
-
76
- # Store in session state
77
- st.session_state.compiled_graph = compiled_graph
78
- st.session_state.checkpointer = checkpointer
79
- st.session_state.langsmith_client = langsmith_client
80
- st.session_state.thread_id = thread_id
81
- st.session_state.agent_initialized = True
82
-
83
- st.success("✅ Sales Assistant initialized successfully!")
84
- return True
85
-
86
- except Exception as e:
87
- st.error(f"❌ Failed to initialize sales assistant: {e}")
88
- return False
89
-
90
-
91
- def display_sidebar():
92
- """Display the sidebar with information and controls."""
93
- with st.sidebar:
94
- st.markdown("# 🤖 Sales Assistant")
95
- st.markdown("---")
96
-
97
- # Status indicator
98
- if st.session_state.agent_initialized:
99
- st.success("🟢 Agent Online")
100
- else:
101
- st.error("🔴 Agent Offline")
102
-
103
- st.markdown("---")
104
-
105
- # Information section
106
- st.markdown("### 🔧 Capabilities")
107
- st.markdown("""
108
- - 🔍 **Product Search**: Find products by criteria
109
- - 📊 **Data Analysis**: Statistical insights
110
- - 💰 **Quote Generation**: Professional quotes
111
- - 🌍 **Exchange Rates**: Current currency rates
112
- - 📈 **Database Insights**: Explore product data
113
- """)
114
-
115
- st.markdown("---")
116
-
117
- # Example queries
118
- st.markdown("### 💡 Example Queries")
119
- example_queries = [
120
- "Show me product information",
121
- "Generate a quote for equipment",
122
- "What are current exchange rates?",
123
- "Find products under $1000",
124
- "Show product statistics"
125
- ]
126
-
127
- for query in example_queries:
128
- if st.button(query, key=f"example_{hash(query)}", use_container_width=True):
129
- st.session_state.messages.append({"role": "user", "content": query})
130
- st.rerun()
131
-
132
- st.markdown("---")
133
-
134
- # Clear chat button
135
- if st.button("🗑️ Clear Chat", use_container_width=True):
136
- st.session_state.messages = []
137
- st.rerun()
138
-
139
- # Restart agent button
140
- if st.button("🔄 Restart Agent", use_container_width=True):
141
- st.session_state.agent_initialized = False
142
- st.session_state.compiled_graph = None
143
- st.session_state.checkpointer = None
144
- st.session_state.langsmith_client = None
145
- st.session_state.thread_id = None
146
- st.rerun()
147
-
148
-
149
- def display_chat_messages():
150
- """Display the chat messages."""
151
- for message in st.session_state.messages:
152
- with st.chat_message(message["role"]):
153
- st.markdown(message["content"])
154
-
155
-
156
- def process_user_input(user_input: str) -> str:
157
- """
158
- Process user input and get response from the sales assistant.
159
-
160
- Args:
161
- user_input: The user's message
162
-
163
- Returns:
164
- The assistant's response
165
- """
166
- if not st.session_state.compiled_graph:
167
- return "❌ Sales Assistant is not properly initialized. Please restart the agent."
168
-
169
- try:
170
- # Run conversation turn
171
- response = run_conversation_turn(
172
- compiled_graph=st.session_state.compiled_graph,
173
- thread_id=st.session_state.thread_id,
174
- user_input=user_input,
175
- langsmith_client=st.session_state.langsmith_client
176
- )
177
- return response
178
-
179
- except Exception as e:
180
- return f"❌ Error processing your request: {str(e)}"
181
-
182
-
183
- def main():
184
- """Main Streamlit application."""
185
- # Initialize session state
186
- initialize_session_state()
187
-
188
- # Main title
189
- st.title("🤖 Sales Assistant with Quote Generation")
190
- st.markdown("---")
191
-
192
- # Initialize agent if not done
193
- if not st.session_state.agent_initialized:
194
- if not initialize_agent():
195
- st.stop()
196
-
197
- # Display sidebar
198
- display_sidebar()
199
-
200
- # Main chat area
201
- col1, col2 = st.columns([3, 1])
202
-
203
- with col1:
204
- # Introduction message
205
- if not st.session_state.messages:
206
- st.markdown("""
207
- ### Welcome to the Sales Assistant! 👋
208
-
209
- I'm here to help you with:
210
- - 🔍 **Product Information**: Search and explore our product database
211
- - 📊 **Data Analysis**: Get insights and statistics about products
212
- - 💰 **Quote Generation**: Create professional quotes with current pricing
213
- - 🌍 **Exchange Rates**: Get up-to-date currency information
214
- - ❓ **General Questions**: Ask me anything about our products and services
215
-
216
- **To get started**, type your question in the chat box below or click one of the example queries in the sidebar.
217
- """)
218
- st.markdown("---")
219
-
220
- # Display chat messages
221
- display_chat_messages()
222
-
223
- # Chat input
224
- if prompt := st.chat_input("Ask me about products, request a quote, or explore our database..."):
225
- # Add user message to chat history
226
- st.session_state.messages.append({"role": "user", "content": prompt})
227
-
228
- # Display user message
229
- with st.chat_message("user"):
230
- st.markdown(prompt)
231
-
232
- # Get and display assistant response
233
- with st.chat_message("assistant"):
234
- with st.spinner("Thinking..."):
235
- response = process_user_input(prompt)
236
- st.markdown(response)
237
-
238
- # Add assistant response to chat history
239
- st.session_state.messages.append({"role": "assistant", "content": response})
240
-
241
- with col2:
242
- # Stats section
243
- st.markdown("### 📊 Chat Statistics")
244
- total_messages = len(st.session_state.messages)
245
- user_messages = len([m for m in st.session_state.messages if m["role"] == "user"])
246
- assistant_messages = len([m for m in st.session_state.messages if m["role"] == "assistant"])
247
-
248
- st.metric("Total Messages", total_messages)
249
- st.metric("Your Messages", user_messages)
250
- st.metric("Assistant Responses", assistant_messages)
251
-
252
- # Recent activity
253
- if st.session_state.messages:
254
- st.markdown("### 🕒 Recent Activity")
255
- recent_messages = st.session_state.messages[-3:]
256
- for msg in recent_messages:
257
- role_icon = "👤" if msg["role"] == "user" else "🤖"
258
- st.text(f"{role_icon} {msg['content'][:50]}...")
259
-
260
- # Footer
261
- st.markdown("---")
262
- st.markdown(
263
- """
264
- <div style='text-align: center; color: #666;'>
265
- Sales Assistant powered by AI | Built with Streamlit
266
- </div>
267
- """,
268
- unsafe_allow_html=True
269
- )
270
-
271
-
272
- if __name__ == "__main__":
273
- main()