diff --git a/README.md b/README.md deleted file mode 100644 index 59c4d60..0000000 --- a/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# OllyMate -K-Cosmetics Oliveyoung Chatbot diff --git a/main.py b/main.py new file mode 100644 index 0000000..84d80c4 --- /dev/null +++ b/main.py @@ -0,0 +1,220 @@ +import streamlit as st + +from search_db import search_db +from chatbot import chatbot_response +import webbrowser + +with st.sidebar: + # Streamlit UI ๊ตฌ์„ฑ + st.title("๐Ÿ’ฌ ๋งž์ถคํ˜• ํ™”์žฅํ’ˆ ์ถ”์ฒœ ์ฑ—๋ด‡") + st.write( + "ํ”ผ๋ถ€ ํƒ€์ž…๊ณผ ๊ณ ๋ฏผ, ์›ํ•˜๋Š” ๊ธฐ๋Šฅ๊ณผ ์ œํ˜•์„ ์„ ํƒํ•˜๋ฉด ์ฑ—๋ด‡์ด ์ œํ’ˆ์„ ์ถ”์ฒœํ•ด์ค๋‹ˆ๋‹ค. ์ถ”๊ฐ€๋กœ ๊ถ๊ธˆํ•œ ์ ์„ ๋ฌผ์–ด๋ณด์„ธ์š”!" + ) + + # ์ฑ—๋ด‡ ์ดˆ๊ธฐํ™” + if "chat_history" not in st.session_state: + st.session_state.chat_history = [] + + # ์‚ฌ์šฉ์ž ์ž…๋ ฅ + with st.form(key="recommendation_form"): + skin_type = st.selectbox( + "ํ”ผ๋ถ€ ํƒ€์ž…์„ ์„ ํƒํ•˜์„ธ์š”:", + ("๊ฑด์„ฑ", "์ง€์„ฑ", "๋ณตํ•ฉ์„ฑ", "๋ฏผ๊ฐ์„ฑ", "์•…๊ฑด์„ฑ", "ํŠธ๋Ÿฌ๋ธ”์„ฑ", "์ค‘์„ฑ"), + index=None, + placeholder="ํ”ผ๋ถ€ ํƒ€์ž…" + ) + skin_tone = st.selectbox( + "ํ”ผ๋ถ€ ํ†ค์„ ์„ ํƒํ•˜์„ธ์š”:", + ("์ฟจํ†ค", "์›œํ†ค", "๋ด„์›œํ†ค", "์—ฌ๋ฆ„์ฟจํ†ค", "๊ฐ€์„์›œํ†ค", "๊ฒจ์šธ์ฟจํ†ค"), + index=None, + placeholder="ํ”ผ๋ถ€ํ†ค" + ) + skin_concern = st.multiselect( + "ํ”ผ๋ถ€ ๊ณ ๋ฏผ์„ ์„ ํƒํ•˜์„ธ์š”:", + [ + "์žกํ‹ฐ", + "์ฃผ๋ฆ„", + "๋ฏธ๋ฐฑ", + "๊ฐ์งˆ", + "ํŠธ๋Ÿฌ๋ธ”", + "๋ธ”๋ž™ํ—ค๋“œ", + "ํ”ผ์ง€๊ณผ๋‹ค", + "๋ฏผ๊ฐ์„ฑ", + "๋ชจ๊ณต", + "ํƒ„๋ ฅ", + "ํ™์กฐ", + "์•„ํ† ํ”ผ", + "๋‹คํฌ์„œํด", + ], + placeholder="ํ”ผ๋ถ€ ๊ณ ๋ฏผ" + ) + product_function = st.selectbox( + "์›ํ•˜๋Š” ํ™”์žฅํ’ˆ ๊ธฐ๋Šฅ์„ ์„ ํƒํ•˜์„ธ์š”:", ("์ˆ˜๋ถ„", "์ง„์ •", "๋ฏธ๋ฐฑ", "ํƒ„๋ ฅ"), + index=None, + placeholder="๊ธฐ๋Šฅ" + ) + product_texture = st.selectbox( + "์›ํ•˜๋Š” ์ œํ˜•์„ ์„ ํƒํ•˜์„ธ์š”:", ("๊ฐ€๋ฒผ์šด ์ œํ˜•", "๋ฌด๊ฑฐ์šด ์ œํ˜•"), + index=None, + placeholder="์ œํ˜•" + ) + category = st.selectbox( + "์›ํ•˜๋Š” ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ ์„ ํƒํ•˜์„ธ์š”:", ("์Šคํ‚จ/ํ† ๋„ˆ", "์—์„ผ์Šค/์„ธ๋Ÿผ/์•ฐํ”Œ", "ํฌ๋ฆผ", "๋กœ์…˜", "๋ฏธ์ŠคํŠธ/์˜ค์ผ"), + index=None, + placeholder="์นดํ…Œ๊ณ ๋ฆฌ" + ) + pricerange = st.selectbox( + "์›ํ•˜๋Š” ๊ฐ€๊ฒฉ๋Œ€๋ฅผ ์„ ํƒํ•˜์„ธ์š”:", ("~2๋งŒ์›", "2๋งŒ์›~3๋งŒ์›", "3๋งŒ์›~5๋งŒ์›", "5๋งŒ์›~"), + index=None, + placeholder="๊ฐ€๊ฒฉ๋Œ€" + ) + + user_data = { + "skintype": skin_type, + "skintone": skin_tone, + "skinconcerns": " ".join(skin_concern), + "function": product_function, + "formulation": product_texture, + "category": category, + "pricerange": pricerange, + } + + st.write(user_data) + + # ์ถ”์ฒœ ๋ฒ„ํŠผ + recommand_button = st.form_submit_button("์ถ”์ฒœ๋ฐ›๊ธฐ") + if recommand_button: + # ๋ชจ๋“  ์„ ํƒ์ง€๊ฐ€ ์„ค์ •๋˜์—ˆ๋Š”์ง€ ํ™•์ธ + if not all( + [ + user_data["formulation"], # ์ œํ˜• + user_data["function"], # ๊ธฐ๋Šฅ + user_data["skinconcerns"], # ํ”ผ๋ถ€ ๊ณ ๋ฏผ + user_data["skintone"], # ํ”ผ๋ถ€ ํ†ค + user_data["skintype"], # ํ”ผ๋ถ€ ํƒ€์ž… + user_data['category'], # ์นดํ…Œ๊ณ ๋ฆฌ + user_data['pricerange'] # ๊ฐ€๊ฒฉ๋Œ€ + ] + ): + st.error("๋ชจ๋“  ์„ ํƒ์ง€๋ฅผ ์„ค์ •ํ•œ ํ›„ ๋‹ค์‹œ ์‹œ๋„ํ•ด์ฃผ์„ธ์š”!") + + +recommand_list = [ + ('A000000186465', 1.0), + ('A000000155321', 1.0), + ('A000000155320', 1.0), + ('A000000211127', 1.0), + ('A000000210068', 1.0), + ('A000000141900', 1.0) +] + +def get_product_info(recommand_list): + recommand_list = [i[0] for i in recommand_list] + product_info = search_db(recommand_list) + return product_info + + +# ์„ธ์…˜ ์ƒํƒœ ์ดˆ๊ธฐํ™” +if "messages" not in st.session_state: + st.session_state.messages = [] # ๋ฉ”์‹œ์ง€ ๊ธฐ๋ก ์ดˆ๊ธฐํ™” + +# ์ƒ˜ํ”Œ ๋ฐ์ดํ„ฐ +product_info = [ + { + "image_link": "https://via.placeholder.com/150", + "goodsName": "์ƒํ’ˆ1", + "price": 10000, + "function": "๋ณด์Šต", + "formulation": "ํฌ๋ฆผ", + "purchase_link": "https://example.com/product1" + }, + { + "image_link": "https://via.placeholder.com/150", + "goodsName": "์ƒํ’ˆ2", + "price": 20000, + "function": "๋ฏธ๋ฐฑ", + "formulation": "๋กœ์…˜", + "purchase_link": "https://example.com/product2" + }, + { + "image_link": "https://via.placeholder.com/150", + "goodsName": "์ƒํ’ˆ3", + "price": 30000, + "function": "์ง„์ •", + "formulation": "์„ธ๋Ÿผ", + "purchase_link": "https://example.com/product3" + } +] + +# ๋ฉ”์‹œ์ง€ ์ถ”๊ฐ€ ํ•จ์ˆ˜ +def add_product_message(product_list): + """์ถ”์ฒœ ์ œํ’ˆ ๋ฉ”์‹œ์ง€๋ฅผ ์„ธ์…˜ ์ƒํƒœ์— ์ถ”๊ฐ€""" + st.session_state.messages.append({ + "role": "assistant", + "type": "product", + "content": product_list + }) + +# ์‚ฌ์šฉ์ž ์ž…๋ ฅ์— ๋Œ€ํ•œ ๋‹ต๋ณ€ ์ƒ์„ฑ ํ•จ์ˆ˜ +def generate_response(user_message): + """์‚ฌ์šฉ์ž ๋ฉ”์‹œ์ง€์— ๋Œ€ํ•œ ๊ฐ„๋‹จํ•œ ๋‹ต๋ณ€ ์ƒ์„ฑ""" + if "์ถ”์ฒœ" in user_message: + return "์ถ”์ฒœ๋ฐ›๊ธฐ ๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ์„œ ์ƒํ’ˆ์„ ํ™•์ธํ•ด ๋ณด์„ธ์š”!" + elif "์•ˆ๋…•" in user_message: + return "์•ˆ๋…•ํ•˜์„ธ์š”! ๋ฌด์—‡์„ ๋„์™€๋“œ๋ฆด๊นŒ์š”?" + else: + return "์ฃ„์†กํ•ด์š”, ๊ทธ ๋‚ด์šฉ์„ ์ž˜ ์ดํ•ดํ•˜์ง€ ๋ชปํ–ˆ์–ด์š”. ๋‹ค์‹œ ๋ง์”€ํ•ด ์ฃผ์‹œ๊ฒ ์–ด์š”?" + +# ๋ฒ„ํŠผ ํด๋ฆญ์œผ๋กœ ์ œํ’ˆ ์ถ”์ฒœ ๋ฉ”์‹œ์ง€ ์ถ”๊ฐ€ +if recommand_button: + product_info = get_product_info(recommand_list) + add_product_message(product_info[:3]) # ์ฒซ 3๊ฐœ์˜ ์ƒํ’ˆ ์ถ”์ฒœ + +# ์‚ฌ์šฉ์ž ์ž…๋ ฅ ์ฒ˜๋ฆฌ +user_input = st.chat_input("Your message:") + +if user_input: # ์‚ฌ์šฉ์ž๊ฐ€ ๋ฉ”์‹œ์ง€๋ฅผ ์ž…๋ ฅํ–ˆ์„ ๊ฒฝ์šฐ + # ์‚ฌ์šฉ์ž ๋ฉ”์‹œ์ง€ ์ €์žฅ + st.session_state.messages.append({ + "role": "user", + "type": "text", + "content": user_input + }) + # ๋‹ต๋ณ€ ์ƒ์„ฑ ๋ฐ ์ €์žฅ + assistant_response = generate_response(user_input) + st.session_state.messages.append({ + "role": "assistant", + "type": "text", + "content": assistant_response + }) + +# ์ด์ „ ๋ฉ”์‹œ์ง€ ์ถœ๋ ฅ +for message in st.session_state.messages: + if message["type"] == "product": + product_list = message["content"] + with st.chat_message("assistant"): + col1, col2, col3 = st.columns(3) + with col1: + st.image(product_list[0]['image_link']) + st.write(product_list[0]['goodsName']) + st.write(product_list[0]['price'], "์›") + st.write(product_list[0]['function']) + st.write(product_list[0]['formulation']) + st.link_button("๊ตฌ๋งคํ•˜๊ธฐ", product_list[0]['purchase_link']) + with col2: + st.image(product_list[1]['image_link']) + st.write(product_list[1]['goodsName']) + st.write(product_list[1]['price'], "์›") + st.write(product_list[1]['function']) + st.write(product_list[1]['formulation']) + st.link_button("๊ตฌ๋งคํ•˜๊ธฐ", product_list[1]['purchase_link']) + with col3: + st.image(product_list[2]['image_link']) + st.write(product_list[2]['goodsName']) + st.write(product_list[2]['price'], "์›") + st.write(product_list[2]['function']) + st.write(product_list[2]['formulation']) + st.link_button("๊ตฌ๋งคํ•˜๊ธฐ", product_list[2]['purchase_link']) + elif message["type"] == "text": + with st.chat_message(message["role"]): + st.write(message["content"]) diff --git a/search_db.py b/search_db.py new file mode 100644 index 0000000..de676fb --- /dev/null +++ b/search_db.py @@ -0,0 +1,46 @@ +import pymysql +from dotenv import load_dotenv +import os + +# product_list -> list +def search_db(product_list): + load_dotenv() + + # ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ๊ฒฐ์— ํ•„์š”ํ•œ ์ •๋ณด๋“ค ์ €์žฅ + host = os.getenv("DB_HOST") + port = os.getenv("DB_PORT") + user = os.getenv("DB_USER") + password = os.getenv("DB_PASSWD") + database = os.getenv("DB_NAME") + + connection = pymysql.connect( + host=host, # ์˜ˆ: "localhost" + port=int(port), # MySQL ํฌํŠธ ๋„˜๋ฒ„ + user=user, # MySQL ์‚ฌ์šฉ์ž ์ด๋ฆ„ + password=password, # MySQL ๋น„๋ฐ€๋ฒˆํ˜ธ + database=database, # MySQL ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ด๋ฆ„ + charset="utf8mb4" # ๋ฌธ์ž ์ธ์ฝ”๋”ฉ + ) + + try: + with connection.cursor() as cursor: + result = [] + for i in product_list: + query = f"select goodsName, purchase_link, image_link, price, `function`, formulation from cosmetic_data where goodsNo = '{i}';" + cursor.execute(query) + fetch = cursor.fetchone() + fetch = { + "goodsName": fetch[0], + "purchase_link": fetch[1], + "image_link": fetch[2], + "price": fetch[3], + "function": fetch[4], + "formulation": fetch[5] + } + result.append(fetch) + + connection.commit() + finally: + connection.close() + + return result