golangAPI调用deepseek

发布于:2025-02-15 ⋅ 阅读:(37) ⋅ 点赞:(0)

1.deepseek官方API调用文档

1.访问格式

在这里插入图片描述
现在我们来解析这个curl

2.curl组装

// 这是请求头要加的参数
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <DeepSeek API Key>" \

// 这是请求体要加的参数
-d '{
        "model": "deepseek-chat",
        "messages": [
          {"role": "system", "content": "You are a helpful assistant."},
          {"role": "user", "content": "Hello!"}
        ],
        "stream": false
      }'

这个里面可以看出,user角色使我们要输入的问题,stream选择是否为流式响应

2.go代码

1. config 配置

type Config struct {
	BaseURL    string
	APIKey     string
	HTTPClient *http.Client
}

2.模型相关

type Model interface {
	Chat(ctx context.Context, req Request) (*Response, error)
	Stream(ctx context.Context, req Request) (<-chan Response, error)
}

type Request struct {
	Model    string    `json:"model"`
	Messages []Message `json:"messages"`
	Stream   bool      `json:"stream"`
}

type Message struct {
	Role    string `json:"role"`
	Content string `json:"content"`
}

type Response struct {
	Content string `json:"content"`
}

3.错误处理

// Error 标准错误类型
type Error struct {
	Code    int
	Message string
	Model   string
}

func (e *Error) Error() string {
	return fmt.Sprintf("[%s] %d: %s", e.Model, e.Code, e.Message)
}

4.deepseekAPI接口实现

type DeepSeek struct {
	Cfg ai.Config
}

func NewDeepSeek(cfg ai.Config) *DeepSeek {
	return &DeepSeek{Cfg: cfg}
}

func (d *DeepSeek) Stream(ctx context.Context, request ai.Request) (<-chan ai.Response, error) {
	return d.handleStreaming(ctx, request)
}

func (d *DeepSeek) Chat(ctx context.Context, request ai.Request) (*ai.Response, error) {
	doRequest, err := d.doRequest(ctx, request, false)
	if err != nil {
		return nil, err
	}
	return d.parseResponse(doRequest)
}

func (d *DeepSeek) parseResponse(resp *http.Response) (*ai.Response, error) {
	all, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("io.ReadAll failed, err: %v\n", err)
	}
	defer resp.Body.Close()
	return &ai.Response{Content: string(all)}, nil
}

// 私有方法
func (d *DeepSeek) doRequest(ctx context.Context, req ai.Request, stream bool) (*http.Response, error) {
	req.Stream = stream
	body, _ := json.Marshal(req)

	httpReq, err := http.NewRequestWithContext(
		ctx,
		"POST",
		d.Cfg.BaseURL+"/chat/completions",
		bytes.NewReader(body),
	)
	// 设置请求头
	httpReq.Header.Set("Content-Type", "application/json")
	httpReq.Header.Set("Authorization", "Bearer "+apiKey)
	resp, err := d.Cfg.HTTPClient.Do(httpReq)
	if err != nil {
		return nil, &ai.Error{
			Model:   "deepseek",
			Code:    http.StatusInternalServerError,
			Message: fmt.Sprintf("HTTP error: %v", err),
		}
	}

	if resp.StatusCode != http.StatusOK {
		return nil, &ai.Error{
			Model:   "deepseek",
			Code:    http.StatusInternalServerError,
			Message: fmt.Sprintf("failed to request: %v", err),
		}
	}
	return resp, nil
}

func (d *DeepSeek) handleStreaming(ctx context.Context, req ai.Request) (<-chan ai.Response, error) {
	ch := make(chan ai.Response)
	go func() {
		defer close(ch)
		// 发起流式请求
		resp, err := d.doRequest(ctx, req, true)
		if err != nil {
			ch <- ai.Response{Content: "request error!"}
			return
		}
		defer resp.Body.Close()

		scanner := bufio.NewScanner(resp.Body)
		for scanner.Scan() {
			select {
			case <-ctx.Done():
				ch <- ai.Response{Content: "ctx done!"}
				return
			default:
				// 解析事件流
				event := parseEvent(scanner.Bytes())
				if event != nil {
					ch <- *event
				}
			}
		}
	}()

	return ch, nil
}

func parseEvent(line []byte) *ai.Response {
	// 处理事件流格式
	if !bytes.HasPrefix(line, []byte("data: ")) {
		return nil
	}

	payload := bytes.TrimPrefix(line, []byte("data: "))
	if string(payload) == "[DONE]" {
		return nil
	}

	// 解析响应结构
	var chunk struct {
		Choices []struct {
			Delta struct {
				Content string `json:"content"`
			}
			FinishReason string `json:"finish_reason"`
		}
	}

	if err := json.Unmarshal(payload, &chunk); err != nil {
		return nil
	}

	if len(chunk.Choices) > 0 {
		content := chunk.Choices[0].Delta.Content
		finishReason := chunk.Choices[0].FinishReason

		if content != "" {
			return &ai.Response{Content: content}
		}

		if finishReason == "stop" {
			return nil
		}
	}
	return nil
}

5. 调用使用

func main() {
	cfg := ai.Config{
		BaseURL:    "https://api.deepseek.com/",
		APIKey:     "key",
		HTTPClient: &http.Client{},
	}

	// 初始化deepseek
	d := deepseek.NewDeepSeek(cfg)

	// 封装请求体
	body := ai.Request{
		Model:    "deepseek-chat",
		Messages: []ai.Message{{Role: "system", Content: "You are a helpful assistant."}, {Role: "user", Content: "你是谁"}},
	}

	// 同步调用
	chat, err := d.Chat(context.Background(), body)
	if err != nil {
		panic(err)
	}
	fmt.Println(chat.Content)

	// 流式调用
	stream, _ := d.Stream(context.Background(), body)
	for chunk := range stream {
		fmt.Printf(chunk.Content)
	}
}

3.响应实例

// 同步
{"id":"","object":"chat.completion","created":,"model":"deepseek-chat","choices":[{"index":0,"message":{"role":"assistant","content":"您好!我是由中国的深度求索(DeepSeek)公司开发的何任何问题,我会尽我所能为您提供帮助。"},"logprobs":null,"finish_reason":"stop"}],"usage":{"prompt_tokens":10,"completion_tokens":37,"total_tokens":47,"prompt_tokens_details":{"cached_tokens":0},"prompt_cache_hit_tokens":0,"proms":10},"system_fingerprint":"fp_3a5770e1b4"}


// 流式
您好!我是由中国的深度求索(DeepSeek)公司开发的智能助手DeepSeek-V3。如您有任何任何问题,我会尽我所能为您提供帮助。

代码地址:https://gitee.com/li-zhuoxuan/go_ai