feat: migrate backend from rust to go
This commit replaces the Axum/Rust backend with a Gin/Go implementation. The original Rust code has been archived in the 'rust' branch.
This commit is contained in:
216
internal/models/models.go
Normal file
216
internal/models/models.go
Normal file
@@ -0,0 +1,216 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/go-resty/resty/v2"
|
||||
)
|
||||
|
||||
// OpenAI-compatible Request/Response Structs
|
||||
|
||||
type ChatCompletionRequest struct {
|
||||
Model string `json:"model"`
|
||||
Messages []ChatMessage `json:"messages"`
|
||||
Temperature *float64 `json:"temperature,omitempty"`
|
||||
TopP *float64 `json:"top_p,omitempty"`
|
||||
TopK *uint32 `json:"top_k,omitempty"`
|
||||
N *uint32 `json:"n,omitempty"`
|
||||
Stop json.RawMessage `json:"stop,omitempty"` // Can be string or array of strings
|
||||
MaxTokens *uint32 `json:"max_tokens,omitempty"`
|
||||
PresencePenalty *float64 `json:"presence_penalty,omitempty"`
|
||||
FrequencyPenalty *float64 `json:"frequency_penalty,omitempty"`
|
||||
Stream *bool `json:"stream,omitempty"`
|
||||
Tools []Tool `json:"tools,omitempty"`
|
||||
ToolChoice json.RawMessage `json:"tool_choice,omitempty"`
|
||||
}
|
||||
|
||||
type ChatMessage struct {
|
||||
Role string `json:"role"` // "system", "user", "assistant", "tool"
|
||||
Content interface{} `json:"content"`
|
||||
ReasoningContent *string `json:"reasoning_content,omitempty"`
|
||||
ToolCalls []ToolCall `json:"tool_calls,omitempty"`
|
||||
Name *string `json:"name,omitempty"`
|
||||
ToolCallID *string `json:"tool_call_id,omitempty"`
|
||||
}
|
||||
|
||||
type ContentPart struct {
|
||||
Type string `json:"type"`
|
||||
Text string `json:"text,omitempty"`
|
||||
ImageUrl *ImageUrl `json:"image_url,omitempty"`
|
||||
}
|
||||
|
||||
type ImageUrl struct {
|
||||
URL string `json:"url"`
|
||||
Detail *string `json:"detail,omitempty"`
|
||||
}
|
||||
|
||||
// Tool-Calling Types
|
||||
|
||||
type Tool struct {
|
||||
Type string `json:"type"`
|
||||
Function FunctionDef `json:"function"`
|
||||
}
|
||||
|
||||
type FunctionDef struct {
|
||||
Name string `json:"name"`
|
||||
Description *string `json:"description,omitempty"`
|
||||
Parameters json.RawMessage `json:"parameters,omitempty"`
|
||||
}
|
||||
|
||||
type ToolCall struct {
|
||||
ID string `json:"id"`
|
||||
Type string `json:"type"`
|
||||
Function FunctionCall `json:"function"`
|
||||
}
|
||||
|
||||
type FunctionCall struct {
|
||||
Name string `json:"name"`
|
||||
Arguments string `json:"arguments"`
|
||||
}
|
||||
|
||||
type ToolCallDelta struct {
|
||||
Index uint32 `json:"index"`
|
||||
ID *string `json:"id,omitempty"`
|
||||
Type *string `json:"type,omitempty"`
|
||||
Function *FunctionCallDelta `json:"function,omitempty"`
|
||||
}
|
||||
|
||||
type FunctionCallDelta struct {
|
||||
Name *string `json:"name,omitempty"`
|
||||
Arguments *string `json:"arguments,omitempty"`
|
||||
}
|
||||
|
||||
// OpenAI-compatible Response Structs
|
||||
|
||||
type ChatCompletionResponse struct {
|
||||
ID string `json:"id"`
|
||||
Object string `json:"object"`
|
||||
Created int64 `json:"created"`
|
||||
Model string `json:"model"`
|
||||
Choices []ChatChoice `json:"choices"`
|
||||
Usage *Usage `json:"usage,omitempty"`
|
||||
}
|
||||
|
||||
type ChatChoice struct {
|
||||
Index uint32 `json:"index"`
|
||||
Message ChatMessage `json:"message"`
|
||||
FinishReason *string `json:"finish_reason,omitempty"`
|
||||
}
|
||||
|
||||
type Usage struct {
|
||||
PromptTokens uint32 `json:"prompt_tokens"`
|
||||
CompletionTokens uint32 `json:"completion_tokens"`
|
||||
TotalTokens uint32 `json:"total_tokens"`
|
||||
ReasoningTokens *uint32 `json:"reasoning_tokens,omitempty"`
|
||||
CacheReadTokens *uint32 `json:"cache_read_tokens,omitempty"`
|
||||
CacheWriteTokens *uint32 `json:"cache_write_tokens,omitempty"`
|
||||
}
|
||||
|
||||
// Streaming Response Structs
|
||||
|
||||
type ChatCompletionStreamResponse struct {
|
||||
ID string `json:"id"`
|
||||
Object string `json:"object"`
|
||||
Created int64 `json:"created"`
|
||||
Model string `json:"model"`
|
||||
Choices []ChatStreamChoice `json:"choices"`
|
||||
Usage *Usage `json:"usage,omitempty"`
|
||||
}
|
||||
|
||||
type ChatStreamChoice struct {
|
||||
Index uint32 `json:"index"`
|
||||
Delta ChatStreamDelta `json:"delta"`
|
||||
FinishReason *string `json:"finish_reason,omitempty"`
|
||||
}
|
||||
|
||||
type ChatStreamDelta struct {
|
||||
Role *string `json:"role,omitempty"`
|
||||
Content *string `json:"content,omitempty"`
|
||||
ReasoningContent *string `json:"reasoning_content,omitempty"`
|
||||
ToolCalls []ToolCallDelta `json:"tool_calls,omitempty"`
|
||||
}
|
||||
|
||||
type StreamUsage struct {
|
||||
PromptTokens uint32 `json:"prompt_tokens"`
|
||||
CompletionTokens uint32 `json:"completion_tokens"`
|
||||
TotalTokens uint32 `json:"total_tokens"`
|
||||
ReasoningTokens uint32 `json:"reasoning_tokens"`
|
||||
CacheReadTokens uint32 `json:"cache_read_tokens"`
|
||||
CacheWriteTokens uint32 `json:"cache_write_tokens"`
|
||||
}
|
||||
|
||||
// Unified Request Format (for internal use)
|
||||
|
||||
type UnifiedRequest struct {
|
||||
ClientID string
|
||||
Model string
|
||||
Messages []UnifiedMessage
|
||||
Temperature *float64
|
||||
TopP *float64
|
||||
TopK *uint32
|
||||
N *uint32
|
||||
Stop []string
|
||||
MaxTokens *uint32
|
||||
PresencePenalty *float64
|
||||
FrequencyPenalty *float64
|
||||
Stream bool
|
||||
HasImages bool
|
||||
Tools []Tool
|
||||
ToolChoice json.RawMessage
|
||||
}
|
||||
|
||||
type UnifiedMessage struct {
|
||||
Role string
|
||||
Content []UnifiedContentPart
|
||||
ReasoningContent *string
|
||||
ToolCalls []ToolCall
|
||||
Name *string
|
||||
ToolCallID *string
|
||||
}
|
||||
|
||||
type UnifiedContentPart struct {
|
||||
Type string
|
||||
Text string
|
||||
Image *ImageInput
|
||||
}
|
||||
|
||||
type ImageInput struct {
|
||||
Base64 string `json:"base64,omitempty"`
|
||||
URL string `json:"url,omitempty"`
|
||||
MimeType string `json:"mime_type,omitempty"`
|
||||
}
|
||||
|
||||
func (i *ImageInput) ToBase64() (string, string, error) {
|
||||
if i.Base64 != "" {
|
||||
return i.Base64, i.MimeType, nil
|
||||
}
|
||||
|
||||
if i.URL != "" {
|
||||
client := resty.New()
|
||||
resp, err := client.R().Get(i.URL)
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("failed to fetch image: %w", err)
|
||||
}
|
||||
|
||||
if !resp.IsSuccess() {
|
||||
return "", "", fmt.Errorf("failed to fetch image: HTTP %d", resp.StatusCode())
|
||||
}
|
||||
|
||||
mimeType := resp.Header().Get("Content-Type")
|
||||
if mimeType == "" {
|
||||
mimeType = "image/jpeg"
|
||||
}
|
||||
|
||||
encoded := base64.StdEncoding.EncodeToString(resp.Body())
|
||||
return encoded, mimeType, nil
|
||||
}
|
||||
|
||||
return "", "", fmt.Errorf("empty image input")
|
||||
}
|
||||
|
||||
// AuthInfo for context
|
||||
type AuthInfo struct {
|
||||
Token string
|
||||
ClientID string
|
||||
}
|
||||
Reference in New Issue
Block a user