188 lines
6.1 KiB
Plaintext
188 lines
6.1 KiB
Plaintext
package prompts
|
||
|
||
import (
|
||
"encoding/json"
|
||
"sdk-generator/internal/models"
|
||
|
||
"github.com/sashabaranov/go-openai"
|
||
)
|
||
|
||
// BuildRefinePrompt 构建文档精炼的请求
|
||
func BuildRefinePrompt(rawDoc string) openai.ChatCompletionRequest {
|
||
return openai.ChatCompletionRequest{
|
||
Messages: []openai.ChatCompletionMessage{
|
||
{
|
||
Role: openai.ChatMessageRoleSystem,
|
||
Content: `你是一个专业的 API 文档分析专家,擅长从各种格式的文档中提取技术信息并判断文档用途。你的输出必须准确、完整,因为后续会基于你的输出生成可运行的代码。`,
|
||
},
|
||
{
|
||
Role: openai.ChatMessageRoleUser,
|
||
Content: RefinePrompt(rawDoc),
|
||
},
|
||
},
|
||
Temperature: 0.1,
|
||
TopP: 0.9,
|
||
MaxTokens: 65536,
|
||
FrequencyPenalty: 0.0,
|
||
PresencePenalty: 0.0,
|
||
// 使用工具调用来强制结构化输出
|
||
ToolChoice: "required",
|
||
Tools: []openai.Tool{
|
||
{
|
||
Type: openai.ToolTypeFunction,
|
||
Function: &openai.FunctionDefinition{
|
||
Name: "classify_and_extract_doc",
|
||
Description: "分析API文档,判断文档类型并提取所有技术信息",
|
||
Parameters: map[string]interface{}{
|
||
"type": "object",
|
||
"properties": map[string]interface{}{
|
||
"doc_type": map[string]interface{}{
|
||
"type": "string",
|
||
"enum": []string{models.DocTypeSdk.String(), models.DocTypeServerBoilerplate.String()},
|
||
"description": "文档类型:client_sdk 表示调用文档(生成客户端SDK),server_boilerplate 表示对接文档(生成服务端骨架)",
|
||
},
|
||
"reason": map[string]interface{}{
|
||
"type": "string",
|
||
"description": "判断依据,简要说明为什么归类为此类型",
|
||
},
|
||
"refined_doc": map[string]interface{}{
|
||
"type": "string",
|
||
"description": "精炼后的文档内容,保留所有技术信息",
|
||
},
|
||
"interfaces": map[string]interface{}{
|
||
"type": "array",
|
||
"description": "提取的接口列表摘要(用于快速预览)",
|
||
"items": map[string]interface{}{
|
||
"type": "object",
|
||
"properties": map[string]interface{}{
|
||
"path": map[string]interface{}{"type": "string"},
|
||
"method": map[string]interface{}{"type": "string"},
|
||
"summary": map[string]interface{}{"type": "string"},
|
||
},
|
||
},
|
||
},
|
||
"has_authentication": map[string]interface{}{
|
||
"type": "boolean",
|
||
"description": "是否包含认证/加密/签名信息",
|
||
},
|
||
},
|
||
"required": []string{"doc_type", "refined_doc"},
|
||
},
|
||
},
|
||
},
|
||
},
|
||
Stream: false,
|
||
}
|
||
}
|
||
|
||
// RefinePrompt 文档精炼提示词模板
|
||
func RefinePrompt(rawDoc string) string {
|
||
return `分析以下 API 文档,为后续代码生成做准备。
|
||
|
||
## 第一步:判断文档类型(最关键)
|
||
|
||
请根据文档内容判断它属于哪一类:
|
||
|
||
| 类型 | 中文名 | 判断依据 | 后续生成 |
|
||
|------|--------|----------|----------|
|
||
| **client_sdk** | 调用文档 | 包含:接口域名、请求方式、请求参数、响应格式、鉴权方式 | 客户端 SDK(供调用方使用) |
|
||
| **server_boilerplate** | 对接文档 | 包含:回调地址、请求格式、响应要求、验签方式、异步通知 | 服务端骨架(供被调用方实现) |
|
||
|
||
**快速判断口诀**:
|
||
- 文档教"我怎么调别人" → client_sdk
|
||
- 文档教"别人怎么调我" → server_boilerplate
|
||
|
||
## 第二步:精炼文档内容
|
||
|
||
### 必须保留的内容(一个不漏)
|
||
- ✅ 所有接口(路径、方法、完整URL)
|
||
- ✅ 所有参数和字段(类型、必填/可选、取值范围、描述)
|
||
- ✅ 所有响应字段(成功/失败)
|
||
- ✅ 所有错误码及含义
|
||
- ✅ 认证、加密、签名的完整流程(算法、密钥来源、拼接顺序)
|
||
- ✅ 所有请求/响应示例
|
||
- ✅ 回调/通知机制(如果有)
|
||
- ✅ 时间戳、随机数、签名等共性参数
|
||
|
||
### 可以去掉的内容
|
||
- ❌ 公司介绍、平台介绍
|
||
- ❌ 接入流程步骤(第一步注册、第二步申请...)
|
||
- ❌ 联调建议、FAQ
|
||
- ❌ 营销文案、联系方式
|
||
- ❌ 重复的示例(保留一个最完整的即可)
|
||
|
||
## 输出要求
|
||
|
||
1. **doc_type**:必须是 "client_sdk" 或 "server_boilerplate"
|
||
2. **reason**:用一句话说明判断依据
|
||
3. **refined_doc**:精炼后的文档,按以下结构组织:
|
||
|
||
### 精炼文档结构
|
||
` + "```" + `
|
||
## 文档概述
|
||
- 文档类型:[client_sdk/server_boilerplate]
|
||
- 接口总数:[N]个
|
||
|
||
## 认证与安全
|
||
[完整的认证/加密/签名流程]
|
||
|
||
## 接口列表
|
||
### 接口 N:[名称]
|
||
- 路径:[完整路径]
|
||
- 方法:[GET/POST/...]
|
||
- 描述:[功能说明]
|
||
|
||
#### 请求参数
|
||
| 参数名 | 类型 | 必填 | 说明 |
|
||
|--------|------|------|------|
|
||
|
||
#### 响应参数
|
||
| 参数名 | 类型 | 说明 |
|
||
|--------|------|------|
|
||
|
||
#### 示例
|
||
[请求示例/响应示例]
|
||
|
||
## 错误码
|
||
| 错误码 | 说明 | 处理建议 |
|
||
|--------|------|----------|
|
||
|
||
## 回调通知(如有)
|
||
[回调机制说明]
|
||
` + "```" + `
|
||
|
||
## 关键原则
|
||
|
||
1. **完整性优先**:不确定是否重要的信息,一律保留
|
||
2. **忠于原文**:类型、字段名、示例值保持原样,不要修改或猜测
|
||
3. **不编造**:文档中没有的信息,绝不补充
|
||
4. **类型明确**:如果文档没有明确标注"必填",视为可选
|
||
|
||
原始文档:
|
||
` + rawDoc
|
||
}
|
||
|
||
type ToolRes struct {
|
||
DocType models.DocType `json:"doc_type"`
|
||
Reason string `json:"reason"`
|
||
RefinedDoc string `json:"refined_doc"`
|
||
Interfaces []interface{} `json:"interfaces"`
|
||
HasAuthentication bool `json:"has_authentication"`
|
||
}
|
||
|
||
func ExtractDocTypeFromToolCall(response openai.ChatCompletionResponse) (toolRes *ToolRes, ok bool) {
|
||
|
||
if len(response.Choices) == 0 {
|
||
return nil, false
|
||
}
|
||
choice := response.Choices[0]
|
||
if choice.Message.ToolCalls == nil || len(choice.Message.ToolCalls) == 0 {
|
||
return nil, false
|
||
}
|
||
if err := json.Unmarshal([]byte(choice.Message.ToolCalls[0].Function.Arguments), &toolRes); err != nil {
|
||
return nil, false
|
||
}
|
||
// 这里需要根据实际的 JSON 解析逻辑实现
|
||
return toolRes, true
|
||
}
|