initial commit
This commit is contained in:
+198
@@ -0,0 +1,198 @@
|
||||
package deepseek
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ChatSession describes a DeepSeek chat session.
|
||||
type ChatSession struct {
|
||||
ID string `json:"id"`
|
||||
SeqID uint64 `json:"seq_id"`
|
||||
Agent string `json:"agent"`
|
||||
ModelType string `json:"model_type"`
|
||||
InsertedAt float64 `json:"inserted_at"`
|
||||
UpdatedAt float64 `json:"updated_at"`
|
||||
}
|
||||
|
||||
// CreateChatRes is the data returned when a chat session is created.
|
||||
type CreateChatRes struct {
|
||||
ChatSession ChatSession `json:"chat_session"`
|
||||
TTLSeconds uint64 `json:"ttl_seconds"`
|
||||
}
|
||||
|
||||
// CreateChat creates a chat session using a background context.
|
||||
func (api *Client) CreateChat() (ChatSession, error) {
|
||||
return api.CreateChatWithContext(context.Background())
|
||||
}
|
||||
|
||||
// CreateChatWithContext creates a chat session and honors ctx cancellation.
|
||||
func (api *Client) CreateChatWithContext(ctx context.Context) (ChatSession, error) {
|
||||
var zero ChatSession
|
||||
req := NewRequest[CreateChatRes]("POST", "chat_session/create", NoParams)
|
||||
resp, err := req.DoWithContext(ctx, api)
|
||||
if err != nil {
|
||||
return zero, err
|
||||
}
|
||||
defer func() {
|
||||
_ = resp.Body.Close()
|
||||
}()
|
||||
data, err := req.unmarshallBizResponse(resp)
|
||||
if err != nil {
|
||||
return zero, err
|
||||
}
|
||||
return data.Data.Data.ChatSession, nil
|
||||
}
|
||||
|
||||
// CompletionReq configures a chat completion request.
|
||||
type CompletionReq struct {
|
||||
ChatSessionID string `json:"chat_session_id"`
|
||||
ParentMessageID *uint64 `json:"parent_message_id"`
|
||||
ModelType ModelType `json:"model_type"`
|
||||
promptBuilder strings.Builder
|
||||
Prompt string `json:"prompt"`
|
||||
RefFileIDs []string `json:"ref_file_ids"`
|
||||
ThinkingEnabled bool `json:"thinking_enabled"`
|
||||
SearchEnabled bool `json:"search_enabled"`
|
||||
}
|
||||
|
||||
// NewCompletionReq creates a completion request for chatID using the default
|
||||
// model type.
|
||||
func NewCompletionReq(chatID string) *CompletionReq {
|
||||
return &CompletionReq{
|
||||
ChatSessionID: chatID, ModelType: ModelTypeDefault,
|
||||
}
|
||||
}
|
||||
|
||||
// SetParentMessageID sets the parent message for a continued conversation.
|
||||
func (req *CompletionReq) SetParentMessageID(id uint64) *CompletionReq {
|
||||
req.ParentMessageID = new(id)
|
||||
return req
|
||||
}
|
||||
|
||||
// SetModelType selects the model used for the completion.
|
||||
func (req *CompletionReq) SetModelType(t ModelType) *CompletionReq {
|
||||
req.ModelType = t
|
||||
return req
|
||||
}
|
||||
|
||||
// AddPrompt appends s to the prompt under construction.
|
||||
func (req *CompletionReq) AddPrompt(s string) *CompletionReq {
|
||||
_, _ = req.promptBuilder.WriteString(s)
|
||||
return req
|
||||
}
|
||||
|
||||
// BuildPrompt stores the accumulated prompt and resets the internal builder.
|
||||
func (req *CompletionReq) BuildPrompt() *CompletionReq {
|
||||
req.Prompt = req.promptBuilder.String()
|
||||
req.promptBuilder = strings.Builder{}
|
||||
return req
|
||||
}
|
||||
|
||||
// SetPrompt replaces the request prompt.
|
||||
func (req *CompletionReq) SetPrompt(prompt string) *CompletionReq {
|
||||
req.Prompt = prompt
|
||||
return req
|
||||
}
|
||||
|
||||
// SetThinkingEnabled enables or disables model thinking output.
|
||||
func (req *CompletionReq) SetThinkingEnabled(b bool) *CompletionReq {
|
||||
req.ThinkingEnabled = b
|
||||
return req
|
||||
}
|
||||
|
||||
// SetSearchEnabled enables or disables web search for the completion.
|
||||
func (req *CompletionReq) SetSearchEnabled(b bool) *CompletionReq {
|
||||
req.SearchEnabled = b
|
||||
return req
|
||||
}
|
||||
|
||||
// ModelType identifies a DeepSeek chat model mode.
|
||||
type ModelType string
|
||||
|
||||
const (
|
||||
// ModelTypeDefault selects the default model mode.
|
||||
ModelTypeDefault ModelType = "default"
|
||||
// ModelTypeExpert selects the expert model mode.
|
||||
ModelTypeExpert ModelType = "expert"
|
||||
)
|
||||
|
||||
// Completion starts a streaming completion using a background context.
|
||||
// The caller owns and must either close the response body or pass the response
|
||||
// to ReadStream or ReadStreamAsString.
|
||||
func (api *Client) Completion(body CompletionReq) (*http.Response, error) {
|
||||
return api.CompletionWithContext(context.Background(), body)
|
||||
}
|
||||
|
||||
// CompletionWithContext starts a streaming completion and honors ctx
|
||||
// cancellation. The caller owns and must either close the response body or
|
||||
// pass the response to ReadStream or ReadStreamAsString.
|
||||
func (api *Client) CompletionWithContext(ctx context.Context, body CompletionReq) (*http.Response, error) {
|
||||
req := NewRequest[CreatePowChallengeRes]("POST", "chat/completion", body)
|
||||
err := req.SolvePow(ctx, api)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp, err := req.DoWithContext(ctx, api)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// ReadStream consumes and closes resp.Body, updates stream state, and calls
|
||||
// onText for newly appended response text. A nil callback is allowed.
|
||||
func (api *Client) ReadStream(ctx context.Context, resp *http.Response, onText func(string)) (*StreamState, error) {
|
||||
defer resp.Body.Close()
|
||||
|
||||
reader := NewSSEReader(resp.Body)
|
||||
state := &StreamState{}
|
||||
|
||||
var previousLength int
|
||||
|
||||
for {
|
||||
event, err := reader.Next(ctx)
|
||||
if errors.Is(err, io.EOF) {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := state.Apply(event); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
current := state.Content.String()
|
||||
|
||||
if len(current) > previousLength {
|
||||
chunk := current[previousLength:]
|
||||
|
||||
if onText != nil {
|
||||
onText(chunk)
|
||||
}
|
||||
|
||||
previousLength = len(current)
|
||||
}
|
||||
|
||||
if event.Event == "close" {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return state, nil
|
||||
}
|
||||
|
||||
// ReadStreamAsString consumes and closes resp.Body and returns the final
|
||||
// response content.
|
||||
func (api *Client) ReadStreamAsString(ctx context.Context, resp *http.Response) (string, error) {
|
||||
state, err := api.ReadStream(ctx, resp, nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return state.Content.String(), nil
|
||||
}
|
||||
Reference in New Issue
Block a user