feat: Excel template export with meeting number auto-generation

- Add meeting_number field (M-YYYYMMDD-XX format) with auto-generation
- Refactor Excel export to use cell coordinates instead of placeholders
- Export files saved to backend/record/ directory with meeting number filename
- Add database migration for meeting_number column
- Add start.sh script for managing frontend/backend/sidecar services
- Update OpenSpec documentation

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
egg
2025-12-11 19:45:53 +08:00
parent a4a2fc3ae7
commit e790f48967
16 changed files with 1139 additions and 122 deletions

View File

@@ -0,0 +1,186 @@
# Change: Update Excel Export with Template Cell Mapping
## Why
目前的 Excel 導出功能使用佔位符方式(`{{subject}}`),但實際模板 `meeting_template.xlsx` 使用固定儲存格座標。此外,數據模型缺少「會議編號」欄位,且需要支援代辦事項的「執行現況」欄位以符合模板需求。
## What Changes
### Backend 修改
- **BREAKING** 重構 `export.py`改用儲存格座標填充方式D3, D4 等)
- 修正模板路徑:`templates/``template/`
- 新增 `meeting_number` 欄位並實作自動生成邏輯
- 實作動態行填充:代辦事項從第 10 行往下延伸
### 數據模型修改
- `MeetingCreate/MeetingResponse`: 新增 `meeting_number` 欄位
### AI 整合調整
- 提供詳細的 Dify System Prompt供用戶在 Dify 後台設定)
## Impact
- Affected specs: `excel-export`, `meeting-management`, `ai-summarization`
- Affected code:
- `backend/app/routers/export.py`
- `backend/app/models/schemas.py`
- `backend/app/routers/meetings.py`
- `backend/app/routers/ai.py`
- `client/src/pages/meeting-detail.html`
## Template Cell Mapping
| 儲存格 | 內容 | 數據來源 |
|--------|------|----------|
| D3 | 會議主題 | `meeting.subject` |
| D4 | 會議時間 | `meeting.meeting_time` |
| D5 | 會議主席 | `meeting.chairperson` |
| F4 | 會議地點 | `meeting.location` |
| F5 | 記錄人員 | `meeting.recorder` |
| D6 | 會議參與人員 | `meeting.attendees`(逗號分隔) |
| C8 | 會議編號 | `meeting.meeting_number` 或生成規則 |
| D8 | 會議結論 | 結論內容(多條用換行分隔) |
| C10+ | 代辦事項編號 | `action.system_code` |
| D10+ | 事項內容 | `action.content` |
| F10+ | 負責人 | `action.owner` |
| G10+ | 預計完成日期 | `action.due_date` |
| H10+ | 執行現況 | `action.status`Open/In Progress/Done/Delayed |
## 現有編號生成機制確認
| 編號類型 | 格式 | 狀態 | 說明 |
|----------|------|------|------|
| 結論編號 | `C-YYYYMMDD-XX` | ✅ 已實作 | `generate_system_code("C", ...)` |
| 行動項編號 | `A-YYYYMMDD-XX` | ✅ 已實作 | `generate_system_code("A", ...)` |
| **會議編號** | `M-YYYYMMDD-XX` | ❌ 需新增 | 需在 DB 新增欄位並實作生成邏輯 |
## 已確認決策
1. **多條結論處理**:✅ 將多條結論用換行符合併放入 D8 單一儲存格
2. **執行現況欄位**:✅ 直接使用現有 `status` 欄位Open/In Progress/Done/Delayed
## Dify System Prompt
以下是完整的 System Prompt請在 Dify 後台設定:
```
# 角色定義
你是專業的會議記錄助手,負責分析會議逐字稿並提取結構化的會議紀錄。
# 任務說明
請仔細閱讀使用者提供的會議逐字稿,從中提取:
1. 會議結論:會議中達成的決定、共識或重要決議
2. 待辦事項:需要後續執行的具體行動項目
# 輸出格式要求
你必須以 JSON 格式回覆,結構如下:
{
"conclusions": [
"結論內容1",
"結論內容2"
],
"action_items": [
{
"content": "待辦事項的具體描述",
"owner": "負責人姓名",
"due_date": "YYYY-MM-DD"
}
]
}
# 欄位說明
## conclusions結論陣列
- 類型:字串陣列
- 數量:根據實際內容決定,可能是 0 個、1 個或多個
- 內容:每個結論應該是完整的一句話,清楚描述決議內容
- 若逐字稿中沒有明確的結論或決議,回傳空陣列 []
## action_items待辦事項陣列
- 類型:物件陣列
- 數量:根據實際內容決定,可能是 0 個、1 個或多個
- 各欄位說明:
- content必填待辦事項的具體描述應清楚說明要做什麼
- owner選填負責執行此事項的人員姓名。若逐字稿中有提及負責人則填入否則填空字串 ""
- due_date選填預計完成日期格式為 YYYY-MM-DD。若逐字稿中有提及日期則填入否則填 null
# 提取原則
1. **結論提取原則**
- 尋找「決定」、「同意」、「確認」、「通過」、「結論是」等關鍵詞
- 提取具有決策性質的陳述
- 不要將一般討論內容當作結論
- 每個結論應該是獨立且完整的
2. **待辦事項提取原則**
- 尋找「請...」、「需要...」、「負責...」、「跟進...」、「處理...」等動作詞
- 提取有明確執行要求的事項
- 若有提到負責人,填入 owner 欄位
- 若有提到期限如「下週」、「月底前」、「12月15日」轉換為 YYYY-MM-DD 格式
3. **數量彈性原則**
- 結論和待辦事項的數量完全取決於逐字稿內容
- 不要為了填充而虛構內容
- 不要合併應該分開的項目
- 不要拆分應該合併的項目
# 輸出範例
## 範例1有多個結論和待辦事項
{
"conclusions": [
"本季度預算調整為新台幣500萬元",
"新產品發布日期確定為2025年3月1日",
"同意增聘兩名工程師"
],
"action_items": [
{
"content": "準備預算調整報告提交財務部",
"owner": "王小明",
"due_date": "2025-12-20"
},
{
"content": "聯繫供應商確認交貨時程",
"owner": "李小華",
"due_date": "2025-12-15"
},
{
"content": "發布工程師職缺招募公告",
"owner": "",
"due_date": null
}
]
}
## 範例2只有一個結論沒有待辦事項
{
"conclusions": [
"維持現有方案不做調整"
],
"action_items": []
}
## 範例3沒有結論有待辦事項
{
"conclusions": [],
"action_items": [
{
"content": "收集更多市場數據供下次會議討論",
"owner": "張三",
"due_date": "2025-12-25"
}
]
}
## 範例4都沒有
{
"conclusions": [],
"action_items": []
}
# 重要提醒
1. 只輸出 JSON不要有其他文字說明
2. 確保 JSON 格式正確,可被程式解析
3. 使用繁體中文
4. 日期格式必須是 YYYY-MM-DD 或 null
5. owner 欄位若無資料請填空字串 "",不要填 null
```

