- Go API server with PostgreSQL + Redis - AI floor replacement (OpenRouter Gemini) - Product database (10 brands, 3539 products) - Recommendation engine, calculator, articles - Redis async queue + worker pool - Hot product caching, brand view tracking - JWT auth, favorites, projects - Docker deployment ready Co-Authored-By: Claude <noreply@anthropic.com>
94 lines
2.4 KiB
Go
94 lines
2.4 KiB
Go
package openrouter
|
|
|
|
import "context"
|
|
|
|
type ChatRequest struct {
|
|
Model string `json:"model"`
|
|
Messages []Message `json:"messages"`
|
|
Modalities []string `json:"modalities,omitempty"`
|
|
ImageConfig *ImageConfig `json:"image_config,omitempty"`
|
|
Provider *Provider `json:"provider,omitempty"`
|
|
TopP *float64 `json:"top_p,omitempty"`
|
|
Stream bool `json:"stream,omitempty"`
|
|
}
|
|
|
|
type ImageConfig struct {
|
|
AspectRatio string `json:"aspect_ratio,omitempty"`
|
|
ImageSize string `json:"image_size,omitempty"`
|
|
}
|
|
|
|
type Provider struct {
|
|
Order []string `json:"order,omitempty"`
|
|
Only []string `json:"only,omitempty"`
|
|
AllowFallbacks *bool `json:"allow_fallbacks,omitempty"`
|
|
RequireParameters *bool `json:"require_parameters,omitempty"`
|
|
}
|
|
|
|
type Message struct {
|
|
Role string `json:"role"`
|
|
Content []ContentPart `json:"content"`
|
|
}
|
|
|
|
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"`
|
|
}
|
|
|
|
type ChatResponse struct {
|
|
Choices []Choice `json:"choices"`
|
|
}
|
|
|
|
type Choice struct {
|
|
Message AssistantMessage `json:"message"`
|
|
}
|
|
|
|
type AssistantMessage struct {
|
|
Content string `json:"content"`
|
|
Images []ResponseImage `json:"images,omitempty"`
|
|
}
|
|
|
|
type ResponseImage struct {
|
|
Type string `json:"type"`
|
|
ImageURL ImageURL `json:"image_url"`
|
|
}
|
|
|
|
// Chat sends a chat completion request to the OpenRouter API.
|
|
func (c *Client) Chat(ctx context.Context, req ChatRequest) (*ChatResponse, error) {
|
|
return c.chatCompletion(ctx, req)
|
|
}
|
|
|
|
func (c *Client) chatCompletion(ctx context.Context, req ChatRequest) (*ChatResponse, error) {
|
|
var resp chatResponseRaw
|
|
if err := c.do(ctx, "/chat/completions", req, &resp); err != nil {
|
|
return nil, err
|
|
}
|
|
if resp.Error != nil {
|
|
return nil, &APIError{Message: resp.Error.Message, Code: resp.Error.Code}
|
|
}
|
|
return &ChatResponse{Choices: resp.Choices}, nil
|
|
}
|
|
|
|
// APIError API 返回的业务错误
|
|
type APIError struct {
|
|
Message string
|
|
Code any
|
|
}
|
|
|
|
func (e *APIError) Error() string {
|
|
return "openrouter: api error: " + e.Message
|
|
}
|
|
|
|
// chatResponseRaw 包含 error 字段,仅用于内部解析
|
|
type chatResponseRaw struct {
|
|
Choices []Choice `json:"choices"`
|
|
Error *struct {
|
|
Message string `json:"message"`
|
|
Code any `json:"code"`
|
|
} `json:"error"`
|
|
}
|