feat: implement core architecture (v0.0.2)
- Implement Config class with YAML loading and environment variable support - Implement Provider interface and factory pattern - Implement SiliconFlow provider as example - Implement Translator core class with prompt management - Create CLI entry point - Add configuration template and unit tests - Update changelog and discussion records Version: 0.0.2
This commit is contained in:
185
internal/provider/siliconflow.go
Normal file
185
internal/provider/siliconflow.go
Normal file
@@ -0,0 +1,185 @@
|
||||
package provider
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
// SiliconFlowProvider 硅基流动厂商实现
|
||||
type SiliconFlowProvider struct {
|
||||
config ProviderConfig
|
||||
client *http.Client
|
||||
}
|
||||
|
||||
// NewSiliconFlowProvider 创建硅基流动厂商实例
|
||||
func NewSiliconFlowProvider(config ProviderConfig) (Provider, error) {
|
||||
return &SiliconFlowProvider{
|
||||
config: config,
|
||||
client: &http.Client{
|
||||
Timeout: 30 * time.Second,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Name 返回厂商名称
|
||||
func (p *SiliconFlowProvider) Name() string {
|
||||
return "siliconflow"
|
||||
}
|
||||
|
||||
// Validate 验证配置
|
||||
func (p *SiliconFlowProvider) Validate() error {
|
||||
if p.config.APIKey == "" {
|
||||
return fmt.Errorf("siliconflow: API key 不能为空")
|
||||
}
|
||||
if p.config.APIHost == "" {
|
||||
p.config.APIHost = "https://api.siliconflow.cn/v1"
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Translate 调用硅基流动API
|
||||
func (p *SiliconFlowProvider) Translate(ctx context.Context, req *TranslateRequest) (*TranslateResponse, error) {
|
||||
// 构建请求体
|
||||
requestBody := map[string]interface{}{
|
||||
"model": p.config.Model,
|
||||
"messages": []map[string]string{
|
||||
{
|
||||
"role": "user",
|
||||
"content": req.Text,
|
||||
},
|
||||
},
|
||||
"stream": false,
|
||||
}
|
||||
|
||||
// 如果有Prompt,添加到系统消息
|
||||
if req.Prompt != "" {
|
||||
messages := requestBody["messages"].([]map[string]string)
|
||||
requestBody["messages"] = append([]map[string]string{
|
||||
{
|
||||
"role": "system",
|
||||
"content": req.Prompt,
|
||||
},
|
||||
}, messages...)
|
||||
}
|
||||
|
||||
// 序列化请求体
|
||||
jsonData, err := json.Marshal(requestBody)
|
||||
if err != nil {
|
||||
return nil, NewTranslateErrorWithDetails("SERIALIZATION_ERROR", "请求序列化失败", err.Error())
|
||||
}
|
||||
|
||||
// 创建HTTP请求
|
||||
url := fmt.Sprintf("%s/chat/completions", p.config.APIHost)
|
||||
httpReq, err := http.NewRequestWithContext(ctx, "POST", url, bytes.NewBuffer(jsonData))
|
||||
if err != nil {
|
||||
return nil, NewTranslateErrorWithDetails("REQUEST_ERROR", "创建请求失败", err.Error())
|
||||
}
|
||||
|
||||
// 设置请求头
|
||||
httpReq.Header.Set("Content-Type", "application/json")
|
||||
httpReq.Header.Set("Authorization", fmt.Sprintf("Bearer %s", p.config.APIKey))
|
||||
|
||||
// 发送请求
|
||||
resp, err := p.client.Do(httpReq)
|
||||
if err != nil {
|
||||
return nil, NewTranslateErrorWithDetails("NETWORK_ERROR", "请求失败", err.Error())
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// 读取响应
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, NewTranslateErrorWithDetails("RESPONSE_ERROR", "读取响应失败", err.Error())
|
||||
}
|
||||
|
||||
// 检查HTTP状态码
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, NewTranslateErrorWithDetails(
|
||||
"HTTP_ERROR",
|
||||
fmt.Sprintf("HTTP错误: %d", resp.StatusCode),
|
||||
string(body),
|
||||
)
|
||||
}
|
||||
|
||||
// 解析响应
|
||||
var apiResp SiliconFlowResponse
|
||||
if err := json.Unmarshal(body, &apiResp); err != nil {
|
||||
return nil, NewTranslateErrorWithDetails("PARSE_ERROR", "解析响应失败", err.Error())
|
||||
}
|
||||
|
||||
// 检查API错误
|
||||
if apiResp.Error != nil {
|
||||
return nil, NewTranslateErrorWithDetails(
|
||||
"API_ERROR",
|
||||
apiResp.Error.Message,
|
||||
apiResp.Error.Code,
|
||||
)
|
||||
}
|
||||
|
||||
// 构建响应
|
||||
if len(apiResp.Choices) == 0 {
|
||||
return nil, NewTranslateError("NO_RESPONSE", "API返回空响应")
|
||||
}
|
||||
|
||||
translatedText := apiResp.Choices[0].Message.Content
|
||||
|
||||
return &TranslateResponse{
|
||||
Text: translatedText,
|
||||
FromLang: req.FromLang,
|
||||
ToLang: req.ToLang,
|
||||
Model: apiResp.Model,
|
||||
Usage: &Usage{
|
||||
PromptTokens: apiResp.Usage.PromptTokens,
|
||||
CompletionTokens: apiResp.Usage.CompletionTokens,
|
||||
TotalTokens: apiResp.Usage.TotalTokens,
|
||||
},
|
||||
RawResponse: body,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// SiliconFlowResponse 硅基流动API响应
|
||||
type SiliconFlowResponse struct {
|
||||
ID string `json:"id"`
|
||||
Object string `json:"object"`
|
||||
Created int64 `json:"created"`
|
||||
Model string `json:"model"`
|
||||
Choices []SiliconFlowChoice `json:"choices"`
|
||||
Usage SiliconFlowUsage `json:"usage"`
|
||||
Error *SiliconFlowError `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// SiliconFlowChoice 选择项
|
||||
type SiliconFlowChoice struct {
|
||||
Index int `json:"index"`
|
||||
Message SiliconFlowMessage `json:"message"`
|
||||
FinishReason string `json:"finish_reason"`
|
||||
}
|
||||
|
||||
// SiliconFlowMessage 消息
|
||||
type SiliconFlowMessage struct {
|
||||
Role string `json:"role"`
|
||||
Content string `json:"content"`
|
||||
}
|
||||
|
||||
// SiliconFlowUsage 用量
|
||||
type SiliconFlowUsage struct {
|
||||
PromptTokens int `json:"prompt_tokens"`
|
||||
CompletionTokens int `json:"completion_tokens"`
|
||||
TotalTokens int `json:"total_tokens"`
|
||||
}
|
||||
|
||||
// SiliconFlowError 错误
|
||||
type SiliconFlowError struct {
|
||||
Code string `json:"code"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
// init 注册硅基流动厂商
|
||||
func init() {
|
||||
RegisterProvider("siliconflow", NewSiliconFlowProvider)
|
||||
}
|
||||
Reference in New Issue
Block a user