Ver código fonte

chore: auto bump version and changelog [skip ci]

iwt 1 mês atrás
pai
commit
643d85d5ef

+ 13 - 13
cfc-frontend/pages/ai/chat.vue

@@ -5,7 +5,7 @@
       <view class="nav-back" @click="goBack">
         <text class="nav-back-icon">‹</text>
       </view>
-      <text class="nav-title">{{ isNutrition ? '精准营养助手' : (isHealthButler ? 'AI 健康管家' : 'AI 家庭助手') }}</text>
+      <text class="nav-title">{{ isNutrition ? '精准营养助手' : (isHealthCoach ? 'AI 健康管家' : 'AI 家庭助手') }}</text>
       <view class="nav-actions">
         <view class="mascot-badge" v-if="mascotCode && !isNutrition" @click="showConversations = !showConversations">
           <text class="mascot-badge-icon">{{ mascotIcon }}</text>
@@ -38,19 +38,19 @@
       @scrolltoupper="loadMoreMessages" id="messageList">
       <view class="message-list-inner">
         <view class="welcome-card" v-if="messages.length === 0 && !sending">
-          <view class="welcome-icon">{{ mascotIcon || (isNutrition ? '🥗' : (isHealthButler ? '🏥' : '🤖')) }}</view>
-          <text class="welcome-title">{{ isNutrition ? '你好!我是精准营养助手' : (isHealthButler ? '你好!我是AI健康管家' : ('你好!我是' + (mascotName || '家庭助手'))) }}</text>
+          <view class="welcome-icon">{{ mascotIcon || (isNutrition ? '🥗' : (isHealthCoach ? '🏥' : '🤖')) }}</view>
+          <text class="welcome-title">{{ isNutrition ? '你好!我是精准营养助手' : (isHealthCoach ? '你好!我是AI健康管家' : ('你好!我是' + (mascotName || '家庭助手'))) }}</text>
           <text class="welcome-desc">{{ welcomeSubtitle }}</text>
           <view class="welcome-suggestions">
-            <view class="welcome-suggestion" v-if="!isNutrition && !isHealthButler" @click="quickQuestion('小明最近任务完成怎么样?')">
+            <view class="welcome-suggestion" v-if="!isNutrition && !isHealthCoach" @click="quickQuestion('小明最近任务完成怎么样?')">
               <text class="suggestion-icon">📋</text>
               <text class="suggestion-text">小明最近任务完成怎么样?</text>
             </view>
-            <view class="welcome-suggestion" v-if="!isNutrition && !isHealthButler" @click="quickQuestion('我家孩子的能量评分怎么样?')">
+            <view class="welcome-suggestion" v-if="!isNutrition && !isHealthCoach" @click="quickQuestion('我家孩子的能量评分怎么样?')">
               <text class="suggestion-icon">⚡</text>
               <text class="suggestion-text">孩子的能量评分怎么样?</text>
             </view>
-            <view class="welcome-suggestion" v-if="!isNutrition && !isHealthButler" @click="quickQuestion('今天有什么需要我做的事情?')">
+            <view class="welcome-suggestion" v-if="!isNutrition && !isHealthCoach" @click="quickQuestion('今天有什么需要我做的事情?')">
               <text class="suggestion-icon">✅</text>
               <text class="suggestion-text">今天有什么需要我做的事情?</text>
             </view>
@@ -62,15 +62,15 @@
               <text class="suggestion-icon">🛒</text>
               <text class="suggestion-text">有哪些食物或产品推荐?</text>
             </view>
-            <view class="welcome-suggestion" v-if="isHealthButler" @click="quickQuestion('我家孩子挑食怎么办?')">
+            <view class="welcome-suggestion" v-if="isHealthCoach" @click="quickQuestion('我家孩子挑食怎么办?')">
               <text class="suggestion-icon">🍽️</text>
               <text class="suggestion-text">我家孩子挑食怎么办?</text>
             </view>
