🎨 优化项目结构 && 完善ai配置

This commit is contained in:
2026-03-03 15:39:23 +08:00
parent 557c865948
commit 2714e63d2a
585 changed files with 62223 additions and 100018 deletions

View File

@@ -1,230 +0,0 @@
# AI 中转代理系统 - App 模块
## 已完成的功能模块
按照 server 目录的标准结构,已将 AI 中转代理项目的代码编写到各个 `app` 目录下:
### 1. Model 层 (server/model/app/)
**核心模型:**
- `ai_preset.go` - AI 预设模板模型(支持 SillyTavern 格式)
- `ai_provider.go` - AI 服务提供商模型
- `ai_preset_binding.go` - 用户-预设-提供商绑定模型
- `ai_request_log.go` - AI 请求日志模型
- `ai_preset_types.go` - 预设相关的自定义类型
**Request 结构体 (server/model/app/request/)**
- `ai_preset.go` - 预设相关请求(创建、更新、导入)
- `ai_provider.go` - 提供商相关请求(创建、更新)
- `ai_proxy.go` - 代理请求(聊天补全、消息、角色卡片)
**Response 结构体 (server/model/app/response/)**
- `ai_proxy.go` - 代理响应OpenAI 兼容格式)
### 2. Service 层 (server/service/app/)
- `ai_preset.go` - 预设服务CRUD、导入导出
- `ai_provider.go` - 提供商服务CRUD、连接测试
- `ai_proxy.go` - 代理服务(核心预设注入引擎、转发到上游 AI
- `enter.go` - Service 统一入口
### 3. API 层 (server/api/v1/app/)
- `ai_preset.go` - 预设管理 API
- `ai_provider.go` - 提供商管理 API
- `ai_proxy.go` - 代理转发 APIOpenAI 兼容接口)
- `enter.go` - API 统一入口
### 4. Router 层 (server/router/app/)
- `ai_preset.go` - 预设路由
- `ai_provider.go` - 提供商路由
- `ai_proxy.go` - 代理路由
- `enter.go` - Router 统一入口
## 核心功能特性
### 1. AI 预设管理
- ✅ 创建、更新、删除预设
- ✅ 获取预设列表和详情
- ✅ 导入 SillyTavern 格式预设
- ✅ 导出预设为 JSON
- ✅ 支持公开/私有预设
- ✅ 完整的 Prompt 注入配置
- ✅ 正则脚本处理
### 2. AI 服务提供商管理
- ✅ 创建、更新、删除提供商
- ✅ 获取提供商列表和详情
- ✅ 支持自定义配置
- ✅ 启用/禁用状态管理
### 3. AI 代理服务
- ✅ OpenAI 兼容的聊天补全接口
- ✅ 预设注入引擎
- ✅ 变量替换({{user}}, {{char}}
- ✅ 正则脚本处理(输入/输出)
- ✅ 转发到上游 AI 服务
- ✅ 请求日志记录
- ⏳ 流式响应(待实现)
## API 端点
### 预设管理
```
POST /app/preset # 创建预设
PUT /app/preset # 更新预设
DELETE /app/preset/:id # 删除预设
GET /app/preset/:id # 获取预设详情
GET /app/preset/list # 获取预设列表
POST /app/preset/import # 导入预设
GET /app/preset/:id/export # 导出预设
```
### 提供商管理
```
POST /app/provider # 创建提供商
PUT /app/provider # 更新提供商
DELETE /app/provider/:id # 删除提供商
GET /app/provider/:id # 获取提供商详情
GET /app/provider/list # 获取提供商列表
```
### 代理接口OpenAI 兼容)
```
POST /v1/chat/completions # 聊天补全
```
## 数据模型说明
### AiPreset预设模板
```go
- UserID: 用户ID
- Name: 预设名称
- Description: 预设描述
- Prompts: 提示词数组支持 SillyTavern 格式
- RegexScripts: 正则脚本数组
- Temperature, TopP, MaxTokens: 模型参数
- StreamEnabled: 是否启用流式
- IsDefault: 是否默认
- IsPublic: 是否公开
```
### Prompt提示词
```go
- Name: 提示词名称
- Role: 角色system/user/assistant
- Content: 提示词内容
- Identifier: 标识符
- InjectionPosition: 注入位置
- InjectionDepth: 注入深度
- InjectionOrder: 注入顺序
- Marker: 是否为占位符
```
### RegexScript正则脚本
```go
- ScriptName: 脚本名称
- FindRegex: 查找正则
- ReplaceString: 替换字符串
- Placement: 应用位置1=输入, 2=输出
- MinDepth, MaxDepth: 深度限制
```
## 预设注入流程
1. 接收用户请求
2. 加载预设配置
3. 按 injection_order 排序 prompts
4. 根据 injection_depth 插入到对话历史中
5. 替换变量({{user}}, {{char}}
6. 应用正则脚本placement=1 处理输入)
7. 转发到上游 AI
8. 应用正则脚本placement=2 处理输出)
9. 记录日志
10. 返回响应
## 待完善功能
1. **完整的预设注入引擎**
- 完整实现 injection_depth 逻辑
- 完整实现正则脚本处理
- 支持更多变量替换
2. **流式响应**
- 实现 SSE 流式输出
- 支持流式日志记录
3. **预设绑定管理**
- 实现 binding_key 机制
- 支持多预设切换
4. **导入导出**
- 完善 SillyTavern JSON 解析
- 支持批量导入导出
## 使用示例
### 1. 创建 AI 提供商
```bash
POST /app/provider
{
"name": "OpenAI",
"baseUrl": "https://api.openai.com/v1",
"apiKey": "sk-xxx",
"model": "gpt-4",
"isActive": true
}
```
### 2. 导入 SillyTavern 预设
```bash
POST /app/preset/import
{
"name": "TG角色扮演",
"data": { ... } // TGbreak.json 内容
}
```
### 3. 发送聊天请求
```bash
POST /v1/chat/completions
{
"messages": [
{"role": "user", "content": "你好"}
],
"presetId": 1,
"characterCard": {
"name": "小美",
"description": "活泼的女孩"
}
}
```
## 项目结构
```
server/
├── model/app/ # 数据模型
│ ├── ai_preset.go
│ ├── ai_provider.go
│ ├── ai_preset_binding.go
│ ├── ai_request_log.go
│ ├── request/ # 请求结构体
│ └── response/ # 响应结构体
├── service/app/ # 业务逻辑
│ ├── ai_preset.go
│ ├── ai_provider.go
│ ├── ai_proxy.go
│ └── enter.go
├── api/v1/app/ # API 处理器
│ ├── ai_preset.go
│ ├── ai_provider.go
│ ├── ai_proxy.go
│ └── enter.go
└── router/app/ # 路由注册
├── ai_preset.go
├── ai_provider.go
├── ai_proxy.go
└── enter.go
```

