跳轉到

建立報告模板

此 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_htmlslots,因此可以一次完成「編輯 + 確認」。

此 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 ' \ -H'Content-Type: application/json' \ -d'{ "jinja_html":"{{ company_name }}", "slots": { "company_name":"Example Company", "report_period":"2025 Q1" } }'

---

## 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/templatesPOST /report-generation/templates/{id}/confirm 皆會觸發非同步處理
狀態查詢 Client 可透過 GET /report-generation/templates/{id} 查詢目前狀態
Webhook 若有提供 webhook_url,系統會在狀態變更時主動通知
Slot 確認 模板解析完成後,必須在 pending_confirm 狀態下確認 slot 結構
模板更新 僅允許在 completed 狀態下透過 PATCH 更新模板內容
Expand 機制 大欄位如 jinja_htmlslotswriting_guidelines 可透過 expand 額外展開

不包含範圍

本階段不包含以下功能:

Feature Description
模板列表 API 不包含 GET /report-generation/templates
模板刪除 API 不包含刪除報告模板功能
Phase 2 報告生成 API 不包含正式生成報告內容的 API
Checkpoint UI / UX 不包含前端 checkpoint 編輯或審核介面