Spaces:
Runtime error
Runtime error
| # --- 1. νμ λΌμ΄λΈλ¬λ¦¬ μν¬νΈ --- | |
| import streamlit as st | |
| from dotenv import load_dotenv | |
| import streamlit.components.v1 as components | |
| import os | |
| # (λ€λ₯Έ import ꡬ문λ€μ μ΄μ κ³Ό λμΌ) | |
| from langchain_core.prompts import ChatPromptTemplate | |
| from langchain_core.output_parsers import StrOutputParser | |
| from langchain_core.runnables import RunnablePassthrough | |
| from langchain_huggingface import HuggingFaceEndpoint, ChatHuggingFace | |
| from rag_logic import create_and_store_vector_db | |
| # (API ν€ λ‘λ λΆλΆμ μ΄μ κ³Ό λμΌ) | |
| load_dotenv() | |
| HUGGINGFACE_API_KEY = os.getenv("HUGGINGFACE_API_KEY") | |
| # --- 2. νμ΄μ§ μ€μ λ° CSS --- | |
| st.set_page_config(page_title="λͺ¨κ΅¬μ± - My RAG μ±λ΄", page_icon="avatar.png", layout="centered") | |
| st.markdown(""" | |
| <style> | |
| /* ... (λ€λ₯Έ CSSλ μ΄μ κ³Ό λμΌ) ... */ | |
| @import url('https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@400;500;700&display=swap'); | |
| html, body, [class*="st-"] { font-family: 'Noto Sans KR', sans-serif; } | |
| .stApp { background: linear-gradient(135deg, #F9F5FF 0%, #E2E1FF 100%); } | |
| .st-emotion-cache-1f1G203 { background-color: white; border-radius: 1.5rem; padding: 1.5rem; margin: 1rem; box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.1); border: 1px solid rgba(255, 255, 255, 0.18); height: 85vh; padding-bottom: 5rem; } | |
| [data-testid="stChatMessage"][data-testid-role="assistant"] .st-emotion-cache-124el85 { background-color: #F0F0F5; border-radius: 20px 20px 20px 5px; color: #111; border: 1px solid #E5E7EB; animation: fadeIn 0.5s ease-in-out; } | |
| /* βββ μλ°ν μ΄λ―Έμ§ ν¬κΈ° μ‘°μ CSS βββ */ | |
| [data-testid="stChatMessage"] img { | |
| width: 5rem; /* λλΉ μ€μ (κΈ°λ³Έκ°μ 2rem) */ | |
| height: 5rem; /* λμ΄ μ€μ (κΈ°λ³Έκ°μ 2rem) */ | |
| border-radius: 50%; | |
| object-fit: cover; /* μ΄λ―Έμ§κ° μ°κ·Έλ¬μ§μ§ μλλ‘ μ€μ */ | |
| } | |
| [data-testid="stChatMessage"][data-testid-role="user"] .st-emotion-cache-124el85 { background: linear-gradient(45deg, #7A42E2, #9469F4); border-radius: 20px 20px 5px 20px; color: white; animation: fadeIn 0.5s ease-in-out; } | |
| .faq-card { background-color: rgba(249, 245, 255, 0.8); border: 1px solid rgba(255, 255, 255, 0.3); padding: 1.2rem; border-radius: 1rem; margin-bottom: 1rem; } | |
| .faq-title { font-size: 18px; font-weight: 700; margin-bottom: 1rem; } | |
| .stButton>button { background-color: #FFFFFF; color: #555; border: 1px solid #DDD; border-radius: 20px; padding: 8px 16px; transition: all 0.2s ease-in-out; box-shadow: 0 1px 2px rgba(0,0,0,0.05); width: 100%; text-align: left; } | |
| .stButton>button:hover { background-color: #F0F0F5; color: #7A42E2; border-color: #7A42E2; transform: translateY(-2px); box-shadow: 0 4px 8px rgba(0,0,0,0.1); } | |
| .stChatInput { background-color: #FFFFFF; padding: 1rem; border-top: 1px solid #E5E7EB; } | |
| @keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } } | |
| </style> | |
| """, unsafe_allow_html=True) | |
| # --- 3. RAG μ±λ΄ λ‘μ§ λ‘λ λ° μ²΄μΈ κ΅¬μ± (μ΄μ κ³Ό λμΌ) --- | |
| def get_rag_chain(): | |
| # ... (λ΄μ© λ³κ²½ μμ) | |
| if not HUGGINGFACE_API_KEY: return None | |
| vector_db = create_and_store_vector_db() | |
| retriever = vector_db.as_retriever(search_kwargs={"k": 10}) | |
| llm_endpoint = HuggingFaceEndpoint(repo_id="meta-llama/Meta-Llama-3-8B-Instruct", huggingfacehub_api_token=HUGGINGFACE_API_KEY, temperature=0.3) | |
| llm = ChatHuggingFace(llm=llm_endpoint) | |
| # AIμ μν μ λ§€μ° μ격νκ² μ ννλ μλ‘μ΄ μμ€ν ν둬ννΈ | |
| system_prompt = """ | |
| λΉμ μ 'λͺ¨κ΅¬μλΉμ€'μ κ·μΉμ μλ΄νλ AI μλ΄μ 'λͺ¨κ΅¬λ΄'μ λλ€. λΉμ μ μ μΌν μ무λ μλμ μ 곡λλ "κ²μλ λ¬Έμ"μ λ΄μ©λ§μ μ¬μ©νμ¬ μ¬μ©μμ μ§λ¬Έμ λ΅λ³νλ κ²μ λλ€. | |
| --- [κ·μΉ] --- | |
| 1. **μ€μ§ "κ²μλ λ¬Έμ"μ λ΄μ©λ§μ μ¬μ©ν΄μΌ ν©λλ€.** μ λλ‘ λΉμ μ μ¬μ μ§μμ΄λ μΈλΆ μ 보λ₯Ό μ¬μ©ν΄μλ μ λ©λλ€. | |
| 2. λ΅λ³μ "κ²μλ λ¬Έμ"μ λͺ μλ μ¬μ€μ κ·Έλλ‘ μ λ¬ν΄μΌ νλ©°, λ΄μ©μ μΆμΈ‘νκ±°λ λ³νν΄μλ μ λ©λλ€. | |
| 3. λ§μ½ "κ²μλ λ¬Έμ"μ λ΄μ©λ§μΌλ‘ μ§λ¬Έμ λ΅λ³ν μ μλ€λ©΄, λ€λ₯Έ μ 보λ₯Ό μ°ΎμΌλ € νμ§ λ§κ³ **λ°λμ** "μμ§ μ€λΉλμ§ μμ μ 보μμ. κ³§ μ λ°μ΄νΈν κ²μ π" λΌκ³ λ§ λ΅λ³ν΄μΌ ν©λλ€. λ€λ₯Έ λ§μ λ§λΆμ΄μ§ λ§μΈμ. | |
| 4. λͺ¨λ λ΅λ³μ μΉμ νκ³ λͺ νν "μ"μ²΄λ‘ μμ±ν΄μΌ ν©λλ€. | |
| --- [κ²μλ λ¬Έμ] --- | |
| {context} | |
| """ | |
| prompt = ChatPromptTemplate.from_messages([("system", system_prompt), ("human", "{question}")]) | |
| rag_chain = ({"context": retriever, "question": RunnablePassthrough()} | prompt | llm | StrOutputParser()) | |
| return rag_chain | |
| rag_chain = get_rag_chain() | |
| # --- 4. μλ μ€ν¬λ‘€ ν¨μ (μ΄μ κ³Ό λμΌ) --- | |
| def auto_scroll(): | |
| # ... (λ΄μ© λ³κ²½ μμ) | |
| components.html( | |
| """<script> window.parent.document.querySelector('.st-emotion-cache-1f1G203').scrollTo(0, 99999); </script>""", | |
| height=0) | |
| # --- 5. UI λ λλ§ ν¨μ (μ΄μ κ³Ό λμΌ) --- | |
| def render_welcome_elements(): | |
| # ... (λ΄μ© λ³κ²½ μμ) | |
| if not st.session_state.messages: | |
| with st.chat_message("assistant", avatar="avatar.png"): | |
| st.markdown("κΆκΈν λ΄μ©μ μ λ ₯ν΄μ£Όμλ©΄,\nλ΅λ³μ λΉ λ₯΄κ² μ±λ΄μ΄ λμλ릴κ²μ.") | |
| st.markdown('<div class="faq-card">', unsafe_allow_html=True) | |
| st.markdown('<div class="faq-title">λ§μ΄ μ°Ύλ μ§λ¬Έ TOP 3</div>', unsafe_allow_html=True) | |
| faq_items = { | |
| "λͺ¨κ΅¬ μμλ£ μ νμ μ΄λ»κ² λλμ?": "π¬ λͺ¨κ΅¬ μμλ£ μ ν", | |
| "λͺ¨κ΅¬ λ§κ° κΈ°νμ λ©°μΉ κΉμ§ κ°λ₯νκ°μ?": "π¬ λͺ¨κ΅¬ λ§κ° κΈ°ν", | |
| "λͺ¨κ΅¬μμ νλ©΄ μλλ 물건μ 무μμΈκ°μ?": "π¬ λͺ¨κ΅¬ νλ§€ κΈμ§ νλͺ©" | |
| } | |
| for query, text in faq_items.items(): | |
| if st.button(text, key=query): | |
| st.session_state.prompt_from_button = query | |
| st.rerun() | |
| st.markdown('</div>', unsafe_allow_html=True) | |
| # --- 6. λ©μΈ μ ν리μΌμ΄μ λ‘μ§ (μ΄μ κ³Ό λμΌ) --- | |
| st.title("λͺ¨κ΅¬μ± β¨") | |
| # ... (μ΄ν λͺ¨λ μ½λ λ³κ²½ μμ) | |
| if "messages" not in st.session_state: | |
| st.session_state.messages = [] | |
| for message in st.session_state.messages: | |
| with st.chat_message(message["role"], avatar="avatar.png" if message["role"] == "assistant" else "π€"): | |
| st.markdown(message["content"]) | |
| render_welcome_elements() | |
| prompt = st.chat_input("κΆκΈνμ λ΄μ©μ μ λ ₯ν΄μ£ΌμΈμ.") | |
| if "prompt_from_button" in st.session_state and st.session_state.prompt_from_button: | |
| prompt = st.session_state.prompt_from_button | |
| st.session_state.prompt_from_button = None | |
| if prompt: | |
| st.session_state.messages.append({"role": "user", "content": prompt}) | |
| with st.chat_message("user", avatar="π€"): | |
| st.markdown(prompt) | |
| with st.chat_message("assistant", avatar="avatar.png"): | |
| if rag_chain: | |
| response_stream = rag_chain.stream(prompt) | |
| full_response = st.write_stream(response_stream) | |
| else: | |
| full_response = "μ£μ‘ν©λλ€, μ±λ΄μ μ΄κΈ°ννλ λ° λ¬Έμ κ° λ°μνμ΅λλ€." | |
| st.write(full_response) | |
| st.session_state.messages.append({"role": "assistant", "content": full_response}) | |
| auto_scroll() | |
| st.rerun() | |
| else: | |
| auto_scroll() |