# Design Document

## Overview

本设计文档描述了Coze AI通用接口调用服务的架构设计，以及爽文剧本AI生成功能的实现方案。核心目标是重构AiChatServiceImpl，提供一个通用的、可配置的AI接口调用方法，支持通过config_key获取配置并调用Coze工作流API。

## Architecture

### 系统架构图

```mermaid
graph TB
    subgraph "Controller Layer"
        EC[EpicScriptController]
    end
    
    subgraph "Service Layer"
        ESS[EpicScriptServiceImpl]
        ACS[AiChatServiceImpl]
        AICS[AiConfigServiceImpl]
    end
    
    subgraph "Data Layer"
        ACM[AiConfigMapper]
        ESM[EpicScriptMapper]
    end
    
    subgraph "External"
        COZE[Coze API]
    end
    
    EC --> ESS
    ESS --> ACS
    ACS --> AICS
    AICS --> ACM
    ESS --> ESM
    ACS --> COZE
```

### 调用流程图

```mermaid
sequenceDiagram
    participant C as Controller
    participant ESS as EpicScriptService
    participant ACS as AiChatService
    participant AICS as AiConfigService
    participant DB as Database
    participant COZE as Coze API
    
    C->>ESS: createScript(request)
    ESS->>ESS: assembleInput(request)
    ESS->>ACS: callWorkflowByConfigKey(configKey, input, userId)
    ACS->>AICS: getByConfigKey(configKey)
    AICS->>DB: SELECT * FROM t_ai_config WHERE config_key = ?
    DB-->>AICS: AiConfig
    AICS-->>ACS: AiConfig
    ACS->>ACS: buildWorkflowRequest(config, input, userId)
    ACS->>COZE: POST /v1/workflow/stream_run
    COZE-->>ACS: SSE Stream Response
    ACS->>ACS: parseStreamResponse(response)
    ACS-->>ESS: AI Generated Content
    ESS->>ESS: parseAndSaveScript(content)
    ESS->>DB: INSERT INTO t_epic_script
    ESS-->>C: EpicScriptResponse
```

## Components and Interfaces

### 1. AiChatService 接口扩展

```java
/**
 * AI聊天服务接口 - 新增通用工作流调用方法
 */
public interface AiChatService {
    
    // ... 现有方法 ...
    
    /**
     * 通过配置键调用Coze工作流API
     * 
     * @param configKey AI配置键（如：coze.course.life.generate）
     * @param input 输入参数，将作为parameters.input传递给工作流
     * @param userId 用户ID
     * @return AI生成的内容
     */
    String callWorkflowByConfigKey(String configKey, String input, String userId);
    
    /**
     * 通过配置键调用Coze工作流API（带自定义参数）
     * 
     * @param configKey AI配置键
     * @param parameters 自定义参数Map，将合并到请求的parameters中
     * @param userId 用户ID
     * @return AI生成的内容
     */
    String callWorkflowByConfigKey(String configKey, Map<String, Object> parameters, String userId);
}
```

### 2. AiConfigService 接口扩展

```java
/**
 * AI配置服务接口 - 新增按配置键获取方法
 */
public interface AiConfigService {
    
    // ... 现有方法 ...
    
    /**
     * 根据配置键获取AI配置
     * 
     * @param configKey 配置键
     * @return AI配置，如果不存在或已禁用则返回null
     */
    AiConfig getByConfigKey(String configKey);
}
```

### 3. EpicScriptService 接口（无变化）

现有接口保持不变，实现层调用新的AI服务方法。

## Data Models

### Coze工作流请求格式

```json
{
    "workflow_id": "7586262962160762926",
    "user_id": "user_123",
    "stream": true,
    "parameters": {
        "input": "用户填写的信息组装后的字符串",
        "user_id": "user_123"
    }
}
```

### Coze工作流响应格式（SSE）

```
id: 0
event: Message
data: {"node_title":"End","node_execute_uuid":"","usage":{"token_count":1571,"output_count":812,"input_count":759},"node_is_finish":true,"node_seq_id":"0","content":"{\"output\":\"AI生成的内容...\"}","content_type":"text","node_type":"End","node_id":"900001"}

id: 1
event: Done
data: {"node_execute_uuid":"","debug_url":"..."}
```

### 用户输入组装格式

```
剧本标题：{title}
主题/渴望：{theme}
风格：{style}
篇幅：{length}
序幕（低谷回响）：{plotIntro}
转折（契机出现）：{plotTurning}
高潮（命运抉择）：{plotClimax}
结局（新的开始）：{plotEnding}
```

## Correctness Properties

*A property is a characteristic or behavior that should hold true across all valid executions of a system-essentially, a formal statement about what the system should do. Properties serve as the bridge between human-readable specifications and machine-verifiable correctness guarantees.*

