marketting_agent.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. import asyncio
  2. from datetime import datetime
  3. import re
  4. import aiofiles
  5. import os
  6. import sys
  7. from typing import List, Dict, Any
  8. from typing import Any, Dict, List, Optional, Union
  9. from pydantic import BaseModel
  10. from typing import List
  11. from llama_index.core.program import LLMTextCompletionProgram
  12. from llama_index.core.output_parsers import PydanticOutputParser
  13. from llama_index.program.lmformatenforcer import (
  14. LMFormatEnforcerPydanticProgram,
  15. )
  16. from llama_index.core.prompts import PromptTemplate
  17. from llama_index.llms.openai import OpenAI
  18. from llama_index.llms.litellm import LiteLLM
  19. from llama_index.core.llms.llm import LLM
  20. from src.models.product_model import Product
  21. from src.manager.template_manager import TemplateManager, TemplateService, TemplateType
  22. from src.models.ai_execution_record import MarketingInfo, LLMConfig, SuperPromptMixin, AgentConfig, AgentContent, AICompetitorAnalyzeMainKeywords, AICompetitorAnalyzeMainKeywordsResult, MarketingContentGeneration
  23. from ai.base_agent import BaseAgent
  24. from utils.file import save_to_file, read_file
  25. from config.settings import MONGO_URL, MONGO_DB_NAME,LITELLM_API_BASE, LITELLM_API_KEY,OPENAI_API_KEY,OPENAI_API_BASE
  26. from utils.logu import get_logger
  27. logger = get_logger("ai")
  28. class MarketingAgent(BaseAgent):
  29. async def get_mainkeys_tailkeys_prompt(self, product_name, prompt: str='',output_type='markdown', verbose=False) -> PromptTemplate:
  30. base_prompt = "```\n{{product_info}}\n{{competitor_info}}\n```\n"
  31. prompt_mainkyes = prompt or '''\
  32. 你是日本站的亚马逊运营,请你根据产品信息为用户选出主要关键词和长尾关键词。
  33. 请根据竞品数据,按以下规则分析:
  34. - 选出搜索量在1万以上的相同关键词作为主要关键词3个。
  35. - 如果竞品的搜索量都不足1万,则从排名前十的关键词中筛选3个搜索量最大且相关性最强的词。
  36. - 结合日本市场特点分析
  37. - 根据我的产品基本信息,从竞品的主要信息和同类竞品的相似关键词中,筛选出最符合我产品的长尾关键词 10个以上
  38. - 如果涉及品牌名,不要将品牌名作为关键词,因为那是竞品关键词参考数据,不是我的产品品牌。
  39. 筛选长尾词的示例:
  40. - 假设我的产品是电线保护,那么竞品关键词中,“隐藏排线管” 就不符合长尾词
  41. - 假设我的产品是“防老化、防动物咬”用途,你就不能在竞品数据中选择不属于我这个使用场景的长尾关键词。
  42. 生成的内容满足以下要求:
  43. - reason 、 suggestions 必须写成中文
  44. - 月搜索量 monthly_searches 必须是 int ,按照从大到小排序,别的字段按照源数据填写即可。
  45. - 内容格式必须是 {output_type}
  46. '''
  47. variables = {'product_name': product_name}
  48. product_info = await self.template_manager.execute_template("product_info", variables)
  49. competitor_info = await self.template_manager.execute_template("competitor_for_llm", variables)
  50. prompt_tmpl = PromptTemplate(template=base_prompt + prompt_mainkyes, )
  51. return prompt_tmpl.partial_format(
  52. product_info=product_info,
  53. competitor_info=competitor_info,
  54. output_type=output_type,
  55. )
  56. def llm_mainkeys_tailkeys_to_model(self, prompt_template:PromptTemplate, prompt_kwargs:Dict={}, verbose=False):
  57. program = LLMTextCompletionProgram.from_defaults(
  58. output_parser=PydanticOutputParser(output_cls=MarketingInfo),
  59. prompt_template_str=prompt_template.format(prompt_kwargs),
  60. llm=self.llm,
  61. verbose=verbose,
  62. )
  63. competitor = program(**prompt_kwargs)
  64. logger.info(f"{competitor}")
  65. return competitor
  66. async def gen_mainkeys_tailkeys(self, product_name, prompt: str='',output_type='markdown', verbose=False, overwrite=False):
  67. logger.info(f"start llm model: {self.llm._get_model_name()}, output_type: {output_type}")
  68. agent_model = await AgentContent.find_one(AgentContent.model_name == self.llm._get_model_name(),AgentContent.product_name == product_name)
  69. if agent_model and not overwrite:
  70. logger.info(f"agent_model exist {agent_model}")
  71. return agent_model
  72. elif not agent_model:
  73. agent_model = AgentContent(model_name=self.llm._get_model_name(), product_name=product_name)
  74. prompt_template = await self.get_mainkeys_tailkeys_prompt(product_name, prompt,output_type, verbose)
  75. logger.info(f"{prompt_template.format()}")
  76. if output_type == 'json':
  77. competitor = self.llm_mainkeys_tailkeys_to_model(prompt_template, verbose)
  78. elif output_type == 'markdown':
  79. response = await self.llm.acomplete(prompt_template.format())
  80. competitor = self.filter_markdown_content(response.text)
  81. agent_model.product = await Product.find_one(Product.basic_info.name == product_name)
  82. agent_model.competitor[output_type] = competitor
  83. agent_model.update_time = datetime.now()
  84. return await agent_model.save()
  85. async def get_marketing_prompt(self, product_name, prompt: str='', verbose=False, llm=None):
  86. prompt_marketing = prompt or '''\
  87. '''
  88. all_keywords = self.template_manager.execute_template('agent.mainkeys_tailkeys')
  89. variables = {'product_name': product_name}
  90. product_info = await self.template_manager.execute_template("product_info", variables)
  91. program = LMFormatEnforcerPydanticProgram(
  92. output_cls=MarketingInfo,
  93. llm=llm or self.llm,
  94. prompt_template_str="{{product_info}}\n{{all_keywords}}\n" + prompt_marketing,
  95. verbose=verbose,
  96. )
  97. competitor = program(product_info=product_info, all_keywords=all_keywords)
  98. return competitor
  99. async def gen_marketing_file(self, product_name, output_path: str, llm_models: List[str] = []):
  100. models = await AgentContent.find(AgentContent.product_name == product_name).to_list()
  101. # 创建一个字典来存储模型及其基础名称
  102. model_dict = {}
  103. unsorted_models = []
  104. for model in models:
  105. # 提取基础名称(去掉前面的xxx/xxx)
  106. base_name = model.model_name.split('/')[-1] if '/' in model.model_name else model.model_name
  107. # 检查是否在优先级列表中
  108. found = False
  109. for priority_model in llm_models:
  110. priority_base = priority_model.split('/')[-1] if '/' in priority_model else priority_model
  111. if base_name == priority_base:
  112. model_dict[priority_model] = (model, base_name) # 存储模型和显示名称
  113. found = True
  114. break
  115. if not found:
  116. # 对于不在列表中的模型,也存储基础名称
  117. unsorted_models.append((model, base_name))
  118. # 按照llm_models顺序生成内容
  119. sorted_content = ''
  120. for priority_model in llm_models:
  121. if priority_model in model_dict:
  122. model, display_name = model_dict[priority_model]
  123. markdown = model.competitor.get('markdown', '')
  124. logger.info(f"llm_name: {model.model_name} , {markdown[:100]}")
  125. sorted_content += f"# {display_name}\n{markdown}\n\n" # 使用基础名称
  126. # 添加未排序的模型
  127. unsorted_content = ''
  128. for model, display_name in unsorted_models:
  129. markdown = model.competitor.get('markdown', '')
  130. logger.info(f"llm_name: {model.model_name} , {markdown[:100]}")
  131. unsorted_content += f"# {display_name}\n{markdown}\n\n" # 使用基础名称
  132. prompt_template = await self.get_mainkeys_tailkeys_prompt(product_name, output_type='markdown')
  133. content = sorted_content + unsorted_content + f'# 提示词 \n{prompt_template.format()}\n\n'
  134. return save_to_file(content, output_path)
  135. async def llm_task(product_name):
  136. m = TemplateManager(MONGO_URL, MONGO_DB_NAME)
  137. await m.initialize()
  138. model = 'openai/groq/llama-3.1-8b-instant'
  139. # model = 'groq/groq/qwen-2.5-coder-32b'
  140. # model = 'openai/glm-4-flash'
  141. # model = 'openai/deepseek-v3'
  142. # model = 'openai/groq/qwen-2.5-32b'
  143. # model = 'openai/deepseek-chat'
  144. # 'openai/QwQ-32B',
  145. model = 'openai/deepseek-reasoner'
  146. # model = 'openai/doubao-pro-32k-241215'
  147. llm_list = [
  148. LiteLLM(model='openai/doubao-pro-32k-241215', api_key=OPENAI_API_KEY, api_base=OPENAI_API_BASE),
  149. LiteLLM(model='openai/Qwen/Qwen3-235B-A22B', api_key=OPENAI_API_KEY, api_base=OPENAI_API_BASE),
  150. LiteLLM(model='openai/deepseek-reasoner', api_key=OPENAI_API_KEY, api_base=OPENAI_API_BASE),
  151. # LiteLLM(model='openai/deepseek-v3', api_key=OPENAI_API_KEY, api_base=OPENAI_API_BASE),
  152. ]
  153. task_list = []
  154. for llm in llm_list:
  155. agent = MarketingAgent(llm=llm, template_manager=m)
  156. agent_model = agent.gen_mainkeys_tailkeys(product_name=product_name, verbose=True, overwrite=True)
  157. task_list.append(agent_model)
  158. # logger.info(f"{agent_model.competitor.items()}")
  159. await asyncio.gather(*task_list)
  160. await gen_marketing_file(product_name)
  161. # llm = LiteLLM(model=model, api_key=OPENAI_API_KEY, api_base=OPENAI_API_BASE)
  162. # agent = MarketingAgent(llm=llm, template_manager=m)
  163. # agent_model = await agent.gen_mainkeys_tailkeys(product_name='大尺寸厚款卸妆棉240片', verbose=True, overwrite=True)
  164. # logger.info(f"{agent_model.competitor.items()}")
  165. async def gen_marketing_file(product_name):
  166. m = TemplateManager(MONGO_URL, MONGO_DB_NAME)
  167. await m.initialize()
  168. model = 'openai/deepseek-reasoner'
  169. llm = LiteLLM(model=model, api_key=OPENAI_API_KEY, api_base=OPENAI_API_BASE)
  170. # product_name = '大尺寸厚款卸妆棉240片'
  171. agent = MarketingAgent(llm=llm, template_manager=m)
  172. output_path = r'G:\code\amazone\copywriting_production\output\temp' + f"\\{product_name}-主关键词长尾词.md"
  173. llm_models = [
  174. 'openai/doubao-pro-32k-241215',
  175. 'openai/deepseek-reasoner',
  176. # 'openai/deepseek-v3',
  177. # 'openai/QwQ-32B',
  178. ]
  179. await agent.gen_marketing_file(product_name=product_name, output_path=output_path, llm_models=llm_models)
  180. logger.info(f"{output_path}")
  181. async def main():
  182. list_product_name = [
  183. '死皮处理五件套',
  184. # '镊子铲两件套',
  185. # '折叠剪刀',
  186. # '脸用刮毛刀4件套',
  187. # '路亚钓鱼小剪刀',
  188. ]
  189. task_list = []
  190. for product_name in list_product_name:
  191. task_list.append(llm_task(product_name))
  192. await asyncio.gather(*task_list)
  193. # asyncio.run(llm_task(product_name=product_name))
  194. if __name__ == "__main__":
  195. asyncio.run(main())