Implement remaining code review suggestions
- Add graceful shutdown with SIGTERM/SIGINT handling\n- Make model list configurable via config.yaml\n- Remove sensitive data from debug logs (log sizes instead of full bodies)\n- Handle array format in system messages (both string and []interface{})\n- Update config.yaml with new models structure
This commit is contained in:
parent
f65ad6b189
commit
cea246da83
5 changed files with 60 additions and 12 deletions
|
|
@ -1,2 +1,8 @@
|
||||||
port: 8080
|
port: 8080
|
||||||
upstream_url: "https://api.z.ai/api/anthropic"
|
upstream_url: "https://api.z.ai/api/anthropic"
|
||||||
|
|
||||||
|
models:
|
||||||
|
- id: "glm-4.7"
|
||||||
|
owned_by: "zhipu"
|
||||||
|
- id: "glm-4.6"
|
||||||
|
owned_by: "zhipu"
|
||||||
|
|
|
||||||
12
converter.go
12
converter.go
|
|
@ -53,8 +53,18 @@ func extractSystemMessage(messages []Message) (string, []Message) {
|
||||||
|
|
||||||
for _, msg := range messages {
|
for _, msg := range messages {
|
||||||
if msg.Role == "system" {
|
if msg.Role == "system" {
|
||||||
if content, ok := msg.Content.(string); ok {
|
switch content := msg.Content.(type) {
|
||||||
|
case string:
|
||||||
systemParts = append(systemParts, content)
|
systemParts = append(systemParts, content)
|
||||||
|
case []interface{}:
|
||||||
|
// Extract text from content array
|
||||||
|
for _, part := range content {
|
||||||
|
if partMap, ok := part.(map[string]interface{}); ok {
|
||||||
|
if text, ok := partMap["text"].(string); ok {
|
||||||
|
systemParts = append(systemParts, text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
rest = append(rest, msg)
|
rest = append(rest, msg)
|
||||||
|
|
|
||||||
27
handler.go
27
handler.go
|
|
@ -11,10 +11,16 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type ModelConfig struct {
|
||||||
|
ID string `yaml:"id"`
|
||||||
|
OwnedBy string `yaml:"owned_by"`
|
||||||
|
}
|
||||||
|
|
||||||
// Config holds the application configuration
|
// Config holds the application configuration
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Port int `yaml:"port"`
|
Port int `yaml:"port"`
|
||||||
UpstreamURL string `yaml:"upstream_url"`
|
UpstreamURL string `yaml:"upstream_url"`
|
||||||
|
Models []ModelConfig `yaml:"models"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var config *Config
|
var config *Config
|
||||||
|
|
@ -56,9 +62,14 @@ func handleModels(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
models := []map[string]interface{}{
|
models := make([]map[string]interface{}, len(config.Models))
|
||||||
{"id": "glm-4.7", "object": "model", "created": 1234567890, "owned_by": "zhipu"},
|
for i, model := range config.Models {
|
||||||
{"id": "glm-4.6", "object": "model", "created": 1234567890, "owned_by": "zhipu"},
|
models[i] = map[string]interface{}{
|
||||||
|
"id": model.ID,
|
||||||
|
"object": "model",
|
||||||
|
"created": 1234567890,
|
||||||
|
"owned_by": model.OwnedBy,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
response := map[string]interface{}{
|
response := map[string]interface{}{
|
||||||
|
|
@ -117,7 +128,7 @@ func handleChatCompletions(w http.ResponseWriter, r *http.Request) {
|
||||||
anthropicReq.Stream = false
|
anthropicReq.Stream = false
|
||||||
|
|
||||||
reqBody, _ := json.Marshal(anthropicReq)
|
reqBody, _ := json.Marshal(anthropicReq)
|
||||||
log.Printf("[debug] Sending to upstream %s, model=%s, body=%s", config.UpstreamURL, req.Model, string(reqBody))
|
log.Printf("[debug] Sending to upstream %s, model=%s, body_size=%d bytes", config.UpstreamURL, req.Model, len(reqBody))
|
||||||
|
|
||||||
// Non-streaming request to upstream
|
// Non-streaming request to upstream
|
||||||
upstreamResp, err := callUpstream(anthropicReq, apiKey, sessionID)
|
upstreamResp, err := callUpstream(anthropicReq, apiKey, sessionID)
|
||||||
|
|
@ -129,7 +140,7 @@ func handleChatCompletions(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
if upstreamResp.StatusCode != http.StatusOK {
|
if upstreamResp.StatusCode != http.StatusOK {
|
||||||
respBody, _ := io.ReadAll(upstreamResp.Body)
|
respBody, _ := io.ReadAll(upstreamResp.Body)
|
||||||
log.Printf("[debug] Upstream error status %d: %s", upstreamResp.StatusCode, string(respBody))
|
log.Printf("[debug] Upstream error status %d, body_size=%d bytes", upstreamResp.StatusCode, len(respBody))
|
||||||
writeError(w, http.StatusBadGateway, fmt.Sprintf("Upstream returned error: %s", string(respBody)), "upstream_error", fmt.Sprintf("status_%d", upstreamResp.StatusCode))
|
writeError(w, http.StatusBadGateway, fmt.Sprintf("Upstream returned error: %s", string(respBody)), "upstream_error", fmt.Sprintf("status_%d", upstreamResp.StatusCode))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -140,7 +151,7 @@ func handleChatCompletions(w http.ResponseWriter, r *http.Request) {
|
||||||
writeError(w, http.StatusBadGateway, "Failed to read upstream response", "upstream_error", "body_read_error")
|
writeError(w, http.StatusBadGateway, "Failed to read upstream response", "upstream_error", "body_read_error")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Printf("[debug] Upstream response: %s", string(respBody))
|
log.Printf("[debug] Upstream response received, body_size=%d bytes", len(respBody))
|
||||||
|
|
||||||
var anthropicResp AnthropicResponse
|
var anthropicResp AnthropicResponse
|
||||||
if err := json.Unmarshal(respBody, &anthropicResp); err != nil {
|
if err := json.Unmarshal(respBody, &anthropicResp); err != nil {
|
||||||
|
|
|
||||||
27
main.go
27
main.go
|
|
@ -6,6 +6,9 @@ import (
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
|
|
@ -38,10 +41,28 @@ func main() {
|
||||||
})
|
})
|
||||||
|
|
||||||
addr := fmt.Sprintf(":%d", config.Port)
|
addr := fmt.Sprintf(":%d", config.Port)
|
||||||
log.Printf("Starting proxx on %s, upstream: %s", addr, config.UpstreamURL)
|
|
||||||
if err := http.ListenAndServe(addr, nil); err != nil {
|
server := &http.Server{Addr: addr}
|
||||||
log.Fatalf("Server failed: %v", err)
|
|
||||||
|
go func() {
|
||||||
|
log.Printf("Starting proxx on %s, upstream: %s", addr, config.UpstreamURL)
|
||||||
|
if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
||||||
|
log.Fatalf("Server failed: %v", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Wait for interrupt signal
|
||||||
|
sigChan := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
|
||||||
|
<-sigChan
|
||||||
|
|
||||||
|
log.Println("Shutting down server...")
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
if err := server.Shutdown(ctx); err != nil {
|
||||||
|
log.Printf("Server shutdown error: %v", err)
|
||||||
}
|
}
|
||||||
|
log.Println("Server stopped")
|
||||||
}
|
}
|
||||||
|
|
||||||
// contextKey is a custom type for context keys
|
// contextKey is a custom type for context keys
|
||||||
|
|
|
||||||
BIN
proxx
BIN
proxx
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue