🎨 优化模型配置 && 新增apikey功能 && 完善通用接口
This commit is contained in:
22
server/model/app/ai_api_key.go
Normal file
22
server/model/app/ai_api_key.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"git.echol.cn/loser/ai_proxy/server/global"
|
||||
)
|
||||
|
||||
// AiApiKey AI API密钥管理
|
||||
type AiApiKey struct {
|
||||
global.GVA_MODEL
|
||||
Name string `json:"name" gorm:"type:varchar(100);not null;comment:密钥名称"`
|
||||
Key string `json:"key" gorm:"type:varchar(255);not null;uniqueIndex;comment:API密钥"`
|
||||
AllowedModels []string `json:"allowed_models" gorm:"type:json;serializer:json;comment:允许使用的模型列表"`
|
||||
AllowedPresets []string `json:"allowed_presets" gorm:"type:json;serializer:json;comment:允许使用的预设列表"`
|
||||
RateLimit int `json:"rate_limit" gorm:"default:0;comment:速率限制(每分钟请求数,0表示不限制)"`
|
||||
ExpiresAt *int64 `json:"expires_at" gorm:"comment:过期时间(Unix时间戳)"`
|
||||
Enabled bool `json:"enabled" gorm:"default:true;comment:是否启用"`
|
||||
UserID uint `json:"user_id" gorm:"index;comment:用户ID"`
|
||||
}
|
||||
|
||||
func (AiApiKey) TableName() string {
|
||||
return "ai_api_keys"
|
||||
}
|
||||
24
server/model/app/ai_model.go
Normal file
24
server/model/app/ai_model.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"git.echol.cn/loser/ai_proxy/server/global"
|
||||
)
|
||||
|
||||
// AiModel AI模型配置
|
||||
type AiModel struct {
|
||||
global.GVA_MODEL
|
||||
Name string `json:"name" gorm:"type:varchar(100);not null;comment:模型名称"`
|
||||
DisplayName string `json:"display_name" gorm:"type:varchar(100);comment:显示名称"`
|
||||
ProviderID uint `json:"provider_id" gorm:"not null;index;comment:提供商ID"`
|
||||
Provider AiProvider `json:"provider" gorm:"foreignKey:ProviderID"`
|
||||
PresetID *uint `json:"preset_id" gorm:"index;comment:绑定的预设ID"`
|
||||
Preset *AiPreset `json:"preset,omitempty" gorm:"foreignKey:PresetID"`
|
||||
Enabled bool `json:"enabled" gorm:"default:true;comment:是否启用"`
|
||||
MaxTokens int `json:"max_tokens" gorm:"default:4096;comment:最大token数"`
|
||||
Description string `json:"description" gorm:"type:text;comment:模型描述"`
|
||||
UserID uint `json:"user_id" gorm:"index;comment:用户ID"`
|
||||
}
|
||||
|
||||
func (AiModel) TableName() string {
|
||||
return "ai_models"
|
||||
}
|
||||
@@ -15,10 +15,10 @@ type AiPreset struct {
|
||||
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:扩展配置"`
|
||||
Prompts PresetPrompts `json:"prompts" gorm:"type:json;serializer:json;comment:提示词列表"`
|
||||
PromptOrder []PromptOrder `json:"prompt_order" gorm:"type:json;serializer:json;comment:提示词顺序"`
|
||||
RegexScripts []RegexScript `json:"regex_scripts" gorm:"type:json;serializer:json;comment:正则脚本"`
|
||||
Extensions PresetExtensions `json:"extensions" gorm:"type:json;serializer:json;comment:扩展配置"`
|
||||
Enabled bool `json:"enabled" gorm:"default:true;comment:是否启用"`
|
||||
UserID uint `json:"user_id" gorm:"index;comment:用户ID"`
|
||||
}
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"git.echol.cn/loser/ai_proxy/server/global"
|
||||
)
|
||||
|
||||
// AiPresetBinding 预设绑定关系
|
||||
type AiPresetBinding struct {
|
||||
global.GVA_MODEL
|
||||
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"`
|
||||
Provider AiProvider `json:"provider" gorm:"foreignKey:ProviderID"`
|
||||
}
|
||||
|
||||
func (AiPresetBinding) TableName() string {
|
||||
return "ai_preset_bindings"
|
||||
}
|
||||
@@ -13,6 +13,7 @@ type AiProvider struct {
|
||||
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:是否启用"`
|
||||
IsDefault bool `json:"is_default" gorm:"default:false;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:超时时间(秒)"`
|
||||
|
||||
@@ -3,6 +3,7 @@ package app
|
||||
var AutoMigrateTables = []interface{}{
|
||||
&AiPreset{},
|
||||
&AiProvider{},
|
||||
&AiPresetBinding{},
|
||||
&AiRequestLog{},
|
||||
&AiApiKey{},
|
||||
&AiModel{},
|
||||
}
|
||||
|
||||
36
server/model/app/request/ai_claude.go
Normal file
36
server/model/app/request/ai_claude.go
Normal file
@@ -0,0 +1,36 @@
|
||||
package request
|
||||
|
||||
// ClaudeMessageRequest Claude API 兼容的消息请求
|
||||
type ClaudeMessageRequest struct {
|
||||
Model string `json:"model"`
|
||||
Messages []ClaudeMessage `json:"messages"`
|
||||
MaxTokens int `json:"max_tokens"`
|
||||
Temperature *float64 `json:"temperature,omitempty"`
|
||||
TopP *float64 `json:"top_p,omitempty"`
|
||||
TopK *int `json:"top_k,omitempty"`
|
||||
Stream bool `json:"stream,omitempty"`
|
||||
StopSequences []string `json:"stop_sequences,omitempty"`
|
||||
System string `json:"system,omitempty"`
|
||||
|
||||
// 扩展字段 - 用于指定预设和提供商
|
||||
PresetName string `json:"preset_name,omitempty"` // 预设名称
|
||||
ProviderName string `json:"provider_name,omitempty"` // 提供商名称
|
||||
BindingName string `json:"binding_name,omitempty"` // 绑定名称(优先级最高)
|
||||
}
|
||||
|
||||
type ClaudeMessage struct {
|
||||
Role string `json:"role"` // user, assistant
|
||||
Content interface{} `json:"content"` // string 或 []ClaudeContentBlock
|
||||
}
|
||||
|
||||
type ClaudeContentBlock struct {
|
||||
Type string `json:"type"` // text, image
|
||||
Text string `json:"text,omitempty"`
|
||||
Source *ClaudeImageSource `json:"source,omitempty"`
|
||||
}
|
||||
|
||||
type ClaudeImageSource struct {
|
||||
Type string `json:"type"` // base64
|
||||
MediaType string `json:"media_type"` // image/jpeg, image/png, image/gif, image/webp
|
||||
Data string `json:"data"` // base64 编码的图片数据
|
||||
}
|
||||
38
server/model/app/response/ai_claude.go
Normal file
38
server/model/app/response/ai_claude.go
Normal file
@@ -0,0 +1,38 @@
|
||||
package response
|
||||
|
||||
// ClaudeMessageResponse Claude API 兼容的消息响应
|
||||
type ClaudeMessageResponse struct {
|
||||
ID string `json:"id"`
|
||||
Type string `json:"type"` // message
|
||||
Role string `json:"role"` // assistant
|
||||
Content []ClaudeContentBlock `json:"content"`
|
||||
Model string `json:"model"`
|
||||
StopReason string `json:"stop_reason,omitempty"` // end_turn, max_tokens, stop_sequence
|
||||
StopSequence string `json:"stop_sequence,omitempty"`
|
||||
Usage ClaudeUsage `json:"usage"`
|
||||
}
|
||||
|
||||
type ClaudeContentBlock struct {
|
||||
Type string `json:"type"` // text
|
||||
Text string `json:"text"`
|
||||
}
|
||||
|
||||
type ClaudeUsage struct {
|
||||
InputTokens int `json:"input_tokens"`
|
||||
OutputTokens int `json:"output_tokens"`
|
||||
}
|
||||
|
||||
// ClaudeStreamResponse Claude 流式响应
|
||||
type ClaudeStreamResponse struct {
|
||||
Type string `json:"type"` // message_start, content_block_start, content_block_delta, content_block_stop, message_delta, message_stop
|
||||
Message *ClaudeMessageResponse `json:"message,omitempty"`
|
||||
Index int `json:"index,omitempty"`
|
||||
ContentBlock *ClaudeContentBlock `json:"content_block,omitempty"`
|
||||
Delta *ClaudeContentBlockDelta `json:"delta,omitempty"`
|
||||
Usage *ClaudeUsage `json:"usage,omitempty"`
|
||||
}
|
||||
|
||||
type ClaudeContentBlockDelta struct {
|
||||
Type string `json:"type"` // text_delta
|
||||
Text string `json:"text"`
|
||||
}
|
||||
15
server/model/app/response/ai_models.go
Normal file
15
server/model/app/response/ai_models.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package response
|
||||
|
||||
// ModelListResponse OpenAI 兼容的模型列表响应
|
||||
type ModelListResponse struct {
|
||||
Object string `json:"object"` // "list"
|
||||
Data []ModelInfo `json:"data"`
|
||||
}
|
||||
|
||||
// ModelInfo 模型信息
|
||||
type ModelInfo struct {
|
||||
ID string `json:"id"`
|
||||
Object string `json:"object"` // "model"
|
||||
Created int64 `json:"created"`
|
||||
OwnedBy string `json:"owned_by"`
|
||||
}
|
||||
Reference in New Issue
Block a user