View File

@@ -0,0 +1,31 @@
## MODIFIED Requirements
### Requirement: Structured Output Format
The AI summarization SHALL return structured data with conclusions and action items.
#### Scenario: Complete structured response
- **WHEN** transcript contains clear decisions and assignments
- **THEN** response SHALL include conclusions array (0 to many items) and action_items array with content, owner, due_date fields
#### Scenario: Partial data extraction
- **WHEN** transcript lacks explicit owner or due_date for action items
- **THEN** those fields SHALL be empty strings or null allowing manual completion
#### Scenario: Variable conclusion count
- **WHEN** transcript has multiple decisions
- **THEN** conclusions array SHALL contain all extracted conclusions without artificial limit
#### Scenario: No conclusions found
- **WHEN** transcript has no clear decisions
- **THEN** conclusions array SHALL be empty []
### Requirement: Dify Prompt Configuration
The Dify workflow SHALL be configured with detailed system prompt for meeting summarization.
#### Scenario: System prompt behavior
- **WHEN** transcript is sent to Dify
- **THEN** Dify SHALL use configured system prompt to extract conclusions and action_items in JSON format
#### Scenario: Flexible output count
- **WHEN** Dify processes transcript
- **THEN** it SHALL return variable number of conclusions and action items based on actual content

View File

@@ -0,0 +1,61 @@
## MODIFIED Requirements
### Requirement: Template-based Generation
The Excel export SHALL use openpyxl with template files and cell coordinate mapping.
#### Scenario: Cell coordinate filling
- **WHEN** Excel is generated from template `meeting_template.xlsx`
- **THEN** data SHALL be filled into specific cells:
- D3: meeting subject
- D4: meeting time
- D5: chairperson
- F4: location
- F5: recorder
- D6: attendees (comma separated)
- C8: meeting number (M-YYYYMMDD-XX format)
- D8: conclusions (newline separated if multiple)
#### Scenario: Dynamic row filling for action items
- **WHEN** meeting has action items
- **THEN** rows SHALL be filled starting from row 10:
- Column C: action item system code (A-YYYYMMDD-XX)
- Column D: action item content
- Column F: owner
- Column G: due date
- Column H: status (Open/In Progress/Done/Delayed)
#### Scenario: Template path resolution
- **WHEN** export is requested
- **THEN** server SHALL load template from `backend/template/meeting_template.xlsx`
### Requirement: Complete Data Inclusion
The exported Excel SHALL include all meeting metadata, conclusions, and action items.
#### Scenario: Full metadata export
- **WHEN** Excel is generated
- **THEN** it SHALL include subject, meeting_time, location, chairperson, recorder, attendees, and meeting_number
#### Scenario: Conclusions export
- **WHEN** Excel is generated with multiple conclusions
- **THEN** all conclusions SHALL be merged with newline separator into cell D8
#### Scenario: Action items export with status
- **WHEN** Excel is generated
- **THEN** all action items SHALL be listed with system_code, content, owner, due_date, and status
## ADDED Requirements
### Requirement: Meeting Number Generation
The system SHALL automatically generate meeting numbers for each meeting record.
#### Scenario: Auto-generate meeting number
- **WHEN** a new meeting is created
- **THEN** system SHALL generate meeting number in format `M-YYYYMMDD-XX` where XX is daily sequence
#### Scenario: Meeting number uniqueness
- **WHEN** multiple meetings are created on same date
- **THEN** each SHALL receive unique sequential number (M-20251211-01, M-20251211-02, etc.)
#### Scenario: Meeting number in export
- **WHEN** Excel is exported
- **THEN** meeting_number SHALL be displayed in cell C8

