# Portal UI 整合建议报告

> 分析日期: 2026-04-28
> 目标: Momentry Portal (WordPress + Elementor)
> 数据源: identities 表 + face.json + holistic.json

---

## 一、现有数据分析

### 1.1 Identity 数据结构

```sql
-- identities 表关键字段
SELECT 
  uuid,
  name,
  identity_type,
  source,
  face_embedding,       -- 512-dim vector
  reference_data,       -- JSONB: {face_embeddings, trace_stats, angle_coverage}
  tmdb_id,
  tmdb_profile,
  created_at
FROM identities
```

### 1.2 reference_data 结构

```json
{
  "face_embeddings": [
    {
      "embedding": [512-dim],
      "angle": "profile_right",
      "frame": 220,
      "quality_score": 0.889
    }
  ],
  "total_references": 4,
  "quality_avg": 0.875,
  "angles_covered": ["three_quarter", "profile_right"],
  "trace_stats": {
    "trace_id": 2,
    "start_frame": 155,
    "end_frame": 297,
    "duration_frames": 143,
    "duration_seconds": 6.5,
    "total_appearances": 143,
    "avg_confidence": 0.8624,
    "pose_distribution": {
      "profile_right": 125,
      "three_quarter": 18
    }
  },
  "selection_method": "trace_filtered_v3"
}
```

---

## 二、Portal UI 功能需求

### 2.1 Identity List 页面

| 列 | 数据 | 说明 |
|-----|------|------|
| **UUID** | `uuid` | 唯一标识 |
| **Name** | `name` | Identity 名称 |
| **Source** | `source` | 来源 (tmdb/manual/auto_trace) |
| **Reference Vectors** | `reference_data.total_references` | 参考向量数量 |
| **Angle Coverage** | `reference_data.angles_covered` | 覆盖角度 |
| **Quality Avg** | `reference_data.quality_avg` | 平均质量 |
| **Trace Duration** | `reference_data.trace_stats.duration_seconds` | Trace 持续时间 |
| **TMDB ID** | `tmdb_id` | TMDB ID (if available) |
| **Created** | `created_at` | 创建时间 |

---

### 2.2 Identity Detail 页面

#### 2.2.1 基本信息

| 字段 | 数据 |
|------|------|
| **UUID** | `uuid` |
| **Name** | `name` |
| **Type** | `identity_type` |
| **Source** | `source` |
| **TMDB Profile** | `tmdb_profile` URL |

---

#### 2.2.2 Reference Vectors 详情

| 字段 | 数据 |
|------|------|
| **Total Vectors** | `total_references` |
| **Quality Avg** | `quality_avg` |
| **Angles Covered** | `angles_covered` (列表) |
| **Angle Distribution** | `trace_stats.pose_distribution` |

**显示方式**:
```
Angle Coverage: ⭐⭐⭐ (3 angles)
  ✅ three_quarter: 18 frames
  ✅ profile_right: 125 frames
  ⚠️ frontal: 0 frames (missing)
```

---

#### 2.2.3 Trace Statistics

| 字段 | 数据 |
|------|------|
| **Trace ID** | `trace_stats.trace_id` |
| **Duration** | `trace_stats.duration_seconds` seconds |
| **Appearances** | `trace_stats.total_appearances` frames |
| **Avg Confidence** | `trace_stats.avg_confidence` |
| **Start Frame** | `trace_stats.start_frame` |
| **End Frame** | `trace_stats.end_frame` |

**显示方式**:
```
Trace Quality Score: 86/100 (Good)
  Duration: 6.5 seconds
  Confidence: 0.8624 (High)
  Frames: 143 appearances
```

---

#### 2.2.4 Angle Quality Chart

| Angle | Count | Quality Avg |
|-------|-------|-------------|
| **three_quarter** | 18 | 0.85 |
| **profile_right** | 125 | **0.90** ✅ |

**可视化**: 饼图或柱状图

---

### 2.3 Reference Vector 页面

#### 列表显示

| 列 | 数据 |
|-----|------|
| **Vector ID** | 索引 |
| **Angle** | `angle` |
| **Frame** | `frame` |
| **Quality Score** | `quality_score` |
| **Pitch** | `pitch` |
| **Attributes** | `attributes.age, gender` |

---

#### 单个向量详情

| 字段 | 数据 |
|------|------|
| **Angle** | `profile_right` |
| **Frame** | 220 |
| **Quality Score** | 0.889 |
| **Pose Confidence** | 0.90 |
| **Pitch** | `neutral` |
| **Detection Confidence** | 0.87 |
| **Attributes** | Age: 31, Gender: male |

