Spaces:
Running
Running
Commit ·
a75702e
1
Parent(s): 5110d54
added customer support usecases
Browse files- .gitignore +4 -0
- README.md +5 -0
- app.py +58 -4
- configfile.ini +1 -1
- cs-flow.png +0 -0
- customer_support.png +0 -0
- data/FAQ.json +83 -0
- data/inventory.json +47 -0
- requirements.txt +3 -1
- src/csbot/customer_support_chatbot.py +80 -0
- src/streamlitui/loadui.py +3 -0
- src/tools/customer_support_tools.py +183 -0
- src/vectorstores/vectore_store.py +122 -0
.gitignore
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
__pycache__/configfile.cpython-311.pyc
|
| 3 |
+
*.pyc
|
| 4 |
+
*.sqlite3
|
README.md
CHANGED
|
@@ -16,3 +16,8 @@ short_description: Langgraph
|
|
| 16 |
### 1. Appointment Receptionist
|
| 17 |
reference:
|
| 18 |

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 16 |
### 1. Appointment Receptionist
|
| 17 |
reference:
|
| 18 |

|
| 19 |
+
|
| 20 |
+
### 2. Customer Support
|
| 21 |
+
reference:
|
| 22 |
+

|
| 23 |
+

|
app.py
CHANGED
|
@@ -51,12 +51,66 @@ if __name__ == "__main__":
|
|
| 51 |
with col2:
|
| 52 |
st.header("Appointments")
|
| 53 |
st.write(APPOINTMENTS)
|
| 54 |
-
|
| 55 |
|
| 56 |
-
|
| 57 |
|
| 58 |
-
|
| 59 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 60 |
|
| 61 |
|
| 62 |
|
|
|
|
| 51 |
with col2:
|
| 52 |
st.header("Appointments")
|
| 53 |
st.write(APPOINTMENTS)
|
|
|
|
| 54 |
|
|
|
|
| 55 |
|
| 56 |
+
|
| 57 |
+
elif user_input['selected_usecase'] == "Customer Support":
|
| 58 |
+
from src.csbot.customer_support_chatbot import Customer_Support_Bot
|
| 59 |
+
from langchain_core.messages import AIMessage, HumanMessage
|
| 60 |
+
from src.tools.customer_support_tools import customers_database, data_protection_checks
|
| 61 |
+
|
| 62 |
+
|
| 63 |
+
st.subheader('Flower Shop Chatbot' + '💐')
|
| 64 |
+
|
| 65 |
+
if 'message_history' not in st.session_state:
|
| 66 |
+
st.session_state.message_history = [AIMessage(content="Hiya, Im the flower shop chatbot. How can I help?")]
|
| 67 |
+
|
| 68 |
+
main_col, right_col = st.columns([2, 1])
|
| 69 |
+
|
| 70 |
+
# 1. Buttons for chat - Clear Button
|
| 71 |
+
|
| 72 |
+
with st.sidebar:
|
| 73 |
+
if st.button('Clear Chat'):
|
| 74 |
+
st.session_state.message_history = []
|
| 75 |
+
|
| 76 |
+
|
| 77 |
+
# 2. Chat history and input
|
| 78 |
+
with main_col:
|
| 79 |
+
user_message = st.chat_input("Type here...")
|
| 80 |
+
|
| 81 |
+
if user_message:
|
| 82 |
+
st.session_state.message_history.append(HumanMessage(content=user_message))
|
| 83 |
+
obj_llm_config = GroqLLM(user_controls_input=user_input)
|
| 84 |
+
llm = obj_llm_config.get_llm_model()
|
| 85 |
+
obj_cs_bot = Customer_Support_Bot(llm=llm)
|
| 86 |
+
app = obj_cs_bot.chat_bot()
|
| 87 |
+
|
| 88 |
+
response = app.invoke({
|
| 89 |
+
'messages': st.session_state.message_history
|
| 90 |
+
})
|
| 91 |
+
|
| 92 |
+
st.session_state.message_history = response['messages']
|
| 93 |
+
|
| 94 |
+
for i in range(1, len(st.session_state.message_history) + 1):
|
| 95 |
+
this_message = st.session_state.message_history[-i]
|
| 96 |
+
if isinstance(this_message, AIMessage):
|
| 97 |
+
message_box = st.chat_message('assistant')
|
| 98 |
+
else:
|
| 99 |
+
message_box = st.chat_message('user')
|
| 100 |
+
message_box.markdown(this_message.content)
|
| 101 |
+
# 3. State variables
|
| 102 |
+
|
| 103 |
+
with right_col:
|
| 104 |
+
st.title('customers database')
|
| 105 |
+
st.write(customers_database)
|
| 106 |
+
st.title('data protection checks')
|
| 107 |
+
st.write(data_protection_checks)
|
| 108 |
+
|
| 109 |
+
|
| 110 |
+
|
| 111 |
+
|
| 112 |
+
|
| 113 |
+
|
| 114 |
|
| 115 |
|
| 116 |
|
configfile.ini
CHANGED
|
@@ -1,6 +1,6 @@
|
|
| 1 |
[DEFAULT]
|
| 2 |
PAGE_TITLE = Langgraph IN ACTION
|
| 3 |
LLM_OPTIONS = Groq
|
| 4 |
-
USECASE_OPTIONS = Appointment Receptionist
|
| 5 |
GROQ_MODEL_OPTIONS = mixtral-8x7b-32768, llama3-8b-8192, llama3-70b-8192, gemma-7b-i
|
| 6 |
|
|
|
|
| 1 |
[DEFAULT]
|
| 2 |
PAGE_TITLE = Langgraph IN ACTION
|
| 3 |
LLM_OPTIONS = Groq
|
| 4 |
+
USECASE_OPTIONS = Appointment Receptionist, Customer Support
|
| 5 |
GROQ_MODEL_OPTIONS = mixtral-8x7b-32768, llama3-8b-8192, llama3-70b-8192, gemma-7b-i
|
| 6 |
|
cs-flow.png
ADDED
|
customer_support.png
ADDED
|
data/FAQ.json
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[
|
| 2 |
+
{
|
| 3 |
+
"question": "What types of flowers do you offer?",
|
| 4 |
+
"answer": "We offer a wide variety of flowers including roses, lilies, tulips, sunflowers, orchids, and seasonal bouquets. Our selection changes regularly to ensure freshness and variety."
|
| 5 |
+
},
|
| 6 |
+
{
|
| 7 |
+
"question": "How do I place an order?",
|
| 8 |
+
"answer": "You can place an order easily through our website. Simply browse our selection, choose your desired flowers, add them to your cart, and proceed to checkout. You'll need to provide delivery details and payment information to complete your order."
|
| 9 |
+
},
|
| 10 |
+
{
|
| 11 |
+
"question": "What are your delivery options?",
|
| 12 |
+
"answer": "We offer same-day delivery for orders placed before noon, next-day delivery, and scheduled delivery for future dates. Delivery options may vary based on your location and the availability of the flowers you've selected."
|
| 13 |
+
},
|
| 14 |
+
{
|
| 15 |
+
"question": "Do you offer international shipping?",
|
| 16 |
+
"answer": "Currently, we only offer delivery within the country. We're working on expanding our services internationally in the future."
|
| 17 |
+
},
|
| 18 |
+
{
|
| 19 |
+
"question": "How do I ensure my flowers stay fresh?",
|
| 20 |
+
"answer": "To keep your flowers fresh, change the water every 2-3 days, trim the stems at an angle, remove any leaves below the waterline, and keep the flowers away from direct sunlight and heat sources."
|
| 21 |
+
},
|
| 22 |
+
{
|
| 23 |
+
"question": "Can I customize my bouquet?",
|
| 24 |
+
"answer": "Yes, we offer customization options. You can choose specific flowers, colors, and arrangements. For special requests, please contact our customer service team."
|
| 25 |
+
},
|
| 26 |
+
{
|
| 27 |
+
"question": "What if my flowers arrive damaged?",
|
| 28 |
+
"answer": "We have a 100% satisfaction guarantee. If your flowers arrive damaged or you're not satisfied with your order, please contact us within 24 hours of delivery, and we'll either replace your order or provide a full refund."
|
| 29 |
+
},
|
| 30 |
+
{
|
| 31 |
+
"question": "Do you offer subscription services?",
|
| 32 |
+
"answer": "Yes, we offer weekly, bi-weekly, and monthly flower subscription services. You can choose the frequency, duration, and type of flowers you'd like to receive regularly."
|
| 33 |
+
},
|
| 34 |
+
{
|
| 35 |
+
"question": "What payment methods do you accept?",
|
| 36 |
+
"answer": "We accept all major credit cards, PayPal, and Apple Pay for online orders. For large corporate orders, we also offer invoicing options."
|
| 37 |
+
},
|
| 38 |
+
{
|
| 39 |
+
"question": "Can I include a personalized message with my flower delivery?",
|
| 40 |
+
"answer": "Absolutely! During the checkout process, you'll have the option to add a personalized message card to your order at no extra cost."
|
| 41 |
+
},
|
| 42 |
+
{
|
| 43 |
+
"question": "Do you offer eco-friendly or sustainable options?",
|
| 44 |
+
"answer": "Yes, we have a range of eco-friendly options including locally sourced flowers, biodegradable packaging, and potted plants that can be replanted."
|
| 45 |
+
},
|
| 46 |
+
{
|
| 47 |
+
"question": "What if the recipient isn't home when the flowers are delivered?",
|
| 48 |
+
"answer": "If the recipient isn't home, our delivery person will try to leave the flowers in a safe place. If that's not possible, we'll leave a note and attempt redelivery the next day."
|
| 49 |
+
},
|
| 50 |
+
{
|
| 51 |
+
"question": "Do you offer corporate or event services?",
|
| 52 |
+
"answer": "Yes, we provide flower arrangements for corporate events, weddings, and other special occasions. Please contact our events team for more information and custom quotes."
|
| 53 |
+
},
|
| 54 |
+
{
|
| 55 |
+
"question": "How far in advance should I order for special occasions like Valentine's Day?",
|
| 56 |
+
"answer": "For major holidays like Valentine's Day, Mother's Day, or Christmas, we recommend placing your order at least 1-2 weeks in advance to ensure availability and timely delivery."
|
| 57 |
+
},
|
| 58 |
+
{
|
| 59 |
+
"question": "Can I track my order?",
|
| 60 |
+
"answer": "Yes, once your order is dispatched, you'll receive a tracking number via email that you can use to monitor the status and estimated delivery time of your flowers."
|
| 61 |
+
},
|
| 62 |
+
{
|
| 63 |
+
"question": "Do you offer flower care tips?",
|
| 64 |
+
"answer": "Yes, each bouquet comes with a care instruction card. You can also find detailed flower care guides on our website under the 'Flower Care' section."
|
| 65 |
+
},
|
| 66 |
+
{
|
| 67 |
+
"question": "What if the flowers I want are out of season?",
|
| 68 |
+
"answer": "If certain flowers are out of season, we offer similar alternatives or can create custom arrangements using in-season blooms that match your desired style and color scheme."
|
| 69 |
+
},
|
| 70 |
+
{
|
| 71 |
+
"question": "Do you offer gift options besides flowers?",
|
| 72 |
+
"answer": "Yes, we offer complementary gifts such as chocolates, teddy bears, balloons, and gift baskets that can be added to your flower order or purchased separately."
|
| 73 |
+
},
|
| 74 |
+
{
|
| 75 |
+
"question": "How do I know which flowers are appropriate for different occasions?",
|
| 76 |
+
"answer": "Our website provides guidance on flower meanings and appropriate choices for various occasions. You can also chat with our customer service team for personalized recommendations."
|
| 77 |
+
},
|
| 78 |
+
{
|
| 79 |
+
"question": "What's your return policy?",
|
| 80 |
+
"answer": "Due to the perishable nature of flowers, we don't accept returns. However, if you're unsatisfied with your order, please contact us within 24 hours of delivery, and we'll work to resolve the issue to your satisfaction."
|
| 81 |
+
}
|
| 82 |
+
|
| 83 |
+
]
|
data/inventory.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[
|
| 2 |
+
{"id": "P001", "name": "Romantic Red Rose Bouquet", "quantity": 15, "price": 80, "type": "bouquet", "description": "A medium-sized bouquet of red roses with green foliage, perfect for anniversaries and weddings. This moderately priced bouquet is a classic choice for romantic occasions."},
|
| 3 |
+
{"id": "P002", "name": "Spring Tulip Medley", "quantity": 12, "price": 65, "type": "bouquet", "description": "A medium-sized bouquet featuring a vibrant mix of yellow, pink, purple, and orange tulips, ideal for birthdays. This affordable bouquet brings the freshness of spring to any celebration."},
|
| 4 |
+
{"id": "P003", "name": "Elegant White Lily Arrangement", "quantity": 10, "price": 90, "type": "arrangement", "description": "A large arrangement of white lilies with green accents, suitable for weddings. This premium arrangement adds a touch of elegance to any venue."},
|
| 5 |
+
{"id": "P004", "name": "Vibrant Sunflower Surprise", "quantity": 8, "price": 70, "type": "bouquet", "description": "A medium-sized bouquet of bright yellow sunflowers with brown centers, great for birthdays and congratulations. This reasonably priced bouquet is sure to bring smiles."},
|
| 6 |
+
{"id": "P005", "name": "Pastel Peony Paradise", "quantity": 10, "price": 95, "type": "bouquet", "description": "A large bouquet featuring a soft blend of pink, purple, white, and blue peonies, perfect for Mother's Day. This luxurious bouquet is a stunning gift for any special woman."},
|
| 7 |
+
{"id": "P006", "name": "Exotic Orchid Ensemble", "quantity": 6, "price": 110, "type": "arrangement", "description": "A medium-sized arrangement of purple and black orchids, suitable for corporate events. This high-end arrangement adds a touch of sophistication to any business setting."},
|
| 8 |
+
{"id": "P007", "name": "Wildflower Wonderland Bouquet", "quantity": 14, "price": 75, "type": "bouquet", "description": "A large, colorful bouquet of mixed wildflowers in red, yellow, pink, purple, blue, and orange, ideal for birthdays and thank you gifts. This mid-range bouquet brings a burst of nature's beauty."},
|
| 9 |
+
{"id": "P008", "name": "Classic Carnation Cluster", "quantity": 18, "price": 60, "type": "bouquet", "description": "A medium-sized bouquet of pink and white carnations, perfect for Mother's Day. This budget-friendly bouquet is a timeless gesture of love and appreciation."},
|
| 10 |
+
{"id": "P009", "name": "Deluxe Mixed Bouquet", "quantity": 10, "price": 85, "type": "bouquet", "description": "A large bouquet with a variety of flowers in red, white, yellow, pink, purple, blue, and orange, suitable for general occasions and congratulations. This diverse, moderately priced bouquet is perfect for any celebration."},
|
| 11 |
+
{"id": "P010", "name": "Seasonal Blooms Bonanza", "quantity": 12, "price": 78, "type": "bouquet", "description": "A medium-sized bouquet featuring seasonal flowers in red, yellow, pink, purple, orange, and brown, perfect for any general occasion. This reasonably priced bouquet showcases the best of the season."},
|
| 12 |
+
{"id": "P011", "name": "Crystal Clear Glass Vase", "quantity": 25, "price": 30, "type": "vase", "description": "A small, clear glass vase with subtle blue tints, suitable for various flower arrangements. This affordable vase complements any bouquet or arrangement."},
|
| 13 |
+
{"id": "P012", "name": "Rustic Ceramic Vase", "quantity": 20, "price": 35, "type": "vase", "description": "A medium-sized ceramic vase in earthy brown and black tones, perfect for rustic or natural arrangements. This reasonably priced vase adds a touch of warmth to any display."},
|
| 14 |
+
{"id": "P013", "name": "Modern Metallic Vase", "quantity": 15, "price": 40, "type": "vase", "description": "A medium-sized vase with a sleek white and black metallic finish, ideal for contemporary corporate settings. This mid-range vase is perfect for modern floral designs."},
|
| 15 |
+
{"id": "P014", "name": "Rustic Farmhouse Arrangement", "quantity": 8, "price": 95, "type": "arrangement", "description": "A large arrangement featuring white and green flowers with brown accents in a rustic container, suitable for general and corporate events. This premium arrangement brings a touch of countryside charm."},
|
| 16 |
+
{"id": "P015", "name": "Tropical Paradise Arrangement", "quantity": 6, "price": 120, "type": "arrangement", "description": "A large, exotic arrangement with vibrant orange, pink, green, and blue tropical flowers, perfect for birthdays and congratulations. This high-end arrangement is a stunning centerpiece for any celebration."},
|
| 17 |
+
{"id": "P016", "name": "Zen Garden Succulent Arrangement", "quantity": 10, "price": 85, "type": "arrangement", "description": "A small, tranquil arrangement of various succulents in shades of green, blue, purple, and brown, ideal for corporate or general gifts. This moderately priced arrangement brings a sense of calm to any space."},
|
| 18 |
+
{"id": "P017", "name": "Vintage Teacup Floral Arrangement", "quantity": 12, "price": 55, "type": "arrangement", "description": "A small, charming arrangement of pink, purple, white, and yellow flowers in a vintage teacup, perfect for Mother's Day or as a thank you gift. This affordable arrangement offers a unique and delightful presentation."},
|
| 19 |
+
{"id": "P018", "name": "Modern Monochrome Arrangement", "quantity": 7, "price": 100, "type": "arrangement", "description": "A medium-sized, sleek arrangement featuring white and green flowers with black accents, suitable for corporate events or modern home decor. This premium arrangement adds a touch of sophistication to any setting."},
|
| 20 |
+
{"id": "P019", "name": "Autumn Harvest Bouquet", "quantity": 10, "price": 75, "type": "bouquet", "description": "A medium-sized bouquet with warm orange, red, yellow, and brown flowers, perfect for Thanksgiving or autumn-themed events. This reasonably priced bouquet captures the essence of fall."},
|
| 21 |
+
{"id": "P020", "name": "Winter Wonderland Arrangement", "quantity": 8, "price": 95, "type": "arrangement", "description": "A large arrangement featuring white and blue flowers with silver accents, ideal for Christmas or winter corporate events. This premium arrangement brings a touch of frosty elegance to any space."},
|
| 22 |
+
{"id": "P021", "name": "Spring Awakening Bouquet", "quantity": 12, "price": 70, "type": "bouquet", "description": "A medium-sized bouquet with fresh pink, yellow, purple, and green spring flowers, suitable for Easter or spring birthdays. This affordable bouquet is a burst of springtime joy."},
|
| 23 |
+
{"id": "P022", "name": "Summer Sunset Arrangement", "quantity": 9, "price": 85, "type": "arrangement", "description": "A large arrangement with warm orange, red, yellow, and pink flowers reminiscent of a summer sunset, perfect for anniversaries and summer weddings. This moderately priced arrangement captures the warmth of summer evenings."},
|
| 24 |
+
{"id": "P023", "name": "Zen Bamboo Arrangement", "quantity": 15, "price": 65, "type": "arrangement", "description": "A small, minimalist arrangement featuring green bamboo and white accents, ideal for corporate settings or as a general gift. This affordable arrangement brings a sense of peace and tranquility."},
|
| 25 |
+
{"id": "P024", "name": "Lavender Dreams Bouquet", "quantity": 11, "price": 72, "type": "bouquet", "description": "A medium-sized bouquet of fragrant purple lavender with white and green accents, perfect for Mother's Day or as a thank you gift. This reasonably priced bouquet offers a soothing and aromatic experience."},
|
| 26 |
+
{"id": "P025", "name": "Citrus Burst Arrangement", "quantity": 7, "price": 88, "type": "arrangement", "description": "A medium-sized arrangement featuring bright orange, yellow, and green flowers, ideal for birthdays or congratulatory occasions. This moderately priced arrangement adds a zesty pop of color to any celebration."},
|
| 27 |
+
{"id": "P026", "name": "Midnight Mystery Bouquet", "quantity": 6, "price": 105, "type": "bouquet", "description": "A large, dramatic bouquet with deep purple, black, and dark red flowers, perfect for Halloween or romantic anniversaries. This premium bouquet offers a bold and mysterious aesthetic."},
|
| 28 |
+
{"id": "P027", "name": "Cherry Blossom Delight", "quantity": 10, "price": 92, "type": "arrangement", "description": "A medium-sized arrangement featuring delicate pink and white cherry blossoms, ideal for weddings or Mother's Day. This moderately priced arrangement brings the beauty of spring to any occasion."},
|
| 29 |
+
{"id": "P028", "name": "Ocean Breeze Bouquet", "quantity": 13, "price": 78, "type": "bouquet", "description": "A medium-sized bouquet with blue, white, and green flowers reminiscent of the sea, perfect for birthdays or as a thank you gift. This reasonably priced bouquet offers a refreshing coastal vibe."},
|
| 30 |
+
{"id": "P029", "name": "Rustic Wildflower Basket", "quantity": 9, "price": 68, "type": "arrangement", "description": "A medium-sized basket filled with a colorful mix of wildflowers, ideal for housewarming gifts or general occasions. This affordable arrangement brings a touch of countryside charm to any home."},
|
| 31 |
+
{"id": "P030", "name": "Elegant Black and White Arrangement", "quantity": 7, "price": 110, "type": "arrangement", "description": "A large, sophisticated arrangement featuring black and white flowers, perfect for corporate events or formal weddings. This premium arrangement offers a timeless and luxurious aesthetic."},
|
| 32 |
+
{"id": "P031", "name": "Sunshine Daisy Bouquet", "quantity": 14, "price": 60, "type": "bouquet", "description": "A small, cheerful bouquet of yellow and white daisies, great for get well wishes or birthdays. This budget-friendly bouquet is sure to brighten anyone's day."},
|
| 33 |
+
{"id": "P032", "name": "Royal Purple Passion", "quantity": 8, "price": 98, "type": "arrangement", "description": "A large arrangement featuring rich purple flowers with silver accents, suitable for anniversaries or upscale corporate events. This premium arrangement exudes luxury and sophistication."},
|
| 34 |
+
{"id": "P033", "name": "Enchanted Forest Terrarium", "quantity": 5, "price": 120, "type": "arrangement", "description": "A small, whimsical terrarium with miniature plants in shades of green and brown, perfect for housewarming or unique birthday gifts. This high-end arrangement offers a magical miniature world."},
|
| 35 |
+
{"id": "P034", "name": "Candy Cane Christmas Bouquet", "quantity": 12, "price": 82, "type": "bouquet", "description": "A medium-sized bouquet with red and white flowers arranged to resemble candy canes, ideal for Christmas or winter corporate events. This moderately priced bouquet brings festive cheer to any space."},
|
| 36 |
+
{"id": "P035", "name": "Peacock Feather Flair", "quantity": 6, "price": 115, "type": "arrangement", "description": "A large, exotic arrangement featuring flowers in peacock-inspired colors of blue, green, and purple, perfect for weddings or high-end corporate events. This premium arrangement offers a stunning and unique display."},
|
| 37 |
+
{"id": "P036", "name": "Pastel Rainbow Bouquet", "quantity": 10, "price": 75, "type": "bouquet", "description": "A medium-sized bouquet featuring a soft rainbow of pastel-colored flowers, ideal for birthdays or baby showers. This reasonably priced bouquet offers a gentle and dreamy aesthetic."},
|
| 38 |
+
{"id": "P037", "name": "Succulent Garden Bowl", "quantity": 15, "price": 65, "type": "arrangement", "description": "A small bowl filled with a variety of green, blue, and pink succulents, perfect for housewarming gifts or corporate desks. This affordable arrangement is low-maintenance and long-lasting."},
|
| 39 |
+
{"id": "P038", "name": "Moonlight Serenade Bouquet", "quantity": 7, "price": 95, "type": "bouquet", "description": "A medium-sized bouquet of white flowers with silver accents, ideal for anniversaries or Valentine's Day. This premium bouquet offers an elegant and romantic gesture."},
|
| 40 |
+
{"id": "P039", "name": "Tropical Tiki Arrangement", "quantity": 8, "price": 108, "type": "arrangement", "description": "A large, vibrant arrangement featuring tropical flowers in orange, pink, yellow, and green, perfect for summer parties or tropical-themed birthdays. This high-end arrangement brings an exotic paradise to any event."},
|
| 41 |
+
{"id": "P040", "name": "English Cottage Garden Bouquet", "quantity": 11, "price": 88, "type": "bouquet", "description": "A large, romantic bouquet with a mix of pink, purple, white, and yellow flowers reminiscent of an English garden, ideal for Mother's Day or as a thank you gift. This moderately priced bouquet offers a charming and nostalgic touch."},
|
| 42 |
+
{"id": "P041", "name": "Desert Oasis Cactus Arrangement", "quantity": 9, "price": 72, "type": "arrangement", "description": "A small arrangement featuring various green cacti and succulents with sandy brown accents, perfect for housewarming or corporate gifts. This affordable arrangement brings a touch of the desert to any space."},
|
| 43 |
+
{"id": "P042", "name": "Fire and Ice Rose Duo", "quantity": 13, "price": 85, "type": "bouquet", "description": "A medium-sized bouquet featuring a striking combination of red and white roses, ideal for anniversaries or Valentine's Day. This moderately priced bouquet offers a classic and passionate statement."},
|
| 44 |
+
{"id": "P043", "name": "Butterfly Garden Delight", "quantity": 10, "price": 79, "type": "arrangement", "description": "A medium-sized arrangement with pink, purple, and yellow flowers that attract butterflies, perfect for spring events or Mother's Day. This reasonably priced arrangement brings the beauty of a butterfly garden indoors."},
|
| 45 |
+
{"id": "P044", "name": "Zen Stone and Orchid Display", "quantity": 6, "price": 118, "type": "arrangement", "description": "A small, minimalist arrangement featuring white orchids and black stones, suitable for corporate settings or modern home decor. This premium arrangement offers a sleek and calming presence."},
|
| 46 |
+
{"id": "P045", "name": "Fairy Tale Princess Bouquet", "quantity": 8, "price": 92, "type": "bouquet", "description": "A medium-sized bouquet with soft pink, white, and purple flowers fit for a princess, perfect for birthdays or graduations. This moderately priced bouquet brings a touch of magic to any celebration."}
|
| 47 |
+
]
|
requirements.txt
CHANGED
|
@@ -4,4 +4,6 @@ langgraph
|
|
| 4 |
langchain_community
|
| 5 |
langchain_openai
|
| 6 |
langchain_core
|
| 7 |
-
langchain_groq
|
|
|
|
|
|
|
|
|
| 4 |
langchain_community
|
| 5 |
langchain_openai
|
| 6 |
langchain_core
|
| 7 |
+
langchain_groq
|
| 8 |
+
chromadb
|
| 9 |
+
llama-index-embeddings-huggingface
|
src/csbot/customer_support_chatbot.py
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from langgraph.graph import StateGraph, MessagesState
|
| 2 |
+
from langchain_core.prompts import ChatPromptTemplate
|
| 3 |
+
from langgraph.prebuilt import ToolNode
|
| 4 |
+
from src.tools.customer_support_tools import query_knowledge_base, search_for_product_reccommendations, data_protection_check, create_new_customer, place_order, retrieve_existing_customer_orders
|
| 5 |
+
|
| 6 |
+
import os
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
class Customer_Support_Bot:
|
| 10 |
+
def __init__(self,llm):
|
| 11 |
+
self.llm = llm
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
def chat_bot(self):
|
| 15 |
+
|
| 16 |
+
prompt = """#Purpose
|
| 17 |
+
|
| 18 |
+
You are a customer service chatbot for a flower shop company. You can help the customer achieve the goals listed below.
|
| 19 |
+
|
| 20 |
+
#Goals
|
| 21 |
+
|
| 22 |
+
1. Answer questions the user might have relating to serivces offered
|
| 23 |
+
2. Recommend products to the user based on their preferences
|
| 24 |
+
3. Help the customer check on an existing order, or place a new order
|
| 25 |
+
4. To place and manage orders, you will need a customer profile (with an associated id). If the customer already has a profile, perform a data protection check to retrieve their details. If not, create them a profile.
|
| 26 |
+
|
| 27 |
+
#Tone
|
| 28 |
+
|
| 29 |
+
Helpful and friendly. Use gen-z emojis to keep things lighthearted. You MUST always include a funny flower related pun in every response."""
|
| 30 |
+
|
| 31 |
+
chat_template = ChatPromptTemplate.from_messages(
|
| 32 |
+
[
|
| 33 |
+
('system', prompt),
|
| 34 |
+
('placeholder', "{messages}")
|
| 35 |
+
]
|
| 36 |
+
)
|
| 37 |
+
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
tools = [query_knowledge_base, search_for_product_reccommendations, data_protection_check, create_new_customer, place_order, retrieve_existing_customer_orders]
|
| 41 |
+
|
| 42 |
+
llm = self.llm
|
| 43 |
+
|
| 44 |
+
llm_with_prompt = chat_template | llm.bind_tools(tools)
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
def call_agent(message_state: MessagesState):
|
| 48 |
+
|
| 49 |
+
response = llm_with_prompt.invoke(message_state)
|
| 50 |
+
|
| 51 |
+
return {
|
| 52 |
+
'messages': [response]
|
| 53 |
+
}
|
| 54 |
+
|
| 55 |
+
def is_there_tool_calls(state: MessagesState):
|
| 56 |
+
last_message = state['messages'][-1]
|
| 57 |
+
if last_message.tool_calls:
|
| 58 |
+
return 'tool_node'
|
| 59 |
+
else:
|
| 60 |
+
return '__end__'
|
| 61 |
+
|
| 62 |
+
|
| 63 |
+
graph = StateGraph(MessagesState)
|
| 64 |
+
|
| 65 |
+
tool_node = ToolNode(tools)
|
| 66 |
+
|
| 67 |
+
graph.add_node('agent', call_agent)
|
| 68 |
+
graph.add_node('tool_node', tool_node)
|
| 69 |
+
|
| 70 |
+
graph.add_conditional_edges(
|
| 71 |
+
"agent",
|
| 72 |
+
is_there_tool_calls
|
| 73 |
+
)
|
| 74 |
+
graph.add_edge('tool_node', 'agent')
|
| 75 |
+
|
| 76 |
+
graph.set_entry_point('agent')
|
| 77 |
+
|
| 78 |
+
app = graph.compile()
|
| 79 |
+
return app
|
| 80 |
+
|
src/streamlitui/loadui.py
CHANGED
|
@@ -51,5 +51,8 @@ class LoadStreamlitUI:
|
|
| 51 |
|
| 52 |
with col2:
|
| 53 |
st.subheader("Appointments")
|
|
|
|
|
|
|
|
|
|
| 54 |
|
| 55 |
return self.user_controls
|
|
|
|
| 51 |
|
| 52 |
with col2:
|
| 53 |
st.subheader("Appointments")
|
| 54 |
+
|
| 55 |
+
elif self.user_controls['selected_usecase']=="Custome Support":
|
| 56 |
+
st.set_page_config(layout='wide', page_title='Flower Shop Chatbot', page_icon='💐')
|
| 57 |
|
| 58 |
return self.user_controls
|
src/tools/customer_support_tools.py
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from langchain_core.tools import tool
|
| 2 |
+
from typing import List, Dict
|
| 3 |
+
from src.vectorstores.vectore_store import FlowerShopVectorStore
|
| 4 |
+
import json
|
| 5 |
+
|
| 6 |
+
vector_store = FlowerShopVectorStore()
|
| 7 |
+
INVENTORY_FILE_PATH = './data/inventory.json'
|
| 8 |
+
|
| 9 |
+
customers_database = [
|
| 10 |
+
{"name": "John Doe", "postcode": "SW1A 1AA", "dob": "1990-01-01", "customer_id": "CUST001", "first_line_address": "123 Main St", "phone_number": "07712345678", "email": "john.doe@example.com"},
|
| 11 |
+
{"name": "Jane Smith", "postcode": "E1 6AN", "dob": "1985-05-15", "customer_id": "CUST002", "first_line_address": "456 High St", "phone_number": "07723456789", "email": "jane.smith@example.com"},
|
| 12 |
+
]
|
| 13 |
+
|
| 14 |
+
orders_database = [
|
| 15 |
+
{"order_id": "ORD001", "customer_id": "CUST001", "status": "Processing", "items": ["Red Roses Bouquet"], "quantity": [1]},
|
| 16 |
+
{"order_id": "ORD002", "customer_id": "CUST002", "status": "Shipped", "items": ["Mixed Tulips", "Vase"], "quantity": [3, 1]},
|
| 17 |
+
]
|
| 18 |
+
|
| 19 |
+
with open(INVENTORY_FILE_PATH, 'r') as f:
|
| 20 |
+
inventory_database = json.load(f)
|
| 21 |
+
|
| 22 |
+
data_protection_checks = []
|
| 23 |
+
|
| 24 |
+
@tool
|
| 25 |
+
def data_protection_check(name: str, postcode: str, year_of_birth: int, month_of_birth: int, day_of_birth: int) -> Dict:
|
| 26 |
+
"""
|
| 27 |
+
Perform a data protection check against a customer to retrieve customer details.
|
| 28 |
+
|
| 29 |
+
Args:
|
| 30 |
+
name (str): Customer first and last name
|
| 31 |
+
postcode (str): Customer registered address
|
| 32 |
+
year_of_birth (int): The year the customer was born
|
| 33 |
+
month_of_birth (int): The month the customer was born
|
| 34 |
+
day_of_birth (int): The day the customer was born
|
| 35 |
+
|
| 36 |
+
Returns:
|
| 37 |
+
Dict: Customer details (name, postcode, dob, customer_id, first_line_address, email)
|
| 38 |
+
"""
|
| 39 |
+
data_protection_checks.append(
|
| 40 |
+
{
|
| 41 |
+
'name': name,
|
| 42 |
+
'postcode': postcode,
|
| 43 |
+
'year_of_birth': year_of_birth,
|
| 44 |
+
'month_of_birth': month_of_birth,
|
| 45 |
+
'day_of_birth': day_of_birth
|
| 46 |
+
}
|
| 47 |
+
)
|
| 48 |
+
for customer in customers_database:
|
| 49 |
+
if (customer['name'].lower() == name.lower() and
|
| 50 |
+
customer['postcode'].lower() == postcode.lower() and
|
| 51 |
+
int(customer['dob'][0:4]) == year_of_birth and
|
| 52 |
+
int(customer["dob"][5:7]) == month_of_birth and
|
| 53 |
+
int(customer["dob"][8:10]) == day_of_birth):
|
| 54 |
+
return f"DPA check passed - Retrieved customer details:\n{customer}"
|
| 55 |
+
|
| 56 |
+
return "DPA check failed, no customer with these details found"
|
| 57 |
+
|
| 58 |
+
@tool
|
| 59 |
+
def create_new_customer(first_name: str, surname: str, year_of_birth: int, month_of_birth: int, day_of_birth: int, postcode: str, first_line_of_address: str, phone_number: str, email: str) -> str:
|
| 60 |
+
"""
|
| 61 |
+
Creates a customer profile, so that they can place orders.
|
| 62 |
+
|
| 63 |
+
Args:
|
| 64 |
+
first_name (str): Customers first name
|
| 65 |
+
surname (str): Customers surname
|
| 66 |
+
year_of_birth (int): Year customer was born
|
| 67 |
+
month_of_birth (int): Month customer was born
|
| 68 |
+
day_of_birth (int): Day customer was born
|
| 69 |
+
postcode (str): Customer's postcode
|
| 70 |
+
first_line_address (str): Customer's first line of address
|
| 71 |
+
phone_number (str): Customer's phone number
|
| 72 |
+
email (str): Customer's email address
|
| 73 |
+
|
| 74 |
+
Returns:
|
| 75 |
+
str: Confirmation that the profile has been created or any issues with the inputs
|
| 76 |
+
"""
|
| 77 |
+
if len(phone_number) != 11:
|
| 78 |
+
return "Phone number must be 11 digits"
|
| 79 |
+
customer_id = len(customers_database) + 1
|
| 80 |
+
customers_database.append({
|
| 81 |
+
'name': first_name + ' ' + surname,
|
| 82 |
+
'dob': f'{year_of_birth}-{month_of_birth:02}-{day_of_birth:02}',
|
| 83 |
+
'postcode': postcode,
|
| 84 |
+
'first_line_address': first_line_of_address,
|
| 85 |
+
'phone_number': phone_number,
|
| 86 |
+
'email': email,
|
| 87 |
+
'customer_id': f'CUST{customer_id}'
|
| 88 |
+
})
|
| 89 |
+
return f"Customer registered, with customer_id {f'CUST{customer_id}'}"
|
| 90 |
+
|
| 91 |
+
|
| 92 |
+
@tool
|
| 93 |
+
def query_knowledge_base(query: str) -> List[Dict[str, str]]:
|
| 94 |
+
"""
|
| 95 |
+
Looks up information in a knowledge base to help with answering customer questions and getting information on business processes.
|
| 96 |
+
|
| 97 |
+
Args:
|
| 98 |
+
query (str): Question to ask the knowledge base
|
| 99 |
+
|
| 100 |
+
Return:
|
| 101 |
+
List[Dict[str, str]]: Potentially relevant question and answer pairs from the knowledge base
|
| 102 |
+
"""
|
| 103 |
+
return vector_store.query_faqs(query=query)
|
| 104 |
+
|
| 105 |
+
|
| 106 |
+
|
| 107 |
+
@tool
|
| 108 |
+
def search_for_product_reccommendations(description: str):
|
| 109 |
+
"""
|
| 110 |
+
Looks up information in a knowledge base to help with product recommendation for customers. For example:
|
| 111 |
+
|
| 112 |
+
"Boquets suitable for birthdays, maybe with red flowers"
|
| 113 |
+
"A large boquet for a wedding"
|
| 114 |
+
"A cheap boquet with wildflowers"
|
| 115 |
+
|
| 116 |
+
Args:
|
| 117 |
+
query (str): Description of product features
|
| 118 |
+
|
| 119 |
+
Return:
|
| 120 |
+
List[Dict[str, str]]: Potentially relevant products
|
| 121 |
+
"""
|
| 122 |
+
return vector_store.query_inventories(query=description)
|
| 123 |
+
|
| 124 |
+
@tool
|
| 125 |
+
def retrieve_existing_customer_orders(customer_id: str) -> List[Dict]:
|
| 126 |
+
"""
|
| 127 |
+
Retrieves the orders associated with the customer, including their status, items and ids
|
| 128 |
+
|
| 129 |
+
Args:
|
| 130 |
+
customer_id (str): Customer unique id associated with the order
|
| 131 |
+
|
| 132 |
+
Returns:
|
| 133 |
+
List[Dict]: All the orders associated with the customer_id passed in
|
| 134 |
+
"""
|
| 135 |
+
customer_orders = [order for order in orders_database if order['customer_id'] == customer_id]
|
| 136 |
+
if not customer_orders:
|
| 137 |
+
return f"No orders associated with this customer id: {customer_id}"
|
| 138 |
+
return customer_orders
|
| 139 |
+
|
| 140 |
+
@tool
|
| 141 |
+
def place_order(items: Dict[str, int], customer_id: str) -> str:
|
| 142 |
+
"""
|
| 143 |
+
Places an order for the requested items, and for the required quantities.
|
| 144 |
+
|
| 145 |
+
Args:
|
| 146 |
+
items (Dict[str, int]): Dictionary of items to order, with item id as the key and the quantity of that item as the value.
|
| 147 |
+
customer_id (str): The customer to place the order for
|
| 148 |
+
|
| 149 |
+
Returns:
|
| 150 |
+
str: Message indicating that the order has been placed, or, it hasnt been placed due to an issue
|
| 151 |
+
"""
|
| 152 |
+
# Check that the item ids are valid
|
| 153 |
+
# Check that the quantities of items are valid
|
| 154 |
+
availability_messages = []
|
| 155 |
+
valid_item_ids = [
|
| 156 |
+
item['id'] for item in inventory_database
|
| 157 |
+
]
|
| 158 |
+
for item_id, quantity in items.items():
|
| 159 |
+
if item_id not in valid_item_ids:
|
| 160 |
+
availability_messages.append(f'Item with id {item_id} is not found in the inventory')
|
| 161 |
+
else:
|
| 162 |
+
inventory_item = [item for item in inventory_database if item['id'] == item_id][0]
|
| 163 |
+
if quantity > inventory_item['quantity']:
|
| 164 |
+
availability_messages.append(f'There is insufficient quantity in the inventory for this item {inventory_item["name"]}\nAvailable: {inventory_item["quantity"]}\nRequested: {quantity}')
|
| 165 |
+
if availability_messages:
|
| 166 |
+
return "Order cannot be placed due to the following issues: \n" + '\n'.join(availability_messages)
|
| 167 |
+
|
| 168 |
+
# Place the order (in pretend database)
|
| 169 |
+
order_id = len(orders_database) + 1
|
| 170 |
+
orders_database.append(
|
| 171 |
+
{
|
| 172 |
+
'order_id': order_id,
|
| 173 |
+
'customer_id': customer_id,
|
| 174 |
+
'status': 'Waiting for payment',
|
| 175 |
+
'items': list(items.keys()),
|
| 176 |
+
'quantity': list(items.values())
|
| 177 |
+
}
|
| 178 |
+
)
|
| 179 |
+
# Update the inventory
|
| 180 |
+
for item_id, quantity in items.items():
|
| 181 |
+
inventory_item = [item for item in inventory_database if item['id'] == item_id][0]
|
| 182 |
+
inventory_item['quantity'] -= quantity
|
| 183 |
+
return f"Order with id {order_id} has been placed successfully"
|
src/vectorstores/vectore_store.py
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from chromadb import PersistentClient, EmbeddingFunction, Embeddings
|
| 2 |
+
from llama_index.embeddings.huggingface import HuggingFaceEmbedding
|
| 3 |
+
from typing import List
|
| 4 |
+
import json
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
MODEL_NAME = 'dunzhang/stella_en_1.5B_v5'
|
| 8 |
+
DB_PATH = './.chroma_db'
|
| 9 |
+
FAQ_FILE_PATH= './data/FAQ.json'
|
| 10 |
+
INVENTORY_FILE_PATH = './data/inventory.json'
|
| 11 |
+
|
| 12 |
+
class Product:
|
| 13 |
+
def __init__(self, name: str, id: str, description: str, type: str, price: float, quantity: int):
|
| 14 |
+
self.name = name
|
| 15 |
+
self.id = id
|
| 16 |
+
self.description = description
|
| 17 |
+
self.type = type
|
| 18 |
+
self.price = price
|
| 19 |
+
self.quantity = quantity
|
| 20 |
+
|
| 21 |
+
class QuestionAnswerPairs:
|
| 22 |
+
def __init__(self, question: str, answer: str):
|
| 23 |
+
self.question = question
|
| 24 |
+
self.answer = answer
|
| 25 |
+
|
| 26 |
+
class CustomEmbeddingClass(EmbeddingFunction):
|
| 27 |
+
def __init__(self, model_name):
|
| 28 |
+
self.embedding_model = HuggingFaceEmbedding(model_name=MODEL_NAME)
|
| 29 |
+
|
| 30 |
+
def __call__(self, input_texts: List[str]) -> Embeddings:
|
| 31 |
+
return [self.embedding_model.get_text_embedding(text) for text in input_texts]
|
| 32 |
+
|
| 33 |
+
class FAQCollection:
|
| 34 |
+
def __init__(self):
|
| 35 |
+
self.documents = []
|
| 36 |
+
self.ids = []
|
| 37 |
+
self.metadatas = []
|
| 38 |
+
|
| 39 |
+
def add(self, documents, ids, metadatas):
|
| 40 |
+
self.documents.extend(documents)
|
| 41 |
+
self.ids.extend(ids)
|
| 42 |
+
self.metadatas.extend(metadatas)
|
| 43 |
+
|
| 44 |
+
def display(self):
|
| 45 |
+
for doc, id_, meta in zip(self.documents, self.ids, self.metadatas):
|
| 46 |
+
print(f"ID: {id_}, Document: {doc}, Metadata: {meta}")
|
| 47 |
+
|
| 48 |
+
# Define the InventoryCollection class
|
| 49 |
+
class InventoryCollection:
|
| 50 |
+
def __init__(self):
|
| 51 |
+
self.documents = []
|
| 52 |
+
self.ids = []
|
| 53 |
+
self.metadatas = []
|
| 54 |
+
|
| 55 |
+
def add(self, documents, ids, metadatas):
|
| 56 |
+
self.documents.extend(documents)
|
| 57 |
+
self.ids.extend(ids)
|
| 58 |
+
self.metadatas.extend(metadatas)
|
| 59 |
+
|
| 60 |
+
def display(self):
|
| 61 |
+
for doc, id_, meta in zip(self.documents, self.ids, self.metadatas):
|
| 62 |
+
print(f"ID: {id_}, Document: {doc}, Metadata: {meta}")
|
| 63 |
+
|
| 64 |
+
|
| 65 |
+
|
| 66 |
+
|
| 67 |
+
class FlowerShopVectorStore:
|
| 68 |
+
def __init__(self):
|
| 69 |
+
db = PersistentClient(path=DB_PATH)
|
| 70 |
+
|
| 71 |
+
custom_embedding_function = CustomEmbeddingClass(MODEL_NAME)
|
| 72 |
+
|
| 73 |
+
self.faq_collection = db.get_or_create_collection(name='FAQ', embedding_function=custom_embedding_function)
|
| 74 |
+
self.inventory_collection = db.get_or_create_collection(name='Inventory', embedding_function=custom_embedding_function)
|
| 75 |
+
|
| 76 |
+
if self.faq_collection.count() == 0:
|
| 77 |
+
try :
|
| 78 |
+
self._load_faq_collection(FAQ_FILE_PATH)
|
| 79 |
+
except Exception as e:
|
| 80 |
+
raise ValueError(e)
|
| 81 |
+
|
| 82 |
+
|
| 83 |
+
if self.inventory_collection.count() == 0:
|
| 84 |
+
self._load_inventory_collection(INVENTORY_FILE_PATH)
|
| 85 |
+
|
| 86 |
+
def _load_faq_collection(self, faq_file_path: str):
|
| 87 |
+
try:
|
| 88 |
+
|
| 89 |
+
with open(faq_file_path, 'r') as f:
|
| 90 |
+
faqs = json.load(f)
|
| 91 |
+
|
| 92 |
+
# Create an instance of FAQCollection
|
| 93 |
+
obj_faq_collection = FAQCollection()
|
| 94 |
+
|
| 95 |
+
obj_faq_collection.add(
|
| 96 |
+
documents=[faq['question'] for faq in faqs] + [faq['answer'] for faq in faqs],
|
| 97 |
+
ids=[str(i) for i in range(0, 2*len(faqs))],
|
| 98 |
+
metadatas = faqs + faqs
|
| 99 |
+
)
|
| 100 |
+
self.faq_collection = obj_faq_collection
|
| 101 |
+
except Exception as ex:
|
| 102 |
+
raise ValueError(ex)
|
| 103 |
+
|
| 104 |
+
def _load_inventory_collection(self, inventory_file_path: str):
|
| 105 |
+
with open(inventory_file_path, 'r') as f:
|
| 106 |
+
inventories = json.load(f)
|
| 107 |
+
|
| 108 |
+
# Create an instance of InventoryCollection
|
| 109 |
+
obj_inventory_collection = InventoryCollection()
|
| 110 |
+
|
| 111 |
+
obj_inventory_collection.add(
|
| 112 |
+
documents=[inventory['description'] for inventory in inventories],
|
| 113 |
+
ids=[str(i) for i in range(0, len(inventories))],
|
| 114 |
+
metadatas = inventories
|
| 115 |
+
)
|
| 116 |
+
self.inventory_collection = obj_inventory_collection
|
| 117 |
+
|
| 118 |
+
def query_faqs(self, query: str):
|
| 119 |
+
return self.faq_collection.query(query_texts=[query], n_results=5)
|
| 120 |
+
|
| 121 |
+
def query_inventories(self, query: str):
|
| 122 |
+
return self.inventory_collection.query(query_texts=[query], n_results=5)
|