View File

@@ -4,51 +4,62 @@ import (
"git.echol.cn/loser/ai_proxy/server/global"
)
// AiPreset AI预设模
// AiPreset AI预设模
type AiPreset struct {
global.GVA_MODEL
UserID uint `json:"userId" gorm:"comment:用户ID;index"`
Name string `json:"name" gorm:"comment:预设名称;size:200;not null"`
Description string `json:"description" gorm:"comment:预设描述;type:text"`
Prompts Prompts `json:"prompts" gorm:"comment:提示词数组;type:jsonb;not null"`
RegexScripts RegexScripts `json:"regexScripts" gorm:"comment:正则脚本;type:jsonb"`
Temperature float64 `json:"temperature" gorm:"comment:温度;default:1.0"`
TopP float64 `json:"topP" gorm:"comment:TopP;default:0.9"`
MaxTokens int `json:"maxTokens" gorm:"comment:最大Token数;default:4096"`
FrequencyPenalty float64 `json:"frequencyPenalty" gorm:"comment:频率惩罚;default:0"`
PresencePenalty float64 `json:"presencePenalty" gorm:"comment:存在惩罚;default:0"`
StreamEnabled bool `json:"streamEnabled" gorm:"comment:是否启用流式;default:true"`
IsDefault bool `json:"isDefault" gorm:"comment:是否默认;default:false"`
IsPublic bool `json:"isPublic" gorm:"comment:是否公开;default:false"`
Name string `json:"name" gorm:"type:varchar(100);not null;uniqueIndex;comment:预设名称"`
Description string `json:"description" gorm:"type:text;comment:预设描述"`
Temperature float64 `json:"temperature" gorm:"type:decimal(3,2);default:1.0;comment:温度"`
FrequencyPenalty float64 `json:"frequency_penalty" gorm:"type:decimal(3,2);default:0;comment:频率惩罚"`
PresencePenalty float64 `json:"presence_penalty" gorm:"type:decimal(3,2);default:0;comment:存在惩罚"`
TopP float64 `json:"top_p" gorm:"type:decimal(3,2);default:0.9;comment:Top P"`
TopK int `json:"top_k" gorm:"type:int;default:0;comment:Top K"`
MaxTokens int `json:"max_tokens" gorm:"type:int;default:4096;comment:最大token数"`
Prompts PresetPrompts `json:"prompts" gorm:"type:json;comment:提示词列表"`
PromptOrder []PromptOrder `json:"prompt_order" gorm:"type:json;comment:提示词顺序"`
RegexScripts []RegexScript `json:"regex_scripts" gorm:"type:json;comment:正则脚本"`
Extensions PresetExtensions `json:"extensions" gorm:"type:json;comment:扩展配置"`
Enabled bool `json:"enabled" gorm:"default:true;comment:是否启用"`
UserID uint `json:"user_id" gorm:"index;comment:用户ID"`
}
func (AiPreset) TableName() string {
return "ai_presets"
}
// Prompt 提示词结构
type Prompt struct {
Name string `json:"name"`
SystemPrompt bool `json:"system_prompt"`
Role string `json:"role"`
Content string `json:"content"`
// PresetPrompt 预设提示词
type PresetPrompt struct {
Identifier string `json:"identifier"`
InjectionPosition int `json:"injection_position"`
Name string `json:"name"`
Role string `json:"role"` // system, user, assistant
Content string `json:"content"`
SystemPrompt bool `json:"system_prompt"`
Enabled bool `json:"enabled"`
Marker bool `json:"marker"`
InjectionPosition int `json:"injection_position"` // 0=相对, 1=绝对
InjectionDepth int `json:"injection_depth"`
InjectionOrder int `json:"injection_order"`
InjectionTrigger []string `json:"injection_trigger"`
Marker bool `json:"marker"`
ForbidOverrides bool `json:"forbid_overrides"`
}
// RegexScript 正则脚本
type PresetPrompts []PresetPrompt
// PromptOrder 提示词顺序配置
type PromptOrder struct {
CharacterID int `json:"character_id"`
Order []PromptOrderItem `json:"order"`
}
type PromptOrderItem struct {
Identifier string `json:"identifier"`
Enabled bool `json:"enabled"`
}
// RegexScript 正则替换脚本
type RegexScript struct {
ID string `json:"id"`
ScriptName string `json:"scriptName"`
FindRegex string `json:"findRegex"`
ReplaceString string `json:"replaceString"`
TrimStrings []string `json:"trimStrings"`
Placement []int `json:"placement"`
Placement []int `json:"placement"` // 1=用户输入前, 2=AI输出后
Disabled bool `json:"disabled"`
MarkdownOnly bool `json:"markdownOnly"`
PromptOnly bool `json:"promptOnly"`
@@ -57,3 +68,38 @@ type RegexScript struct {
MinDepth *int `json:"minDepth"`
MaxDepth *int `json:"maxDepth"`
}
// PresetExtensions 预设扩展配置
type PresetExtensions struct {
ChatSquash *ChatSquashConfig `json:"ChatSquash,omitempty"`
RegexBinding *RegexBindingConfig `json:"RegexBinding,omitempty"`
MacroNest bool `json:"MacroNest"`
}
type ChatSquashConfig struct {
Enabled bool `json:"enabled"`
SeparateChatHistory bool `json:"separate_chat_history"`
ParseClewd bool `json:"parse_clewd"`
UserRoleSystem bool `json:"user_role_system"`
Role string `json:"role"`
StopString string `json:"stop_string"`
UserPrefix string `json:"user_prefix"`
UserSuffix string `json:"user_suffix"`
CharPrefix string `json:"char_prefix"`
CharSuffix string `json:"char_suffix"`
PrefixSystem string `json:"prefix_system"`
SuffixSystem string `json:"suffix_system"`
EnableSquashedSeparator bool `json:"enable_squashed_separator"`
SquashedSeparatorRegex bool `json:"squashed_separator_regex"`
SquashedSeparatorString string `json:"squashed_separator_string"`
SquashedPostScriptEnable bool `json:"squashed_post_script_enable"`
SquashedPostScript string `json:"squashed_post_script"`
}
type RegexBindingConfig struct {
Regexes []RegexScript `json:"regexes"`
}
func (AiPreset) TableName() string {
return "ai_presets"
}

View File

@@ -4,13 +4,14 @@ import (
"git.echol.cn/loser/ai_proxy/server/global"
)
// AiPresetBinding 预设-提供商绑定关系
// AiPresetBinding 预设绑定关系
type AiPresetBinding struct {
global.GVA_MODEL
PresetID uint `json:"presetId" gorm:"comment:预设ID;index"`
ProviderID uint `json:"providerId" gorm:"comment:提供商ID;index"`
Priority int `json:"priority" gorm:"comment:优先级;default:0"` // 多个预设时的执行顺序
IsActive bool `json:"isActive" gorm:"comment:是否启用;default:true"`
Name string `json:"name" gorm:"type:varchar(100);not null;uniqueIndex:idx_user_binding;comment:绑定名称"`
PresetID uint `json:"preset_id" gorm:"not null;index;comment:预设ID"`
ProviderID uint `json:"provider_id" gorm:"not null;index;comment:提供商ID"`
Enabled bool `json:"enabled" gorm:"default:true;comment:是否启用"`
UserID uint `json:"user_id" gorm:"index:idx_user_binding;comment:用户ID"`
// 关联
Preset AiPreset `json:"preset" gorm:"foreignKey:PresetID"`

View File

@@ -1,36 +0,0 @@
package app
import (
"database/sql/driver"
"encoding/json"
)
// Prompts 提示词数组类型
type Prompts []Prompt
func (p Prompts) Value() (driver.Value, error) {
return json.Marshal(p)
}
func (p *Prompts) Scan(value interface{}) error {
bytes, ok := value.([]byte)
if !ok {
return nil
}
return json.Unmarshal(bytes, p)
}
// RegexScripts 正则脚本数组类型
type RegexScripts []RegexScript
func (r RegexScripts) Value() (driver.Value, error) {
return json.Marshal(r)
}
func (r *RegexScripts) Scan(value interface{}) error {
bytes, ok := value.([]byte)
if !ok {
return nil
}
return json.Unmarshal(bytes, r)
}

View File

@@ -4,18 +4,19 @@ import (
"git.echol.cn/loser/ai_proxy/server/global"
)
// AiProvider AI服务提供商配置
// AiProvider AI提供商配置
type AiProvider struct {
global.GVA_MODEL
Name string `json:"name" gorm:"comment:提供商名称;size:100;not null;uniqueIndex"`
Type string `json:"type" gorm:"comment:提供商类型;size:50;not null"` // openai, claude, gemini
BaseURL string `json:"baseUrl" gorm:"comment:API基础地址;size:500;not null"`
Endpoint string `json:"endpoint" gorm:"comment:API端点;size:200"` // 如 /v1/chat/completions
UpstreamKey string `json:"upstreamKey" gorm:"comment:上游API密钥;type:text"` // 上游 AI 的 key
Model string `json:"model" gorm:"comment:默认模型;size:100"`
ProxyKey string `json:"proxyKey" gorm:"comment:代理访问密钥;size:100;uniqueIndex"` // 用户访问本代理时使用的 key
Config map[string]interface{} `json:"config" gorm:"comment:额外配置;type:jsonb;serializer:json"`
IsActive bool `json:"isActive" gorm:"comment:是否启用;default:true"`
Name string `json:"name" gorm:"type:varchar(100);not null;uniqueIndex:idx_user_provider;comment:提供商名称"`
Type string `json:"type" gorm:"type:varchar(50);not null;comment:提供商类型"` // openai, claude, gemini
BaseURL string `json:"base_url" gorm:"type:varchar(255);not null;comment:API基础URL"`
APIKey string `json:"api_key" gorm:"type:varchar(255);not null;comment:API密钥"`
Model string `json:"model" gorm:"type:varchar(100);comment:默认模型"`
Enabled bool `json:"enabled" gorm:"default:true;comment:是否启用"`
Priority int `json:"priority" gorm:"default:0;comment:优先级"`
MaxRetries int `json:"max_retries" gorm:"default:3;comment:最大重试次数"`
Timeout int `json:"timeout" gorm:"default:60;comment:超时时间(秒)"`
UserID uint `json:"user_id" gorm:"index:idx_user_provider;comment:用户ID"`
}
func (AiProvider) TableName() string {

View File

@@ -2,23 +2,24 @@ package app
import (
"git.echol.cn/loser/ai_proxy/server/global"
"time"
)
// AiRequestLog AI请求日志
type AiRequestLog struct {
global.GVA_MODEL
UserID *uint `json:"userId" gorm:"comment:用户ID;index"`
PresetID *uint `json:"presetId" gorm:"comment:预设ID"`
ProviderID *uint `json:"providerId" gorm:"comment:提供商ID"`
OriginalMessage string `json:"originalMessage" gorm:"comment:原始消息;type:text"`
InjectedPrompt map[string]interface{} `json:"injectedPrompt" gorm:"comment:注入后的提示词;type:jsonb;serializer:json"`
ResponseText string `json:"responseText" gorm:"comment:响应文本;type:text"`
ResponseTokens int `json:"responseTokens" gorm:"comment:响应Token数"`
PromptTokens int `json:"promptTokens" gorm:"comment:提示Token数"`
TotalTokens int `json:"totalTokens" gorm:"comment:总Token数"`
LatencyMs int `json:"latencyMs" gorm:"comment:延迟(毫秒)"`
Status string `json:"status" gorm:"comment:状态;size:20"` // success/error/timeout
ErrorMessage string `json:"errorMessage" gorm:"comment:错误信息;type:text"`
UserID uint `json:"user_id" gorm:"index;comment:用户ID"`
BindingID uint `json:"binding_id" gorm:"index;comment:绑定ID"`
ProviderID uint `json:"provider_id" gorm:"index;comment:提供商ID"`
PresetID uint `json:"preset_id" gorm:"index;comment:预设ID"`
Model string `json:"model" gorm:"type:varchar(100);comment:使用的模型"`
PromptTokens int `json:"prompt_tokens" gorm:"comment:输入token数"`
CompletionTokens int `json:"completion_tokens" gorm:"comment:输出token数"`
TotalTokens int `json:"total_tokens" gorm:"comment:总token数"`
Duration int64 `json:"duration" gorm:"comment:请求耗时(毫秒)"`
Status string `json:"status" gorm:"type:varchar(20);index;comment:请求状态"` // success, error
ErrorMessage string `json:"error_message" gorm:"type:text;comment:错误信息"`
RequestTime time.Time `json:"request_time" gorm:"index;comment:请求时间"`
}
func (AiRequestLog) TableName() string {

View File

@@ -0,0 +1,8 @@
package app
var AutoMigrateTables = []interface{}{
&AiPreset{},
&AiProvider{},
&AiPresetBinding{},
&AiRequestLog{},
}

View File

@@ -1,42 +0,0 @@
package request
import "git.echol.cn/loser/ai_proxy/server/model/app"
// CreateAiPresetRequest 创建预设请求
type CreateAiPresetRequest struct {
Name string `json:"name" binding:"required"`
Description string `json:"description"`
Prompts []app.Prompt `json:"prompts" binding:"required"`
RegexScripts []app.RegexScript `json:"regexScripts"`
Temperature float64 `json:"temperature"`
TopP float64 `json:"topP"`
MaxTokens int `json:"maxTokens"`
FrequencyPenalty float64 `json:"frequencyPenalty"`
PresencePenalty float64 `json:"presencePenalty"`
StreamEnabled bool `json:"streamEnabled"`
IsDefault bool `json:"isDefault"`
IsPublic bool `json:"isPublic"`
}
// UpdateAiPresetRequest 更新预设请求
type UpdateAiPresetRequest struct {
ID uint `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
Prompts []app.Prompt `json:"prompts"`
RegexScripts []app.RegexScript `json:"regexScripts"`
Temperature float64 `json:"temperature"`
TopP float64 `json:"topP"`
MaxTokens int `json:"maxTokens"`
FrequencyPenalty float64 `json:"frequencyPenalty"`
PresencePenalty float64 `json:"presencePenalty"`
StreamEnabled bool `json:"streamEnabled"`
IsDefault bool `json:"isDefault"`
IsPublic bool `json:"isPublic"`
}
// ImportAiPresetRequest 导入预设请求支持SillyTavern格式
type ImportAiPresetRequest struct {
Name string `json:"name" binding:"required"`
Data interface{} `json:"data" binding:"required"`
}

View File

@@ -1,23 +0,0 @@
package request
// CreateBindingRequest 创建绑定请求
type CreateBindingRequest struct {
PresetID uint `json:"presetId" binding:"required"`
ProviderID uint `json:"providerId" binding:"required"`
Priority int `json:"priority"`
}
// UpdateBindingRequest 更新绑定请求
type UpdateBindingRequest struct {
ID uint `json:"id" binding:"required"`
Priority int `json:"priority"`
IsActive bool `json:"isActive"`
}
// GetBindingListRequest 获取绑定列表请求
type GetBindingListRequest struct {
Page int `json:"page" form:"page"`
PageSize int `json:"pageSize" form:"pageSize"`
ProviderID uint `json:"providerId" form:"providerId"`
PresetID uint `json:"presetId" form:"presetId"`
}

View File

@@ -1,28 +0,0 @@
package request
// CreateAiProviderRequest 创建AI提供商请求
type CreateAiProviderRequest struct {
Name string `json:"name" binding:"required"`
Type string `json:"type" binding:"required"`
BaseURL string `json:"baseUrl" binding:"required,url"`
Endpoint string `json:"endpoint"`
UpstreamKey string `json:"upstreamKey" binding:"required"`
Model string `json:"model"`
ProxyKey string `json:"proxyKey" binding:"required"`
Config map[string]interface{} `json:"config"`
IsActive bool `json:"isActive"`
}
// UpdateAiProviderRequest 更新AI提供商请求
type UpdateAiProviderRequest struct {
ID uint `json:"id"`
Name string `json:"name"`
Type string `json:"type"`
BaseURL string `json:"baseUrl"`
Endpoint string `json:"endpoint"`
UpstreamKey string `json:"upstreamKey"`
Model string `json:"model"`
ProxyKey string `json:"proxyKey"`
Config map[string]interface{} `json:"config"`
IsActive bool `json:"isActive"`
}

View File

@@ -1,15 +0,0 @@
package request
// TestConnectionRequest 测试连接请求
type TestConnectionRequest struct {
BaseURL string `json:"baseUrl" binding:"required"`
UpstreamKey string `json:"upstreamKey" binding:"required"`
Type string `json:"type" binding:"required"` // openai, claude, gemini 等
}
// GetModelsRequest 获取模型列表请求
type GetModelsRequest struct {
BaseURL string `json:"baseUrl" binding:"required"`
UpstreamKey string `json:"upstreamKey" binding:"required"`
Type string `json:"type" binding:"required"`
}

View File

@@ -1,31 +1,28 @@
package request
// Message 消息结构
type Message struct {
Role string `json:"role"`
Content string `json:"content"`
}
// CharacterCard 角色卡片
type CharacterCard struct {
Name string `json:"name"`
Description string `json:"description"`
Personality string `json:"personality"`
Scenario string `json:"scenario"`
}
// ChatCompletionRequest 聊天补全请求OpenAI兼容
// ChatCompletionRequest OpenAI兼容的聊天请求
type ChatCompletionRequest struct {
Model string `json:"model"`
Messages []Message `json:"messages" binding:"required"`
PresetID uint `json:"presetId"`
BindingKey string `json:"bindingKey"`
CharacterCard *CharacterCard `json:"characterCard"`
Variables map[string]string `json:"variables"`
Temperature *float64 `json:"temperature"`
TopP *float64 `json:"topP"`
MaxTokens *int `json:"maxTokens"`
FrequencyPenalty *float64 `json:"frequencyPenalty"`
PresencePenalty *float64 `json:"presencePenalty"`
Stream bool `json:"stream"`
Model string `json:"model"`
Messages []ChatMessage `json:"messages"`
Temperature *float64 `json:"temperature,omitempty"`
TopP *float64 `json:"top_p,omitempty"`
N *int `json:"n,omitempty"`
Stream bool `json:"stream,omitempty"`
Stop interface{} `json:"stop,omitempty"`
MaxTokens *int `json:"max_tokens,omitempty"`
PresencePenalty *float64 `json:"presence_penalty,omitempty"`
FrequencyPenalty *float64 `json:"frequency_penalty,omitempty"`
LogitBias map[string]float64 `json:"logit_bias,omitempty"`
User string `json:"user,omitempty"`
// 扩展字段 - 用于指定预设和提供商
PresetName string `json:"preset_name,omitempty"` // 预设名称
ProviderName string `json:"provider_name,omitempty"` // 提供商名称
BindingName string `json:"binding_name,omitempty"` // 绑定名称(优先级最高)
}
type ChatMessage struct {
Role string `json:"role"` // system, user, assistant
Content string `json:"content"`
Name string `json:"name,omitempty"`
}

View File

@@ -1,16 +0,0 @@
package response
import "time"
// BindingInfo 绑定信息
type BindingInfo struct {
ID uint `json:"id"`
PresetID uint `json:"presetId"`
PresetName string `json:"presetName"`
ProviderID uint `json:"providerId"`
ProviderName string `json:"providerName"`
Priority int `json:"priority"`
IsActive bool `json:"isActive"`
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
}

View File

@@ -1,15 +0,0 @@
package response
// ModelInfo 模型信息
type ModelInfo struct {
ID string `json:"id"`
Name string `json:"name"`
OwnedBy string `json:"ownedBy"`
}
// TestConnectionResponse 测试连接响应
type TestConnectionResponse struct {
Success bool `json:"success"`
Message string `json:"message"`
Latency int64 `json:"latency"` // 延迟(毫秒)
}

View File

@@ -1,38 +1,48 @@
package response
// ChatCompletionResponse OpenAI兼容的聊天补全响应
// ChatCompletionResponse OpenAI兼容的聊天响应
type ChatCompletionResponse struct {
ID string `json:"id"`
Object string `json:"object"`
Created int64 `json:"created"`
Model string `json:"model"`
Choices []Choice `json:"choices"`
Usage Usage `json:"usage"`
ID string `json:"id"`
Object string `json:"object"`
Created int64 `json:"created"`
Model string `json:"model"`
Choices []ChatCompletionChoice `json:"choices"`
Usage ChatCompletionUsage `json:"usage"`
}
// Choice 选择项
type Choice struct {
Index int `json:"index"`
Message Message `json:"message"`
FinishReason string `json:"finish_reason"`
type ChatCompletionChoice struct {
Index int `json:"index"`
Message ChatMessage `json:"message"`
FinishReason string `json:"finish_reason"`
}
// Message 消息
type Message struct {
type ChatMessage struct {
Role string `json:"role"`
Content string `json:"content"`
}
// Usage Token使用情况
type Usage struct {
type ChatCompletionUsage struct {
PromptTokens int `json:"prompt_tokens"`
CompletionTokens int `json:"completion_tokens"`
TotalTokens int `json:"total_tokens"`
}
// StreamChunk 流式响应
type StreamChunk struct {
Content string `json:"content"`
Done bool `json:"done"`
Error error `json:"error,omitempty"`
// ChatCompletionStreamResponse 流式响应
type ChatCompletionStreamResponse struct {
ID string `json:"id"`
Object string `json:"object"`
Created int64 `json:"created"`
Model string `json:"model"`
Choices []ChatCompletionStreamChoice `json:"choices"`
}
type ChatCompletionStreamChoice struct {
Index int `json:"index"`
Delta ChatMessageDelta `json:"delta"`
FinishReason *string `json:"finish_reason"`
}
type ChatMessageDelta struct {
Role string `json:"role,omitempty"`
Content string `json:"content,omitempty"`
}