mirror of
https://github.com/router-for-me/CLIProxyAPI.git
synced 2026-02-03 21:10:51 +08:00
107 lines
2.4 KiB
Go
107 lines
2.4 KiB
Go
package geminiwebapi
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
"unicode/utf8"
|
|
|
|
"github.com/luispater/CLIProxyAPI/v5/internal/config"
|
|
)
|
|
|
|
const continuationHint = "\n(More messages to come, please reply with just 'ok.')"
|
|
|
|
func ChunkByRunes(s string, size int) []string {
|
|
if size <= 0 {
|
|
return []string{s}
|
|
}
|
|
chunks := make([]string, 0, (len(s)/size)+1)
|
|
var buf strings.Builder
|
|
count := 0
|
|
for _, r := range s {
|
|
buf.WriteRune(r)
|
|
count++
|
|
if count >= size {
|
|
chunks = append(chunks, buf.String())
|
|
buf.Reset()
|
|
count = 0
|
|
}
|
|
}
|
|
if buf.Len() > 0 {
|
|
chunks = append(chunks, buf.String())
|
|
}
|
|
if len(chunks) == 0 {
|
|
return []string{""}
|
|
}
|
|
return chunks
|
|
}
|
|
|
|
func MaxCharsPerRequest(cfg *config.Config) int {
|
|
// Read max characters per request from config with a conservative default.
|
|
if cfg != nil {
|
|
if v := cfg.GeminiWeb.MaxCharsPerRequest; v > 0 {
|
|
return v
|
|
}
|
|
}
|
|
return 1_000_000
|
|
}
|
|
|
|
func SendWithSplit(chat *ChatSession, text string, files []string, cfg *config.Config) (ModelOutput, error) {
|
|
// Validate chat session
|
|
if chat == nil {
|
|
return ModelOutput{}, fmt.Errorf("nil chat session")
|
|
}
|
|
|
|
// Resolve max characters per request
|
|
max := MaxCharsPerRequest(cfg)
|
|
if max <= 0 {
|
|
max = 1_000_000
|
|
}
|
|
|
|
// If within limit, send directly
|
|
if utf8.RuneCountInString(text) <= max {
|
|
return chat.SendMessage(text, files)
|
|
}
|
|
|
|
// Decide whether to use continuation hint (enabled by default)
|
|
useHint := true
|
|
if cfg != nil && cfg.GeminiWeb.DisableContinuationHint {
|
|
useHint = false
|
|
}
|
|
|
|
// Compute chunk size in runes. If the hint does not fit, disable it for this request.
|
|
hintLen := 0
|
|
if useHint {
|
|
hintLen = utf8.RuneCountInString(continuationHint)
|
|
}
|
|
chunkSize := max - hintLen
|
|
if chunkSize <= 0 {
|
|
// max is too small to accommodate the hint; fall back to no-hint splitting
|
|
useHint = false
|
|
chunkSize = max
|
|
}
|
|
if chunkSize <= 0 {
|
|
// As a last resort, split by single rune to avoid exceeding the limit
|
|
chunkSize = 1
|
|
}
|
|
|
|
// Split into rune-safe chunks
|
|
chunks := ChunkByRunes(text, chunkSize)
|
|
if len(chunks) == 0 {
|
|
chunks = []string{""}
|
|
}
|
|
|
|
// Send all but the last chunk without files, optionally appending hint
|
|
for i := 0; i < len(chunks)-1; i++ {
|
|
part := chunks[i]
|
|
if useHint {
|
|
part += continuationHint
|
|
}
|
|
if _, err := chat.SendMessage(part, nil); err != nil {
|
|
return ModelOutput{}, err
|
|
}
|
|
}
|
|
|
|
// Send final chunk with files and return the actual output
|
|
return chat.SendMessage(chunks[len(chunks)-1], files)
|
|
}
|