Просмотр исходного кода

feat(mind): add AI emotion recognition to emotion-checkin page

Adds an AI emotion analysis section after photo capture. Shows a '识别照片中的情绪' button, simulated analysis with confidence bars (adjusts by weather selection), and '应用为情绪标签' to merge detected emotions into the existing tag selector.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Xiaogang Liao 4 месяцев назад
Родитель
Сommit
3bc428a2cb
1 измененных файлов с 194 добавлено и 0 удалено
  1. 194 0
      cfc-frontend/pages/mind/emotion-checkin.vue

+ 194 - 0
cfc-frontend/pages/mind/emotion-checkin.vue

@@ -57,6 +57,33 @@
       <text class="photo-note">照片仅对自己可见</text>
     </view>
 
+    <!-- AI 情绪识别 -->
+    <view class="section" v-if="photoPath">
+      <text class="section-title">\uD83E\uDD16 AI 情绪识别</text>
+      <view class="ai-recognize-btn" v-if="!aiResult && !aiAnalyzing" @click="analyzeEmotion">
+        <text class="ai-btn-icon">\uD83D\uDD0D</text>
+        <text class="ai-btn-text">识别照片中的情绪</text>
+      </view>
+      <view class="ai-analyzing" v-if="aiAnalyzing">
+        <text class="ai-loading-text">AI 分析中...</text>
+      </view>
+      <view class="ai-result" v-if="aiResult">
+        <text class="ai-result-title">识别结果</text>
+        <view class="ai-emotion-list">
+          <view class="ai-emotion-item" v-for="em in aiResult" :key="em.label">
+            <text class="ai-emotion-label">{{ em.label }}</text>
+            <view class="ai-emotion-bar-track">
+              <view class="ai-emotion-bar-fill" :style="{ width: em.confidence + '%', background: em.color }"></view>
+            </view>
+            <text class="ai-emotion-value">{{ em.confidence }}%</text>
+          </view>
+        </view>
+        <view class="ai-apply-tags" @click="applyAiTags">
+          <text class="ai-apply-text">应用为情绪标签</text>
+        </view>
+      </view>
+    </view>
+
     <!-- 文字记录 -->
     <view class="section">
       <text class="section-title">记录一下(选填)</text>
@@ -101,6 +128,18 @@ export default {
       photoPath: '',
       note: '',
       submitting: false,
+      aiAnalyzing: false,
+      aiResult: null,
+      aiEmotionColors: {
+        '开心': '#10B981',
+        '平静': '#3B82F6',
+        '惊喜': '#8B5CF6',
+        '难过': '#6B9BD2',
+        '生气': '#EF4444',
+        '紧张': '#F59E0B',
+        '疲惫': '#9CA3AF',
+        '害怕': '#7C3AED'
+      },
       stats: null,
       weatherOptions: [
         { value: 'sunny', icon: '\u2600\uFE0F', label: '心情很好', color: '#FFB347' },
@@ -173,10 +212,73 @@ export default {
         sourceType: ['camera', 'album'],
         success: (res) => {
           this.photoPath = res.tempFilePaths[0]
+          this.aiResult = null
         }
       })
     },
 
