Skip to content

Commit 90d2b32

Browse files
committed
change to math tutor
1 parent 5067d30 commit 90d2b32

File tree

6 files changed

+113
-527
lines changed

6 files changed

+113
-527
lines changed

.github/workflows/dog-chatbot.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: Dog Breed Assistant Chatbot
1+
name: Math Assistant Chatbot
22
on:
33
push:
44
branches:
@@ -47,4 +47,4 @@ jobs:
4747
context: .
4848
file: dockerfile.prod
4949
push: true
50-
tags: ghcr.io/nocapcbas/dog-breed-assistant-chatbot:prod
50+
tags: ghcr.io/nocapcbas/math-assistant-chatbot:prod

Makefile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
build:
2-
docker build -t dog-breed-assistant-chatbot .
2+
docker build -f dockerfile.prod -t math-assistant-chatbot .
33

44
run:
5-
docker run -p 8501:8501 dog-breed-assistant-chatbot
5+
docker run -p 8080:8080 math-assistant-chatbot
66

77
local:
8-
streamlit run app.py --server.port=8080
8+
streamlit run app.py --server.port=8080

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
# Dog Breed Assistant Chatbot
1+
# Math Assistant Chatbot
22

3-
This is a chatbot using Llama 2, Sentence Transformers, CTransformers, Langchain, and Streamlit.
3+
This is a chatbot using Phi 3, Sentence Transformers, CTransformers, Langchain, and Streamlit.
44

5-
A Streamlit-based chatbot that helps users learn about different dog breeds. Built with:
5+
A Streamlit-based chatbot that helps users learn about different math problems. Built with:
66
- Streamlit for the web interface
7-
- Mistral 7B (via Ollama) for the language model
7+
- Phi 3 (via Ollama) for the language model
88
- FAISS for vector storage
99
- LangChain for the conversation chain
1010

app.py

Lines changed: 85 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,14 @@
11
import streamlit as st
2-
import pandas as pd
32
from streamlit_chat import message
4-
from langchain_community.document_loaders.csv_loader import CSVLoader
5-
from langchain_community.embeddings import HuggingFaceEmbeddings
6-
from langchain_community.vectorstores import FAISS
73
from langchain_community.llms import Ollama
8-
from langchain.chains import ConversationalRetrievalChain
94
import time
5+
import re
106

11-
DB_FAISS_PATH = 'vectorstore/db_faiss'
12-
CSV_FILE_PATH = r'dogs_cleaned.csv' # Replace with your CSV file path
137
st.set_page_config(
14-
page_title="Dog Breed Assistant",
15-
page_icon="🐕",
8+
page_title="Math Assistant",
9+
page_icon="🔢",
1610
)
11+
1712
# Hide Streamlit's default menu and footer
1813
hide_streamlit_style = """
1914
<style>
@@ -24,60 +19,48 @@
2419
"""
2520
st.markdown(hide_streamlit_style, unsafe_allow_html=True)
2621

27-
28-
#Loading the model
2922
def load_llm():
30-
# Load Mistral through Ollama
23+
# Load Phi-2 through Ollama
3124
llm = Ollama(
32-
model="mistral", # Using Mistral 7B - a powerful open source model
33-
# model="phi",
34-
temperature=0.5,
25+
model="phi3", # Using Phi-2 - good balance of size and math capability
26+
temperature=0.1, # Lower temperature for more precise math
3527
)
3628
return llm
3729

38-
@st.cache_resource # This ensures the data is loaded only once
39-
def load_and_process_data():
40-
loader = CSVLoader(file_path=CSV_FILE_PATH, encoding="utf-8", csv_args={
41-
'delimiter': ','})
42-
data = loader.load()
43-
44-
embeddings = HuggingFaceEmbeddings(
45-
model_name='sentence-transformers/all-MiniLM-L6-v2',
46-
model_kwargs={'device': 'cpu'},
47-
encode_kwargs={'normalize_embeddings': True}
48-
)
30+
def is_math_related(query):
31+
# List of math-related keywords and patterns
32+
math_keywords = [
33+
'math', 'calculate', 'solve', 'equation', 'problem', 'plus', 'minus',
34+
'multiply', 'divide', 'sum', 'difference', 'product', 'quotient',
35+
'algebra', 'geometry', 'trigonometry', 'calculus', 'number',
36+
'fraction', 'decimal', 'percentage', 'square root', 'power',
37+
'logarithm', 'factorial', 'series', 'sequence', 'probability',
38+
'statistics', 'mean', 'median', 'mode', 'variance', 'derivative',
39+
'integral', 'function', 'graph', 'plot', 'coordinate'
40+
"add", "subtract"
41+
]
4942

