Spaces:
Sleeping
Sleeping
| # tools/marketing_strategy.py | |
| import traceback | |
| import json | |
| from typing import List | |
| from langchain_core.tools import tool | |
| import config | |
| from modules.llm_provider import get_llm | |
| from modules.knowledge_base import load_marketing_vectorstore | |
| from tools.profile_analyzer import get_festival_profile_by_name | |
| logger = config.get_logger(__name__) | |
| def search_contextual_marketing_strategy(user_query: str, store_profile: str) -> str: | |
| """ | |
| (RAG Tool) μ¬μ©μμ μ§λ¬Έκ³Ό κ°κ² νλ‘ν(JSON λ¬Έμμ΄)μ λ°νμΌλ‘ 'λ§μΌν μ λ΅' Vector DBμμ | |
| κ΄λ ¨μ±μ΄ λμ 컨ν μ€νΈ(μ λ΅)λ₯Ό κ²μνκ³ , LLMμ ν΅ν΄ μ΅μ’ λ΅λ³μ μμ±νμ¬ λ°νν©λλ€. | |
| """ | |
| logger.info("--- [Tool] RAG λ§μΌν μ λ΅ κ²μ νΈμΆλ¨ ---") | |
| try: | |
| retriever = load_marketing_vectorstore() | |
| if retriever is None: | |
| raise RuntimeError("λ§μΌν Retrieverκ° λ‘λλμ§ μμμ΅λλ€.") | |
| # 1. 컨ν μ€νΈλ₯Ό κ³ λ €ν κ²μ 쿼리 μμ± | |
| try: | |
| profile_dict = json.loads(store_profile) | |
| profile_for_query = ( | |
| f"κ°κ² μμΉ: {profile_dict.get('μ£Όμ', 'μ μ μμ')}\n" | |
| f"κ°κ² μ μ’ : {profile_dict.get('μ μ’ ', 'μ μ μμ')}\n" | |
| f"ν΅μ¬ κ³ κ°: {profile_dict.get('μλμΆμΆνΉμ§', {}).get('ν΅μ¬κ³ κ°', 'μ μ μμ')}" | |
| ) | |
| except Exception: | |
| profile_for_query = store_profile | |
| contextual_query = f"[κ°κ² μ 보:\n{profile_for_query}\n]μ λν [μ§λ¬Έ: {user_query}]" | |
| logger.info(f"--- [Tool] RAG κ²μ 쿼리: {contextual_query} ---") | |
| # 2. Vector DB κ²μ | |
| docs = retriever.invoke(contextual_query) | |
| if not docs: | |
| logger.warning("--- [Tool] RAG κ²μ κ²°κ³Ό μμ ---") | |
| return "μ£μ‘ν©λλ€. μ¬μ₯λμ κ°κ² νλ‘νκ³Ό μ§λ¬Έμ λ§λ λ§μΌν μ λ΅μ μ°Ύμ§ λͺ»νμ΅λλ€. κ°κ²μ νΉμ§μ μ‘°κΈ λ μλ €μ£Όμκ±°λ, λ€λ₯Έ μ§λ¬Έμ μλν΄λ³΄μκ² μ΄μ?" | |
| # 3. LLMμ μ λ¬ν 컨ν μ€νΈ ν¬λ§·ν | |
| context = "\n\n---\n\n".join([doc.page_content for doc in docs]) | |
| logger.info("--- [Tool] RAG 컨ν μ€νΈ μμ± μλ£ ---") | |
| # 4. LLMμ ν΅ν λ΅λ³ μ¬κ΅¬μ± | |
| llm = get_llm(temperature=0.3) | |
| # --- (μ¬μ©μ μμ²) ν둬ννΈ μλ³Έ μ μ§ --- | |
| prompt = f""" | |
| λΉμ μ μμκ³΅μΈ μ λ¬Έ λ§μΌν 컨μ€ν΄νΈμ λλ€. | |
| μλ [κ°κ² νλ‘ν]κ³Ό [μ°Έκ³ λ§μΌν μ λ΅]μ λ°νμΌλ‘, μ¬μ©μμ [μ§λ¬Έ]μ λν λ§μΆ€ν λ§μΌν μ λ΅ 3κ°μ§λ₯Ό μ μν΄μ£ΌμΈμ. | |
| [κ°κ² νλ‘ν] | |
| {store_profile} | |
| [μ§λ¬Έ] | |
| {user_query} | |
| [μ°Έκ³ λ§μΌν μ λ΅] | |
| {context} | |
| [μμ± κ°μ΄λλΌμΈ] | |
| 1. [μ°Έκ³ λ§μΌν μ λ΅]μ κ·Έλλ‘ λ³΅μ¬νμ§ λ§κ³ , [κ°κ² νλ‘ν]μ νΉμ§(μ: μ μ’ , ν΅μ¬ κ³ κ°, μκΆ)κ³Ό [μ§λ¬Έ]μ μλλ₯Ό μ‘°ν©νμ¬ **κ°κ²μ νΉνλ μλ‘μ΄ μμ΄λμ΄**λ‘ μ¬κ΅¬μ±ν΄μ£ΌμΈμ. | |
| 2. κ° μ λ΅μ ꡬ체μ μΈ μ€ν λ°©μμ ν¬ν¨ν΄μΌ ν©λλ€. | |
| 3. μΉμ νκ³ μ λ¬Έμ μΈ λ§ν¬λ₯Ό μ¬μ©νμΈμ. | |
| 4. μλ [μΆλ ₯ νμ]μ μ νν μ§μΌμ£ΌμΈμ. | |
| 5. **μ·¨μμ κΈμ§**: μ λλ‘ `~~text~~`μ κ°μ μ·¨μμ λ§ν¬λ€μ΄μ μ¬μ©νμ§ λ§μΈμ. | |
| [μΆλ ₯ νμ] | |
| μ¬μ₯λ κ°κ²μ νΉμ±μ κ³ λ €ν 3κ°μ§ λ§μΌν μμ΄λμ΄λ₯Ό μ μν΄ λ립λλ€. | |
| **1. [μ λ΅ μ λͺ© 1]** | |
| * **μ λ΅ λ΄μ©:** (κ°κ²μ μ΄λ€ νΉμ§μ νμ©νμ¬ μ΄λ»κ² μ€ννλμ§ κ΅¬μ²΄μ μΌλ‘ μμ ) | |
| * **κΈ°λ ν¨κ³Ό:** (μ΄ μ λ΅μ ν΅ν΄ μ»μ μ μλ ꡬ체μ μΈ ν¨κ³Ό) | |
| **2. [μ λ΅ μ λͺ© 2]** | |
| * **μ λ΅ λ΄μ©:** (κ°κ²μ μ΄λ€ νΉμ§μ νμ©νμ¬ μ΄λ»κ² μ€ννλμ§ κ΅¬μ²΄μ μΌλ‘ μμ ) | |
| * **κΈ°λ ν¨κ³Ό:** (μ΄ μ λ΅μ ν΅ν΄ μ»μ μ μλ ꡬ체μ μΈ ν¨κ³Ό) | |
| **3. [μ λ΅ μ λͺ© 3]** | |
| * **μ λ΅ λ΄μ©:** (κ°κ²μ μ΄λ€ νΉμ§μ νμ©νμ¬ μ΄λ»κ² μ€ννλμ§ κ΅¬μ²΄μ μΌλ‘ μμ ) | |
| * **κΈ°λ ν¨κ³Ό:** (μ΄ μ λ΅μ ν΅ν΄ μ»μ μ μλ ꡬ체μ μΈ ν¨κ³Ό) | |
| """ | |
| try: | |
| response = llm.invoke(prompt) | |
| logger.info("--- [Tool] RAG + LLM λ΅λ³ μμ± μλ£ ---") | |
| return response.content | |
| except Exception as llm_e: | |
| logger.critical(f"--- [Tool CRITICAL] RAG LLM νΈμΆ μ€ μ€λ₯: {llm_e} ---", exc_info=True) | |
| return f"μ€λ₯: κ²μλ μ λ΅μ μ²λ¦¬νλ μ€ μ€λ₯κ° λ°μνμ΅λλ€. (LLM μ€λ₯: {llm_e})" | |
| except Exception as e: | |
| logger.critical(f"--- [Tool CRITICAL] RAG λ§μΌν μ λ΅ κ²μ μ€ μ€λ₯: {e} ---", exc_info=True) | |
| return f"μ£μ‘ν©λλ€. λ§μΌν μ λ΅μ μμ±νλ μ€ μ€λ₯κ° λ°μνμ΅λλ€: {e}" | |
| def create_festival_specific_marketing_strategy(festival_name: str, store_profile: str) -> str: | |
| """ | |
| (RAG x2 Tool) νΉμ μΆμ μ΄λ¦(μ: 'κ΄μ κ°κ°μ°¬μΆμ ')κ³Ό κ°κ² νλ‘ν(JSON λ¬Έμμ΄)μ μ λ ₯λ°μ, | |
| 'μΆμ DB'μ 'λ§μΌν DB'λ₯Ό *λμμ* RAGλ‘ μ°Έμ‘°νμ¬, | |
| ν΄λΉ μΆμ κΈ°κ° λμ μ€νν μ μλ λ§μΆ€ν λ§μΌν μ λ΅ *1κ°*λ₯Ό μμ±ν©λλ€. | |
| """ | |
| logger.info(f"--- [Tool] '*λ¨μΌ* μΆμ λ§μΆ€ν μ λ΅ μμ± (RAGx2)' λꡬ νΈμΆ (λμ: {festival_name}) ---") | |
| try: | |
| # 1. (RAG 1) μΆμ μ 보 κ°μ Έμ€κΈ° (κΈ°μ‘΄ λꡬ μ¬μ¬μ©) | |
| festival_profile_str = get_festival_profile_by_name.invoke({"festival_name": festival_name}) | |
| if "μ€λ₯" in festival_profile_str or "μ°Ύμ μ μμ" in festival_profile_str: | |
| logger.warning(f"--- [Tool WARNING] μΆμ νλ‘νμ μ°Ύμ§ λͺ»ν¨: {festival_name} ---") | |
| festival_profile_str = f"{{\"μΆμ λͺ \": \"{festival_name}\", \"μ 보\": \"μμΈ μ 보λ₯Ό μ°Ύμ μ μμ΅λλ€.\"}}" | |
| else: | |
| logger.info(f"--- [Tool] (RAG 1) μΆμ νλ‘ν λ‘λ μ±κ³΅: {festival_name} ---") | |
| # 2. (RAG 2) κ΄λ ¨ λ§μΌν μ λ΅ κ²μ | |
| marketing_retriever = load_marketing_vectorstore() | |
| if marketing_retriever is None: | |
| raise RuntimeError("λ§μΌν Retrieverκ° λ‘λλμ§ μμμ΅λλ€.") | |
| combined_query = f""" | |
| μΆμ μ 보: {festival_profile_str} | |
| κ°κ² νλ‘ν: {store_profile} | |
| μ§λ¬Έ: μ κ°κ²κ° μ μΆμ κΈ°κ° λμ ν μ μλ μ΅κ³ μ λ§μΌν μ λ΅μ? | |
| """ | |
| marketing_docs = marketing_retriever.invoke(combined_query) | |
| if not marketing_docs: | |
| marketing_context = "μ°Έκ³ ν λ§ν λ§μΌν μ λ΅μ μ°Ύμ§ λͺ»νμ΅λλ€." | |
| logger.warning("--- [Tool] (RAG 2) λ§μΌν μ λ΅ κ²μ κ²°κ³Ό μμ ---") | |
| else: | |
| marketing_context = "\n\n---\n\n".join([doc.page_content for doc in marketing_docs]) | |
| logger.info(f"--- [Tool] (RAG 2) λ§μΌν μ λ΅ μ»¨ν μ€νΈ {len(marketing_docs)}κ° ν보 ---") | |
| # 3. LLMμ ν΅ν μ΅μ’ μ λ΅ μμ± | |
| llm = get_llm(temperature=0.5) | |
| # --- (μ¬μ©μ μμ²) ν둬ννΈ μλ³Έ μ μ§ --- | |
| prompt = f""" | |
| λΉμ μ μΆμ μ°κ³ λ§μΌν μ λ¬Έ 컨μ€ν΄νΈμ λλ€. | |
| μλ [κ°κ² νλ‘ν], [μΆμ νλ‘ν], [μ°Έκ³ λ§μΌν μ λ΅]μ λͺ¨λ κ³ λ €νμ¬, | |
| [κ°κ² νλ‘ν]μ μ¬μ₯λμ΄ [μΆμ νλ‘ν] κΈ°κ° λμ μ€νν μ μλ | |
| **μ°½μμ μ΄κ³ ꡬ체μ μΈ λ§μΆ€ν λ§μΌν μ λ΅ 1κ°μ§**λ₯Ό μ μν΄μ£ΌμΈμ. | |
| [κ°κ² νλ‘ν] | |
| {store_profile} | |
| [μΆμ νλ‘ν] | |
| {festival_profile_str} | |
| [μ°Έκ³ λ§μΌν μ λ΅] | |
| {marketing_context} | |
| [μμ± κ°μ΄λλΌμΈ] | |
| 1. **λ§€μ° μ€μ:** [κ°κ² νλ‘ν]μ νΉμ§(μ μ’ , μμΉ, ν΅μ¬ κ³ κ°)κ³Ό [μΆμ νλ‘ν]μ νΉμ§(μ£Όμ , μ£Όμ λ°©λ¬Έκ°)μ | |
| **λ°λμ μ°κ΄μ§μ΄** ꡬ체μ μΈ μ λ΅μ λ§λμΈμ. | |
| 2. [μ°Έκ³ λ§μΌν μ λ΅]μ μμ΄λμ΄ λ°μμλ§ νμ©νκ³ , 볡μ¬νμ§ λ§μΈμ. | |
| 3. μ λ΅μ 1κ°μ§λ§ κΉμ΄ μκ² μ μν©λλ€. | |
| 4. μΉμ νκ³ μ λ¬Έμ μΈ λ§ν¬λ₯Ό μ¬μ©νμΈμ. | |
| 5. μλ [μΆλ ₯ νμ]μ μ νν μ§μΌμ£ΌμΈμ. | |
| 6. **μ·¨μμ κΈμ§**: μ λλ‘ `~~text~~`μ κ°μ μ·¨μμ λ§ν¬λ€μ΄μ μ¬μ©νμ§ λ§μΈμ. | |
| [μΆλ ₯ νμ] | |
| ### π {json.loads(festival_profile_str).get('μΆμ λͺ ', festival_name)} λ§μΆ€ν λ§μΌν μ λ΅ | |
| **1. (μ λ΅ μμ΄λμ΄ μ λͺ©)** | |
| * **μ λ΅ κ°μ:** (κ°κ²μ μ΄λ€ νΉμ§κ³Ό μΆμ μ μ΄λ€ νΉμ§μ μ°κ΄μ§μλμ§ μ€λͺ ) | |
| * **ꡬ체μ μ€ν λ°©μ:** (μ¬μ₯λμ΄ '무μμ', 'μ΄λ»κ²' ν΄μΌ νλμ§ λ¨κ³λ³λ‘ μ€λͺ . μ: λ©λ΄ κ°λ°, ν보 문ꡬ, SNS μ΄λ²€νΈ λ±) | |
| * **νκ² κ³ κ°:** (μ΄ μ λ΅μ΄ μΆμ λ°©λ¬Έκ° μ€ λꡬμκ² λ§€λ ₯μ μΌμ§) | |
| * **κΈ°λ ν¨κ³Ό:** (μμλλ κ²°κ³Ό, μ: μ κ· κ³ κ° μ μ , κ°λ¨κ° μμΉ λ±) | |
| """ | |
| try: | |
| response = llm.invoke(prompt) | |
| logger.info("--- [Tool] (RAGx2) μ΅μ’ μ λ΅ μμ± μλ£ ---") | |
| return response.content | |
| except Exception as llm_e: | |
| logger.critical(f"--- [Tool CRITICAL] 'μΆμ λ§μΆ€ν μ λ΅ μμ± (RAGx2)' LLM νΈμΆ μ€ μ€λ₯: {llm_e} ---", exc_info=True) | |
| return f"μ€λ₯: κ²μλ μ λ΅μ μ²λ¦¬νλ μ€ μ€λ₯κ° λ°μνμ΅λλ€. (LLM μ€λ₯: {llm_e})" | |
| except Exception as e: | |
| logger.critical(f"--- [Tool CRITICAL] 'μΆμ λ§μΆ€ν μ λ΅ μμ± (RAG)' μ€ μ€λ₯: {e} ---", exc_info=True) | |
| return f"μ£μ‘ν©λλ€. '{festival_name}' μΆμ μ λ΅μ μμ±νλ μ€ μ€λ₯κ° λ°μνμ΅λλ€: {e}" | |
| def create_marketing_strategies_for_multiple_festivals(festival_names: List[str], store_profile: str) -> str: | |
| """ | |
| μ¬λ¬ κ°μ μΆμ μ΄λ¦ 리μ€νΈμ κ°κ² νλ‘ν(JSON λ¬Έμμ΄)μ μ λ ₯λ°μ, | |
| κ° μΆμ μ νΉνλ λ§μΆ€ν λ§μΌν μ λ΅μ *λͺ¨λ* μμ±νκ³ νλμ λ¬Έμμ΄λ‘ μ·¨ν©νμ¬ λ°νν©λλ€. | |
| (μ: ["μ²μ‘μ¬κ³ΌμΆμ ", "λΆμ²κ΅μ λ§νμΆμ "]) | |
| """ | |
| logger.info(f"--- [Tool] '*λ€μ* μΆμ λ§μΆ€ν μ λ΅ μμ±' λꡬ νΈμΆ (λμ: {festival_names}) ---") | |
| final_report = [] | |
| if not festival_names: | |
| logger.warning("--- [Tool] μΆμ μ΄λ¦ λͺ©λ‘μ΄ λΉμ΄μμ ---") | |
| return "μ€λ₯: μΆμ μ΄λ¦ λͺ©λ‘μ΄ λΉμ΄μμ΅λλ€. μ λ΅μ μμ±ν μ μμ΅λλ€." | |
| # κ°λ³ μ λ΅ μμ± λꡬλ₯Ό μ¬μ¬μ© | |
| for festival_name in festival_names: | |
| try: | |
| strategy = create_festival_specific_marketing_strategy.invoke({ | |
| "festival_name": festival_name, | |
| "store_profile": store_profile | |
| }) | |
| final_report.append(strategy) | |
| except Exception as e: | |
| error_message = f"--- [μ€λ₯] '{festival_name}'μ μ λ΅ μμ± μ€ λ¬Έμ κ° λ°μνμ΅λλ€: {e} ---" | |
| logger.critical(f"--- [Tool CRITICAL] '{festival_name}' μ λ΅ μμ± μ€ μ€λ₯: {e} ---", exc_info=True) | |
| final_report.append(error_message) | |
| logger.info("--- [Tool] 'λ€μ μΆμ λ§μΆ€ν μ λ΅ μμ±' μλ£ ---") | |
| return "\n\n---\n\n".join(final_report) | |