Skip to content

support deepseek-r1: reasoning_content #938

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 55 additions & 32 deletions chat.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,9 @@
Refusal string `json:"refusal,omitempty"`
MultiContent []ChatMessagePart

// supported by deepseek-reasoner https://api-docs.deepseek.com/
ReasoningContent string `json:"reasoning_content,omitempty"`

// This property isn't in the official documentation, but it's in
// the documentation for the official library for python:
// - https://github.com/openai/openai-python/blob/main/chatml.md
Expand All @@ -119,56 +122,60 @@
}
if len(m.MultiContent) > 0 {
msg := struct {
Role string `json:"role"`
Content string `json:"-"`
Refusal string `json:"refusal,omitempty"`
MultiContent []ChatMessagePart `json:"content,omitempty"`
Name string `json:"name,omitempty"`
FunctionCall *FunctionCall `json:"function_call,omitempty"`
ToolCalls []ToolCall `json:"tool_calls,omitempty"`
ToolCallID string `json:"tool_call_id,omitempty"`
Role string `json:"role"`
Content string `json:"-"`
Refusal string `json:"refusal,omitempty"`
MultiContent []ChatMessagePart `json:"content,omitempty"`
ReasoningContent string `json:"reasoning_content,omitempty"`
Name string `json:"name,omitempty"`
FunctionCall *FunctionCall `json:"function_call,omitempty"`
ToolCalls []ToolCall `json:"tool_calls,omitempty"`
ToolCallID string `json:"tool_call_id,omitempty"`
}(m)
return json.Marshal(msg)
}

msg := struct {
Role string `json:"role"`
Content string `json:"content,omitempty"`
Refusal string `json:"refusal,omitempty"`
MultiContent []ChatMessagePart `json:"-"`
Name string `json:"name,omitempty"`
FunctionCall *FunctionCall `json:"function_call,omitempty"`
ToolCalls []ToolCall `json:"tool_calls,omitempty"`
ToolCallID string `json:"tool_call_id,omitempty"`
Role string `json:"role"`
Content string `json:"content,omitempty"`
Refusal string `json:"refusal,omitempty"`
MultiContent []ChatMessagePart `json:"-"`
ReasoningContent string `json:"reasoning_content,omitempty"`
Name string `json:"name,omitempty"`
FunctionCall *FunctionCall `json:"function_call,omitempty"`
ToolCalls []ToolCall `json:"tool_calls,omitempty"`
ToolCallID string `json:"tool_call_id,omitempty"`
}(m)
return json.Marshal(msg)
}