-            <view class="welcome-suggestion" v-if="isHealthButler" @click="quickQuestion('孩子最近总感冒,怎么调养?')">
+            <view class="welcome-suggestion" v-if="isHealthCoach" @click="quickQuestion('孩子最近总感冒,怎么调养?')">
               <text class="suggestion-icon">🤧</text>
               <text class="suggestion-text">孩子最近总感冒,怎么调养?</text>
             </view>
-            <view class="welcome-suggestion" v-if="isHealthButler" @click="quickQuestion('什么样的体质?如何调理?')">
+            <view class="welcome-suggestion" v-if="isHealthCoach" @click="quickQuestion('什么样的体质?如何调理?')">
               <text class="suggestion-icon">🔍</text>
               <text class="suggestion-text">什么样的体质?如何调理?</text>
             </view>
@@ -84,7 +84,7 @@
           </view>
           <!-- AI 回复 -->
           <view class="message message-ai" v-if="msg.answer">
-<view class="message-avatar">{{ isHealthButler ? '🏥' : (mascotIcon || '🤖') }}</view>
+<view class="message-avatar">{{ isHealthCoach ? '🏥' : (mascotIcon || '🤖') }}</view>
             <view class="message-bubble ai-bubble">
               <text class="ai-answer-text">{{ msg.answer }}</text>
         <!-- 推荐卡片 -->
@@ -140,7 +140,7 @@
 </template>
 
 <script>
-import { aiSendMessage, aiGetConversations, aiGetMessages, aiDeleteConversation, aiSendNutritionMessage, aiSendHealthButlerMessage } from '../../utils/api.js'
+import { aiSendMessage, aiGetConversations, aiGetMessages, aiDeleteConversation, aiSendNutritionMessage, aiSendHealthCoachMessage } from '../../utils/api.js'
 import BaseEmpty from '../../components/BaseEmpty.vue'
 import AITaskCard from '../../components/AITaskCard.vue'
 
