diff --git a/config/outdoor_agent.py b/config/outdoor_agent.py new file mode 100644 index 0000000000000000000000000000000000000000..af24216ab8835d75bdabaac47d078f442b9030a4 --- /dev/null +++ b/config/outdoor_agent.py @@ -0,0 +1,281 @@ +import os +import json +from datetime import datetime +from lazyllm import OnlineChatModule, WebModule, TrainableModule +import re + +# 户外用品选品智能助手Agent +class OutdoorAgent: + def __init__(self): + # 初始化LazyLLM聊天模块 + try: + # 首先尝试使用OnlineChatModule + self.chat_module = self._init_local_model() + print(f"成功加载模型") + except Exception as e: + print(f"无法初始化模型: {e}") + try: + # 如果模型加载失败,尝试在线模型 + self.chat_module = OnlineChatModule() + print("成功加载在线模型") + except Exception as e2: + print(f"无法初始化在线模型: {e2}") + print("请设置API密钥,例如:export OPENAI_API_KEY=your_key") + # 使用模拟的聊天模块作为后备 + self.chat_module = self._create_mock_chat_module() + print("使用模拟聊天模块作为后备方案") + + # 户外用品类别数据 + self.product_categories = { + "露营装备": { + "subcategories": ["帐篷", "睡袋", "防潮垫", "露营灯", "烧烤炉", "露营桌椅", "车载露营装备"], + "features": ["便携性", "防水性", "耐用性", "保暖性", "易搭建"] + }, + "徒步登山": { + "subcategories": ["登山包", "登山鞋", "登山杖", "冲锋衣", "抓绒衣", "户外手套", "护目镜"], + "features": ["轻量化", "透气性", "防水性", "支撑性", "耐磨性"] + }, + "水上运动": { + "subcategories": ["冲浪板", "潜水装备", "皮划艇", "救生衣", "浮潜装备", "水上摩托配件"], + "features": ["浮力", "防水性", "耐用性", "便携性", "安全性"] + }, + "骑行装备": { + "subcategories": ["自行车", "骑行头盔", "骑行服", "骑行手套", "骑行眼镜", "自行车配件", "电动车配件"], + "features": ["轻量化", "透气性", "防护性", "舒适性", "功能性"] + }, + "钓鱼装备": { + "subcategories": ["鱼竿", "鱼线", "鱼钩", "鱼漂", "鱼饵", "钓鱼箱", "钓鱼服"], + "features": ["灵敏度", "耐用性", "便携性", "功能性", "隐蔽性"] + }, + "户外防护": { + "subcategories": ["防晒霜", "驱蚊剂", "急救包", "户外手表", "GPS导航", "户外刀具", "手电筒"], + "features": ["有效性", "便携性", "耐用性", "功能性", "安全性"] + } + } + + # 目标市场数据 + self.target_markets = { + "北美": { + "countries": ["美国", "加拿大"], + "preferences": ["高品质", "品牌认知", "创新功能", "环保材料", "大容量", "多功能"], + "price_sensitivity": "中低", + "logistics_cost_factor": 1.2 + }, + "欧洲": { + "countries": ["德国", "英国", "法国", "意大利", "西班牙"], + "preferences": ["环保认证", "质量标准", "设计感", "隐私保护", "轻量化", "便携性"], + "price_sensitivity": "中", + "logistics_cost_factor": 1.3 + }, + "东南亚": { + "countries": ["新加坡", "马来西亚", "泰国", "越南", "菲律宾"], + "preferences": ["性价比", "耐用性", "多功能", "本地化适配", "防热性", "防潮性"], + "price_sensitivity": "高", + "logistics_cost_factor": 0.8 + }, + "澳洲": { + "countries": ["澳大利亚", "新西兰"], + "preferences": ["防晒功能", "防水性", "耐用性", "户外性能", "环保材料", "轻量化"], + "price_sensitivity": "中", + "logistics_cost_factor": 1.4 + } + } + + # 初始化完成,不需要额外的pipeline构建 + + def _init_local_model(self): + """初始化本地模型""" + try: + # 尝试从环境变量获取API密钥 + api_key = os.environ.get("DOUBAO_API_KEY") or os.environ.get("LAZYLLM_DOUBAO_API_KEY") or os.environ.get("OPENAI_API_KEY") + if api_key: + print("检测到环境变量中的API密钥,使用在线模型") + try: + # 优先尝试豆包模型 + if os.environ.get("DOUBAO_API_KEY") or os.environ.get("LAZYLLM_DOUBAO_API_KEY"): + model = OnlineChatModule( + source="doubao", + api_key=api_key + ) + else: + # 如果没有豆包密钥但有OpenAI密钥,尝试OpenAI + model = OnlineChatModule( + source="openai", + api_key=api_key + ) + + # 测试API密钥是否有效 + try: + test_response = model("测试") + print("API密钥验证成功,使用在线模型") + return model + except Exception as test_error: + print(f"API密钥验证失败: {str(test_error)}") + print("将尝试其他模型选项") + # 继续尝试其他选项 + except Exception as api_error: + print(f"使用API密钥初始化在线模型失败: {str(api_error)}") + print("将尝试其他模型选项") + # 继续尝试其他选项 + + # 尝试加载本地模型 + local_model_path = os.environ.get("LOCAL_MODEL_PATH") + if local_model_path: + if os.path.exists(local_model_path): + print(f"尝试加载本地模型: {local_model_path}") + try: + model = TrainableModule(local_model_path) + # 尝试启动模型 + try: + model.start() + print("本地模型启动成功") + except Exception as start_error: + print(f"本地模型启动失败: {str(start_error)}") + print("将尝试使用在线模型作为后备") + raise start_error + return model + except Exception as e: + print(f"加载本地模型失败: {str(e)}") + else: + print(f"本地模型路径不存在: {local_model_path}") + + # 尝试使用常见的本地模型路径 + common_model_paths = [ + os.path.expanduser("~/.cache/huggingface/hub"), + "/models", + "./models" + ] + + for path in common_model_paths: + if os.path.exists(path): + print(f"尝试从常见路径加载模型: {path}") + try: + # 尝试列出目录中的模型 + model_dirs = [d for d in os.listdir(path) + if os.path.isdir(os.path.join(path, d))] + if model_dirs: + # 尝试第一个模型目录 + model_path = os.path.join(path, model_dirs[0]) + print(f"找到模型目录: {model_path}") + model = TrainableModule(model_path) + # 尝试启动模型 + try: + model.start() + print("本地模型启动成功") + return model + except Exception as start_error: + print(f"本地模型启动失败: {str(start_error)}") + print("将尝试下一个模型或在线模型") + continue + except Exception as e: + print(f"从常见路径加载模型失败: {str(e)}") + continue + + # 尝试使用在线模型 + print("尝试使用在线模型...") + try: + model = OnlineChatModule(source="doubao") + # 测试模型是否可用 + try: + test_response = model("测试") + print("在线模型验证成功") + return model + except Exception as test_error: + print(f"在线模型验证失败: {str(test_error)}") + # 使用模拟聊天模块作为后备 + print("使用模拟聊天模块作为后备") + model = self._create_mock_chat_module() + return model + except Exception as online_error: + print(f"在线模型初始化失败: {str(online_error)}") + # 使用模拟聊天模块作为后备 + print("使用模拟聊天模块作为后备") + model = self._create_mock_chat_module() + return model + except Exception as e: + print(f"初始化模型失败: {str(e)}") + # 使用模拟聊天模块作为后备 + print("使用模拟聊天模块作为后备") + model = self._create_mock_chat_module() + return model + + def _create_mock_chat_module(self): + """创建模拟聊天模块作为后备方案""" + class MockChatModule: + def __call__(self, prompt): + # 简单的模拟响应 + return "我是跨境户外用品选品智能助手,我可以帮助您分析市场趋势、选择合适的户外用品进行跨境销售。请告诉我您想了解哪方面的信息?" + + return MockChatModule() + + def select_products(self, category, market): + """选品方法""" + # 构建选品提示词,让模型根据类别和市场生成专业建议 + prompt = f"""作为专业的跨境户外用品选品专家,请根据以下信息提供5个最适合的户外用品选品建议: + - 产品类别:{category} + - 目标市场:{market} + + 请按照以下格式返回结果(只返回产品名称列表,不要添加其他内容): + 1. 产品名称1 + 2. 产品名称2 + 3. 产品名称3 + 4. 产品名称4 + 5. 产品名称5""" + + # 使用模型生成选品建议 + model_response = self.chat_module(prompt) + + # 解析模型响应,提取产品建议 + suggestions = [] + lines = model_response.strip().split('\n') + for line in lines: + line = line.strip() + if line and (line.startswith('1.') or line.startswith('2.') or + line.startswith('3.') or line.startswith('4.') or + line.startswith('5.')): + product = line.split('.', 1)[1].strip() + if product: + suggestions.append(product) + + # 如果模型响应不符合预期,提供基础建议 + if not suggestions or len(suggestions) < 5: + suggestions = [ + "多功能户外工具", + "防水户外背包", + "便携户外炉具", + "户外照明设备", + "户外防护装备" + ] + + return suggestions + + def chat(self, message): + """对话方法""" + # 构建对话提示词,让模型作为专业的跨境户外用品选品助手回答 + prompt = f"""你是一个专业的跨境户外用品选品智能助手,专门帮助用户进行户外用品的跨境销售选品。 + + 请根据用户的问题,提供专业、准确、有针对性的回答: + 用户问题:{message} + + 要求: + 1. 回答要专业,基于跨境户外用品市场的实际情况 + 2. 回答要简洁明了,重点突出 + 3. 如果涉及选品建议,请具体到产品类型 + 4. 保持友好和乐于助人的态度""" + + # 完全使用模型生成对话响应 + return self.chat_module(prompt) + + def get_categories(self): + """获取产品类别""" + return list(self.product_categories.keys()) + + def get_subcategories(self, category): + """获取子类别""" + if category in self.product_categories: + return self.product_categories[category]["subcategories"] + return [] + + def get_markets(self): + """获取目标市场""" + return list(self.target_markets.keys()) diff --git a/index.py b/index.py new file mode 100644 index 0000000000000000000000000000000000000000..0be8a1e99b30c0fb40c6405424c24a914f0d0e4c --- /dev/null +++ b/index.py @@ -0,0 +1,631 @@ +from flask import Flask, render_template_string, request, jsonify +from config.outdoor_agent import OutdoorAgent +import markdown + +app = Flask(__name__) + +# 创建户外用品选品智能助手实例 +agent = OutdoorAgent() + +# HTML模板 +html_template = ''' + + +
+ + +专业的户外用品选品分析,助您拓展跨境电商市场
+我可以帮您分析市场趋势、选择合适的户外用品
+