---

### 2.4 Body Actions 页面

#### 2.4.1 Action Timeline

| 字段 | 数据 |
|------|------|
| **Frame** | `frame_number` |
| **Face Pose** | `pose_angle.angle` |
| **Eye Action** | `eye_action` |
| **Mouth Action** | `mouth_action` |
| **Arm Actions** | `left_arm_action, right_arm_action` |
| **Hand Gestures** | `left_hand_gesture, right_hand_gesture` |
| **Leg Action** | `leg_action` |

---

#### 2.4.2 Action Statistics

| Category | Top Actions | Count |
|----------|-------------|-------|
| **Face** | pose_three_quarter | 6 |
| **Eyes** | eye_squint | 8 |
| **Arms** | cross_arms | 8 |
| **Hands** | open_hand | 5 |
| **Legs** | leg_stand | 8 |

---

## 三、API 端点设计

### 3.1 Identity List API

```http
GET /api/v1/identities
```

**响应**:
```json
{
  "success": true,
  "data": [
    {
      "uuid": "a9a90105-...",
      "name": "Trace 2 Fixed Format",
      "source": "auto_trace",
      "total_references": 4,
      "angles_covered": ["three_quarter", "profile_right"],
      "quality_avg": 0.875,
      "trace_duration": 6.5,
      "trace_confidence": 0.8624
    }
  ]
}
```

---

### 3.2 Identity Detail API

```http
GET /api/v1/identities/{uuid}
```

**响应**:
```json
{
  "uuid": "a9a90105-...",
  "name": "Trace 2 Fixed Format",
  "source": "auto_trace",
  "reference_vectors": {
    "total": 4,
    "angles": ["three_quarter", "profile_right"],
    "quality_avg": 0.875,
    "vectors": [
      {
        "angle": "profile_right",
        "frame": 220,
        "quality_score": 0.889
      }
    ]
  },
  "trace_stats": {
    "trace_id": 2,
    "duration_seconds": 6.5,
    "total_appearances": 143,
    "avg_confidence": 0.8624,
    "pose_distribution": {
      "profile_right": 125,
      "three_quarter": 18
    }
  }
}
```

---

### 3.3 Angle Coverage API

```http
GET /api/v1/identities/{uuid}/angle-coverage
```

**响应**:
```json
{
  "uuid": "a9a90105-...",
  "angles": {
    "frontal": {
      "count": 0,
      "quality_avg": null,
      "status": "missing"
    },
    "three_quarter": {
      "count": 18,
      "quality_avg": 0.85,
      "status": "present"
    },
    "profile_right": {
      "count": 125,
      "quality_avg": 0.90,
      "status": "dominant"
    }
  },
  "coverage_score": 66,  // 2/3 angles = 66%
  "recommendation": "Add frontal angle for better coverage"
}
```

---

### 3.4 Body Actions API

```http
GET /api/v1/identities/{uuid}/body-actions
```

**响应**:
```json
{
  "uuid": "a9a90105-...",
  "actions": {
    "face": [{"action": "pose_three_quarter", "count": 6}],
    "eyes": [{"action": "eye_squint", "count": 8}],
    "arms": [{"action": "cross_arms", "count": 8}],
    "hands": [{"action": "open_hand", "count": 5}],
    "legs": [{"action": "leg_stand", "count": 8}]
  },
  "action_timeline": [
    {
      "frame": 180,
      "pose": "three_quarter",
      "eye": "squint",
      "mouth": "closed",
      "arms": ["extend_left", "cross_arms"],
      "hands": ["thumbs_up", "open_hand"],
      "legs": "stand"
    }
  ]
}
```

---

## 四、UI 元素设计

### 4.1 Angle Coverage Badge

```
┌─────────────────────────────────────┐
│  Angle Coverage: ⭐⭐⭐☆ (3/4)      │
│                                     │
│  ✅ three_quarter  (18 frames)      │
│  ✅ profile_right  (125 frames)     │
│  ⚠️ frontal        (0 frames)       │
│  ✅ profile_left   (0 frames)       │
└─────────────────────────────────────┘
```

**颜色编码**:
- ✅ Green: present (count > 0)
- ⚠️ Yellow: missing (count = 0)
- ❌ Red: required missing (frontal = 0)

---

### 4.2 Quality Score Bar

```
Quality Score: ████████░░ 86/100 (Good)
               ^^^^^^^^    86% quality
```

