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 = ''' + + + + + + 户外用品选品智能助手 + + + +
+
+

🌲 跨境户外用品选品智能助手

+

专业的户外用品选品分析,助您拓展跨境电商市场

+
+ +
+

🎯 快速选品

+
+
+ + +
+
+ + +
+ +
+ +
+ +
+
+
🤖
+
+

户外用品选品助手

+

我可以帮您分析市场趋势、选择合适的户外用品

+
+
+
+
+
+ 您好!我是跨境户外用品选品智能助手。我可以帮您分析市场趋势、选择合适的户外用品进行跨境销售。您想了解哪方面的信息? +
+
刚刚
+
+
+
+ + +
+
+ + + + +
+
+
+ + + + +''' + +# 首页路由 +@app.route('/') +def index(): + # 获取产品类别和目标市场 + categories = agent.get_categories() + markets = agent.get_markets() + + return render_template_string(html_template, categories=categories, markets=markets) + +# 聊天路由 +@app.route('/chat', methods=['POST']) +def chat(): + data = request.get_json() + message = data.get('message', '') + + # 获取助手回复 + response = agent.chat(message) + + # 将Markdown格式转换为HTML + html_response = markdown.markdown(response, extensions=['extra']) + + return jsonify({'response': html_response}) + +# 选品路由 +@app.route('/select_products', methods=['POST']) +def select_products(): + data = request.get_json() + category = data.get('category', '露营装备') + market = data.get('market', '北美') + + # 获取选品建议 + result = agent.select_products(category, market) + + # 检查result的类型,如果是字符串则转换为HTML + if isinstance(result, str): + html_result = markdown.markdown(result, extensions=['extra']) + return jsonify({'suggestions': html_result, 'is_html': True}) + + return jsonify({'suggestions': result, 'is_html': False}) + +if __name__ == '__main__': + app.run(debug=True, host='0.0.0.0', port=5000) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..5bed4a7dafd3f8e440830ef0799d3bf23b59e357 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,18 @@ +lazyllm>=0.1.0 +transformers>=4.30.0 +pydantic>=2.0.0 +requests>=2.31.0 +pandas>=2.0.0 +flask>=2.0.0 +numpy>=1.24.0 +matplotlib>=3.7.0 +openai>=1.0.0 # 用于真实API调用 +tiktoken>=0.5.0 # 用于token计算 +aiohttp>=3.8.0 # 用于异步HTTP请求 +asyncio # 用于异步处理 +torch>=2.0.0 # 本地模型所需 +accelerate>=0.20.0 # 本地模型加速 +sentencepiece>=0.1.99 # 本地模型分词 +protobuf>=3.20.0 # 本地模型依赖 +scipy>=1.10.0 # 本地模型依赖 +modelscope>=1.30.0 # 本地模型下载和管理 diff --git "a/\346\212\200\346\234\257\346\226\207\346\241\243.md" "b/\346\212\200\346\234\257\346\226\207\346\241\243.md" new file mode 100644 index 0000000000000000000000000000000000000000..556ce1b3ebea911d8c26f2ed52ea25b4153d4b7f --- /dev/null +++ "b/\346\212\200\346\234\257\346\226\207\346\241\243.md" @@ -0,0 +1,102 @@ +# 海外户外用品智推 技术文档 + +## 1. 项目介绍 + +海外户外用品智推,专为海外电商卖家设计,旨在解决海外户外用品选品难题。基于LazyLLM框架开发,集成了AI大语言模型能力,提供精准的选品建议、市场分析和趋势预测。支持北美、欧洲、东南亚、澳洲等多个海外市场,覆盖露营装备、徒步登山、水上运动、骑行装备、钓鱼装备、户外防护等多个户外用品类别,帮助卖家快速找到高潜力、高利润的产品,提升跨境电商业务的成功率和效率。 + +## 2. 成员详情 + +- 主要负责人:杨龙 +- 技术栈:LazyLLM框架、Flask Web框架、Python编程语言 +- 核心功能:AI模型集成、选品流程构建、市场数据分析、Web应用开发 + +## 3. 技术栈 + +| 技术/框架 | 版本要求 | 用途 | +| ------------ | -------- | -------------------------- | +| LazyLLM | >=0.7.0 | 构建智能对话和选品分析模块 | +| Flask | >=3.0.0 | 构建Web应用界面 | +| Python | 3.8+ | 编程语言 | +| Markdown | >=3.0.0 | Markdown转HTML | +| Transformers | >=4.30.0 | 自然语言处理模型 | +| Pydantic | >=2.0.0 | 数据验证 | +| Requests | >=2.31.0 | HTTP请求 | +| Pandas | >=2.0.0 | 数据分析 | +| NumPy | >=1.24.0 | 数值计算 | +| Matplotlib | >=3.7.0 | 数据可视化 | +| OpenAI | >=1.0.0 | 真实API调用 | +| Torch | >=2.0.0 | 本地模型支持 | +| Accelerate | >=0.20.0 | 本地模型加速 | +| aiohttp | >=3.8.0 | 异步HTTP请求 | +| tiktoken | >=0.5.0 | Token计算 | +| ModelScope | >=1.30.0 | 本地模型下载和管理 | +| SentencePiece| >=0.1.99 | 本地模型分词 | +| protobuf | >=3.20.0 | 本地模型依赖 | +| SciPy | >=1.10.0 | 本地模型依赖 | + +## 4. 接口设计 + +### 4.1 核心类接口 + +#### OutdoorAgent类 + +```python +class OutdoorAgent: + def __init__(self): + """初始化OutdoorAgent,加载模型和数据""" + + def _init_local_model(self): + """初始化本地模型""" + + def _create_mock_chat_module(self): + """创建模拟聊天模块作为后备""" + + def select_products(self, category, market): + """根据产品类别和目标市场提供选品建议""" + + def chat(self, message): + """与用户进行对话,处理用户请求""" + + def get_categories(self): + """获取所有产品类别""" + + def get_subcategories(self, category): + """获取指定类别的子类别""" + + def get_markets(self): + """获取所有目标市场""" +``` + +### 4.2 Web接口 + +| 接口路径 | 请求方法 | 参数 | 返回值 | 用途 | +| ---------------- | -------- | ----------------- | ------------ | ---------------------------------- | +| / | GET | 无 | 首页HTML | 显示Web应用首页 | +| /chat | POST | message | 对话响应 | 处理用户聊天请求 | +| /select_products | POST | category, market | 选品建议列表 | 根据产品类别和目标市场提供选品建议 | + +## 5. 系统架构 + +### 5.1 整体架构 + +采用分层架构设计,主要分为以下几个层次: + +1. **表示层**:基于Flask框架的Web应用,提供用户界面和交互功能 +2. **业务逻辑层**:包含选品算法、对话管理和业务规则等核心功能 +3. **数据层**:包含产品类别数据、目标市场数据和市场趋势数据等 +4. **AI服务层**:集成多种AI大模型,提供自然语言处理和对话功能 + +### 5.2 模块结构 + +``` +[项目名称]/ +├── config/ +│ └── outdoor_agent.py # 核心选品Agent实现 +│ └── OutdoorAgent类 # 主Agent类 +├── index.py # Web应用入口文件 +│ ├── Flask应用初始化 +│ ├── 路由定义 +│ ├── HTML模板 +│ └── JavaScript交互逻辑 +└── requirements.txt # 项目依赖清单 +``` \ No newline at end of file