func (m *ChatCompletionMessage) UnmarshalJSON(bs []byte) error {
msg := struct {
Role string `json:"role"`
Content string `json:"content,omitempty"`
Refusal string `json:"refusal,omitempty"`
MultiContent []ChatMessagePart
Name string `json:"name,omitempty"`
FunctionCall *FunctionCall `json:"function_call,omitempty"`
ToolCalls []ToolCall `json:"tool_calls,omitempty"`
ToolCallID string `json:"tool_call_id,omitempty"`
Role string `json:"role"`
Content string `json:"content,omitempty"`
Refusal string `json:"refusal,omitempty"`
MultiContent []ChatMessagePart
ReasoningContent string `json:"reasoning_content,omitempty"`
Name string `json:"name,omitempty"`
FunctionCall *FunctionCall `json:"function_call,omitempty"`
ToolCalls []ToolCall `json:"tool_calls,omitempty"`
ToolCallID string `json:"tool_call_id,omitempty"`
}{}

if err := json.Unmarshal(bs, &msg); err == nil {
*m = ChatCompletionMessage(msg)
return nil
}
multiMsg := struct {
Role string `json:"role"`
Content string
Refusal string `json:"refusal,omitempty"`
MultiContent []ChatMessagePart `json:"content"`
Name string `json:"name,omitempty"`
FunctionCall *FunctionCall `json:"function_call,omitempty"`
ToolCalls []ToolCall `json:"tool_calls,omitempty"`
ToolCallID string `json:"tool_call_id,omitempty"`
Role string `json:"role"`
Content string
Refusal string `json:"refusal,omitempty"`
MultiContent []ChatMessagePart `json:"content"`
ReasoningContent string `json:"reasoning_content,omitempty"`
Name string `json:"name,omitempty"`
FunctionCall *FunctionCall `json:"function_call,omitempty"`
ToolCalls []ToolCall `json:"tool_calls,omitempty"`
ToolCallID string `json:"tool_call_id,omitempty"`
}{}
if err := json.Unmarshal(bs, &multiMsg); err != nil {
return err
Expand Down Expand Up @@ -263,6 +270,22 @@
ReasoningEffort string `json:"reasoning_effort,omitempty"`
// Metadata to store with the completion.
Metadata map[string]string `json:"metadata,omitempty"`

// reasoning for deepseek
Reasoning bool `json:"reasoning,omitempty"`

// GD
GuidedChoice []string `json:"guided_choice,omitempty"`
GuidedRegex string `json:"guided_regex,omitempty"`
GuidedJson string `json:"guided_json,omitempty"`

Check failure on line 280 in chat.go

View workflow job for this annotation

GitHub Actions / Sanity check

var-naming: struct field GuidedJson should be GuidedJSON (revive)
GuidedGrammar string `json:"guided_grammar,omitempty"`

// LoraType
LoraType string `json:"lora_type,omitempty"`

// For Hugging Face models
TopK int `json:"top_k,omitempty"`
RepetitionPenalty float32 `json:"repetition_penalty,omitempty"`
}

type StreamOptions struct {
Expand Down
11 changes: 6 additions & 5 deletions chat_stream.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ import (
)

type ChatCompletionStreamChoiceDelta struct {
Content string `json:"content,omitempty"`
Role string `json:"role,omitempty"`
FunctionCall *FunctionCall `json:"function_call,omitempty"`
ToolCalls []ToolCall `json:"tool_calls,omitempty"`
Refusal string `json:"refusal,omitempty"`
Content string `json:"content,omitempty"`
Role string `json:"role,omitempty"`
FunctionCall *FunctionCall `json:"function_call,omitempty"`
ToolCalls []ToolCall `json:"tool_calls,omitempty"`
Refusal string `json:"refusal,omitempty"`
ReasoningContent string `json:"reasoning_content,omitempty"`
}

type ChatCompletionStreamChoiceLogprobs struct {
Expand Down
4 changes: 4 additions & 0 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,10 @@ func (c *Client) setCommonHeaders(req *http.Request) {
if c.config.OrgID != "" {
req.Header.Set("OpenAI-Organization", c.config.OrgID)
}

for k, v := range c.config.HTTPHeaderSets {
req.Header[k] = v
}
}

func isFailureStatusCode(resp *http.Response) bool {
Expand Down
2 changes: 2 additions & 0 deletions common.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ type Usage struct {
PromptTokens int `json:"prompt_tokens"`
CompletionTokens int `json:"completion_tokens"`
TotalTokens int `json:"total_tokens"`
PromptCacheHitTokens int `json:"prompt_cache_hit_tokens"`
PromptCacheMissTokens int `json:"prompt_cache_miss_tokens"`
PromptTokensDetails *PromptTokensDetails `json:"prompt_tokens_details"`
CompletionTokensDetails *CompletionTokensDetails `json:"completion_tokens_details"`
}
Expand Down
10 changes: 10 additions & 0 deletions completion.go
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,16 @@
Temperature float32 `json:"temperature,omitempty"`
TopP float32 `json:"top_p,omitempty"`
User string `json:"user,omitempty"`

// GD
GuidedChoice []string `json:"guided_choice,omitempty"`
GuidedRegex string `json:"guided_regex,omitempty"`
GuidedJson string `json:"guided_json,omitempty"`
GuidedGrammar string `json:"guided_grammar,omitempty"`

// For Hugging Face models
TopK int `json:"top_k,omitempty"`
RepetitionPenalty float32 `json:"repetition_penalty,omitempty"`
}

// CompletionChoice represents one of possible completions.
Expand All @@ -201,7 +211,7 @@
Text string `json:"text"`
Index int `json:"index"`
FinishReason string `json:"finish_reason"`
LogProbs LogprobResult `json:"logprobs"`

Check failure on line 214 in completion.go

View workflow job for this annotation

GitHub Actions / Sanity check

var-naming: struct field GuidedJson should be GuidedJSON (revive)
}

// LogprobResult represents logprob result of Choice.
Expand Down
4 changes: 2 additions & 2 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ type ClientConfig struct {
AssistantVersion string
AzureModelMapperFunc func(model string) string // replace model to azure deployment name func
HTTPClient HTTPDoer

EmptyMessagesLimit uint
HTTPHeaderSets http.Header
EmptyMessagesLimit uint
}

func DefaultConfig(authToken string) ClientConfig {
Expand Down
60 changes: 44 additions & 16 deletions examples/chatbot/main.go
Original file line number Diff line number Diff line change
@@ -1,19 +1,33 @@
package main

import (
"bufio"
"context"
"crypto/tls"
"fmt"
"os"
"net/http"

"github.com/sashabaranov/go-openai"
)

func main() {
client := openai.NewClient(os.Getenv("OPENAI_API_KEY"))
config := openai.DefaultConfig("sk-xxxx")
config.BaseURL = "https://10.20.152.76:30002/v1"
config.HTTPHeaderSets = http.Header{
"123": []string{"Bearer sk-xxxx"},
"abc": []string{"application/json"},
"efg": []string{"application/json"},
}
config.HTTPClient = &http.Client{
Transport: &http.Transport{
DisableKeepAlives: true,
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
},
}

client := openai.NewClientWithConfig(config)

req := openai.ChatCompletionRequest{
Model: openai.GPT3Dot5Turbo,
Model: "HengNao-v4",
Messages: []openai.ChatCompletionMessage{
{
Role: openai.ChatMessageRoleSystem,
Expand All @@ -24,19 +38,33 @@ func main() {
fmt.Println("Conversation")
fmt.Println("---------------------")
fmt.Print("> ")
s := bufio.NewScanner(os.Stdin)
for s.Scan() {
req.Messages = append(req.Messages, openai.ChatCompletionMessage{
Role: openai.ChatMessageRoleUser,
Content: s.Text(),
})
resp, err := client.CreateChatCompletion(context.Background(), req)
// s := bufio.NewScanner(os.Stdin)
// for s.Scan() {
req.Messages = append(req.Messages, openai.ChatCompletionMessage{
Role: openai.ChatMessageRoleUser,
Content: "你好",
})
resp, err := client.CreateChatCompletion(context.Background(), req)
if err != nil {
fmt.Printf("ChatCompletion error: %v\n", err)
// continue
}
fmt.Printf("%s\n\n", resp.Choices[0].Message.Content)
req.Messages = append(req.Messages, resp.Choices[0].Message)
fmt.Print("> ")
// }

stream, err := client.CreateChatCompletionStream(context.Background(), req)
if err != nil {
return
}

for {
evt, err := stream.Recv()
if err != nil {
fmt.Printf("ChatCompletion error: %v\n", err)
continue
return
}
fmt.Printf("%s\n\n", resp.Choices[0].Message.Content)
req.Messages = append(req.Messages, resp.Choices[0].Message)
fmt.Print("> ")

fmt.Printf("%s", evt.Choices[0].Delta.Content)
}
}
Loading