+    analyzeEmotion() {
+      this.aiAnalyzing = true
+      this.aiResult = null
+      // Simulate AI emotion analysis (in production, call a vision API)
+      var self = this
+      setTimeout(function() {
+        self.aiAnalyzing = false
+        // Simulated result based on the selected weather/mood as hint
+        var baseEmotions = [
+          { label: '开心', confidence: 45, color: '#10B981' },
+          { label: '平静', confidence: 30, color: '#3B82F6' },
+          { label: '惊喜', confidence: 15, color: '#8B5CF6' },
+          { label: '疲惫', confidence: 10, color: '#9CA3AF' }
+        ]
+        // Adjust based on weather selection if available
+        if (self.selectedWeather === 'rainy') {
+          baseEmotions = [
+            { label: '难过', confidence: 55, color: '#6B9BD2' },
+            { label: '疲惫', confidence: 25, color: '#9CA3AF' },
+            { label: '平静', confidence: 12, color: '#3B82F6' },
+            { label: '生气', confidence: 8, color: '#EF4444' }
+          ]
+        } else if (self.selectedWeather === 'stormy') {
+          baseEmotions = [
+            { label: '生气', confidence: 48, color: '#EF4444' },
+            { label: '紧张', confidence: 32, color: '#F59E0B' },
+            { label: '害怕', confidence: 12, color: '#7C3AED' },
+            { label: '开心', confidence: 8, color: '#10B981' }
+          ]
+        } else if (self.selectedWeather === 'rainbow') {
+          baseEmotions = [
+            { label: '开心', confidence: 60, color: '#10B981' },
+            { label: '惊喜', confidence: 25, color: '#8B5CF6' },
+            { label: '平静', confidence: 10, color: '#3B82F6' },
+            { label: '期待', confidence: 5, color: '#F59E0B' }
+          ]
+        }
+        self.aiResult = baseEmotions
+      }, 1200)
+    },
+
+    applyAiTags() {
+      if (!this.aiResult) return
+      var detected = []
+      for (var i = 0; i < this.aiResult.length; i++) {
+        var em = this.aiResult[i]
+        // Only apply high-confidence emotions as tags
+        if (em.confidence >= 20 && this.emotionTags.indexOf(em.label) !== -1) {
+          detected.push(em.label)
+        }
+      }
+      // Merge with existing selections (no duplicates)
+      var merged = this.selectedTags.slice()
+      for (var j = 0; j < detected.length; j++) {
+        if (merged.indexOf(detected[j]) === -1) {
+          merged.push(detected[j])
+        }
+      }
+      this.selectedTags = merged
+      uni.showToast({ title: '已应用情绪标签', icon: 'success' })
+    },
+
     submitCheckin() {
       if (!this.canSubmit || this.submitting) return
       this.submitting = true
@@ -422,6 +524,98 @@ export default {
   margin-top: 12rpx;
 }
 
+/* ===== AI 情绪识别 ===== */
+.ai-recognize-btn {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  padding: 20rpx;
+  background: linear-gradient(135deg, #8B5CF6, #A78BFA);
+  border-radius: 16rpx;
+  cursor: pointer;
+}
+.ai-btn-icon {
+  font-size: 32rpx;
+  margin-right: 10rpx;
+}
+.ai-btn-text {
+  font-size: 26rpx;
+  color: #fff;
+  font-weight: 500;
+}
+.ai-recognize-btn:active {
+  opacity: 0.8;
+}
+.ai-analyzing {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  padding: 30rpx 0;
+}
+.ai-loading-text {
+  font-size: 26rpx;
+  color: #8B5CF6;
+}
+.ai-result {
+  margin-top: 16rpx;
+}
+.ai-result-title {
+  font-size: 24rpx;
+  color: #666;
+  margin-bottom: 12rpx;
+  display: block;
+}
+.ai-emotion-list {
+  display: flex;
+  flex-direction: column;
+  gap: 12rpx;
+}
+.ai-emotion-item {
+  display: flex;
+  align-items: center;
+  gap: 12rpx;
+}
+.ai-emotion-label {
+  font-size: 24rpx;
+  color: #333;
+  width: 64rpx;
+  flex-shrink: 0;
+}
+.ai-emotion-bar-track {
+  flex: 1;
+  height: 16rpx;
+  background: #F0F0F0;
+  border-radius: 8rpx;
+  overflow: hidden;
+}
+.ai-emotion-bar-fill {
+  height: 100%;
+  border-radius: 8rpx;
+  transition: width 0.5s;
+}
+.ai-emotion-value {
+  font-size: 22rpx;
+  color: #999;
+  width: 56rpx;
+  text-align: right;
+}
+.ai-apply-tags {
+  margin-top: 20rpx;
+  padding: 16rpx;
+  background: #F5F0FF;
+  border-radius: 12rpx;
+  text-align: center;
+  cursor: pointer;
+}
+.ai-apply-text {
+  font-size: 26rpx;
+  color: #8B5CF6;
+  font-weight: 500;
+}
+.ai-apply-tags:active {
+  opacity: 0.7;
+}
+
 .note-input {
   width: 100%;
   min-height: 140rpx;