50-
db = FAISS.from_documents(data, embeddings)
51-
llm = load_llm()
52-
chain = ConversationalRetrievalChain.from_llm(llm=llm, retriever=db.as_retriever())
53-
return chain
54-
55-
st.markdown("<h1 style='text-align: center; color: white;'>🐕 Dog Breed Assistant 🦮</h1>", unsafe_allow_html=True)
56-
st.markdown("<h3 style='text-align: center; color: white;'>Your Friendly Guide to Dog Breeds</h3>", unsafe_allow_html=True)
57-
st.markdown("<h3 style='text-align: center; color: red;'> This chatbot uses open source model Phi due to its smaller size and faster response time</h3>", unsafe_allow_html=True)
58-
59-
# Load the chain once at startup
60-
chain = load_and_process_data()
61-
62-
def is_dog_related(query):
63-
# List of dog-related keywords
64-
dog_keywords = [
65-
'dog', 'breed', 'puppy', 'canine', 'hound', 'terrier', 'shepherd',
66-
'retriever', 'poodle', 'bulldog', 'labrador', 'german', 'golden',
67-
'bark', 'pet', 'training', 'grooming', 'walk', 'leash', 'collar',
68-
'kennel', 'veterinary', 'vet', 'pup', 'pooch', 'dog breed', 'dog breeds',
69-
'chew', 'bite', 'paw', 'paws', 'paw print', 'paw print', 'paw print', 'paw print',
43+
# Mathematical symbols and patterns
44+
math_patterns = [
45+
r'[\d+\-*/^√∫∑π=]', # Basic math operators and symbols
46+
r'\d+', # Numbers
47+
r'[xyz]\s*=', # Variables
48+
r'\b\d+\s*[\+\-\*/]\s*\d+\b', # Basic arithmetic
49+
r'\b\d+\s*%', # Percentages
50+
r'sqrt|sin|cos|tan|log|ln', # Math functions
7051
]
71-
# read first column of csv file
72-
df = pd.read_csv(CSV_FILE_PATH)
73-
df = df.iloc[:, 0]
74-
# add all the values in the first column to the dog_keywords list as lowercase
75-
dog_keywords.extend(df.str.lower().tolist())
76-
# Convert query to lowercase for case-insensitive matching
52+
7753
query_lower = query.lower()
7854

79-
# Check if any dog-related keyword is in the query
80-
return any(keyword in query_lower for keyword in dog_keywords)
55+
# Check for math keywords
56+
if any(keyword in query_lower for keyword in math_keywords):
57+
return True
58+
59+
# Check for math patterns
60+
if any(re.search(pattern, query) for pattern in math_patterns):
61+
return True
62+
63+
return False
8164

8265
def conversational_chat(query):
8366
current_time = time.time()
@@ -87,89 +70,94 @@ def conversational_chat(query):
8770
time_since_last_query = current_time - st.session_state.last_query_time
8871
if time_since_last_query < 10:
8972
remaining_time = int(10 - time_since_last_query)
90-
st.error(f"Rate limit exceeded! ⏳ Please wait {remaining_time} seconds before sending another message! This is to prevent abuse and overload my server. This rate limit is applied to all users. Resend you query to continue and Thanks for your patience!")
73+
st.error(f"Rate limit exceeded! ⏳ Please wait {remaining_time} seconds before sending another message!")
9174
return None
9275

93-
# Check if query is dog-related
94-
if not is_dog_related(query):
95-
return "I am a dog breed expert assistant. I can only answer questions about dogs and dog breeds. Please ask me about dogs! 🐕"
76+
# Check if query is math-related
77+
# if not is_math_related(query):
78+
# return "I am a math assistant. I can only help with mathematical questions and calculations. Please ask me about math! 🔢"
9679

9780
st.session_state.last_query_time = current_time
9881

99-
with st.spinner('🐾 Fetching response... Thank you for your patience! 🐕'):
100-
context = """You are a dog breed expert assistant. You must ONLY answer questions about dogs and dog breeds.
101-
If the question is not about dogs, respond with "I am a dog breed expert assistant. I can only answer questions about dogs and dog breeds."
102-
103-
These are the columns in the data:
104-
Breed Name,Detailed Description Link,Dog Size,Dog Breed Group,Height,"Avg. Height, cm",Weight,"Avg. Weight, kg",Life Span,"Avg. Life Span, years",Adaptability,Adapts Well To Apartment Living,Good For Novice Owners,Sensitivity Level,Tolerates Being Alone,Tolerates Cold Weather,Tolerates Hot Weather,All Around Friendliness,Affectionate With Family,Kid-Friendly,Dog Friendly,Friendly Toward Strangers,Health And Grooming Needs,Amount Of Shedding,Drooling Potential,Easy To Groom,General Health,Potential For Weight Gain,Size,Trainability,Easy To Train,Intelligence,Potential For Mouthiness,Prey Drive,Tendency To Bark Or Howl,Wanderlust Potential,Physical Needs,Energy Level,Intensity,Exercise Needs,Potential For Playfulness
82+
with st.spinner('🔢 Computing... Thank you for your patience!'):
83+
context = """You are a math assistant. You must ONLY answer questions about mathematics.
84+
If the question is not about math, or about how to solve a math problem, respond with "I am a math assistant. I can only help with mathematical questions."
10585
106-
The data contains ratings on a scale of 1-5 for columns (Adaptability, Adapts Well To Apartment Living, Good For Novice Owners, Sensitivity Level, Tolerates Being Alone, Tolerates Cold Weather, Tolerates Hot Weather, All Around Friendliness, Affectionate With Family, Kid-Friendly, Dog Friendly, Friendly Toward Strangers, Health And Grooming Needs, Amount Of Shedding, Drooling Potential, Easy To Groom, General Health, Potential For Weight Gain, Size, Trainability, Easy To Train, Intelligence, Potential For Mouthiness, Prey Drive, Tendency To Bark Or Howl, Wanderlust Potential, Physical Needs, Energy Level, Intensity, Exercise Needs, Potential For Playfulness) where:
107-
- 5 is the BEST/HIGHEST score (excellent)
108-
- 4 is ABOVE AVERAGE
109-
- 3 is AVERAGE
110-
- 2 is BELOW AVERAGE
111-
- 1 is the WORST/LOWEST score (poor)
86+
Example questions:
87+
- What is the square root of 16?
88+
- How do I solve the equation 2x + 3 = 7?
89+
- What is the sum of 10 and 5?
90+
- What is the product of 3 and 4?
91+
- What is the difference between 10 and 5?
11292
11393
Important rules:
114-
1. NEVER answer questions that are not about dogs
115-
2. Do not mention the data or ratings in your response
116-
3. If unsure, say "Sorry, I don't know the answer to that question"
117-
4. Keep responses focused only on dogs and dog breeds
118-
5. Be friendly and helpful, but stay strictly within dog-related topics
94+
1. NEVER answer questions that are not about math
95+
2. Show your work step by step
96+
3. If unsure, say "Sorry, I don't know how to solve this problem"
97+
4. Use proper mathematical notation
98+
5. Be precise and accurate
99+
6. Explain concepts clearly
100+
7. If the question involves complex calculations, break them down
101+
8. Use LaTeX notation for complex mathematical expressions
119102
120103
User Question: """
121104

122105
enhanced_query = context + query
123-
124-
result = chain({"question": enhanced_query, "chat_history": st.session_state['history']})
125-
st.session_state['history'].append((query, result["answer"]))
126-
return result["answer"]
106+
llm = load_llm()
107+
result = llm.invoke(enhanced_query)
108+
return result
127109

110+
# Initialize session state
128111
if 'history' not in st.session_state:
129112
st.session_state['history'] = []
130113

131114
if 'generated' not in st.session_state:
132-
st.session_state['generated'] = ["Woof! I'm your friendly dog breed expert! Ask me anything about dogs! 🐕"]
115+
st.session_state['generated'] = ["Hello! I'm your math assistant. Ask me any math question! 🔢"]
133116

134117
if 'past' not in st.session_state:
135118
st.session_state['past'] = ["Hey! 👋"]
136119

120+
# Title and description
121+
st.markdown("<h1 style='text-align: center; color: white;'>🔢 Math Assistant</h1>", unsafe_allow_html=True)
122+
st.markdown("<h3 style='text-align: center; color: white;'>Your Step-by-Step Math Problem Solver</h3>", unsafe_allow_html=True)
123+
137124
# Add suggested questions
138-
st.sidebar.markdown("### 📝 Suggested Questions")
125+
st.sidebar.markdown("### 📝 Example Math Problems")
139126
suggested_questions = [
140-
"What dog breeds are best for beginners?",
141-
"What are some rare or unusual dog breeds?",
142-
"What are the largest dog breeds?",
143-
"Which breeds are best with children?",
144-
"What are the most low-maintenance dog breeds?",
145-
"Which breeds are best for apartment living?"
127+
"What is 15% of 80?",
128+
"Solve the equation: 2x + 5 = 13",
129+
"Find the area of a circle with radius 5",
130+
"What is the square root of 144?",
131+
"Calculate 3^4",
132+
"Find the mean of 12, 15, 18, 21, 24"
146133
]
147134

148135
if st.sidebar.button("Clear Chat History"):
149136
st.session_state['history'] = []
150137
st.session_state['past'] = ["Hey! 👋"]
151-
st.session_state['generated'] = ["Woof! I'm your friendly dog breed expert! Ask me anything about dogs! 🐕"]
138+
st.session_state['generated'] = ["Hello! I'm your math assistant. Ask me any math question! 🔢"]
152139

153140
for question in suggested_questions:
154141
if st.sidebar.button(question):
155142
st.session_state['past'].append(question)
156143
output = conversational_chat(question)
157-
st.session_state['generated'].append(output)
144+
if output:
145+
st.session_state['generated'].append(output)
158146

159-
#container for the chat history
147+
# Chat interface
160148
response_container = st.container()
161-
#container for the user's text input
162149
container = st.container()
163150

164151
with container:
165152
with st.form(key='my_form', clear_on_submit=True):
166-
user_input = st.text_input("Query:", placeholder="Ask me anything about dogs! 🐕", key='input')
167-
submit_button = st.form_submit_button(label='Send')
153+
user_input = st.text_input("Query:", placeholder="Enter your math question here! 🔢", key='input')
154+
submit_button = st.form_submit_button(label='Calculate')
168155

169156
if submit_button and user_input:
170157
output = conversational_chat(user_input)
171-
st.session_state['past'].append(user_input)
172-
st.session_state['generated'].append(output)
158+
if output:
159+
st.session_state['past'].append(user_input)
160+
st.session_state['generated'].append(output)
173161

174162
if st.session_state['generated']:
175163
with response_container:
@@ -180,8 +168,8 @@ def conversational_chat(query):
180168
avatar_style="big-smile")
181169
message(st.session_state["generated"][i],
182170
key=str(i),
183-
avatar_style="bottts-neutral", # This gives a more dog-like cartoon avatar
184-
seed="Buddy") # This helps maintain consistent avatar appearance
171+
avatar_style="bottts",
172+
seed="Math")
185173

186174

187175

dockerfile.prod

Lines changed: 19 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,37 @@
1-
# Build stage
2-
FROM python:3.12-slim-bullseye as builder
1+
# Use an official Python runtime as a parent image
2+
FROM python:3.12-slim
33

4+
# Set working directory in the container
45
WORKDIR /app
56

6-
# Install build dependencies
7+
# Install system dependencies including Ollama
78
RUN apt-get update && apt-get install -y \
89
curl \
9-
build-essential \
1010
&& rm -rf /var/lib/apt/lists/*
1111

12-
# Copy and install requirements with CPU-only PyTorch
13-
COPY requirements.txt .
14-
RUN pip install --no-cache-dir -r requirements.txt \
15-
&& pip uninstall -y torch \
16-
&& pip install --no-cache-dir torch --index-url https://download.pytorch.org/whl/cpu
17-
18-
# Final stage
19-
FROM python:3.12-slim-bullseye
20-
21-
WORKDIR /app
12+
# Install Ollama
13+
RUN curl https://ollama.ai/install.sh | sh
2214

23-
# Install only essential runtime dependencies
24-
RUN apt-get update && apt-get install -y \
25-
curl \
26-
&& rm -rf /var/lib/apt/lists/* \
27-
&& curl https://ollama.ai/install.sh | sh
15+
# Copy the requirements
16+
COPY requirements.txt .
2817

29-
# Copy only necessary Python packages
30-
COPY --from=builder /usr/local/lib/python3.12/site-packages/ /usr/local/lib/python3.12/site-packages/
18+
# Install Python dependencies
19+
RUN pip install --no-cache-dir -r requirements.txt
3120

32-
# Copy application files
33-
COPY app.py .
34-
COPY dogs_cleaned.csv .
21+
# Copy the application
22+
COPY . .
3523

36-
# Start Ollama, pull model, and clean up unnecessary files
24+
# Start Ollama service and pull the model
3725
RUN ollama serve & \
3826
sleep 10 && \
39-
ollama pull mistral && \
40-
rm -rf /root/.cache
27+
ollama pull phi3
4128

29+
# Expose the port Streamlit runs on
4230
EXPOSE 8080
4331

44-
RUN echo '#!/bin/bash\nollama serve & sleep 5 && streamlit run app.py --server.address=0.0.0.0 --server.port=8080' > start.sh \
45-
&& chmod +x start.sh
32+
# Create a shell script to start both Ollama and Streamlit
33+
RUN echo '#!/bin/bash\nollama serve & sleep 5 && streamlit run app.py --server.address=0.0.0.0 --server.port=8080' > start.sh
34+
RUN chmod +x start.sh
4635

36+
# Command to run the script
4737
CMD ["./start.sh"]

0 commit comments

Comments
 (0)