@@ -170,14 +170,14 @@ export default {
     isNutrition: function() {
       return this.mode === 'nutrition'
     },
-    isHealthButler: function() {
+    isHealthCoach: function() {
       return this.mode === 'health'
     },
     welcomeSubtitle: function() {
       if (this.isNutrition) {
         return '我可以基于菌群检测报告,为你提供个性化的营养建议和推荐'
       }
-      if (this.isHealthButler) {
+      if (this.isHealthCoach) {
         return '专注儿童健康咨询:体质调理、营养喂养、科学保健'
       }
       if (this.fromPage) {

+ 4 - 4
cfc-frontend/utils/api.js

@@ -1149,8 +1149,8 @@ export const aiSendNutritionMessage = (data) => {
   })
 }
 
-// AI 健康管家
-export const aiSendHealthButlerMessage = (data) => {
+// AI 健康教练
+export const aiSendHealthCoachMessage = (data) => {
   var query = data && data.query ? data.query : ''
   var conversationId = data && data.conversationId ? data.conversationId : ''
   var userId = uni.getStorageSync('userId') || ''
@@ -1160,13 +1160,13 @@ export const aiSendHealthButlerMessage = (data) => {
     user_id: userId,
     conversation_id: conversationId,
     response_mode: 'blocking',
-    bot_name: '健康管家'
+    bot_name: '健康教练'
   }
   if (data && data.childId) {
     langgraphBody.inputs = { child_id: data.childId }
   }
   return langgraphRequest({
-    langgraphPath: '/api/v1/health/butler',
+    langgraphPath: '/api/v1/health/coach',
     langgraphBody: langgraphBody,
     difyFallbackPath: '/api/ai/chat/send',
     difyFallbackData: data,

+ 5 - 5
cfc-langgraph/app/api/adapter.py

@@ -3,7 +3,7 @@ from pydantic import BaseModel
 from typing import Optional
 from app.graphs.chat_graph import create_chat_graph
 from app.graphs.analysis_graph import create_analysis_graph
-from app.graphs.health_butler_graph import create_health_butler_graph
+from app.graphs.health_coach_graph import create_health_coach_graph
 import uuid
 import time
 
@@ -155,13 +155,13 @@ async def analysis_run(req: DifyAnalysisRequest):
     )
 
 
-@router.post("/health/butler", response_model=DifyResponse)
-async def health_butler(req: DifyChatRequest):
+@router.post("/health/coach", response_model=DifyResponse)
+async def health_coach(req: DifyChatRequest):
     query = _extract_query(req)
     if not query:
         raise HTTPException(status_code=400, detail="query 为空")
 
-    graph = create_health_butler_graph()
+    graph = create_health_coach_graph()
     initial_state = {
         "query": query,
         "user_id": int(req.user_id) if str(req.user_id).isdigit() else 0,
@@ -189,7 +189,7 @@ async def health_butler(req: DifyChatRequest):
     return DifyResponse(
         id=f"health-{uuid.uuid4().hex[:24]}",
         created=_now_ts(),
-        model="langgraph-health-butler",
+        model="langgraph-health-coach",
         choices=[
             DifyChoice(
                 index=0,

+ 31 - 23
cfc-langgraph/app/graphs/health_butler_graph.py → cfc-langgraph/app/graphs/health_coach_graph.py

@@ -1,5 +1,5 @@
 """
-健康管家 LangGraph - 专为儿童健康咨询设计的对话图
+AI 健康教练 LangGraph - 专为儿童健康咨询设计的对话图
 Uses RAG retrieval from health knowledge base.
 """
 from typing import TypedDict
@@ -15,7 +15,7 @@ import logging
 logger = logging.getLogger(__name__)
 
 
-class HealthButlerState(TypedDict):
+class HealthCoachState(TypedDict):
     query: str
     user_id: int
     child_id: int | None
@@ -26,28 +26,36 @@ class HealthButlerState(TypedDict):
     memory_messages: list | None
 
 
-HEALTH_BUTLER_PROMPT = """你是一个专业、温暖的家庭健康顾问,专注于儿童健康成长。
+HEALTH_COACH_PROMPT = """你是一个儿童健康教练,喜欢用提问的方式引导家长发现问题和解决方案。
+
+核心原则:
+1. 先问后答:不要直接给答案,用问题引导家长思考
+   - "孩子这种情况多久了?"、"平时饮食习惯是怎样的?"、"体重身高发育曲线有没有记录?"
+2. 用开放式问题了解情况,再给针对性建议
+3. 语气温暖,像一个耐心的教练在陪伴家长成长
 
 你的职责:
-1. 儿童体质调理咨询(如:挑食、瘦弱、易疲劳、反复生病)
-2. 科学喂养和营养建议(辅食搭配、食欲不振、营养补充)
-3. 日常保健知识(科学睡眠、运动建议、季节防护)
-4. 体质辨识基础咨询(气虚/阳虚/阴虚/痰湿等体质特征解读)
-5. 健康问题初步判断和就医建议
-
-回答原则:
-1. 用中文,语气温暖专业,像一个关心孩子的家庭医生
-2. 涉及具体健康问题,先问清年龄、性别、症状持续时间等关键信息
-3. 不确定时明确说"建议咨询专业医生",绝不臆断严重疾病
-4. 回答结构:问题分析 → 建议方案 → 日常调养tip
-5. 涉及儿童安全(性早熟、严重外伤、急性症状等)立刻建议就医
-
-你可以通过检索健康知识库来获取依据。
+1. 儿童体质调理(如挑食、瘦弱、易疲劳、反复生病)—— 用提问了解情况
+2. 科学喂养和营养建议 —— 先问饮食现状再给建议
+3. 日常保健(睡眠、运动、季节防护)—— 引导家长发现生活中的问题
+4. 体质辨识基础咨询 —— 通过提问帮助家长理解孩子体质特点
+5. 健康问题判断 —— 先收集症状信息再建议是否就医
+
+回答结构(教练风格):
+1. 提问:先问1-2个关键问题了解情况
+2. 分析:简短总结你观察到的问题
+3. 建议:给出2-3个可操作的建议
+4. 跟进问句:留一个后续跟进的问题,体现教练陪伴感
+
+原则:
+- 涉及严重症状(急性腹痛、高烧不退、严重外伤等)立刻建议就医,不提问
+- 不确定时明确说"建议咨询专业医生"
+- 始终用中文回答
 """
 
 
-def create_health_butler_graph():
-    """创建健康管家 StateGraph"""
+def create_health_coach_graph():
+    """创建AI健康教练 StateGraph"""
     # LLM
     llm = ChatOpenAI(
         model=settings.llm_model,
@@ -78,7 +86,7 @@ def create_health_butler_graph():
             logger.warning("健康知识检索失败: %s", e)
             return []
 
-    async def generate_answer(state: HealthButlerState) -> dict:
+    async def generate_answer(state: HealthCoachState) -> dict:
         """带健康知识检索的 LLM 生成"""
         messages = [SystemMessage(content=HEALTH_BUTLER_PROMPT)]
 
@@ -141,7 +149,7 @@ def create_health_butler_graph():
             ],
         }
 
-    async def save_memory(state: HealthButlerState) -> dict:
+    async def save_memory(state: HealthCoachState) -> dict:
         """保存对话到长期记忆"""
         try:
             if state.get("memory_messages"):
@@ -151,12 +159,12 @@ def create_health_butler_graph():
                     state["memory_messages"],
                 )
         except Exception as e:
-            logger.warning("保存健康管家记忆失败: %s", e)
+            logger.warning("保存健康教练记忆失败: %s", e)
         return {}
 
     # ── 构建图 ──
 
-    builder = StateGraph(HealthButlerState)
+    builder = StateGraph(HealthCoachState)
 
     builder.add_node("generate_answer", generate_answer)
     builder.add_node("save_memory", save_memory)

+ 1 - 1
cfc-web/.last_build_commit

@@ -1 +1 @@
-9231a9d60152470f299c1e6b21d2738089096d6a
+a0418972a456651b184d0db62e4c4d0c8a968fba

+ 2 - 2
cfc-web/package-lock.json

@@ -1,12 +1,12 @@
 {
   "name": "cfc-web",
-  "version": "1.0.501",
+  "version": "1.0.502",
   "lockfileVersion": 3,
   "requires": true,
   "packages": {
     "": {
       "name": "cfc-web",
-      "version": "1.0.501",
+      "version": "1.0.502",
       "dependencies": {
         "@wangeditor/editor": "^5.1.23",
         "@wangeditor/editor-for-vue": "^1.0.2",

+ 1 - 1
cfc-web/package.json

@@ -1,6 +1,6 @@
 {
   "name": "cfc-web",
-  "version": "1.0.502",
+  "version": "1.0.503",
   "private": true,
   "scripts": {
     "dev": "vue-cli-service serve",

+ 10 - 0
cfc-web/public/CHANGELOG-v1.0.md

@@ -4,6 +4,16 @@
 
 ---
 
+## v1.0.503 (2026-07-23)
+
+### Bug 修复
+- 修正子目录路径引用,添加 turmeric 文章
+
+### 其他
+- - 新增 turmeric.html (姜黄/黄原糖健康科普)
+- 
+
+
 ## v1.0.502 (2026-07-23)
 
 ### 其他

+ 11 - 1
cfc-web/public/CHANGELOG.md

@@ -1,6 +1,6 @@
 # 更新日志
 
-> 当前版本: v1.0.502
+> 当前版本: v1.0.503
 
 ## 历史版本
 
@@ -8,6 +8,16 @@
 
 ---
 
+## v1.0.503 (2026-07-23)
+
+### Bug 修复
+- 修正子目录路径引用,添加 turmeric 文章
+
+### 其他
+- - 新增 turmeric.html (姜黄/黄原糖健康科普)
+- 
+
+
 ## v1.0.502 (2026-07-23)
 
 ### 其他