**等级**:
- 90-100: Excellent (绿色)
- 80-89: Good (蓝色)
- 70-79: Fair (黄色)
- <70: Poor (红色)

---

### 4.3 Trace Timeline

```
Trace Timeline: ────────●────────●──────●
                 Frame 155    220    297
                 
Duration: 6.5s | Confidence: 0.86 | Frames: 143
```

---

### 4.4 Pose Distribution Pie Chart

```
┌───────────────────────────┐
│   Pose Distribution       │
│                           │
│   profile_right: 87%      │
│   ████ ████ ████ ███      │
│                           │
│   three_quarter: 13%      │
│   ██                      │
└───────────────────────────┘
```

---

### 4.5 Action Icons

| Action | Icon |
|--------|------|
| **pose_frontal** | 👤 |
| **pose_profile_right** | 👤→ |
| **pose_profile_left** | 👤← |
| **eye_blink** | 👁️⭕ |
| **eye_squint** | 👁️◐ |
| **mouth_smile** | 😊 |
| **cross_arms** | 🤷 |
| **thumbs_up** | 👍 |
| **leg_stand** | 🧍 |

---

## 五、WordPress/Elementor 整合方案

### 5.1 页面结构

| 页面 | Elementor Template | API Endpoint |
|------|-------------------|--------------|
| **Identity List** | Archive Template | `/api/v1/identities` |
| **Identity Detail** | Single Template | `/api/v1/identities/{uuid}` |
| **Angle Coverage** | Custom Widget | `/api/v1/identities/{uuid}/angle-coverage` |
| **Body Actions** | Custom Widget | `/api/v1/identities/{uuid}/body-actions` |

---

### 5.2 Elementor Widgets

#### Widget 1: Identity Card

```html
<div class="identity-card">
  <h3>{{name}}</h3>
  <div class="angle-coverage">
    Angle Coverage: ⭐⭐⭐☆ (3/4)
  </div>
  <div class="quality-score">
    Quality: 86/100
  </div>
  <div class="trace-stats">
    Duration: 6.5s | Confidence: 0.86
  </div>
</div>
```

---

#### Widget 2: Angle Coverage Chart

```html
<div class="angle-chart">
  <div class="angle-item present">
    <span class="icon">✅</span>
    <span class="label">three_quarter</span>
    <span class="count">18 frames</span>
  </div>
  <div class="angle-item dominant">
    <span class="icon">✅</span>
    <span class="label">profile_right</span>
    <span class="count">125 frames</span>
  </div>
  <div class="angle-item missing">
    <span class="icon">⚠️</span>
    <span class="label">frontal</span>
    <span class="count">0 frames</span>
  </div>
</div>
```

---

#### Widget 3: Action Timeline

```html
<div class="action-timeline">
  <table>
    <tr>
      <th>Frame</th>
      <th>Pose</th>
      <th>Eyes</th>
      <th>Arms</th>
      <th>Hands</th>
    </tr>
    <tr>
      <td>180</td>
      <td>👤 three_quarter</td>
      <td>👁️◐ squint</td>
      <td>🤷 cross_arms</td>
      <td>👍 thumbs_up</td>
    </tr>
  </table>
</div>
```

---

### 5.3 REST API 实现

```php
// wp-content/themes/momentry/inc/api/identity-api.php

class Identity_API {
  
  public function register_routes() {
    register_rest_route('momentry/v1', '/identities', [
      'methods' => 'GET',
      'callback' => [$this, 'get_identities'],
    ]);
    
    register_rest_route('momentry/v1', '/identities/(?P<uuid>[a-f0-9-]+)', [
      'methods' => 'GET',
      'callback' => [$this, 'get_identity_detail'],
    ]);
    
    register_rest_route('momentry/v1', '/identities/(?P<uuid>[a-f0-9-]+)/angle-coverage', [
      'methods' => 'GET',
      'callback' => [$this, 'get_angle_coverage'],
    ]);
  }
  
  public function get_identities($request) {
    global $wpdb;
    
    $results = $wpdb->get_results(
      "SELECT uuid, name, identity_type, source, 
             reference_data->>'total_references' as ref_count,
             reference_data->>'quality_avg' as quality,
             reference_data->'trace_stats'->>'duration_seconds' as duration
       FROM identities
       ORDER BY created_at DESC
       LIMIT 50"
    );
    
    return rest_ensure_response([
      'success' => true,
      'data' => $results
    ]);
  }
  
  public function get_identity_detail($request) {
    $uuid = $request['uuid'];
    
    global $wpdb;
    
    $identity = $wpdb->get_row(
      $wpdb->prepare(
        "SELECT * FROM identities WHERE uuid = %s",
        $uuid
      )
    );
    
    if (!$identity) {
      return new WP_Error('not_found', 'Identity not found', ['status' => 404]);
    }
    
    $reference_data = json_decode($identity->reference_data, true);
    
    return rest_ensure_response([
      'uuid' => $identity->uuid,
      'name' => $identity->name,
      'source' => $identity->source,
      'reference_vectors' => [
        'total' => $reference_data['total_references'],
        'angles' => $reference_data['angles_covered'],
        'quality_avg' => $reference_data['quality_avg'],
      ],
      'trace_stats' => $reference_data['trace_stats']
    ]);
  }
}

add_action('rest_api_init', [new Identity_API(), 'register_routes']);
```

