mirror of
https://github.com/CJackHwang/ds2api.git
synced 2026-05-02 07:25:26 +08:00
92 lines
2.7 KiB
Go
92 lines
2.7 KiB
Go
package history
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"ds2api/internal/auth"
|
|
dsclient "ds2api/internal/deepseek/client"
|
|
"ds2api/internal/httpapi/openai/shared"
|
|
"ds2api/internal/promptcompat"
|
|
)
|
|
|
|
const (
|
|
currentInputFilename = promptcompat.CurrentInputContextFilename
|
|
currentInputContentType = "text/plain; charset=utf-8"
|
|
currentInputPurpose = "assistants"
|
|
)
|
|
|
|
func (s Service) ApplyCurrentInputFile(ctx context.Context, a *auth.RequestAuth, stdReq promptcompat.StandardRequest) (promptcompat.StandardRequest, error) {
|
|
if s.DS == nil || s.Store == nil || a == nil || !s.Store.CurrentInputFileEnabled() {
|
|
return stdReq, nil
|
|
}
|
|
threshold := s.Store.CurrentInputFileMinChars()
|
|
|
|
index, text := latestUserInputForFile(stdReq.Messages)
|
|
if index < 0 {
|
|
return stdReq, nil
|
|
}
|
|
if len([]rune(text)) < threshold {
|
|
return stdReq, nil
|
|
}
|
|
fileText := promptcompat.BuildOpenAICurrentInputContextTranscript(stdReq.Messages)
|
|
if strings.TrimSpace(fileText) == "" {
|
|
return stdReq, errors.New("current user input file produced empty transcript")
|
|
}
|
|
result, err := s.DS.UploadFile(ctx, a, dsclient.UploadFileRequest{
|
|
Filename: currentInputFilename,
|
|
ContentType: currentInputContentType,
|
|
Purpose: currentInputPurpose,
|
|
Data: []byte(fileText),
|
|
}, 3)
|
|
if err != nil {
|
|
return stdReq, fmt.Errorf("upload current user input file: %w", err)
|
|
}
|
|
fileID := strings.TrimSpace(result.ID)
|
|
if fileID == "" {
|
|
return stdReq, errors.New("upload current user input file returned empty file id")
|
|
}
|
|
|
|
messages := []any{
|
|
map[string]any{
|
|
"role": "user",
|
|
"content": currentInputFilePrompt(),
|
|
},
|
|
}
|
|
|
|
stdReq.Messages = messages
|
|
stdReq.HistoryText = fileText
|
|
stdReq.CurrentInputFileApplied = true
|
|
stdReq.RefFileIDs = prependUniqueRefFileID(stdReq.RefFileIDs, fileID)
|
|
stdReq.FinalPrompt, stdReq.ToolNames = promptcompat.BuildOpenAIPrompt(messages, stdReq.ToolsRaw, "", stdReq.ToolChoice, stdReq.Thinking)
|
|
// Token accounting must reflect the actual downstream context:
|
|
// the uploaded history.txt file content + the neutral live prompt.
|
|
stdReq.PromptTokenText = fileText + "\n" + stdReq.FinalPrompt
|
|
return stdReq, nil
|
|
}
|
|
|
|
func latestUserInputForFile(messages []any) (int, string) {
|
|
for i := len(messages) - 1; i >= 0; i-- {
|
|
msg, ok := messages[i].(map[string]any)
|
|
if !ok {
|
|
continue
|
|
}
|
|
role := strings.ToLower(strings.TrimSpace(shared.AsString(msg["role"])))
|
|
if role != "user" {
|
|
continue
|
|
}
|
|
text := promptcompat.NormalizeOpenAIContentForPrompt(msg["content"])
|
|
if strings.TrimSpace(text) == "" {
|
|
return -1, ""
|
|
}
|
|
return i, text
|
|
}
|
|
return -1, ""
|
|
}
|
|
|
|
func currentInputFilePrompt() string {
|
|
return "The current request and prior conversation context have already been provided. Answer the latest user request directly."
|
|
}
|