View File

@@ -0,0 +1,35 @@
## MODIFIED Requirements
### Requirement: Create Meeting
The system SHALL allow users to create meetings with required metadata and auto-generated meeting number.
#### Scenario: Create meeting with all fields
- **WHEN** user submits POST /api/meetings with subject, meeting_time, chairperson, location, recorder, attendees
- **THEN** a new meeting record SHALL be created with auto-generated UUID, meeting_number, and the meeting data SHALL be returned
#### Scenario: Create meeting with missing required fields
- **WHEN** user submits POST /api/meetings without subject or meeting_time
- **THEN** the server SHALL return HTTP 400 with validation error details
#### Scenario: Recorder defaults to current user
- **WHEN** user creates meeting without specifying recorder
- **THEN** the recorder field SHALL default to the logged-in user's email
#### Scenario: Auto-generate meeting number
- **WHEN** a new meeting is created
- **THEN** meeting_number SHALL be auto-generated in format M-YYYYMMDD-XX
### Requirement: System Code Generation
The system SHALL auto-generate unique system codes for meetings, conclusions, and action items.
#### Scenario: Generate meeting number
- **WHEN** a meeting is created on 2025-12-10
- **THEN** the meeting_number SHALL follow format M-20251210-XX where XX is sequence number
#### Scenario: Generate conclusion code
- **WHEN** a conclusion is created for a meeting on 2025-12-10
- **THEN** the system_code SHALL follow format C-20251210-XX where XX is sequence number
#### Scenario: Generate action item code
- **WHEN** an action item is created for a meeting on 2025-12-10
- **THEN** the system_code SHALL follow format A-20251210-XX where XX is sequence number

View File

@@ -0,0 +1,64 @@
# Tasks: Update Excel Template Export
## 1. Database Schema Updates
- [x] 1.1 新增 `meeting_number` 欄位至 `meeting_records`VARCHAR(20),格式 M-YYYYMMDD-XX
- Migration SQL: `backend/migrations/001_add_meeting_number.sql`
## 2. Backend Model Updates
- [x] 2.1 更新 `schemas.py``MeetingResponse` 新增 `meeting_number` 欄位
## 3. Backend API Updates
- [x] 3.1 更新 `meetings.py`:實作會議編號自動生成邏輯(使用現有 `generate_system_code("M", ...)`)
- [x] 3.2 更新 `meetings.py`:在 create_meeting 和 response 中包含 meeting_number
## 4. Excel Export Refactoring
- [x] 4.1 修正 `export.py`:模板路徑從 `templates/` 改為 `template/`
- [x] 4.2 重構 `export.py`改用儲存格座標填充方式D3, D4, D5, F4, F5, D6, C8, D8
- [x] 4.3 實作動態行填充:代辦事項從第 10 行開始往下延伸C, D, F, G, H 列)
- [x] 4.4 實作結論合併邏輯:多條結論用換行符合併至 D8
- [x] 4.5 H 列填入 action.status 作為執行現況
## 5. Testing
- [x] 5.1 手動測試 Excel 導出與模板填充
- [x] 5.2 驗證各欄位正確填入對應儲存格
- 測試腳本:`backend/tests/test_excel_export.py`
- 測試結果:✅ 全部通過
## 6. Documentation
- [x] 6.1 ✅ Dify System Prompt 已提供於 proposal.md
## 測試結果
```
Template exists: True
=== Testing with template ===
D3 (Subject): 專案進度討論會議
D4 (Time): 2025-12-11 14:30
D5 (Chair): 王經理
F4 (Location): 會議室A
F5 (Recorder): 李小明
D6 (Attendees): 張三, 李四, 王五
C8 (Meeting Number): M-20251211-01
D8 (Conclusions): 確認專案時程延後兩週
同意增加測試人力
下次會議改為線上進行
Action Items:
Row 10: C=A-20251211-01, D=更新專案時程表, F=張三, G=2025-12-15, H=Open
Row 11: C=A-20251211-02, D=聯繫人資部門增聘測試人員, F=李四, G=2025-12-20, H=In Progress
Row 12: C=A-20251211-03, D=準備線上會議設備, F=王五, G=, H=Open
✅ Test completed successfully!
```
## 部署前須執行
請在資料庫執行以下 SQL 來新增 `meeting_number` 欄位:
```sql
ALTER TABLE meeting_records
ADD COLUMN meeting_number VARCHAR(20) NULL AFTER uuid;
CREATE INDEX idx_meeting_number ON meeting_records(meeting_number);
```