|
|
@@ -1,6 +1,6 @@
|
|
|
from abc import ABC, abstractmethod
|
|
|
import json
|
|
|
-from typing import Optional, Union
|
|
|
+from typing import Optional, Set, Union
|
|
|
from llama_index.core import PromptTemplate
|
|
|
import asyncio
|
|
|
import aiofiles
|
|
|
@@ -10,14 +10,14 @@ from dotenv import load_dotenv
|
|
|
from pydantic import BaseModel
|
|
|
from src.models.product_model import (
|
|
|
Product, CompetitorCrawlData, AICompetitorAnalyzeMainKeywords,
|
|
|
- TrafficKeywordResult, ProductImageInfo,
|
|
|
+ TrafficKeywordResult, ProductImageInfo,AICompetitorAnalyzeMainKeywordsResult,
|
|
|
SearchAmazoneKeyResult, ProductBaseInfo, Variant
|
|
|
)
|
|
|
from llama_index.llms.openai import OpenAI
|
|
|
from llama_index.llms.litellm import LiteLLM
|
|
|
from src.manager.core.db_mongo import BaseMongoManager
|
|
|
from utils.logu import get_logger
|
|
|
-from src.models.field_config import FieldConfig
|
|
|
+from src.models.field_config import FieldConfig,get_field_descriptions
|
|
|
load_dotenv()
|
|
|
logger = get_logger('ai')
|
|
|
|
|
|
@@ -86,24 +86,6 @@ def get_competitor_prompt_data(
|
|
|
|
|
|
return list_data
|
|
|
|
|
|
-def get_field_descriptions(
|
|
|
- model_class: BaseModel,
|
|
|
- field_config: FieldConfig = ConfigManager.get_field_config(),
|
|
|
- model_name: Optional[str] = None
|
|
|
-) -> dict:
|
|
|
- """
|
|
|
- 获取模型字段描述信息
|
|
|
-
|
|
|
- Args:
|
|
|
- model_class: Pydantic模型类
|
|
|
- field_config: 字段配置
|
|
|
- model_name: 模型名称(用于查找配置)
|
|
|
-
|
|
|
- Returns:
|
|
|
- 字段名到描述的字典
|
|
|
- """
|
|
|
- return field_config.get_model_fields(model_class, model_name)
|
|
|
-
|
|
|
class Formatter(ABC):
|
|
|
"""格式化器抽象基类"""
|
|
|
def __init__(self, notes: Optional[dict] = None):
|
|
|
@@ -207,47 +189,29 @@ class LiteLLMService(LLMService):
|
|
|
class AnalysisService:
|
|
|
"""分析领域服务"""
|
|
|
def __init__(self, llm_service: LLMService, db_manager: BaseMongoManager):
|
|
|
- self.llm_service = llm_service
|
|
|
+ self.llm_service:LiteLLMService = llm_service
|
|
|
self.db_manager = db_manager
|
|
|
|
|
|
async def execute_analysis(self, product:Product, format_type: str = "json", dry_run=False) -> tuple[dict, str]:
|
|
|
prompt = await self._prepare_prompt(product, format_type)
|
|
|
logger.info(f"prompt: {prompt}")
|
|
|
-
|
|
|
- if dry_run:
|
|
|
- mock_result = {
|
|
|
- "results": [{
|
|
|
- "asin": "MOCK_ASIN",
|
|
|
- "main_key": "MOCK_KEYWORD",
|
|
|
- "monthly_searches": "1,000",
|
|
|
- "reason": "模拟分析结果"
|
|
|
- }],
|
|
|
- "supplement": "模拟补充信息"
|
|
|
- }
|
|
|
- return mock_result, prompt
|
|
|
-
|
|
|
analysis_result = await self.llm_service.analyze(prompt)
|
|
|
return analysis_result, prompt
|
|
|
|
|
|
- async def _prepare_prompt(self, product: Product, format_type: str = "json", main_key_num: int = 3) -> str:
|
|
|
+ async def _prepare_prompt(self, product: Product, format_type: str = "json", main_key_num: int = 3, tail_key_num:int = 12) -> str:
|
|
|
competitor_data = get_competitor_prompt_data(product)
|
|
|
- output_fields = {
|
|
|
- "results": {
|
|
|
- "asin": "商品(竞品)编号",
|
|
|
- "main_key": "主要关键词",
|
|
|
- "monthly_searches": "月搜索量",
|
|
|
- "reason": "分析理由"
|
|
|
- },
|
|
|
- "supplement": "补充说明"
|
|
|
- }
|
|
|
-
|
|
|
+ # 从数据模型获取输出字段描述
|
|
|
+ output_fields = get_field_descriptions(
|
|
|
+ AICompetitorAnalyzeMainKeywordsResult,
|
|
|
+ exclude=['results.crawl_result', 'results.created_at']
|
|
|
+ )
|
|
|
formatter = FormatterFactory.create_formatter(format_type)
|
|
|
output_format = formatter.format(output_fields)
|
|
|
|
|
|
return f'''各个字段说明:
|
|
|
-{get_field_descriptions(CompetitorCrawlData)}
|
|
|
-{get_field_descriptions(ProductImageInfo)}
|
|
|
-{get_field_descriptions(TrafficKeywordResult)}
|
|
|
+{get_field_descriptions(CompetitorCrawlData, include=['asin'])}
|
|
|
+{get_field_descriptions(ProductImageInfo, include=['main_text'])}
|
|
|
+{get_field_descriptions(TrafficKeywordResult, include=['traffic_keyword', 'monthly_searches'])}
|
|
|
|
|
|
竞品数据:
|
|
|
{competitor_data}
|
|
|
@@ -255,6 +219,7 @@ class AnalysisService:
|
|
|
我是日本站的亚马逊运营,我在给产品名称为 {product.basic_info.name} 选主要关键词,请根据以上 {len(competitor_data)} 个竞品数据,按以下规则分析:
|
|
|
- 选出搜索量在1万以上的相同关键词作为主要关键词{main_key_num}个。
|
|
|
- 如果竞品的搜索量都不足1万,则从排名前十的关键词中筛选 {main_key_num} 个搜索量最大且相关性最强的词。
|
|
|
+- 根据我的产品基本信息,从竞品的主要信息和同类竞品的相似关键词中,筛选出最符合我产品的长尾关键词 tail_keys {tail_key_num} 个以上
|
|
|
- 结合日本市场特点分析
|
|
|
输出格式:
|
|
|
{output_format}'''
|