### Property 1: Request Format Correctness (请求格式正确性)

*For any* valid AiConfig and input parameters, the generated Coze workflow request SHALL contain:
- workflow_id from the AiConfig
- user_id from the call parameters
- stream set to true
- parameters.input containing the input string
- Authorization header with "Bearer {api_token}"
- Content-Type header set to "application/json"

**Validates: Requirements 2.1, 2.2, 2.3, 2.4, 2.5, 2.6**

### Property 2: Stream Response Parsing (流式响应解析)

*For any* valid Coze SSE stream response containing an "event: Message" line followed by a "data:" line with JSON containing "node_type": "End" and a "content" field with nested JSON containing "output", the parser SHALL extract and return the output value.

**Validates: Requirements 3.1, 3.2, 3.3**

### Property 3: Input Assembly Completeness (输入组装完整性)

*For any* EpicScriptCreateRequest with non-null field values, the assembled input string SHALL contain all provided field values (title, theme, style, length, plotIntro, plotTurning, plotClimax, plotEnding).

**Validates: Requirements 4.2**

### Property 4: Configuration Application (配置应用正确性)

*For any* AiConfig retrieved by config_key:
- If is_enabled = 0, the system SHALL reject the config and throw an exception
- The api_base_url, api_token, and workflow_id SHALL be used in the request construction
- The custom_params SHALL be merged with runtime parameters

**Validates: Requirements 1.3, 5.2, 5.3**

### Property 5: Error Message Quality (错误消息质量)

*For any* error that occurs during AI API calls:
- The error message SHALL be meaningful and descriptive
- The error message SHALL NOT contain sensitive information such as API tokens
- The error message SHALL include relevant context (config_key, status code if applicable)

**Validates: Requirements 6.4, 6.5**

## Error Handling

### 错误类型和处理策略

| 错误类型 | 处理策略 | 返回值 |
|---------|---------|--------|
| 配置不存在 | 抛出RuntimeException | "未找到AI配置: {configKey}" |
| 配置已禁用 | 抛出RuntimeException | "AI配置已禁用: {configKey}" |
| API调用超时 | 重试（根据配置） | 重试失败后返回错误消息 |
| HTTP非200响应 | 记录日志，返回错误 | "AI服务调用失败: {statusCode}" |
| 流式解析失败 | 记录原始数据，返回错误 | "AI响应解析失败" |
| JSON解析失败 | 返回原始内容 | 原始content字符串 |

### 日志记录规范

```java
// 请求日志
log.info("调用Coze工作流: configKey={}, workflowId={}, userId={}", configKey, workflowId, userId);

// 响应日志
log.info("Coze工作流响应: configKey={}, contentLength={}", configKey, content.length());

// 错误日志
log.error("Coze工作流调用失败: configKey={}, statusCode={}, error={}", configKey, statusCode, errorMsg);
```

## Testing Strategy

### 单元测试

1. **AiConfigService测试**
   - 测试getByConfigKey返回正确配置
   - 测试配置不存在时返回null
   - 测试配置禁用时返回null

2. **请求构建测试**
   - 测试buildWorkflowRequest生成正确的请求格式
   - 测试参数合并逻辑

3. **响应解析测试**
   - 测试parseStreamResponse正确解析SSE格式
   - 测试extractOutputFromContent正确提取output字段

4. **输入组装测试**
   - 测试assembleInput正确组装用户输入

### 属性测试

使用JUnit 5进行属性测试，每个属性测试至少运行100次迭代：

1. **Property 1: Request Format Correctness**
   - 生成随机的AiConfig和输入参数
   - 验证生成的请求包含所有必需字段
   - 验证请求头正确设置
   - **Feature: coze-ai-integration, Property 1: Request Format Correctness**

2. **Property 2: Stream Response Parsing**
   - 生成各种有效的SSE格式响应
   - 验证正确提取output内容
   - 测试边界情况（空content、嵌套JSON等）
   - **Feature: coze-ai-integration, Property 2: Stream Response Parsing**

3. **Property 3: Input Assembly Completeness**
   - 生成随机的EpicScriptCreateRequest
   - 验证所有非空字段都出现在组装结果中
   - **Feature: coze-ai-integration, Property 3: Input Assembly Completeness**

4. **Property 4: Configuration Application**
   - 生成随机的AiConfig
   - 验证配置值正确应用到请求
   - 验证禁用配置被拒绝
   - **Feature: coze-ai-integration, Property 4: Configuration Application**

5. **Property 5: Error Message Quality**
   - 模拟各种错误场景
   - 验证错误消息有意义且不包含敏感信息
   - **Feature: coze-ai-integration, Property 5: Error Message Quality**

### 集成测试

1. 端到端测试：从Controller到Coze API的完整调用流程
2. 配置变更测试：验证配置更新后立即生效
