建立報告模板¶
此 API 用於根據使用者上傳的 PDF 報告模板,自動解析模板結構、抽取可填寫欄位,並生成後續報告撰寫所需的指引資料。
系統會串接報告生成的三個核心模組:
-
Document Converter:將 PDF 模板轉換為 HTML 結構
-
Template Extractor:從模板中抽取 Jinja HTML 與 slots 欄位
-
Outline Generator:根據模板結構生成報告撰寫指引
此流程主要用於建立可重複使用的報告模板,供後續報告生成、人工編輯、結構確認或自動化內容填寫使用。
整體流程¶
```plain text Client 上傳 PDF(透過 PrivAI Files API) ↓ POST /report-generation/templates { source_file_id } ↓ state: parsing_template(async) ↓ 內部:Document Converter → Template Extractor ↓ webhook 通知 ↓ state: pending_confirm
Client 確認 / 編輯 slot 結構 ↓ POST /report-generation/templates/{id}/confirm { jinja_html?, slots? } ↓ state: generating_guidelines(async) ↓ 內部:Outline Generator ↓ webhook 通知 ↓ state: completed
Client 可透過 PATCH 更新模板內容
---
# 1. 建立報告模板
建立新的報告模板,並觸發非同步模板解析流程。
建立後,模板狀態會先進入 `parsing_template`。系統會在背景執行 PDF 轉換與模板欄位抽取,完成後會轉為 `pending_confirm`,等待使用者確認或編輯 slot 結構。
```plain text
curl-X'POST' \
'http://127.0.0.1:8000/v1/report-generation/templates' \
-H'accept: application/json' \
-H'Authorization: Bearer <your-api-key>' \
-H'Content-Type: application/json' \
-d'{
"name":"Monthly Financial Report Template",
"source_file_id":"file_123456789",
"webhook_url":"https://example.com/webhook/report-template"
}'
Request Headers¶
| Key | Value |
|---|---|
| Request Method | POST |
| accept | application/json |
| Authorization | Bearer <your-api-key> |
| Content-Type | application/json |
Request Payload¶
```plain text { "name":"Monthly Financial Report Template", "source_file_id":"file_123456789", "webhook_url":"https://example.com/webhook/report-template" }
---
## Field Explanation
| **Field** | **Type** | **Detail** | **Required** |
| --- | --- | --- | --- |
| name | string | 模板名稱,用於識別此報告模板 | false |
| source_file_id | string | 透過 PrivAI Files API 上傳 PDF 後取得的 file ID | true |
| webhook_url | string | 狀態變更時的 callback URL。若有設定,系統會在狀態變更時主動通知 caller | false |
---
## Response Body
```plain text
{
"id":"b9f375f8-048f-4d5a-a3ec-63b7f062f074",
"object":"report_template",
"name":"Monthly Financial Report Template",
"state":"parsing_template",
"source_file_id":"file_123456789",
"jinja_html":null,
"slots":null,
"writing_guidelines":null,
"metadata": {},
"created_at":"2025-01-01T01:20:00.000Z",
"updated_at":"2025-01-01T01:20:00.000Z"
}
Field Explanation¶
| Field | Type | Detail |
|---|---|---|
| id | string | 報告模板 ID |
| object | string | 固定值為 report_template |
| name | string | 模板名稱 |
| state | string | 目前模板狀態 |
| source_file_id | string | 原始 PDF 檔案的 file ID |
| jinja_html | string / null | Template Extractor 產出的 Jinja HTML 框架。於解析完成後產生 |
| slots | object / null | Template Extractor 產出的 slot 定義。於解析完成後產生 |
| writing_guidelines | object / null | Outline Generator 產出的撰寫指引。於確認後產生 |
| metadata | object | 自訂 metadata |
| created_at | string | 建立時間 |
| updated_at | string | 最後更新時間 |
2. 取得報告模板狀態與資料¶
此 API 用於查詢報告模板目前的處理狀態與資料內容。
預設回傳輕量資料,包含:
-
id -
object -
name -
state -
source_file_id -
metadata -
created_at -
updated_at
若需要取得較大的欄位內容,可使用 expand query parameter 額外展開指定欄位。
```plain text
curl-X'GET' \
'http://127.0.0.1:8000/v1/report-generation/templates/{id}?expand=jinja_html,slots' \
-H'accept: application/json' \
-H'Authorization: Bearer ---
## Request Headers
| **Key** | **Value** |
| --- | --- |
| Request Method | GET |
| accept | application/json |
| Authorization | Bearer `<your-api-key>` |
---
## Path Parameters
| **Field** | **Type** | **Note** | **Required** |
| --- | --- | --- | --- |
| id | string | 報告模板 ID | true |
---
## Query Parameters
| **Field** | **Type** | **Note** | **Required** |
| --- | --- | --- | --- |
| expand | string | 以逗號分隔要額外回傳的欄位,例如 `jinja_html,slots` | false |
---
## Expandable Fields
| **Field** | **Description** |
| --- | --- |
| jinja_html | 展開 Template Extractor 產出的 Jinja HTML 框架 |
| slots | 展開 Template Extractor 產出的 slot 定義 |
| writing_guidelines | 展開 Outline Generator 產出的撰寫指引 |
> 展開欄位只會在該 state 已產生資料時回傳。
例如模板仍在 `parsing_template` 狀態時,即使指定 `expand=slots`,`slots` 仍可能為 `null`。
---
## Response Body
```plain text
{
"id":"b9f375f8-048f-4d5a-a3ec-63b7f062f074",
"object":"report_template",
"name":"Monthly Financial Report Template",
"state":"pending_confirm",
"source_file_id":"file_123456789",
"metadata": {},
"created_at":"2025-01-01T01:20:00.000Z",
"updated_at":"2025-01-01T01:25:00.000Z",
"jinja_html":"<html><body>{{ company_name }}</body></html>",
"slots": {
"company_name":"Example Company",
"report_period":"2025 Q1"
}
}
3. 確認報告模板結構¶
此 API 用於確認 Template Extractor 產出的 slot 結構,並觸發撰寫指引生成流程。
使用者可在確認時同時帶入修改後的 jinja_html 或 slots,因此可以一次完成「編輯 + 確認」。
此 API 僅允許在 pending_confirm 狀態下呼叫。
呼叫後,模板狀態會轉為 generating_guidelines。系統會在背景執行 Outline Generator,完成後自動轉為 completed。
```plain text
curl-X'POST' \
'http://127.0.0.1:8000/v1/report-generation/templates/{id}/confirm' \
-H'accept: application/json' \
-H'Authorization: Bearer ---
## Request Headers
| **Key** | **Value** |
| --- | --- |
| Request Method | POST |
| accept | application/json |
| Authorization | Bearer `<your-api-key>` |
| Content-Type | application/json |
---
## Path Parameters
| **Field** | **Type** | **Note** | **Required** |
| --- | --- | --- | --- |
| id | string | 報告模板 ID | true |
---
## Request Payload
```plain text
{
"jinja_html":"<html><body>{{ company_name }}</body></html>",
"slots": {
"company_name":"Example Company",
"report_period":"2025 Q1"
}
}
Field Explanation¶
| Field | Type | Detail | Required |
|---|---|---|---|
| jinja_html | string | 修改後的 Jinja HTML 框架。若未提供,則使用系統解析出的版本 | false |
| slots | object | 修改後的 slot 定義,格式為 {slot_name: example_content}。若未提供,則使用系統解析出的版本 |
false |
Response Body¶
```plain text { "id":"b9f375f8-048f-4d5a-a3ec-63b7f062f074", "object":"report_template", "name":"Monthly Financial Report Template", "state":"generating_guidelines", "source_file_id":"file_123456789", "jinja_html":"
{{ company_name }}", "slots": { "company_name":"Example Company", "report_period":"2025 Q1" }, "writing_guidelines":null, "metadata": {}, "created_at":"2025-01-01T01:20:00.000Z", "updated_at":"2025-01-01T01:30:00.000Z" }---
# 4. 更新已完成的報告模板
此 API 用於更新已建立完成的報告模板內容。
此 API 僅允許在 `completed` 狀態下呼叫,可用於修改模板名稱、Jinja HTML、slots、撰寫指引或自訂 metadata。
---
```plain text
curl-X'PATCH' \
'http://127.0.0.1:8000/v1/report-generation/templates/{id}' \
-H'accept: application/json' \
-H'Authorization: Bearer <your-api-key>' \
-H'Content-Type: application/json' \
-d'{
"name":"Updated Financial Report Template",
"jinja_html":"<html><body>{{ company_name }}</body></html>",
"slots": {
"company_name":"Example Company",
"report_period":"2025 Q1"
},
"writing_guidelines": {
"global_guidelines":"請使用正式、客觀且清楚的語氣撰寫報告。",
"chapters": [
{
"title":"Executive Summary",
"guidelines":"摘要說明本期報告重點與主要結論。"
}
]
},
"metadata": {
"department":"finance"
}
}'
Request Headers¶
| Key | Value |
|---|---|
| Request Method | PATCH |
| accept | application/json |
| Authorization | Bearer <your-api-key> |
| Content-Type | application/json |
Path Parameters¶
| Field | Type | Note | Required |
|---|---|---|---|
| id | string | 報告模板 ID | true |
Request Payload¶
```plain text { "name":"Updated Financial Report Template", "jinja_html":"
{{ company_name }}", "slots": { "company_name":"Example Company", "report_period":"2025 Q1" }, "writing_guidelines": { "global_guidelines":"請使用正式、客觀且清楚的語氣撰寫報告。", "chapters": [ { "title":"Executive Summary", "guidelines":"摘要說明本期報告重點與主要結論。" } ] }, "metadata": { "department":"finance" } }---
## Field Explanation
| **Field** | **Type** | **Detail** | **Required** |
| --- | --- | --- | --- |
| name | string | 模板名稱 | false |
| jinja_html | string | Jinja HTML 框架 | false |
| slots | object | slot 定義,格式為 `{slot_name: example_content}` | false |
| writing_guidelines | object | 撰寫指引,包含全局指引與章節指引 | false |
| metadata | object | 自訂 metadata | false |
---
## Response Body
```plain text
{
"id":"b9f375f8-048f-4d5a-a3ec-63b7f062f074",
"object":"report_template",
"name":"Updated Financial Report Template",
"state":"completed",
"source_file_id":"file_123456789",
"jinja_html":"<html><body>{{ company_name }}</body></html>",
"slots": {
"company_name":"Example Company",
"report_period":"2025 Q1"
},
"writing_guidelines": {
"global_guidelines":"請使用正式、客觀且清楚的語氣撰寫報告。",
"chapters": [
{
"title":"Executive Summary",
"guidelines":"摘要說明本期報告重點與主要結論。"
}
]
},
"metadata": {
"department":"finance"
},
"created_at":"2025-01-01T01:20:00.000Z",
"updated_at":"2025-01-01T01:40:00.000Z"
}
State Machine¶
報告模板建立流程會依照以下狀態轉換:
```plain text parsing_template → pending_confirm → generating_guidelines → completed ↘ ↘ failed failed
---
## State Explanation
| **State** | **Description** |
| --- | --- |
| parsing_template | 系統正在將 PDF 轉換為 HTML,並透過 Template Extractor 抽取 Jinja HTML 與 slots |
| pending_confirm | 模板結構已解析完成,等待使用者確認或編輯 slot 結構 |
| generating_guidelines | 使用者已確認模板結構,系統正在透過 Outline Generator 生成撰寫指引 |
| completed | 模板建立完成,可用於後續報告生成流程,並允許透過 PATCH 更新 |
| failed | 任一非同步步驟失敗 |
---
# Webhook
建立模板時若有提供 `webhook_url`,系統會在模板狀態變更時主動發送 callback。
Webhook body 會包含完整模板資料,包含:
- `jinja_html`
- `slots`
- `writing_guidelines`
- `metadata`
- `state`
- `source_file_id`
因此 caller 收到 webhook 後,不一定需要再額外呼叫 GET API 取得完整資料。
---
## Webhook Trigger Timing
| **State** | **Trigger Timing** |
| --- | --- |
| pending_confirm | parsing 完成,已產生 Jinja HTML 與 slots,等待使用者確認 |
| completed | 撰寫指引生成完成,模板已可使用 |
| failed | 任一非同步處理步驟發生錯誤 |
---
## Webhook Body Example
```plain text
{
"id":"b9f375f8-048f-4d5a-a3ec-63b7f062f074",
"object":"report_template",
"name":"Monthly Financial Report Template",
"state":"completed",
"source_file_id":"file_123456789",
"jinja_html":"<html><body>{{ company_name }}</body></html>",
"slots": {
"company_name":"Example Company",
"report_period":"2025 Q1"
},
"writing_guidelines": {
"global_guidelines":"請使用正式、客觀且清楚的語氣撰寫報告。",
"chapters": [
{
"title":"Executive Summary",
"guidelines":"摘要說明本期報告重點與主要結論。"
}
]
},
"metadata": {},
"created_at":"2025-01-01T01:20:00.000Z",
"updated_at":"2025-01-01T01:35:00.000Z"
}
writing_guidelines 結構¶
writing_guidelines 用於描述報告撰寫時的全局規則與章節撰寫建議。
```plain text { "global_guidelines":"請使用正式、客觀且清楚的語氣撰寫報告。", "chapters": [ { "title":"Executive Summary", "guidelines":"摘要說明本期報告重點與主要結論。" }, { "title":"Financial Performance", "guidelines":"說明本期財務表現、主要變動原因與關鍵指標。" } ] }
---
## Field Explanation
| **Field** | **Type** | **Detail** |
| --- | --- | --- |
| global_guidelines | string | 整份報告共用的撰寫規範 |
| chapters | array | 各章節的撰寫指引 |
| chapters[].title | string | 章節標題 |
| chapters[].guidelines | string | 該章節的撰寫建議 |
---
# DB Schema
Table:`report_templates`
| **Column** | **Type** | **Description** |
| --- | --- | --- |
| id | UUID PK | 報告模板 ID |
| object | TEXT | 固定值為 `report_template` |
| name | TEXT | 模板名稱 |
| state | ENUM | `parsing_template` / `pending_confirm` / `generating_guidelines` / `completed` / `failed` |
| source_file_id | TEXT | PrivAI Files API 的 file ID |
| jinja_html | TEXT | Template Extractor 產出,可編輯 |
| slots | JSONB | slot 定義,格式為 `{"slot_name": "example_content"}`,可編輯 |
| writing_guidelines | JSONB | 撰寫指引,包含全局指引與章節結構 |
| metadata | JSONB | 彈性欄位 |
| created_at | TIMESTAMP | 建立時間 |
| updated_at | TIMESTAMP | 最後更新時間 |
---
# Error Handling
若非同步處理過程失敗,模板狀態會轉為 `failed`。
可能失敗的階段包含:
- PDF 轉換失敗
- Template Extractor 抽取失敗
- 使用者確認資料格式不正確
- Outline Generator 生成撰寫指引失敗
- 系統內部非同步處理失敗
---
## Failed Response Example
```plain text
{
"id":"b9f375f8-048f-4d5a-a3ec-63b7f062f074",
"object":"report_template",
"name":"Monthly Financial Report Template",
"state":"failed",
"source_file_id":"file_123456789",
"jinja_html":null,
"slots":null,
"writing_guidelines":null,
"metadata": {
"fail_reason":"template_extraction_failed",
"fail_detail": {
"message":"Unable to extract slots from the uploaded template."
}
},
"created_at":"2025-01-01T01:20:00.000Z",
"updated_at":"2025-01-01T01:25:00.000Z"
}
注意事項¶
| Item | Description |
|---|---|
| 非同步處理 | POST /report-generation/templates 與 POST /report-generation/templates/{id}/confirm 皆會觸發非同步處理 |
| 狀態查詢 | Client 可透過 GET /report-generation/templates/{id} 查詢目前狀態 |
| Webhook | 若有提供 webhook_url,系統會在狀態變更時主動通知 |
| Slot 確認 | 模板解析完成後,必須在 pending_confirm 狀態下確認 slot 結構 |
| 模板更新 | 僅允許在 completed 狀態下透過 PATCH 更新模板內容 |
| Expand 機制 | 大欄位如 jinja_html、slots、writing_guidelines 可透過 expand 額外展開 |
不包含範圍¶
本階段不包含以下功能:
| Feature | Description |
|---|---|
| 模板列表 API | 不包含 GET /report-generation/templates |
| 模板刪除 API | 不包含刪除報告模板功能 |
| Phase 2 報告生成 API | 不包含正式生成報告內容的 API |
| Checkpoint UI / UX | 不包含前端 checkpoint 編輯或審核介面 |