---

## 六、数据同步策略

### 6.1 同步时机

| 时机 | 操作 |
|------|------|
| **Identity Registration** | 同步到 WordPress |
| **Reference Vector Update** | 更新 angle_coverage |
| **Trace Completion** | 更新 trace_stats |

---

### 6.2 缓存策略

| 数据类型 | 缓存时间 |
|----------|----------|
| **Identity List** | 5 minutes |
| **Identity Detail** | 10 minutes |
| **Angle Coverage** | 15 minutes |
| **Body Actions** | 30 minutes |

---

### 6.3 数据库索引

```sql
-- 确保 identities 表有索引
CREATE INDEX IF NOT EXISTS idx_identities_uuid ON identities(uuid);
CREATE INDEX IF NOT EXISTS idx_identities_name ON identities(name);
CREATE INDEX IF NOT EXISTS idx_identities_source ON identities(source);
```

---

## 七、推荐优先级

### 7.1 Phase 1 (High)

| 功能 | 说明 |
|------|------|
| **Identity List 页面** | 显示所有 identities + 基础信息 |
| **Angle Coverage Badge** | 显示角度覆盖情况 |
| **Quality Score Bar** | 显示质量评分 |

---

### 7.2 Phase 2 (Medium)

| 功能 | 说明 |
|------|------|
| **Identity Detail 页面** | 详细信息 + Trace stats |
| **Reference Vector 页面** | 单个向量详情 |
| **Pose Distribution Chart** | Pie chart 显示 |

---

### 7.3 Phase 3 (Low)

| 功能 | 说明 |
|------|------|
| **Body Actions 页面** | 完整动作列表 |
| **Action Timeline** | 时间线可视化 |
| **Recommendation System** | 自动建议补充角度 |

---

## 八、技术栈建议

| 层级 | 技术 |
|------|------|
| **Frontend** | WordPress + Elementor |
| **API** | WordPress REST API |
| **Database** | PostgreSQL (identities) |
| **Cache** | Redis (optional) |
| **Visualization** | Chart.js 或 D3.js |

---

## 九、实施步骤

### Step 1: API 开发 (Backend)

```bash
# 创建 WordPress REST API
wp-content/themes/momentry/inc/api/
  ├── identity-api.php      # Identity endpoints
  ├── angle-coverage-api.php # Angle coverage
  └── body-actions-api.php  # Body actions
```

---

### Step 2: Elementor 模板

```bash
# 创建 Elementor templates
wp-content/themes/momentry/templates/
  ├── identity-archive.php  # Identity list
  ├── identity-single.php   # Identity detail
  └── identity-widgets.php  # Custom widgets
```

---

### Step 3: 测试

```bash
# 测试 API
curl http://localhost:1420/wp-json/momentry/v1/identities
curl http://localhost:1420/wp-json/momentry/v1/identities/{uuid}
```

---

## 十、预估工作量

| Phase | 工作量 | 说明 |
|-------|--------|------|
| **Phase 1** | 2-3 days | Identity List + Badge |
| **Phase 2** | 3-4 days | Detail + Charts |
| **Phase 3** | 2-3 days | Actions + Timeline |

---

## 十一、结论

✅ **建议优先实施 Phase 1**

关键功能:
1. Identity List 页面 (显示 trace_stats)
2. Angle Coverage Badge (可视化角度覆盖)
3. Quality Score Bar (质量评分)

这些功能能立即展示 Pose-based Matching 的价值。

---

## 版本信息

- 版本: 1.0
- 创建日期: 2026-04-28
- 目标: Momentry Portal Phase 5.3
