mirror of
https://github.com/router-for-me/CLIProxyAPI.git
synced 2026-02-03 04:50:52 +08:00
The Gemini Web API client logic has been relocated from `internal/client/gemini-web` to a new, more specific `internal/provider/gemini-web` package. This refactoring improves code organization and modularity by better isolating provider-specific implementations. As a result of this move, the `GeminiWebState` struct and its methods have been exported (capitalized) to make them accessible from the executor. All call sites have been updated to use the new package path and the exported identifiers.
132 lines
3.6 KiB
Go
132 lines
3.6 KiB
Go
package geminiwebapi
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
|
|
log "github.com/sirupsen/logrus"
|
|
)
|
|
|
|
// init honors GEMINI_WEBAPI_LOG to keep parity with the Python client.
|
|
func init() {
|
|
if lvl := os.Getenv("GEMINI_WEBAPI_LOG"); lvl != "" {
|
|
SetLogLevel(lvl)
|
|
}
|
|
}
|
|
|
|
// SetLogLevel adjusts logging verbosity using CLI-style strings.
|
|
func SetLogLevel(level string) {
|
|
switch strings.ToUpper(level) {
|
|
case "TRACE":
|
|
log.SetLevel(log.TraceLevel)
|
|
case "DEBUG":
|
|
log.SetLevel(log.DebugLevel)
|
|
case "INFO":
|
|
log.SetLevel(log.InfoLevel)
|
|
case "WARNING", "WARN":
|
|
log.SetLevel(log.WarnLevel)
|
|
case "ERROR":
|
|
log.SetLevel(log.ErrorLevel)
|
|
case "CRITICAL", "FATAL":
|
|
log.SetLevel(log.FatalLevel)
|
|
default:
|
|
log.SetLevel(log.InfoLevel)
|
|
}
|
|
}
|
|
|
|
func prefix(format string) string { return "[gemini_webapi] " + format }
|
|
|
|
func Debug(format string, v ...any) { log.Debugf(prefix(format), v...) }
|
|
|
|
// DebugRaw logs without the module prefix; use sparingly for messages
|
|
// that should integrate with global formatting without extra tags.
|
|
func DebugRaw(format string, v ...any) { log.Debugf(format, v...) }
|
|
func Info(format string, v ...any) { log.Infof(prefix(format), v...) }
|
|
func Warning(format string, v ...any) { log.Warnf(prefix(format), v...) }
|
|
func Error(format string, v ...any) { log.Errorf(prefix(format), v...) }
|
|
func Success(format string, v ...any) { log.Infof(prefix("SUCCESS "+format), v...) }
|
|
|
|
// MaskToken28 returns a fixed-length (28) masked representation showing:
|
|
// first 8 chars + 8 asterisks + 4 middle chars + last 8 chars.
|
|
// If the input is shorter than 20 characters, it returns a fully masked string
|
|
// of length min(len(s), 28).
|
|
func MaskToken28(s string) string {
|
|
n := len(s)
|
|
if n == 0 {
|
|
return ""
|
|
}
|
|
if n < 20 {
|
|
return strings.Repeat("*", n)
|
|
}
|
|
// Pick 4 middle characters around the center
|
|
midStart := n/2 - 2
|
|
if midStart < 8 {
|
|
midStart = 8
|
|
}
|
|
if midStart+4 > n-8 {
|
|
midStart = n - 8 - 4
|
|
if midStart < 8 {
|
|
midStart = 8
|
|
}
|
|
}
|
|
prefixByte := s[:8]
|
|
middle := s[midStart : midStart+4]
|
|
suffix := s[n-8:]
|
|
return prefixByte + strings.Repeat("*", 4) + middle + strings.Repeat("*", 4) + suffix
|
|
}
|
|
|
|
// BuildUpstreamRequestLog builds a compact preview string for upstream request logging.
|
|
func BuildUpstreamRequestLog(account string, contextOn bool, useTags, explicitContext bool, prompt string, filesCount int, reuse bool, metaLen int, gem *Gem) string {
|
|
var sb strings.Builder
|
|
sb.WriteString("\n\n=== GEMINI WEB UPSTREAM ===\n")
|
|
sb.WriteString(fmt.Sprintf("account: %s\n", account))
|
|
if contextOn {
|
|
sb.WriteString("context_mode: on\n")
|
|
} else {
|
|
sb.WriteString("context_mode: off\n")
|
|
}
|
|
if reuse {
|
|
sb.WriteString("reuseIdx: 1\n")
|
|
} else {
|
|
sb.WriteString("reuseIdx: 0\n")
|
|
}
|
|
sb.WriteString(fmt.Sprintf("useTags: %t\n", useTags))
|
|
sb.WriteString(fmt.Sprintf("metadata_len: %d\n", metaLen))
|
|
if explicitContext {
|
|
sb.WriteString("explicit_context: true\n")
|
|
} else {
|
|
sb.WriteString("explicit_context: false\n")
|
|
}
|
|
if filesCount > 0 {
|
|
sb.WriteString(fmt.Sprintf("files: %d\n", filesCount))
|
|
}
|
|
|
|
if gem != nil {
|
|
sb.WriteString("gem:\n")
|
|
if gem.ID != "" {
|
|
sb.WriteString(fmt.Sprintf(" id: %s\n", gem.ID))
|
|
}
|
|
if gem.Name != "" {
|
|
sb.WriteString(fmt.Sprintf(" name: %s\n", gem.Name))
|
|
}
|
|
sb.WriteString(fmt.Sprintf(" predefined: %t\n", gem.Predefined))
|
|
} else {
|
|
sb.WriteString("gem: none\n")
|
|
}
|
|
|
|
chunks := ChunkByRunes(prompt, 4096)
|
|
preview := prompt
|
|
truncated := false
|
|
if len(chunks) > 1 {
|
|
preview = chunks[0]
|
|
truncated = true
|
|
}
|
|
sb.WriteString("prompt_preview:\n")
|
|
sb.WriteString(preview)
|
|
if truncated {
|
|
sb.WriteString("\n... [truncated]\n")
|
|
}
|
|
return sb.String()
|
|
}
|