diff --git a/config/config.yaml b/config/config.yaml index a53dfa4..326f896 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -3,50 +3,6 @@ server: port: 8090 host: "0.0.0.0" -ollama: - base_url: "http://172.17.0.1:11434" - # model: "qwen3:8b" - # generate_model: "qwen3:8b" - # mapping_model: "qwen3:8b" - model: "qwen3-coder:480b-cloud" - generate_model: "qwen3-coder:480b-cloud" - mapping_model: "deepseek-v3.2:cloud" - vl_model: "qwen2.5vl:3b" - timeout: "120s" - level: "info" - format: "json" - -vllm: - base_url: "http://172.17.0.1:8001/v1" - vl_model: "qwen2.5-vl-3b-awq" - timeout: "120s" - level: "info" - -coze: - base_url: "https://api.coze.cn" - -lsxd: - # 统一登录 - login_url: "https://api.user.1688sup.com/v1/login/phone" - phone: "ORlviZN7N06W2+WKLe76xg==" - password: "V5Uh8C4bamEM6UQZh4TCeQ==" - code: "456789" - check_token_url: "https://api.user.1688sup.com/v1/user/welcome" - - -sys: - session_len: 6 - channel_pool_len: 100 - channel_pool_size: 32 - llm_pool_len: 5 - heartbeat_interval: 300 - key: report-api - pollSize: 5 #连接池大小,不配置,或配置为0表示不启用连接池 - minIdleConns: 2 #最小空闲连接数 - maxIdleTime: 30 #每个连接最大空闲时间,如果超过了这个时间会被关闭 - tls: 30 - db: - # 数字销售(AI 客户自动运营) advicer: # 上游个人微信协议服务 Token(后端主动发送消息/查询联系人时使用;可留空) @@ -64,19 +20,21 @@ advicer: auto_reply: false # 每日客户等级评估执行小时(0=凌晨0点) daily_evaluate_hour: 0 + redis: host: 47.97.27.195:6379 - type: node pass: lansexiongdi@666 key: ai_scheduler_prov - pollSize: 5 #连接池大小,不配置,或配置为0表示不启用连接池 - minIdleConns: 2 #最小空闲连接数 - maxIdleTime: 30 #每个连接最大空闲时间,如果超过了这个时间会被关闭 + poolSize: 5 + maxIdle: 2 + maxIdleTime: 30 tls: 30 - db: + db: 0 + db: driver: mysql source: root:SD###sdf323r343@tcp(121.199.38.107:3306)/sys_ai?charset=utf8mb4&parseTime=true&loc=Asia%2FShanghai + mongo: source: mongodb://root:lsxd2026123@192.168.6.115:27017 dataBase: ai_scheduler @@ -85,6 +43,7 @@ mongo: maxConnIdleTime: 30 connectTimeout: 10 socketTimeout: 30 + oss: access_key: "LTAI5tGGZzjf3tvqWk8SQj2G" secret_key: "S0NKOAUaYWoK4EGSxrMFmYDzllhvpq" @@ -92,126 +51,4 @@ oss: domain: "https://attachment-public.oss-cn-hangzhou.aliyuncs.com" endpoint: "https://oss-cn-hangzhou.aliyuncs.com" -tools: - zltxOrderDetail: - enabled: true - base_url: "https://revcl.1688sup.com/api/admin/direct/ai/%s" - add_url: "https://revcl.1688sup.com/api/admin/direct/log/%s/%s" - api_key: "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ1c2VyQ2VudGVyIiwiZXhwIjoxNzU4MDkxOTU4LCJuYmYiOjE3NTgwOTAxNTgsImp0aSI6IjEiLCJQaG9uZSI6IjE4MDAwMDAwMDAwIiwiVXNlck5hbWUiOiJsc3hkIiwiUmVhbE5hbWUiOiLotoXnuqfnrqHnkIblkZgiLCJBY2NvdW50VHlwZSI6MSwiR3JvdXBDb2RlcyI6IlZDTF9DQVNISUVSLFZDTF9PUEVSQVRFLFZDTF9BRE1JTixWQ0xfQUFBLFZDTF9WQ0xfT1BFUkFULFZDTF9JTlZPSUNFLENSTV9BRE1JTixMSUFOTElBTl9BRE1JTixNQVJLRVRNQUcyX0FETUlOLFBIT05FQklMTF9BRE1JTixRSUFOWkhVX1NVUFBFUl9BRE0sTUFSS0VUSU5HU0FBU19TVVBFUkFETUlOLENBUkRfQ09ERSxDQVJEX1BST0NVUkVNRU5ULE1BUktFVElOR1NZU1RFTV9TVVBFUixTVEFUSVNUSUNBTFNZU1RFTV9BRE1JTixaTFRYX0FETUlOLFpMVFhfT1BFUkFURSIsIkRpbmdVc2VySWQiOiIxNjIwMjYxMjMwMjg5MzM4MzQifQ.Bjsx9f8yfcrV9EWxb0n6POwnXVOq9XPRD78JFZnnf1_VAVMN78W4W570SZL27PWuDnkD7E4oUg6RzeZwZgl7BZrNpNr-a-QpNC5qCptqrqXeNfVStmX7pxWA8GqnzI8ybkZgbhQ58Gje7DzdJtBq_8zte_LDaYhTYXdIc5EAG0AbCzAk22nPTl47nkMeHtmisXQVLEsdibl1hW3ViFJlXwfXvUrOENItmL1_mRYkggUB0MaTu2nHJOYM6PaOVGLHx-74eepnmK2rm6konFEb6ed-Ukc6gVR-nM9yWZaYLYNGNKJLwZoCX3tRuerq74n4kzQgWmUEJeaVI1yIGSw1zw" - zltxProduct: - enabled: true - base_url: "https://revcl.1688sup.com/api/admin/oursProduct" - add_url: "https://revcl.1688sup.com/api/admin/platformProduct/getProductsByOfficialProductId" - api_key: "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ1c2VyQ2VudGVyIiwiZXhwIjoxNzU2MTgyNTM1LCJuYmYiOjE3NTYxODA3MzUsImp0aSI6IjEiLCJQaG9uZSI6IjE4MDAwMDAwMDAwIiwiVXNlck5hbWUiOiJsc3hkIiwiUmVhbE5hbWUiOiLotoXnuqfnrqHnkIblkZgiLCJBY2NvdW50VHlwZSI6MSwiR3JvdXBDb2RlcyI6IlZDTF9DQVNISUVSLFZDTF9PUEVSQVRFLFZDTF9BRE1JTixWQ0xfQUFBLFZDTF9WQ0xfT1BFUkFULFZDTF9JTlZPSUNFLENSTV9BRE1JTixMSUFOTElBTl9BRE1JTixNQVJLRVRNQUcyX0FETUlOLFBIT05FQklMTF9BRE1JTixRSUFOWkhVX1NVUFBFUl9BRE0sTUFSS0VUSU5HU0FBU19TVVBFUkFETUlOLENBUkRfQ09ERSxDQVJEX1BST0NVUkVNRU5ULE1BUktFVElOR1NZU1RFTV9TVVBFUixTVEFUSVNUSUNBTFNZU1RFTV9BRE1JTixaTFRYX0FETUlOLFpMVFhfT1BFUkFURSIsIkRpbmdVc2VySWQiOiIxNjIwMjYxMjMwMjg5MzM4MzQifQ.N1xv1PYbcO8_jR5adaczc16YzGsr4z101gwEZdulkRaREBJNYTOnFrvRxTFx3RJTooXsqTqroE1MR84v_1WPX6BS6kKonA-kC1Jgot6yrt5rFWhGNGb2Cpr9rKIFCCQYmiGd3AUgDazEeaQ0_sodv3E-EXg9VfE1SX8nMcck9Yjnc8NCy7RTWaBIaSeOdZcEl-JfCD0S6GSx3oErp_hk-U9FKGwf60wAuDGTY1R0BP4BYpcEqS-C2LSnsSGyURi54Cuk5xH8r1WuF0Dm5bwAj5d7Hvs77-N_sUF-C5ONqyZJRAEhYLgcmN9RX_WQZfizdQJxizlTczdpzYfy-v-1eQ" - zltxOrderStatistics: - base_url: "https://revcl.1688sup.com/api/admin/direct/ai/search/" - enabled: true - api_key: "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ1c2VyQ2VudGVyIiwiZXhwIjoxNzU2MTgyNTM1LCJuYmYiOjE3NTYxODA3MzUsImp0aSI6IjEiLCJQaG9uZSI6IjE4MDAwMDAwMDAwIiwiVXNlck5hbWUiOiJsc3hkIiwiUmVhbE5hbWUiOiLotoXnuqfnrqHnkIblkZgiLCJBY2NvdW50VHlwZSI6MSwiR3JvdXBDb2RlcyI6IlZDTF9DQVNISUVSLFZDTF9PUEVSQVRFLFZDTF9BRE1JTixWQ0xfQUFBLFZDTF9WQ0xfT1BFUkFULFZDTF9JTlZPSUNFLENSTV9BRE1JTixMSUFOTElBTl9BRE1JTixNQVJLRVRNQUcyX0FETUlOLFBIT05FQklMTF9BRE1JTixRSUFOWkhVX1NVUFBFUl9BRE0sTUFSS0VUSU5HU0FBU19TVVBFUkFETUlOLENBUkRfQ09ERSxDQVJEX1BST0NVUkVNRU5ULE1BUktFVElOR1NZU1RFTV9TVVBFUixTVEFUSVNUSUNBTFNZU1RFTV9BRE1JTixaTFRYX0FETUlOLFpMVFhfT1BFUkFURSIsIkRpbmdVc2VySWQiOiIxNjIwMjYxMjMwMjg5MzM4MzQifQ.N1xv1PYbcO8_jR5adaczc16YzGsr4z101gwEZdulkRaREBJNYTOnFrvRxTFx3RJTooXsqTqroE1MR84v_1WPX6BS6kKonA-kC1Jgot6yrt5rFWhGNGb2Cpr9rKIFCCQYmiGd3AUgDazEeaQ0_sodv3E-EXg9VfE1SX8nMcck9Yjnc8NCy7RTWaBIaSeOdZcEl-JfCD0S6GSx3oErp_hk-U9FKGwf60wAuDGTY1R0BP4BYpcEqS-C2LSnsSGyURi54Cuk5xH8r1WuF0Dm5bwAj5d7Hvs77-N_sUF-C5ONqyZJRAEhYLgcmN9RX_WQZfizdQJxizlTczdpzYfy-v-1eQ" - knowledge: - base_url: "http://117.175.169.61:10000" - enabled: true - DingTalkBot: - enabled: true - api_key: "dingsbbntrkeiyazcfdg" - api_secret: "ObqxwyR20r9rVNhju0sCPQyQA98_FZSc32W4vgxnGFH_b02HZr1BPCJsOAF816nu" - zltxOrderAfterSaleSupplier: - enabled: true - base_url: "https://revcl.1688sup.com/api/admin/afterSales/directs" - zltxOrderAfterSaleReseller: - enabled: true - base_url: "https://revcl.1688sup.com/api/admin/afterSales/reseller_pre_ai" - zltxOrderAfterSaleResellerBatch: - enabled: true - base_url: "https://revcl.1688sup.com/api/admin/afterSales/reseller_pre_ai" - weather: - enabled: true - base_url: "https://restapi.amap.com/v3/weather/weatherInfo" - api_key: "12afbde5ab78cb7e575ff76bd0bdef2b" - cozeExpress: - enabled: true - base_url: "https://api.coze.cn" - api_key: "7582477438102552616" - api_secret: "pat_eEN0BdLNDughEtABjJJRYTW71olvDU0qUbfQUeaPc2NnYWO8HeyNoui5aR9z0sSZ" - cozeCompany: - enabled: true - base_url: "https://api.coze.cn" - api_key: "7583905168607100978" - api_secret: "pat_eEN0BdLNDughEtABjJJRYTW71olvDU0qUbfQUeaPc2NnYWO8HeyNoui5aR9z0sSZ" - zltxResellerAuthProductToManagerAndDefaultLossReason: - base_url: "https://revcl.1688sup.com/api/admin/reseller/resellerAuthProduct/getManagerAndDefaultLossReason" - -# eino tool 配置 -eino_tools: - # 货易通商品上传 - hytProductUpload: - base_url: "https://hyt.86698.cn/admin_upload/api/v1/goods/supplier/batch/add/complete" - add_url: "https://hyt.86698.cn/#/goods/goodsManage" - # 货易通供应商查询 - hytSupplierSearch: - base_url: "https://hyt.86698.cn/admin_upload/api/v1/supplier/list" - # 货易通仓库查询 - hytWarehouseSearch: - base_url: "https://hyt.86698.cn/admin_upload/api/v1/warehouse/list" - # 货易通商品添加 - hytGoodsAdd: - base_url: "https://hyt.86698.cn/admin_upload/api/v1/goods/add" - add_url: "https://hyt.86698.cn/#/goods/goodsManage" - # 货易通商品图片添加 - hytGoodsMediaAdd: - base_url: "https://hyt.86698.cn/admin_upload/api/v1/media/add/batch" - # 货易通商品分类添加 - hytGoodsCategoryAdd: - base_url: "https://hyt.86698.cn/admin_upload/api/v1/good/category/relation/add" - # 货易通商品分类查询 - hytGoodsCategorySearch: - base_url: "https://hyt.86698.cn/admin_upload/api/v1/goods/category/list" - # 货易通商品品牌查询 - hytGoodsBrandSearch: - base_url: "https://hyt.86698.cn/admin_upload/api/v1/goods/brand/list" - # == 电商充值系统 == - # 我们的商品统计 - rechargeStatisticsOursProduct: - base_url: "http://admin.lanseds.cn/admin/statistics/oursProduct" - # == 通用工具 == - # 表格转图片 - excel2pic: - base_url: "http://excel2pic:8000/api/v1/convert" - -dingtalk: - api_key: "dingsbbntrkeiyazcfdg" - api_secret: "ObqxwyR20r9rVNhju0sCPQyQA98_FZSc32W4vgxnGFH_b02HZr1BPCJsOAF816nu" - table_demand: - url: "https://alidocs.dingtalk.com/i/nodes/2Amq4vjg89RnYx9DTp66m2orW3kdP0wQ" - base_id: "2Amq4vjg89RnYx9DTp66m2orW3kdP0wQ" - sheet_id_or_name: "数据表" - # 机器人群组 - bot_group_id: - bbxt: 29 - -qywx: - corp_id: "ww48151f694fb8ec67" - app_secret: "uYqtdwdtdH4Uv_P4is2AChuGzBCoB6cQDyRvpbW0Vmk" - token: "zJdukry6" - aes_key: "4VLH47qRGUogc2d3QLWuUhvJlk8Y0YuRjXzeBquBq8B" - init_account: "les.,FuZhongYun" - chat_id_len: 16 - default_config_id: 1 - bot_group_id: - bbxt: 37 - -default_prompt: - img_recognize: - system_prompt: - '你是一个具备图像理解与用户意图分析能力的智能助手。当用户提供一张图片时,请完成以下任务: - 1. 关键信息提取: - 提取出图片中对用户可能有用的关键信息(例如金额、日期、标题、编号、联系信息、商品名称等)。 - 若图片为文档类(如合同、发票、收据),请结构化输出关键字段(如客户名称、金额、开票日期等)。 - ' - user_prompt: '识别图片内容' - -# 权限配置 -permissionConfig: - permission_url: "https://api.user.1688sup.com/v1/menu/myCodes?systemId=" - - -jwt_secret: "lsxd20260918" \ No newline at end of file +jwt_secret: "lsxd20260918" diff --git a/config/config_env.yaml b/config/config_env.yaml index 9ea7bfd..7bf9835 100644 --- a/config/config_env.yaml +++ b/config/config_env.yaml @@ -3,44 +3,6 @@ server: port: 8090 host: "0.0.0.0" -ollama: - base_url: "http://192.168.6.115:11434" - model: "qwen3:8b" - generate_model: "qwen3:8b" - mapping_model: "qwen3:8b" - # model: "qwen3-coder:480b-cloud" - # generate_model: "qwen3-coder:480b-cloud" - # mapping_model: "deepseek-v3.2:cloud" - vl_model: "qwen2.5vl:7b" - timeout: "120s" - level: "info" - format: "json" - -vllm: - base_url: "http://117.175.169.61:16001/v1" - vl_model: "qwen2.5-vl-3b-awq" - timeout: "120s" - level: "info" - -coze: - base_url: "https://api.coze.cn" - api_secret: "sat_AqvFcdNgesP8megy1ItTscWFXRcsHRzmM4NJ1KNavfcdT0EPwYuCPkDqGhItpx13" - -lsxd: - # 统一登录 - login_url: "https://api.user.1688sup.com/v1/login/phone" - phone: "ORlviZN7N06W2+WKLe76xg==" - password: "V5Uh8C4bamEM6UQZh4TCeQ==" - check_token_url: "https://api.user.1688sup.com/v1/user/welcome" - code: "456789" - -sys: - session_len: 6 - channel_pool_len: 100 - channel_pool_size: 32 - llm_pool_len: 5 - heartbeat_interval: 30 - # 数字销售(AI 客户自动运营) advicer: # 上游个人微信协议服务 Token(后端主动发送消息/查询联系人时使用;可留空) @@ -58,19 +20,21 @@ advicer: auto_reply: false # 每日客户等级评估执行小时(0=凌晨0点) daily_evaluate_hour: 0 + redis: host: 47.97.27.195:6379 - type: node pass: lansexiongdi@666 key: report-api-test - pollSize: 5 #连接池大小,不配置,或配置为0表示不启用连接池 - minIdleConns: 2 #最小空闲连接数 - maxIdleTime: 30 #每个连接最大空闲时间,如果超过了这个时间会被关闭 + poolSize: 5 + maxIdle: 2 + maxIdleTime: 30 tls: 30 - db: + db: 0 + db: driver: mysql source: root:SD###sdf323r343@tcp(121.199.38.107:3306)/sys_ai_test?charset=utf8mb4&parseTime=true&loc=Asia%2FShanghai + mongo: source: mongodb://root:lsxd2026123@192.168.6.115:27017 dataBase: ai_scheduler_test @@ -79,6 +43,7 @@ mongo: maxConnIdleTime: 30 connectTimeout: 10 socketTimeout: 30 + oss: access_key: "LTAI5tGGZzjf3tvqWk8SQj2G" secret_key: "S0NKOAUaYWoK4EGSxrMFmYDzllhvpq" @@ -86,163 +51,4 @@ oss: domain: "https://attachment-public.oss-cn-hangzhou.aliyuncs.com" endpoint: "https://oss-cn-hangzhou.aliyuncs.com" -tools: - zltxOrderDetail: - enabled: true - base_url: "https://gateway.dev.cdlsxd.cn/zltx_api/admin/direct/ai/%s" - add_url: "https://gateway.dev.cdlsxd.cn/zltx_api/admin/direct/log/%s/%s" - api_key: "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ1c2VyQ2VudGVyIiwiZXhwIjoxNzU4MDkxOTU4LCJuYmYiOjE3NTgwOTAxNTgsImp0aSI6IjEiLCJQaG9uZSI6IjE4MDAwMDAwMDAwIiwiVXNlck5hbWUiOiJsc3hkIiwiUmVhbE5hbWUiOiLotoXnuqfnrqHnkIblkZgiLCJBY2NvdW50VHlwZSI6MSwiR3JvdXBDb2RlcyI6IlZDTF9DQVNISUVSLFZDTF9PUEVSQVRFLFZDTF9BRE1JTixWQ0xfQUFBLFZDTF9WQ0xfT1BFUkFULFZDTF9JTlZPSUNFLENSTV9BRE1JTixMSUFOTElBTl9BRE1JTixNQVJLRVRNQUcyX0FETUlOLFBIT05FQklMTF9BRE1JTixRSUFOWkhVX1NVUFBFUl9BRE0sTUFSS0VUSU5HU0FBU19TVVBFUkFETUlOLENBUkRfQ09ERSxDQVJEX1BST0NVUkVNRU5ULE1BUktFVElOR1NZU1RFTV9TVVBFUixTVEFUSVNUSUNBTFNZU1RFTV9BRE1JTixaTFRYX0FETUlOLFpMVFhfT1BFUkFURSIsIkRpbmdVc2VySWQiOiIxNjIwMjYxMjMwMjg5MzM4MzQifQ.Bjsx9f8yfcrV9EWxb0n6POwnXVOq9XPRD78JFZnnf1_VAVMN78W4W570SZL27PWuDnkD7E4oUg6RzeZwZgl7BZrNpNr-a-QpNC5qCptqrqXeNfVStmX7pxWA8GqnzI8ybkZgbhQ58Gje7DzdJtBq_8zte_LDaYhTYXdIc5EAG0AbCzAk22nPTl47nkMeHtmisXQVLEsdibl1hW3ViFJlXwfXvUrOENItmL1_mRYkggUB0MaTu2nHJOYM6PaOVGLHx-74eepnmK2rm6konFEb6ed-Ukc6gVR-nM9yWZaYLYNGNKJLwZoCX3tRuerq74n4kzQgWmUEJeaVI1yIGSw1zw" - zltxProduct: - enabled: true - base_url: "https://gateway.dev.cdlsxd.cn/zltx_api/admin/oursProduct" - add_url: "https://gateway.dev.cdlsxd.cn/zltx_api/admin/platformProduct/getProductsByOfficialProductId" - api_key: "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ1c2VyQ2VudGVyIiwiZXhwIjoxNzU2MTgyNTM1LCJuYmYiOjE3NTYxODA3MzUsImp0aSI6IjEiLCJQaG9uZSI6IjE4MDAwMDAwMDAwIiwiVXNlck5hbWUiOiJsc3hkIiwiUmVhbE5hbWUiOiLotoXnuqfnrqHnkIblkZgiLCJBY2NvdW50VHlwZSI6MSwiR3JvdXBDb2RlcyI6IlZDTF9DQVNISUVSLFZDTF9PUEVSQVRFLFZDTF9BRE1JTixWQ0xfQUFBLFZDTF9WQ0xfT1BFUkFULFZDTF9JTlZPSUNFLENSTV9BRE1JTixMSUFOTElBTl9BRE1JTixNQVJLRVRNQUcyX0FETUlOLFBIT05FQklMTF9BRE1JTixRSUFOWkhVX1NVUFBFUl9BRE0sTUFSS0VUSU5HU0FBU19TVVBFUkFETUlOLENBUkRfQ09ERSxDQVJEX1BST0NVUkVNRU5ULE1BUktFVElOR1NZU1RFTV9TVVBFUixTVEFUSVNUSUNBTFNZU1RFTV9BRE1JTixaTFRYX0FETUlOLFpMVFhfT1BFUkFURSIsIkRpbmdVc2VySWQiOiIxNjIwMjYxMjMwMjg5MzM4MzQifQ.N1xv1PYbcO8_jR5adaczc16YzGsr4z101gwEZdulkRaREBJNYTOnFrvRxTFx3RJTooXsqTqroE1MR84v_1WPX6BS6kKonA-kC1Jgot6yrt5rFWhGNGb2Cpr9rKIFCCQYmiGd3AUgDazEeaQ0_sodv3E-EXg9VfE1SX8nMcck9Yjnc8NCy7RTWaBIaSeOdZcEl-JfCD0S6GSx3oErp_hk-U9FKGwf60wAuDGTY1R0BP4BYpcEqS-C2LSnsSGyURi54Cuk5xH8r1WuF0Dm5bwAj5d7Hvs77-N_sUF-C5ONqyZJRAEhYLgcmN9RX_WQZfizdQJxizlTczdpzYfy-v-1eQ" - zltxOrderStatistics: - base_url: "https://gateway.dev.cdlsxd.cn/zltx_api/admin/direct/ai/search/" - enabled: true - api_key: "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ1c2VyQ2VudGVyIiwiZXhwIjoxNzU2MTgyNTM1LCJuYmYiOjE3NTYxODA3MzUsImp0aSI6IjEiLCJQaG9uZSI6IjE4MDAwMDAwMDAwIiwiVXNlck5hbWUiOiJsc3hkIiwiUmVhbE5hbWUiOiLotoXnuqfnrqHnkIblkZgiLCJBY2NvdW50VHlwZSI6MSwiR3JvdXBDb2RlcyI6IlZDTF9DQVNISUVSLFZDTF9PUEVSQVRFLFZDTF9BRE1JTixWQ0xfQUFBLFZDTF9WQ0xfT1BFUkFULFZDTF9JTlZPSUNFLENSTV9BRE1JTixMSUFOTElBTl9BRE1JTixNQVJLRVRNQUcyX0FETUlOLFBIT05FQklMTF9BRE1JTixRSUFOWkhVX1NVUFBFUl9BRE0sTUFSS0VUSU5HU0FBU19TVVBFUkFETUlOLENBUkRfQ09ERSxDQVJEX1BST0NVUkVNRU5ULE1BUktFVElOR1NZU1RFTV9TVVBFUixTVEFUSVNUSUNBTFNZU1RFTV9BRE1JTixaTFRYX0FETUlOLFpMVFhfT1BFUkFURSIsIkRpbmdVc2VySWQiOiIxNjIwMjYxMjMwMjg5MzM4MzQifQ.N1xv1PYbcO8_jR5adaczc16YzGsr4z101gwEZdulkRaREBJNYTOnFrvRxTFx3RJTooXsqTqroE1MR84v_1WPX6BS6kKonA-kC1Jgot6yrt5rFWhGNGb2Cpr9rKIFCCQYmiGd3AUgDazEeaQ0_sodv3E-EXg9VfE1SX8nMcck9Yjnc8NCy7RTWaBIaSeOdZcEl-JfCD0S6GSx3oErp_hk-U9FKGwf60wAuDGTY1R0BP4BYpcEqS-C2LSnsSGyURi54Cuk5xH8r1WuF0Dm5bwAj5d7Hvs77-N_sUF-C5ONqyZJRAEhYLgcmN9RX_WQZfizdQJxizlTczdpzYfy-v-1eQ" - knowledge: - base_url: "http://117.175.169.61:10000" - enabled: true - DingTalkBot: - enabled: true - api_key: "dingsbbntrkeiyazcfdg" - api_secret: "ObqxwyR20r9rVNhju0sCPQyQA98_FZSc32W4vgxnGFH_b02HZr1BPCJsOAF816nu" - zltxOrderAfterSaleSupplier: - enabled: true - base_url: "https://gateway.dev.cdlsxd.cn/zltx_api/admin/afterSales/directs" - zltxOrderAfterSaleReseller: - enabled: true - base_url: "https://gateway.dev.cdlsxd.cn/zltx_api/admin/afterSales/reseller_pre_ai" - zltxOrderAfterSaleResellerBatch: - enabled: true - base_url: "https://gateway.dev.cdlsxd.cn/zltx_api/admin/afterSales/reseller_pre_ai" - weather: - enabled: true - base_url: "https://restapi.amap.com/v3/weather/weatherInfo" - api_key: "12afbde5ab78cb7e575ff76bd0bdef2b" - cozeExpress: - enabled: true - base_url: "https://api.coze.cn" - api_key: "7582477438102552616" - api_secret: "pat_eEN0BdLNDughEtABjJJRYTW71olvDU0qUbfQUeaPc2NnYWO8HeyNoui5aR9z0sSZ" - cozeCompany: - enabled: true - base_url: "https://api.coze.cn" - api_key: "7583905168607100978" - api_secret: "pat_eEN0BdLNDughEtABjJJRYTW71olvDU0qUbfQUeaPc2NnYWO8HeyNoui5aR9z0sSZ" - zltxResellerAuthProductToManagerAndDefaultLossReason: - base_url: "https://revcl.1688sup.com/api/admin/reseller/resellerAuthProduct/getManagerAndDefaultLossReason" -# eino tool 配置 -eino_tools: - # == 货易通 hyt == - # 货易通商品上传 - hytProductUpload: - base_url: "https://gateway.dev.cdlsxd.cn/goods-admin/api/v1/goods/supplier/batch/add/complete" - add_url: "https://gateway.dev.cdlsxd.cn/sw//#/goods/goodsManage" - # 货易通供应商查询 - hytSupplierSearch: - base_url: "https://gateway.dev.cdlsxd.cn/goods-admin/api/v1/supplier/list" - # 货易通仓库查询 - hytWarehouseSearch: - base_url: "https://gateway.dev.cdlsxd.cn/goods-admin/api/v1/warehouse/list" - # 货易通商品添加 - hytGoodsAdd: - base_url: "https://gateway.dev.cdlsxd.cn/goods-admin/api/v1/goods/add" - add_url: "https://gateway.dev.cdlsxd.cn/sw//#/goods/goodsManage" - # 货易通商品图片添加 - hytGoodsMediaAdd: - base_url: "https://gateway.dev.cdlsxd.cn/goods-admin/api/v1/media/add/batch" - # 货易通商品分类添加 - hytGoodsCategoryAdd: - base_url: "https://gateway.dev.cdlsxd.cn/goods-admin/api/v1/good/category/relation/add" - # 货易通商品分类查询 - hytGoodsCategorySearch: - base_url: "https://gateway.dev.cdlsxd.cn/goods-admin/api/v1/goods/category/list" - # 货易通商品品牌查询 - hytGoodsBrandSearch: - base_url: "https://gateway.dev.cdlsxd.cn/goods-admin/api/v1/goods/brand/list" - # == 报表分析 data analytics == - # 负利润分析列表 - daOursProductLoss: - base_url: "https://reportapi.1688sup.com/api/dataanalytics/statisOursProductLossSum" - # 利润同比排行榜 - daProfitRanking: - base_url: "https://reportapi.1688sup.com/api/dataanalytics/profitRankingSum" - # 销售同比分析列表 - daOfficialProduct: - base_url: "https://reportapi.1688sup.com/api/dataanalytics/statisOfficialProduct" - # == 电商充值系统 == - # 我们的商品统计 - rechargeStatisticsOursProduct: - base_url: "http://admin.lanseds.cn/admin/statistics/oursProduct" - # == 通用工具 == - # 表格转图片 - excel2pic: - base_url: "http://192.168.6.109:8010/api/v1/convert" - -dingtalk: - api_key: "dingsbbntrkeiyazcfdg" - api_secret: "ObqxwyR20r9rVNhju0sCPQyQA98_FZSc32W4vgxnGFH_b02HZr1BPCJsOAF816nu" - table_demand: - url: "https://alidocs.dingtalk.com/i/nodes/YQBnd5ExVE6qAbnOiANQg2KKJyeZqMmz" - base_id: "YQBnd5ExVE6qAbnOiANQg2KKJyeZqMmz" - sheet_id_or_name: "数据表" - # 机器人群组 - bot_group_id: - bbxt: 23 - # 互动卡片 - card: - # 卡片回调路由key - https://gateway.dev.cdlsxd.cn/zltx_api/aitest/api/v1//callback/dingtalk-card - callback_route_key: "gateway.dev.cdlsxd.cn-dingtalk-card" - # 卡片调试工具 [show:展示 hide:隐藏] - debug_tool_entry_show: "hide" - # 卡片模板 - template: - # 基础消息卡片(title + content) - base_msg: "291468f8-a048-4132-a37e-a14365e855e9.schema" - # 内容收集卡片(title + textarea + button) - content_collect: "3a447814-6a3e-4a02-b48a-92c57b349d77.schema" - # 创建群聊申请(title + content + button) - create_group_approve: "faad6d5d-726d-467f-a6ba-28c1930aa5f3.schema" - # 场景群 - scene_group: - # 问题处理群模板ID - group_template_id_issue_handling: "aa3aa4fe-e709-4491-b24b-c3d5b27e86d0" - # 问题处理群模板机器人ID - group_template_robot_id_issue_handling: "VqgJYpB91j3RnB217690607273471011" - -qywx: - corp_id: "ww48151f694fb8ec67" - app_secret: "uYqtdwdtdH4Uv_P4is2AChuGzBCoB6cQDyRvpbW0Vmk" - token: "zJdukry6" - aes_key: "4VLH47qRGUogc2d3QLWuUhvJlk8Y0YuRjXzeBquBq8B" - init_account: "les.,FuZhongYun" - chat_id_len: 16 - default_config_id: 1 - bot_group_id: - bbxt: 36 - - -default_prompt: - img_recognize: - system_prompt: - '你是一个具备图像理解与用户意图分析能力的智能助手。当用户提供一张图片时,请完成以下任务: - 1. 关键信息提取: - 提取出图片中对用户可能有用的关键信息(例如金额、日期、标题、编号、联系信息、商品名称等)。 - 若图片为文档类(如合同、发票、收据),请结构化输出关键字段(如客户名称、金额、开票日期等)。 - ' - user_prompt: '识别图片内容' - -# 权限配置 -permissionConfig: - permission_url: "http://api.test.user.1688sup.cn:8001/v1/menu/myCodes?systemId=" - -# 知识库配置 -knowledge_config: - base_url: "http://192.168.6.115:9600" - tenant_id: "default" - mode: "naive" - stream: true - think: false - only_rag: true +jwt_secret: "lsxd20260918" diff --git a/config/config_test.yaml b/config/config_test.yaml index f98ab7d..62c6e3f 100644 --- a/config/config_test.yaml +++ b/config/config_test.yaml @@ -3,43 +3,6 @@ server: port: 8090 host: "0.0.0.0" -ollama: - base_url: "http://host.docker.internal:11434" - model: "qwen3-coder:480b-cloud" - generate_model: "qwen3-coder:480b-cloud" - mapping_model: "deepseek-v3.2:cloud" - vl_model: "gemini-3-pro-preview" - timeout: "120s" - level: "info" - format: "json" - -vllm: - base_url: "http://host.docker.internal:8001/v1" - vl_model: "qwen2.5-vl-3b-awq" - timeout: "120s" - level: "info" - -coze: - base_url: "https://api.coze.cn" - api_secret: "sat_AqvFcdNgesP8megy1ItTscWFXRcsHRzmM4NJ1KNavfcdT0EPwYuCPkDqGhItpx13" - - -lsxd: - # 统一登录 - login_url: "http://api.test.user.1688sup.com/v1/login/phone" - phone: "OFJ8UpqOlI7+w3Qklf36ZA==" - password: "tEbFegH/DRRh6LutFb7o3g==" - code: "123456" - check_token_url: "http://api.test.user.1688sup.com/v1/user/welcome" - - -sys: - session_len: 6 - channel_pool_len: 100 - channel_pool_size: 32 - llm_pool_len: 5 - heartbeat_interval: 30 - # 数字销售(AI 客户自动运营) advicer: # 上游个人微信协议服务 Token(后端主动发送消息/查询联系人时使用;可留空) @@ -57,21 +20,23 @@ advicer: auto_reply: false # 每日客户等级评估执行小时(0=凌晨0点) daily_evaluate_hour: 0 + redis: host: 47.97.27.195:6379 - type: node pass: lansexiongdi@666 key: ai_scheduler_test - pollSize: 5 #连接池大小,不配置,或配置为0表示不启用连接池 - minIdleConns: 2 #最小空闲连接数 - maxIdleTime: 30 #每个连接最大空闲时间,如果超过了这个时间会被关闭 + poolSize: 5 + maxIdle: 2 + maxIdleTime: 30 tls: 30 - db: + db: 0 + db: driver: mysql source: root:SD###sdf323r343@tcp(121.199.38.107:3306)/sys_ai_test?charset=utf8mb4&parseTime=true&loc=Asia%2FShanghai + mongo: - source: mongodb://root:lsxd2026123@8.147.107.207:27017 #mongodb://root:lsxd2026123@127.0.0.1:27017 + source: mongodb://root:lsxd2026123@8.147.107.207:27017 dataBase: ai_scheduler_test maxPoolSize: 100 minPoolSize: 10 @@ -86,205 +51,4 @@ oss: domain: "https://attachment-public.oss-cn-hangzhou.aliyuncs.com" endpoint: "https://oss-cn-hangzhou.aliyuncs.com" -tools: - zltxOrderDetail: - enabled: true - base_url: "https://gateway.dev.cdlsxd.cn/zltx_api/admin/direct/ai/%s" - add_url: "https://gateway.dev.cdlsxd.cn/zltx_api/admin/direct/log/%s/%s" - api_key: "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ1c2VyQ2VudGVyIiwiZXhwIjoxNzU4MDkxOTU4LCJuYmYiOjE3NTgwOTAxNTgsImp0aSI6IjEiLCJQaG9uZSI6IjE4MDAwMDAwMDAwIiwiVXNlck5hbWUiOiJsc3hkIiwiUmVhbE5hbWUiOiLotoXnuqfnrqHnkIblkZgiLCJBY2NvdW50VHlwZSI6MSwiR3JvdXBDb2RlcyI6IlZDTF9DQVNISUVSLFZDTF9PUEVSQVRFLFZDTF9BRE1JTixWQ0xfQUFBLFZDTF9WQ0xfT1BFUkFULFZDTF9JTlZPSUNFLENSTV9BRE1JTixMSUFOTElBTl9BRE1JTixNQVJLRVRNQUcyX0FETUlOLFBIT05FQklMTF9BRE1JTixRSUFOWkhVX1NVUFBFUl9BRE0sTUFSS0VUSU5HU0FBU19TVVBFUkFETUlOLENBUkRfQ09ERSxDQVJEX1BST0NVUkVNRU5ULE1BUktFVElOR1NZU1RFTV9TVVBFUixTVEFUSVNUSUNBTFNZU1RFTV9BRE1JTixaTFRYX0FETUlOLFpMVFhfT1BFUkFURSIsIkRpbmdVc2VySWQiOiIxNjIwMjYxMjMwMjg5MzM4MzQifQ.Bjsx9f8yfcrV9EWxb0n6POwnXVOq9XPRD78JFZnnf1_VAVMN78W4W570SZL27PWuDnkD7E4oUg6RzeZwZgl7BZrNpNr-a-QpNC5qCptqrqXeNfVStmX7pxWA8GqnzI8ybkZgbhQ58Gje7DzdJtBq_8zte_LDaYhTYXdIc5EAG0AbCzAk22nPTl47nkMeHtmisXQVLEsdibl1hW3ViFJlXwfXvUrOENItmL1_mRYkggUB0MaTu2nHJOYM6PaOVGLHx-74eepnmK2rm6konFEb6ed-Ukc6gVR-nM9yWZaYLYNGNKJLwZoCX3tRuerq74n4kzQgWmUEJeaVI1yIGSw1zw" - zltxProduct: - enabled: true - base_url: "https://gateway.dev.cdlsxd.cn/zltx_api/admin/oursProduct" - add_url: "https://gateway.dev.cdlsxd.cn/zltx_api/admin/platformProduct/getProductsByOfficialProductId" - api_key: "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ1c2VyQ2VudGVyIiwiZXhwIjoxNzU2MTgyNTM1LCJuYmYiOjE3NTYxODA3MzUsImp0aSI6IjEiLCJQaG9uZSI6IjE4MDAwMDAwMDAwIiwiVXNlck5hbWUiOiJsc3hkIiwiUmVhbE5hbWUiOiLotoXnuqfnrqHnkIblkZgiLCJBY2NvdW50VHlwZSI6MSwiR3JvdXBDb2RlcyI6IlZDTF9DQVNISUVSLFZDTF9PUEVSQVRFLFZDTF9BRE1JTixWQ0xfQUFBLFZDTF9WQ0xfT1BFUkFULFZDTF9JTlZPSUNFLENSTV9BRE1JTixMSUFOTElBTl9BRE1JTixNQVJLRVRNQUcyX0FETUlOLFBIT05FQklMTF9BRE1JTixRSUFOWkhVX1NVUFBFUl9BRE0sTUFSS0VUSU5HU0FBU19TVVBFUkFETUlOLENBUkRfQ09ERSxDQVJEX1BST0NVUkVNRU5ULE1BUktFVElOR1NZU1RFTV9TVVBFUixTVEFUSVNUSUNBTFNZU1RFTV9BRE1JTixaTFRYX0FETUlOLFpMVFhfT1BFUkFURSIsIkRpbmdVc2VySWQiOiIxNjIwMjYxMjMwMjg5MzM4MzQifQ.N1xv1PYbcO8_jR5adaczc16YzGsr4z101gwEZdulkRaREBJNYTOnFrvRxTFx3RJTooXsqTqroE1MR84v_1WPX6BS6kKonA-kC1Jgot6yrt5rFWhGNGb2Cpr9rKIFCCQYmiGd3AUgDazEeaQ0_sodv3E-EXg9VfE1SX8nMcck9Yjnc8NCy7RTWaBIaSeOdZcEl-JfCD0S6GSx3oErp_hk-U9FKGwf60wAuDGTY1R0BP4BYpcEqS-C2LSnsSGyURi54Cuk5xH8r1WuF0Dm5bwAj5d7Hvs77-N_sUF-C5ONqyZJRAEhYLgcmN9RX_WQZfizdQJxizlTczdpzYfy-v-1eQ" - zltxOrderStatistics: - base_url: "https://gateway.dev.cdlsxd.cn/zltx_api/admin/direct/ai/search/" - enabled: true - api_key: "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ1c2VyQ2VudGVyIiwiZXhwIjoxNzU2MTgyNTM1LCJuYmYiOjE3NTYxODA3MzUsImp0aSI6IjEiLCJQaG9uZSI6IjE4MDAwMDAwMDAwIiwiVXNlck5hbWUiOiJsc3hkIiwiUmVhbE5hbWUiOiLotoXnuqfnrqHnkIblkZgiLCJBY2NvdW50VHlwZSI6MSwiR3JvdXBDb2RlcyI6IlZDTF9DQVNISUVSLFZDTF9PUEVSQVRFLFZDTF9BRE1JTixWQ0xfQUFBLFZDTF9WQ0xfT1BFUkFULFZDTF9JTlZPSUNFLENSTV9BRE1JTixMSUFOTElBTl9BRE1JTixNQVJLRVRNQUcyX0FETUlOLFBIT05FQklMTF9BRE1JTixRSUFOWkhVX1NVUFBFUl9BRE0sTUFSS0VUSU5HU0FBU19TVVBFUkFETUlOLENBUkRfQ09ERSxDQVJEX1BST0NVUkVNRU5ULE1BUktFVElOR1NZU1RFTV9TVVBFUixTVEFUSVNUSUNBTFNZU1RFTV9BRE1JTixaTFRYX0FETUlOLFpMVFhfT1BFUkFURSIsIkRpbmdVc2VySWQiOiIxNjIwMjYxMjMwMjg5MzM4MzQifQ.N1xv1PYbcO8_jR5adaczc16YzGsr4z101gwEZdulkRaREBJNYTOnFrvRxTFx3RJTooXsqTqroE1MR84v_1WPX6BS6kKonA-kC1Jgot6yrt5rFWhGNGb2Cpr9rKIFCCQYmiGd3AUgDazEeaQ0_sodv3E-EXg9VfE1SX8nMcck9Yjnc8NCy7RTWaBIaSeOdZcEl-JfCD0S6GSx3oErp_hk-U9FKGwf60wAuDGTY1R0BP4BYpcEqS-C2LSnsSGyURi54Cuk5xH8r1WuF0Dm5bwAj5d7Hvs77-N_sUF-C5ONqyZJRAEhYLgcmN9RX_WQZfizdQJxizlTczdpzYfy-v-1eQ" - knowledge: - base_url: "http://117.175.169.61:10000" - enabled: true - DingTalkBot: - enabled: true - api_key: "dingsbbntrkeiyazcfdg" - api_secret: "ObqxwyR20r9rVNhju0sCPQyQA98_FZSc32W4vgxnGFH_b02HZr1BPCJsOAF816nu" - zltxOrderAfterSaleSupplier: - enabled: true - base_url: "https://gateway.dev.cdlsxd.cn/zltx_api/admin/afterSales/directs" - zltxOrderAfterSaleReseller: - enabled: true - base_url: "https://gateway.dev.cdlsxd.cn/zltx_api/admin/afterSales/reseller_pre_ai" - zltxOrderAfterSaleResellerBatch: - enabled: true - base_url: "https://gateway.dev.cdlsxd.cn/zltx_api/admin/afterSales/reseller_pre_ai" - weather: - enabled: true - base_url: "https://restapi.amap.com/v3/weather/weatherInfo" - api_key: "12afbde5ab78cb7e575ff76bd0bdef2b" - cozeExpress: - enabled: true - base_url: "https://api.coze.cn" - api_key: "7582477438102552616" - api_secret: "pat_eEN0BdLNDughEtABjJJRYTW71olvDU0qUbfQUeaPc2NnYWO8HeyNoui5aR9z0sSZ" - cozeCompany: - enabled: true - base_url: "https://api.coze.cn" - api_key: "7583905168607100978" - api_secret: "pat_eEN0BdLNDughEtABjJJRYTW71olvDU0qUbfQUeaPc2NnYWO8HeyNoui5aR9z0sSZ" - zltxResellerAuthProductToManagerAndDefaultLossReason: - base_url: "https://revcl.1688sup.com/api/admin/reseller/resellerAuthProduct/getManagerAndDefaultLossReason" - -# eino tool 配置 -eino_tools: - # 货易通商品上传 - hytProductUpload: - base_url: "https://gateway.dev.cdlsxd.cn/goods-admin/api/v1/goods/supplier/batch/add/complete" - add_url: "https://gateway.dev.cdlsxd.cn/sw//#/goods/goodsManage" - # 货易通供应商查询 - hytSupplierSearch: - base_url: "https://gateway.dev.cdlsxd.cn/goods-admin/api/v1/supplier/list" - # 货易通仓库查询 - hytWarehouseSearch: - base_url: "https://gateway.dev.cdlsxd.cn/goods-admin/api/v1/warehouse/list" - # 货易通商品添加 - hytGoodsAdd: - base_url: "https://gateway.dev.cdlsxd.cn/goods-admin/api/v1/goods/add" - add_url: "https://gateway.dev.cdlsxd.cn/sw//#/goods/goodsManage" - # 货易通商品图片添加 - hytGoodsMediaAdd: - base_url: "https://gateway.dev.cdlsxd.cn/goods-admin/api/v1/media/add/batch" - # 货易通商品分类添加 - hytGoodsCategoryAdd: - base_url: "https://gateway.dev.cdlsxd.cn/goods-admin/api/v1/good/category/relation/add" - # 货易通商品分类查询 - hytGoodsCategorySearch: - base_url: "https://gateway.dev.cdlsxd.cn/goods-admin/api/v1/goods/category/list" - # 货易通商品品牌查询 - hytGoodsBrandSearch: - base_url: "https://gateway.dev.cdlsxd.cn/goods-admin/api/v1/goods/brand/list" - # == 电商充值系统 == - # 我们的商品统计 - rechargeStatisticsOursProduct: - base_url: "http://admin.lanseds.cn/admin/statistics/oursProduct" - # == 通用工具 == - # 表格转图片 - excel2pic: - base_url: "http://192.168.6.109:8010/api/v1/convert" - -dingtalk: - api_key: "dingsbbntrkeiyazcfdg" - api_secret: "ObqxwyR20r9rVNhju0sCPQyQA98_FZSc32W4vgxnGFH_b02HZr1BPCJsOAF816nu" - table_demand: - url: "https://alidocs.dingtalk.com/i/nodes/YQBnd5ExVE6qAbnOiANQg2KKJyeZqMmz" - base_id: "YQBnd5ExVE6qAbnOiANQg2KKJyeZqMmz" - sheet_id_or_name: "数据表" - # 机器人群组 - bot_group_id: - bbxt: 23 - # 互动卡片 - card: - # 卡片回调路由key - callback_route_key: "gateway.dev.cdlsxd.cn-dingtalk-card" - # 卡片调试工具 [show:展示 hide:隐藏] - debug_tool_entry_show: "show" - # 卡片模板 - template: - # 基础消息卡片(title + content) - base_msg: "291468f8-a048-4132-a37e-a14365e855e9.schema" - # 内容收集卡片(title + textarea + button) - content_collect: "3a447814-6a3e-4a02-b48a-92c57b349d77.schema" - # 创建群聊申请(title + content + button) - create_group_approve: "faad6d5d-726d-467f-a6ba-28c1930aa5f3.schema" - # 场景群 - scene_group: - # 问题处理群模板ID - group_template_id_issue_handling: "aa3aa4fe-e709-4491-b24b-c3d5b27e86d0" - # 问题处理群模板机器人ID - group_template_robot_id_issue_handling: "VqgJYpB91j3RnB217690607273471011" - -qywx: - corp_id: "ww48151f694fb8ec67" - app_secret: "uYqtdwdtdH4Uv_P4is2AChuGzBCoB6cQDyRvpbW0Vmk" - token: "zJdukry6" - aes_key: "4VLH47qRGUogc2d3QLWuUhvJlk8Y0YuRjXzeBquBq8B" - init_account: "les.,FuZhongYun" - chat_id_len: 16 - default_config_id: 1 - bot_group_id: - bbxt: 36 - -default_prompt: - img_recognize: - system_prompt: - '你是一个具备图像理解与用户意图分析能力的智能助手。当用户提供一张图片时,请完成以下任务: - 1. 关键信息提取: - 提取出图片中对用户可能有用的关键信息(例如金额、日期、标题、编号、联系信息、商品名称等)。 - 若图片为文档类(如合同、发票、收据),请结构化输出关键字段(如客户名称、金额、开票日期等)。 - ' - user_prompt: '识别图片内容' -# 权限配置 -permissionConfig: - permission_url: "http://api.test.user.1688sup.cn:8001/v1/menu/myCodes?systemId=" - -# 知识库配置 -knowledge_config: - base_url: "http://192.168.6.115:9600" - tenant_id: "default" - mode: "naive" - stream: true - think: false - only_rag: true - -# llm 服务配置 -llm: - providers: - ollama: - endpoint: http://host.docker.internal:11434 - timeout: 60s - models: - - id: qwen3-coder:480b-cloud - name: qwen3-coder:480b-cloud - streaming: true - modalities: [text] - max_tokens: 4096 - - vllm: - endpoint: http://117.175.169.61:16001 - timeout: 60s - models: - - id: models/Qwen2.5-VL-3B-Instruct-AWQ - name: qwen2.5-vl-3b - streaming: true - modalities: [text, image] - max_tokens: 4096 - - # 每个能力只绑定一个 provider+model,不做自动回退 - capabilities: - intent: - provider: vllm - model: qwen2.5-vl-3b - parameters: - temperature: 0.2 - max_tokens: 4096 - stream: false - - vision: - provider: vllm - model: qwen2.5-vl-3b - parameters: - temperature: 0.5 - max_tokens: 4096 - stream: true - - chat: - provider: ollama - model: qwen3-coder:480b-cloud - parameters: - temperature: 0.7 - max_tokens: 4096 - stream: true - - - - -jwt_secret: "lsxd20260918" \ No newline at end of file +jwt_secret: "lsxd20260918" diff --git a/doc/AI_DEV_GUIDE.md b/doc/AI_DEV_GUIDE.md index aee6c4a..515aabd 100644 --- a/doc/AI_DEV_GUIDE.md +++ b/doc/AI_DEV_GUIDE.md @@ -44,13 +44,13 @@ ai_scheduler/ ├── config/config.yaml # MySQL/Mongo/Redis/JWT/微信协议地址 ├── internal/ │ ├── biz/ # ★ 业务逻辑层 -│ │ ├── advice_wx.go # 微信回调处理 + 消息流水 + 会话聚合 -│ │ ├── advice_wx_send.go # 微信消息发送 +│ │ ├── advice_wx.go # 微信回调处理 + 消息流水 + 会话聚合 + ★ 托管自动注册 +│ │ ├── advice_wx_send.go # 微信消息发送(含模拟真人打字延迟) │ │ ├── advice_strategy.go # 智能策略(四级回复/主动对话) │ │ ├── advice_client.go # 客户管理 + 等级评估 │ │ ├── advice_customer_new.go # ★ 微信好友 CRUD + 差集同步(ai_advice_customer) │ │ ├── advice_label.go # ★ 标签同步(与 DB 比对增删改) -│ │ ├── advice_chat.go # AI 对话(LLM 调用) +│ │ ├── advice_chat.go # AI 对话(LLM 调用 + ChatWithSession 复用优化) │ │ ├── advice_evaluate.go # 客户等级评估 │ │ ├── advice_proactive.go # 主动触达 │ │ ├── advice_iterate.go # 画像自迭代 @@ -102,12 +102,12 @@ ai_scheduler/ | 表名 | 说明 | 关键字段 | |---|---|---| -| `ai_advice_customer` | ★ 微信好友(`self_wxid` + `user_name` 唯一键) | label_list(逗号分隔的标签ID) | +| `ai_advice_customer` | ★ 微信好友(`self_wxid` + `user_name` 唯一键) | label_list, session_id(当前活跃会话) | | `ai_advice_label` | ★ 微信标签(`self_wxid` + `label_id` 唯一键) | label_id, label_name | | `ai_advice_advicer` | 销售基本信息 | wx_device_id(即 appId) | | `ai_advice_project` | 项目信息 | wx_token | | `ai_advice_admin` | 管理员账号 | | -| `ai_advice_session` | AI 对话会话 | | +| `ai_advice_session` | AI 对话会话 | advicer_id(托管场景动态取最新版本) | ### MongoDB 核心集合 @@ -207,8 +207,37 @@ loadLabels()(并行) → 去重(AppId + NewMsgId)→ 入库 MongoDB advicer_wx_msg → WebSocket 广播 new_message(按 appId 匹配推送) → 触发智能策略(客户文本消息异步 AI 决策) + → 触发托管自动注册(文本私聊消息异步检查) ``` +### 托管自动注册流程 + +``` +消息回调 → 文本私聊 → goroutine tryHostingAutoRegis + → (1) 查 advicer(FindByWxDeviceId)→ hosting_enabled=1? + → (2) 查 projectInfo → 取项目级 wxToken + → (3) 若 peerWxid == "filehelper" 且 advicer.reply_filehelper=1 → 跳过标签检查,直接进入回复流程 + 否则调微信 contacts/getDetailInfo 取好友 labelList("1,2,3" 形式) + labelList 为空 → 直接 return,不做回复 + → (4) 取 ai_advice_label 中该销售 hosting=1 的标签 ID 列表 + → (5) 判断好友 labelList 与托管标签是否有交集,无交集 → return + → (6) 查 ai_advice_customer 取 session_id(无则自动注册;filehelper 不在 customer 表,每次都自动注册) + → (7) hostingChatAndSend(Chat 生成 AI 回复 → 拆段 → 模拟打字延迟 → 分段发送) +``` + +**关键设计**: +- 标签判断改用微信实时返回的 labelList,不再依赖 customer 表缓存的标签 +- projectInfo 提前到步骤 2 查询(后续 getDetailInfo 和 Chat 都需要 wxToken) +- 客户昵称优先使用微信备注名(Remark),回退到 NickName,最后才用 customer 表中的昵称 +- customer 表仅用于存取 session_id,不再承担标签判断职责 +- 文件传输助手(filehelper)特殊路径:销售开启 `reply_filehelper` 后,跳过标签检查,直接作为客户进行 AI 回复;由于 filehelper 是微信系统账号,不在 customer 表,因此不写回 session_id,每条消息都新建一个会话 + +**模拟真人发送算法**: +- AI 回复拆分为多条短消息(每条 ≤80 字,按换行/句末标点拆分) +- 初始延迟 3~8 秒(模拟阅读 + 思考) +- 每条消息间延迟 = 思考时间(2~5s) + 打字时间(每字 300~500ms) +- 提示词约束:每条消息 10~30 字,用 `\n` 分隔 + ### WebSocket 实时通信 ``` @@ -222,7 +251,7 @@ loadLabels()(并行) --- -## 当前开发状态(截至 2026-09-24) +## 当前开发状态(截至 2026-09-25) ### 已完成 @@ -235,10 +264,34 @@ loadLabels()(并行) - [x] 联系人详情悬浮气泡(hover popup,含视口边界检测) - [x] WebSocket 实时推送新消息 + 在线状态 - [x] 去掉 localStorage 缓存(brief/labels 全部内存 state) +- [x] 托管标签自动会话注册:检查标签交集 → 自动注册 AI 会话 → 回写 session_id +- [x] 托管自动回复:注册会话 → Chat → 拆段 → 模拟真人打字延迟 → 分段发送 +- [x] 项目级 wx_token 支持:SendTextWithToken 方法,托管场景使用项目级 token +- [x] 查询优化:消除重复查询(projectInfo/advicer/session),新注册路径从 ~16 次降至 ~10 次 DB +- [x] 文件传输助手自动回复:销售级开关 `reply_filehelper`,开启后 peerWxid=filehelper 跳过标签检查直接作为客户进行 AI 回复 ### 待开发(下一步) -#### 1. 标签标记为客户标签 → 客户管理联动 +#### 1. 聊天算法深度优化 + +**目标**:进一步提升 AI 回复的真实感,让对话更自然、更像真人销售。 + +**优化方向**: +- **回复节奏优化**:根据消息内容复杂度动态调整延迟(简单问候快一些,复杂问题慢一些) +- **上下文感知回复**:结合客户画像、历史对话、当前时间段等因素调整回复风格 +- **多轮对话连贯性**:确保多轮对话中话题过渡自然,不重复、不突兀 +- **情绪感知**:识别客户情绪(犹豫/急迫/不满),动态调整回复语气和节奏 +- **回复长度自适应**:根据客户消息长度调整回复长度(客户发短句,AI 也回短句) +- **提示词迭代**:根据实际对话效果持续优化 BasePrompt,减少 AI 味、增强人味 + +**涉及文件**: +- `internal/data/constants/prompt.go`(提示词模板) +- `internal/biz/advice_wx.go`(splitReplyToChunks / hostingChatAndSend) +- `internal/biz/advice_wx_send.go`(typingDelay 算法) +- `internal/biz/advice_chat.go`(Chat / ChatWithSession) +- `internal/biz/advice_strategy.go`(智能策略回复) + +#### 2. 标签标记为客户标签 → 客户管理联动 **目标**:给标签打上"客户标记",被标记标签下的好友自动识别为客户,在客户管理模块体现,并在销售托管(自动回复)开启时仅对这些客户生效。 @@ -258,7 +311,7 @@ loadLabels()(并行) - 前端:`wx.js`(标签 tab 渲染标记按钮)、`theme.css`(标记样式) - SQL:`06_ai_advice_label_customer_tag.sql`(ALTER TABLE 或迁移脚本) -#### 2. 好友/会话列表 → 给好友打标签 +#### 3. 好友/会话列表 → 给好友打标签 **目标**:在好友列表和会话列表中,可以对好友(非 chatroom)添加到指定标签,类似微信原生标签管理。 @@ -326,4 +379,4 @@ docker-compose up -d --- -*最后更新:2026-09-24* +*最后更新:2026-09-25* diff --git a/internal/biz/advice_advicer.go b/internal/biz/advice_advicer.go index bfc97c6..3093a80 100644 --- a/internal/biz/advice_advicer.go +++ b/internal/biz/advice_advicer.go @@ -109,6 +109,10 @@ func (a *AdviceAdvicerBiz) HostingUpdate(ctx context.Context, req *entitys.Advic "hosting_version_id": req.HostingVersionId, "hosting_skill_id": req.HostingSkillId, } + // reply_filehelper 为可选字段,仅当显式传入时才更新 + if req.ReplyFilehelper != nil { + updates["reply_filehelper"] = *req.ReplyFilehelper + } cond := builder.NewCond() cond = cond.And(builder.Eq{"advicer_id": req.AdvicerId}) return a.advicerImpl.UpdateByCond(&cond, updates) diff --git a/internal/biz/advice_chat.go b/internal/biz/advice_chat.go index e0ccf18..8615187 100644 --- a/internal/biz/advice_chat.go +++ b/internal/biz/advice_chat.go @@ -15,6 +15,7 @@ import ( "errors" "fmt" + "github.com/gofiber/fiber/v2/log" "github.com/google/uuid" "github.com/sashabaranov/go-openai" "go.mongodb.org/mongo-driver/bson" @@ -95,10 +96,20 @@ func (a *AdviceChatBiz) Regis(ctx context.Context, chatData *entitys.ChatData, r return "", err } err = a.rdb.Rdb.SetEx(ctx, sessionId, promptJson, 3600*time.Second).Err() - + // 存储 ChatData 供后续 Chat 全量注入提示词 + if chatDataJson, e := json.Marshal(chatData); e == nil { + _ = a.rdb.Rdb.SetEx(ctx, "chatdata:"+sessionId, string(chatDataJson), 3600*time.Second).Err() + } return sessionId, err } +// UpdateSessionMission 仅更新 session 的 mission 字段(用于复用已有会话时刷新人格/项目信息) +func (a *AdviceChatBiz) UpdateSessionMission(ctx context.Context, sessionId, mission string) error { + cond := builder.NewCond() + cond = cond.And(builder.Eq{"session_id": sessionId}) + return a.aiAdviceSessionImpl.UpdateByCond(&cond, map[string]interface{}{"mission": mission}) +} + func (a *AdviceChatBiz) Chat(ctx context.Context, chat *entitys.AdvicerChatReq) (assistant mongo_model.Assistant, err error) { var session dbmodel.AiAdviceSession cond := builder.NewCond() @@ -127,16 +138,22 @@ func (a *AdviceChatBiz) Chat(ctx context.Context, chat *entitys.AdvicerChatReq) if err != nil { return assistant, err } - prompt, err := a.buildChatPromptResponse(ctx, chat, &session, chatHis) + var chatData entitys.ChatData + if cdStr, e := a.rdb.Rdb.Get(ctx, "chatdata:"+session.SessionID).Result(); e == nil { + _ = json.Unmarshal([]byte(cdStr), &chatData) + } + prompt, err := a.buildChatPromptResponse(ctx, chat, &session, chatHis, &chatData) if err != nil { return assistant, err } + log.Infof("[提示词] sessionId=%s prompt=%s", session.SessionID, pkg.JsonStringIgonErr(prompt)) resContent, err := a.callLlmResponse(ctx, prompt, modelInfo.Key, modelInfo.URL, modelInfo.ChatModel, session.ContextCache) if err != nil { return assistant, err } result := resContent.GetOutputText() + log.Infof("[AI回复] sessionId=%s content=%s", session.SessionID, result) if err = json.Unmarshal([]byte(result), &assistant); err != nil { return assistant, err } @@ -183,16 +200,22 @@ func (a *AdviceChatBiz) ChatWithSession(ctx context.Context, chat *entitys.Advic if err != nil { return assistant, err } - prompt, err := a.buildChatPromptResponse(ctx, chat, session, chatHis) + var chatData entitys.ChatData + if cdStr, e := a.rdb.Rdb.Get(ctx, "chatdata:"+session.SessionID).Result(); e == nil { + _ = json.Unmarshal([]byte(cdStr), &chatData) + } + prompt, err := a.buildChatPromptResponse(ctx, chat, session, chatHis, &chatData) if err != nil { return assistant, err } + log.Infof("[提示词] sessionId=%s prompt=%s", session.SessionID, pkg.JsonStringIgonErr(prompt)) resContent, err := a.callLlmResponse(ctx, prompt, modelInfo.Key, modelInfo.URL, modelInfo.ChatModel, session.ContextCache) if err != nil { return assistant, err } result := resContent.GetOutputText() + log.Infof("[AI回复] sessionId=%s content=%s", session.SessionID, result) if err = json.Unmarshal([]byte(result), &assistant); err != nil { return assistant, err } @@ -223,11 +246,53 @@ func (a *AdviceChatBiz) ChatWithSession(ctx context.Context, chat *entitys.Advic return } -func (a *AdviceChatBiz) buildChatPromptResponse(ctx context.Context, chat *entitys.AdvicerChatReq, session *dbmodel.AiAdviceSession, chatList []mongo_model.AdvicerChatHisMongoEntity) ([]openai.ResponseInputMessage, error) { +func (a *AdviceChatBiz) buildChatPromptResponse(ctx context.Context, chat *entitys.AdvicerChatReq, session *dbmodel.AiAdviceSession, chatList []mongo_model.AdvicerChatHisMongoEntity, chatData *entitys.ChatData) ([]openai.ResponseInputMessage, error) { + const outputFormatHint = "\n[输出格式]请用 json 格式返回你的回复,结构为 {\"result\":\"回复内容\",\"mission_status\":\"in_progress|completed|fail\",\"mission_complete_desc\":\"本轮进展小结\"}。" + var sys strings.Builder + // 基础规则 + 任务 + 风控红线 + sys.WriteString(constants.BasePrompt) + if session.Mission != "" { + sys.WriteString(session.Mission) + sys.WriteString("\n") + } + if chatData != nil && chatData.RuleDimension != "" { + sys.WriteString(constants.RulePromptPrefix) + sys.WriteString(chatData.RuleDimension) + sys.WriteString("\n") + } + sys.WriteString(constants.BasePrompt2) + // 全量结构化数据注入 + if chatData != nil { + if chatData.ProjectInfo != nil { + sys.WriteString("\n[项目信息]\n") + sys.WriteString(pkg.JsonStringIgonErr(chatData.ProjectInfo)) + } + if chatData.ProjectData != nil && len(chatData.ProjectData) > 0 { + sys.WriteString("\n[项目资料]\n") + sys.WriteString(pkg.JsonStringIgonErr(chatData.ProjectData)) + } + if chatData.AdvicerInfo != nil { + sys.WriteString("\n[销售信息]\n") + sys.WriteString(pkg.JsonStringIgonErr(chatData.AdvicerInfo)) + } + if chatData.AdvicerVersion != nil && len(chatData.AdvicerVersion) > 0 { + sys.WriteString("\n[销售人设风格]\n") + sys.WriteString(pkg.JsonStringIgonErr(chatData.AdvicerVersion)) + } + if chatData.ClientInfo != nil { + sys.WriteString("\n[客户信息]\n") + sys.WriteString(pkg.JsonStringIgonErr(chatData.ClientInfo)) + } + if chatData.TalkSkill != nil { + sys.WriteString("\n[销售技巧]\n") + sys.WriteString(pkg.JsonStringIgonErr(chatData.TalkSkill)) + } + } + sys.WriteString(outputFormatHint) message := []openai.ResponseInputMessage{ { Role: openai.ChatMessageRoleSystem, - Content: a.taskPrompt(session), + Content: sys.String(), }, { Role: openai.ChatMessageRoleSystem, @@ -468,6 +533,8 @@ func formatPersonaPrompt(v map[string]interface{}) string { } // asMap 将 interface{} 安全转为 map[string]interface{} +// 使用 JSON 中转,兼容 bson.M / primitive.M / map[string]interface{} 等各种 map 类型, +// 解决 mongo-driver 返回 primitive.M 时类型断言 v.(bson.M) 匹配不上的问题。 func asMap(v interface{}) map[string]interface{} { if v == nil { return nil @@ -475,13 +542,24 @@ func asMap(v interface{}) map[string]interface{} { if m, ok := v.(map[string]interface{}); ok { return m } - if m, ok := v.(bson.M); ok { - return map[string]interface{}(m) + // bson.D(有序文档):mongo-driver 解码嵌套文档时可能返回 bson.D 而非 bson.M + if d, ok := v.(bson.D); ok { + return d.Map() } - return nil + // JSON 中转,兼容 primitive.M 等其他 bson 类型 + data, err := json.Marshal(v) + if err != nil { + return nil + } + var m map[string]interface{} + if err = json.Unmarshal(data, &m); err != nil { + return nil + } + return m } // asStringSlice 将 interface{} 安全转为 []string +// 使用 JSON 中转,兼容 bson.A / primitive.A / []interface{} 等各种 slice 类型。 func asStringSlice(v interface{}) []string { if v == nil { return nil @@ -498,7 +576,22 @@ func asStringSlice(v interface{}) []string { } return out } - return nil + // JSON 中转,兼容 primitive.A 等 bson 切片类型 + data, err := json.Marshal(v) + if err != nil { + return nil + } + var arr []interface{} + if err = json.Unmarshal(data, &arr); err != nil { + return nil + } + out := make([]string, 0, len(arr)) + for _, item := range arr { + if s, ok := item.(string); ok { + out = append(out, s) + } + } + return out } // asFloat64 将 interface{} 安全转为 float64 diff --git a/internal/biz/advice_wx.go b/internal/biz/advice_wx.go index fdce12b..c5fd258 100644 --- a/internal/biz/advice_wx.go +++ b/internal/biz/advice_wx.go @@ -128,13 +128,15 @@ func (a *AdviceWxBiz) handleOneEvent(ctx context.Context, body []byte) error { // 判定消息方向与对话方 wxid direction := mongo_model.WxMsgDirectionCustomer peerWxid := event.PeerWxid() + to := event.Data.ToUserName.Val() - if event.IsSelfMsg() { + // 销售自己发的消息通常标记为 Self,但发给 filehelper 的除外: + // 给文件传输助手发消息时,保持 Customer 方向,让托管流程能作为客户消息触发 AI 回复 + if event.IsSelfMsg() && to != "filehelper" { direction = mongo_model.WxMsgDirectionSelf } else if len(event.Wxid) == 0 && a.clientBiz != nil { // 报文未提供登录微信标识:借助客户绑定库判定 from := event.Data.FromUserName.Val() - to := event.Data.ToUserName.Val() if _, found, _ := a.clientBiz.FindByWxid(ctx, from); !found { if _, foundTo, _ := a.clientBiz.FindByWxid(ctx, to); foundTo { direction = mongo_model.WxMsgDirectionSelf @@ -222,7 +224,6 @@ func (a *AdviceWxBiz) handleOneEvent(ctx context.Context, body []byte) error { // WebSocket 实时广播:向对应 appId 的已连接前端推送新消息事件 if a.wsBroadcaster != nil { - log.Infof("[WS] broadcasting new_message appId=%s wxid=%s", event.AppId, peerWxid) a.wsBroadcaster.Broadcast(event.AppId, "new_message", map[string]interface{}{ "appId": event.AppId, "wxid": peerWxid, @@ -242,74 +243,97 @@ func (a *AdviceWxBiz) handleOneEvent(ctx context.Context, body []byte) error { } // 智能策略:客户文本消息异步触发 AI 回复决策 - if direction == mongo_model.WxMsgDirectionCustomer && len(peerWxid) != 0 && wx.IsTextMsg(msgType) && a.strategyBiz != nil { - wxid, msgContent := peerWxid, content - go func() { - sctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute) - defer cancel() - a.strategyBiz.OnCustomerMessage(sctx, wxid, msgContent) - }() - } // 托管自动注册 + AI 回复:双向触发(不限 direction),文本私聊消息检查 if wx.IsTextMsg(msgType) && !event.IsGroupMsg() { appId, selfWxid, msgContent := event.AppId, event.Wxid, content - go a.tryHostingAutoRegis(context.Background(), appId, selfWxid, peerWxid, msgContent, direction) + + go a.tryHostingAutoRegis(context.Background(), appId, selfWxid, peerWxid, to, msgContent, direction) } return nil } // ==================== 托管自动注册 ==================== -// tryHostingAutoRegis 托管自动注册 + AI 回复:检查消息是否触发托管会话, -// 若客户无 session 则自动注册,然后用触发消息调用 Chat 生成 AI 回复并发送。 -func (a *AdviceWxBiz) tryHostingAutoRegis(ctx context.Context, appId, selfWxid, peerWxid, content string, direction string) { +// tryHostingAutoRegis 托管自动回复流程: +// 1. 查 advicer,确认处于托管状态(hosting_enabled=1) +// 2. 查 projectInfo 取项目级 wxToken +// 3. 若回调数据 ToUserName.string == "filehelper" 且 advicer.reply_filehelper=1 → 跳过标签检查,直接进入回复流程 +// 否则调微信 contacts/getDetailInfo 取好友的 labelList("1,2,3" 形式) +// labelList 为空 → 直接 return,不做回复 +// 4. 取 ai_advice_label 中该销售 hosting=1 的标签 ID 列表 +// 5. 判断好友 labelList 与托管标签是否有交集,无交集 → return +// 6. 查 ai_advice_customer 取 session_id(无则自动注册;filehelper 不在 customer 表,每次都自动注册) +// 7. 调 Chat 生成 AI 回复 → hostingChatAndSend 发送 +func (a *AdviceWxBiz) tryHostingAutoRegis(ctx context.Context, appId, selfWxid, peerWxid, toUserName, content string, direction string) { if appId == "" || selfWxid == "" || peerWxid == "" { return } - // 1. 通过 appId(即 wx_device_id)查 advicer + // 1. 通过 appId(即 wx_device_id)查 advicer,确认托管状态 advicer, err := a.adviceAdvicerBiz.FindByWxDeviceId(ctx, appId) if err != nil { - log.Infof("[托管] 查 advicer 失败 appId=%s err=%v", appId, err) return } if advicer.AdvicerID == 0 || advicer.HostingEnabled != 1 { return } - // 2. 查 customer(selfWxid + peerWxid) - customer, err := a.adviceCustomerBiz.FindBySelfWxidAndUserName(ctx, selfWxid, peerWxid) + // 2. 查项目信息(含项目级 wxToken),后续 getDetailInfo 与 Chat 都要用 + projectInfo, err := a.adviceProjectBiz.Info(ctx, &entitys.AdvicerProjectInfoReq{ProjectId: advicer.ProjectID}) if err != nil { - log.Infof("[托管] 查 customer 失败 selfWxid=%s peerWxid=%s err=%v", selfWxid, peerWxid, err) return } - if customer.CustomerID == 0 { + wxToken := projectInfo.Base.WxToken + if wxToken == "" { return } - sessionId := customer.SessionId + // 3. 文件传输助手特殊路径:仅看回调 ToUserName.string 是否为 "filehelper" + // 是 → 跳过标签检查,直接检查 advicer.reply_filehelper 开关 + // 否 → 走正常标签交集检查流程 + isFilehelper := toUserName == "filehelper" + + var sessionId string var cachedSession *dbmodel.AiAdviceSession var cachedModelInfo *dbmodel.AiAdviceModelSup + var customerNickName string + if !isFilehelper { + // 3a. 调微信 contacts/getDetailInfo 取好友的 labelList + var detailRes []wx.GetDetailInfoResData + if err := wx.Request(ctx, wxToken, wx.GetDetailInfo, wx.GetDetailInfoReq{ + AppId: appId, + Wxids: []string{peerWxid}, + }, &detailRes); err != nil { + return + } + if len(detailRes) == 0 { + return + } + detail := detailRes[0] + friendLabelList := strings.TrimSpace(detail.LabelList) + if friendLabelList == "" { + // 好友没有任何标签,不进入托管回复 + return + } - // 3. 无会话 → 检查标签交集 → 自动注册(projectInfo 延迟到需要时才查) - if sessionId == "" { + // 4. 取该销售下 hosting=1 的托管标签 ID 列表 hostingLabelIds, _ := a.adviceLabelBiz.GetHostingLabelIds(ctx, selfWxid) if len(hostingLabelIds) == 0 { return } - customerLabelSet := make(map[int]bool) - if customer.LabelList != "" { - for _, s := range strings.Split(customer.LabelList, ",") { - var id int - if _, e := fmt.Sscanf(strings.TrimSpace(s), "%d", &id); e == nil { - customerLabelSet[id] = true - } + + // 5. 判断好友标签与托管标签是否有交集 + friendLabelSet := make(map[int]bool) + for _, s := range strings.Split(friendLabelList, ",") { + var id int + if _, e := fmt.Sscanf(strings.TrimSpace(s), "%d", &id); e == nil && id > 0 { + friendLabelSet[id] = true } } hasIntersection := false for _, id := range hostingLabelIds { - if customerLabelSet[id] { + if friendLabelSet[id] { hasIntersection = true break } @@ -317,39 +341,88 @@ func (a *AdviceWxBiz) tryHostingAutoRegis(ctx context.Context, appId, selfWxid, if !hasIntersection { return } - // 标签有交集,才查项目信息(用于注册 + 后续发送) - projectInfo, err := a.adviceProjectBiz.Info(ctx, &entitys.AdvicerProjectInfoReq{ProjectId: advicer.ProjectID}) + + // 6. 查 ai_advice_customer 取 session_id + customer, err := a.adviceCustomerBiz.FindBySelfWxidAndUserName(ctx, selfWxid, peerWxid) if err != nil { - log.Infof("[托管] 查项目信息失败 projectId=%d err=%v", advicer.ProjectID, err) return } - sessionId, cachedSession, cachedModelInfo, err = a.autoRegisSession(ctx, advicer, projectInfo, customer.CustomerID, customer.NickName) - if err != nil { - log.Infof("[托管] 自动注册会话失败 err=%v", err) + if customer.CustomerID == 0 { return } + + sessionId = customer.SessionId + // 优先使用微信备注/昵称(更像真人),回退到 customer 表中的昵称 + customerNickName = detail.Remark + if customerNickName == "" { + customerNickName = detail.NickName + } + if customerNickName == "" { + customerNickName = customer.NickName + } + + // 无会话 → 自动注册 + if sessionId == "" { + sessionId, cachedSession, cachedModelInfo, err = a.autoRegisSession(ctx, advicer, projectInfo, customer.CustomerID, customerNickName, peerWxid) + if err != nil { + // autoRegisSession error + return + } + } else { + // 复用已有会话时,刷新 mission 确保人格和项目信息是最新的 + } + } else { + // filehelper 路径:跳过标签检查,直接检查 advicer.reply_filehelper 开关 + if advicer.ReplyFilehelper != 1 { + // 开关未开启,不回复 filehelper + return + } + // filehelper 与普通客户同等对待:查 ai_advice_customer 表,复用 session_id + customerNickName = "文件传输助手" + customer, err := a.adviceCustomerBiz.FindBySelfWxidAndUserName(ctx, selfWxid, peerWxid) + if err != nil { + return + } + if customer.CustomerID == 0 { + if err = a.adviceCustomerBiz.Add(ctx, &entitys.AdvicerCustomerAddReq{ + SelfWxid: selfWxid, + UserName: peerWxid, + NickName: customerNickName, + }); err != nil { + return + } + customer, err = a.adviceCustomerBiz.FindBySelfWxidAndUserName(ctx, selfWxid, peerWxid) + if err != nil || customer.CustomerID == 0 { + return + } + } + sessionId = customer.SessionId + if sessionId == "" { + sessionId, cachedSession, cachedModelInfo, err = a.autoRegisSession(ctx, advicer, projectInfo, customer.CustomerID, customerNickName, peerWxid) + if err != nil { + // filehelper autoRegis error + return + } + } else { + // 复用已有会话时,刷新 mission 确保人格和项目信息是最新的 + } } - // 4. 有会话 + 客户发的消息 → 调用 Chat 生成 AI 回复并发送 + // 7. 有会话 + 客户发的消息 → 调 Chat 生成 AI 回复并发送 if sessionId != "" && direction == mongo_model.WxMsgDirectionCustomer && content != "" { - // 延迟获取 wxToken(已有会话路径才需要查项目信息) - wxToken := "" - if p, err := a.adviceProjectBiz.Info(ctx, &entitys.AdvicerProjectInfoReq{ProjectId: advicer.ProjectID}); err == nil { - wxToken = p.Base.WxToken - } else { - log.Infof("[托管] 查项目信息失败 projectId=%d err=%v", advicer.ProjectID, err) - return - } a.hostingChatAndSend(ctx, sessionId, content, appId, peerWxid, wxToken, cachedSession, cachedModelInfo) } } +// 确保旧 session 也能拿到最新的人格和项目数据,而不是沿用老的空 mission。 + // autoRegisSession 自动注册托管会话,返回 sessionId + session对象 + modelInfo(供后续 Chat 复用)。 // advicer 和 projectInfo 由调用方传入,避免重复查询。 func (a *AdviceWxBiz) autoRegisSession(ctx context.Context, advicer dbmodel.AiAdviceAdvicer, projectInfo *entitys.AdvicerProjectInfoRes, customerId int32, customerNickName string, + peerWxid string, ) (string, *dbmodel.AiAdviceSession, *dbmodel.AiAdviceModelSup, error) { // 解析版本 versionId := advicer.HostingVersionId @@ -377,12 +450,49 @@ func (a *AdviceWxBiz) autoRegisSession(ctx context.Context, return "", nil, nil, fmt.Errorf("查版本数据失败: %w", err) } - // 构建 ChatData(直接使用传入的 advicer,不再重复查询) + // 加载销售技巧 + var talkSkillEntity *mongo_model.AdvicerTalkSkillMongoEntity + if advicer.HostingSkillId != "" { + // 指定了技巧ID,直接加载 + if skillInfo, e := a.adviceSkillBiz.Info(ctx, &entitys.AdvicerTalkSkillInfoReq{Id: advicer.HostingSkillId}); e == nil { + talkSkillEntity = skillInfo.Entity() + } + } else { + // 未指定技巧ID,取该项目最新的技巧 + if list, e := a.adviceSkillBiz.VersionList(ctx, &entitys.AdvicerTalkSkillListReq{ProjectId: projectInfo.Base.ProjectID}); e == nil && len(list) > 0 { + talkSkillEntity = list[0].AdvicerTalkSkillMongo.Entity() + } + } + // 加载客户信息(MongoDB advicer_client) + var clientEntity *mongo_model.AdvicerClientMongoEntity + if peerWxid != "" { + var clientDoc mongo_model.AdvicerClientMongo + filter := bson.M{"projectId": projectInfo.Base.ProjectID, "advicerId": advicer.AdvicerID, "wxid": peerWxid} + if e := a.mongo.Co(mongo_model.NewAdvicerClientMongo()).FindOne(ctx, filter).Decode(&clientDoc); e == nil { + clientEntity = clientDoc.Entity() + } + } + // 构建完整 ProjectInfo(确保 MySQL 项目名不丢) + projEntity := projectInfo.ConfigInfo.Entity() + if projEntity.ProjectInfo.Name == "" && projectInfo.Base.Name != "" { + projEntity.ProjectInfo.Name = projectInfo.Base.Name + } + + // 加载项目资料(advicer_project_data 集合,扁平栏目数据) + var projectData map[string]interface{} + if projData, e := a.adviceProjectBiz.ProjectDataLoad(ctx, projectInfo.Base.ProjectID); e == nil && len(projData.Data) > 0 { + projectData = projData.Data + } + + // 构建 ChatData(全量数据注入) chatData := &entitys.ChatData{ AdvicerInfo: advicer.Entity(), AdvicerVersion: versionInfo.Data, - ProjectInfo: projectInfo.ConfigInfo.Entity(), + ProjectInfo: projEntity, + ProjectData: projectData, RuleDimension: projectInfo.Base.RuleDimension, + TalkSkill: talkSkillEntity, + ClientInfo: clientEntity, } // 构建注册请求(托管场景额外强调短消息格式) @@ -390,6 +500,27 @@ func (a *AdviceWxBiz) autoRegisSession(ctx context.Context, if customerNickName == "" { mission = "自动托管会话。注意:每条回复必须简短(10~30字),像真人微信聊天一样拆成多条短消息,用\\n分隔。" } + // 将项目基本信息拼接到 mission,让后续每次 Chat 的 taskPrompt 都能带上项目名称和地址。 + // 原因:Chat 时只传 taskPrompt + 聊天历史 + 用户消息,PreviousResponseID 续写不会让模型可靠获取项目信息, + // 因此必须把项目信息直接写入 mission 字段,随 session 持久化,每次 Chat 都能看到。 + // 项目信息:优先用 MySQL 的 Base.Name(一定有),MongoDB 的 ProjectInfo 作为补充 + projectDesc := "\n[项目信息]" + hasProjectInfo := false + if projectInfo.Base.Name != "" { + projectDesc += "\n项目名称:" + projectInfo.Base.Name + hasProjectInfo = true + } + if pi := projectInfo.ConfigInfo.ProjectInfo; pi.Address != "" { + projectDesc += "\n项目地址:" + pi.Address + hasProjectInfo = true + } + if hasProjectInfo { + mission = mission + projectDesc + } + // 将销售人格拼接到 mission + if persona := formatPersonaPrompt(chatData.AdvicerVersion); persona != "" { + mission = mission + "\n\n" + persona + } regisReq := &entitys.AdvicerChatRegistReq{ AdvicerVersionId: versionId, TalkSkillId: advicer.HostingSkillId, @@ -419,9 +550,8 @@ func (a *AdviceWxBiz) autoRegisSession(ctx context.Context, // 回写 customer.session_id if err = a.adviceCustomerBiz.UpdateSessionId(ctx, customerId, sessionId); err != nil { - log.Infof("[托管] 回写 session_id 失败 customerId=%d sessionId=%s err=%v", customerId, sessionId, err) + // ignore } - log.Infof("[托管] 自动注册会话成功 customerId=%d sessionId=%s advicerId=%d", customerId, sessionId, advicer.AdvicerID) return sessionId, session, &modelInfo, nil } @@ -442,12 +572,10 @@ func (a *AdviceWxBiz) hostingChatAndSend(ctx context.Context, sessionId, content assistant, err = a.adviceChatBiz.Chat(ctx, chatReq) } if err != nil { - log.Infof("[托管] Chat 失败 sessionId=%s err=%v", sessionId, err) return } reply := strings.TrimSpace(assistant.Result) if reply == "" { - log.Infof("[托管] Chat 返回空回复 sessionId=%s", sessionId) return } // 拆分回复为多段消息,模拟真人分段发送 @@ -458,9 +586,9 @@ func (a *AdviceWxBiz) hostingChatAndSend(ctx context.Context, sessionId, content // 通过微信分段发送 AI 回复(使用项目级 wx_token) if a.wxSendBiz != nil { if _, err = a.wxSendBiz.SendMultiWithToken(ctx, wxToken, appId, peerWxid, chunks, mongo_model.WxMsgSourceCallback); err != nil { - log.Infof("[托管] 发送回复失败 appId=%s peerWxid=%s err=%v", appId, peerWxid, err) + // ignore } else { - log.Infof("[托管] 发送回复成功 sessionId=%s chunks=%d reply=%s", sessionId, len(chunks), reply) + log.Infof("[微信回复] sessionId=%s reply=%s", sessionId, reply) } } } diff --git a/internal/data/constants/prompt.go b/internal/data/constants/prompt.go index 1e7b3a6..4434679 100644 --- a/internal/data/constants/prompt.go +++ b/internal/data/constants/prompt.go @@ -8,6 +8,7 @@ const BasePrompt = `**[场景]**现在你是专业的顾问,我们在聊天软 2.像真人发微信一样说话:一条消息只表达一个意思,每条尽量控制在10~30个字;要说的内容较多时,必须拆成2~4条短消息,在result里用\n分隔。禁止把超过40个字的内容塞进同一条消息!记住:真人微信聊天不会发长段落,每条消息就像一口气打出来的那么短。 3.结合[任务内容]信息,若任务状态为"in_progress",则在对话中尽量完成任务;如果任务状态为"completed"或"fail",则主动结束对话,且该轮对话中不再更新任务状态,mission_complete_desc记录最终结果且不再更改。不要每一句对话都包含任务内容,不要目的性太强! 4.不能有任何画外音的文字格式出现!比如(等待对方回复) +5.严禁编造任何你不确定或不了解的信息!如果客户问到的事情不在提供的json数据范围内(比如你的宠物、个人经历、家庭情况等),请自然地回避或说「这个记不太清了」,绝对不能瞎编!只有json数据中明确提供的信息才能作为你的回答依据。 **[任务内容]**` // RulePromptPrefix 风控红线前缀(项目级 rule_dimension 非空时拼入系统提示) diff --git a/internal/data/model/ai_advice_advicer.gen.go b/internal/data/model/ai_advice_advicer.gen.go index 7fe7534..b7fc361 100644 --- a/internal/data/model/ai_advice_advicer.gen.go +++ b/internal/data/model/ai_advice_advicer.gen.go @@ -23,6 +23,7 @@ type AiAdviceAdvicer struct { HostingEnabled int32 `gorm:"column:hosting_enabled;not null;default:0;comment:托管开关 0关 1开" json:"hosting_enabled"` HostingVersionId string `gorm:"column:hosting_version_id;not null;default:'';comment:指定版本ID,空=最新" json:"hosting_version_id"` HostingSkillId string `gorm:"column:hosting_skill_id;not null;default:'';comment:指定技巧ID,空=最新" json:"hosting_skill_id"` + ReplyFilehelper int32 `gorm:"column:reply_filehelper;not null;default:0;comment:是否回复文件传输助手 0关 1开" json:"reply_filehelper"` CreateAt time.Time `gorm:"column:create_at;default:CURRENT_TIMESTAMP" json:"create_at"` } diff --git a/internal/data/mongo_model/advicer_project.go b/internal/data/mongo_model/advicer_project.go index 05f7d64..4ec3b9a 100644 --- a/internal/data/mongo_model/advicer_project.go +++ b/internal/data/mongo_model/advicer_project.go @@ -24,6 +24,7 @@ func (a *AdvicerProjectMongo) MongoTableName() string { } type AdvicerProjectMongoEntity struct { + ProjectInfo ProjectInfo `json:"projectInfo" bson:"projectInfo"` RegionValue RegionValue `json:"regionValue" bson:"regionValue"` CompetitionComparison CompetitionComparison `json:"competitionComparison" bson:"competitionComparison"` CoreSellingPoints CoreSellingPoints `json:"coreSellingPoints" bson:"coreSellingPoints"` @@ -33,6 +34,7 @@ type AdvicerProjectMongoEntity struct { func (a *AdvicerProjectMongo) Entity() *AdvicerProjectMongoEntity { return &AdvicerProjectMongoEntity{ + ProjectInfo: a.ProjectInfo, RegionValue: a.RegionValue, CompetitionComparison: a.CompetitionComparison, CoreSellingPoints: a.CoreSellingPoints, diff --git a/internal/entitys/advicer.go b/internal/entitys/advicer.go index e00a441..93e0402 100644 --- a/internal/entitys/advicer.go +++ b/internal/entitys/advicer.go @@ -9,6 +9,7 @@ type ChatData struct { ClientInfo *mongo_model.AdvicerClientMongoEntity `json:"clientInfo"` TalkSkill *mongo_model.AdvicerTalkSkillMongoEntity `json:"talkSkill"` ProjectInfo *mongo_model.AdvicerProjectMongoEntity `json:"projectInfo"` + ProjectData map[string]interface{} `json:"projectData"` // advicer_project_data 扁平栏目数据 AdvicerInfo *model.AiAdviceAdvicerEntity `json:"advicerInfo"` AdvicerVersion map[string]interface{} `json:"advicerVersion"` // 扁平维度数据 // RuleDimension 项目风控红线(来自项目模板 rule_dimension,可为空) diff --git a/internal/entitys/advicer_data.go b/internal/entitys/advicer_data.go index cc27038..a1ad964 100644 --- a/internal/entitys/advicer_data.go +++ b/internal/entitys/advicer_data.go @@ -40,6 +40,7 @@ type AdvicerHostingUpdateReq struct { HostingEnabled int32 `json:"hostingEnabled"` // 0=关闭 1=开启 HostingVersionId string `json:"hostingVersionId"` // 指定数字人版本ID,空=动态取最新 HostingSkillId string `json:"hostingSkillId"` // 指定聊天技巧ID,空=动态取最新 + ReplyFilehelper *int32 `json:"replyFilehelper"` // 是否回复文件传输助手(nil=不更新;0=关闭;1=开启) } // ProjectWxTokenUpdateReq 更新项目的微信协议 Token diff --git a/server.exe b/server.exe index 50712ae..649aaf1 100755 Binary files a/server.exe and b/server.exe differ diff --git a/sql/08_advicer_reply_filehelper.sql b/sql/08_advicer_reply_filehelper.sql new file mode 100644 index 0000000..291012b --- /dev/null +++ b/sql/08_advicer_reply_filehelper.sql @@ -0,0 +1,4 @@ +-- 销售级开关:是否回复文件传输助手(filehelper) +-- 0=关闭(默认),1=开启;开启后 peerWxid=filehelper 的文本消息跳过标签检查直接作为客户进行 AI 回复 +ALTER TABLE `ai_advice_advicer` + ADD COLUMN `reply_filehelper` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否回复文件传输助手 0关 1开' AFTER `hosting_skill_id`; diff --git a/web/assets/js/project_data.js b/web/assets/js/project_data.js index 083505a..a87d9fa 100644 --- a/web/assets/js/project_data.js +++ b/web/assets/js/project_data.js @@ -62,7 +62,7 @@ function renderTabAdvicers(body) { html += '
◉
暂无销售人员,点击右上角新增
'; } else { html += '
' + - "" + + "" + list.map(function (a) { var gender = a.gender === 1 ? "男" : a.gender === 2 ? "女" : "-"; var hOn = a.hosting_enabled === 1 || a.hosting_enabled === true; @@ -75,6 +75,7 @@ function renderTabAdvicers(body) { "" + '" + '' + + '' + '" + '
ID姓名生日入职时间性别行业经验微信设备ID托管创建时间操作
ID姓名生日入职时间性别行业经验微信设备ID托管文件助手创建时间操作
" + (a.working_years || "-") + " 年' + Core.esc(a.wx_device_id || '-') + "' + Core.fmtTime(a.create_at) + "' + '' + @@ -131,6 +132,21 @@ function renderTabAdvicers(body) { ); }; }); + // 文件助手开关:独立切换,立即生效 + $$(".adv-filehelper").forEach(function (b) { + b.onchange = function () { + var advicerId = Number(b.dataset.id); + Core.api("advicer/hosting/update", { + advicerId: advicerId, + replyFilehelper: b.checked ? 1 : 0 + }).then(function () { + Core.toast(b.checked ? "文件助手回复已开启" : "文件助手回复已关闭", "ok"); + }).catch(function (e) { + Core.toast(e.message, "err"); + b.checked = !b.checked; + }); + }; + }); }).catch(function (e) { body.innerHTML = '
⚠
' + Core.esc(e.message) + "
"; }); diff --git a/web/project.html b/web/project.html index eeebffa..a95656f 100644 --- a/web/project.html +++ b/web/project.html @@ -99,7 +99,7 @@ - +