From 7e75a589e054867669255ddbabfc12e927d71cfa Mon Sep 17 00:00:00 2001 From: Luxferre Date: Fri, 31 Jul 2026 10:37:20 +0300 Subject: [PATCH] added -model --- README.md | 7 ++++--- hygate_test.go | 20 ++++++++++++++++---- main.go | 23 +++++++++++++++-------- 3 files changed, 35 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 2dab8a8..c64693a 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Hygate is a standalone, single-binary gateway that exposes Tencent's Hunyuan 3 ( - Reasoning content passthrough (`reasoning_content`) - Tool/function calling, including incremental streaming of tool-call arguments - Fibonacci backoff retry on upstream calls -- Configurable endpoint and User-Agent +- Configurable endpoint, model name, and User-Agent - No external dependencies (standard library only) ## Installation @@ -38,13 +38,14 @@ Alternatively, you can directly build from source by running `make`. This produc Run the gateway: ``` -hygate [-port 8080] [-endpoint https://tencent-hy3.hf.space] +hygate [-port 8080] [-endpoint https://tencent-hy3.hf.space] [-model hy3] ``` Available flags: - `-port` — TCP port to listen on (default `8080`) - `-endpoint` — root URL of the Hunyuan Gradio space (default `https://tencent-hy3.hf.space`) +- `-model` — exposed model name (default `hy3`) - `-user-agent` / `-ua` — custom User-Agent sent to the upstream Endpoints served: @@ -72,7 +73,7 @@ Even through the Gradio API, Tencent Hy3 is a very fast and performant model whe ### Which models are reported? -A single model, `hy3`, is advertised via `/v1/models`. +By default, a single model, `hy3` (configurable via the `-model` flag), is advertised via `/v1/models`. ### Are token usage counts returned? diff --git a/hygate_test.go b/hygate_test.go index 90b0877..f2bdde9 100644 --- a/hygate_test.go +++ b/hygate_test.go @@ -10,7 +10,7 @@ import ( ) func TestHunyuanServiceEndpoint(t *testing.T) { - svc := NewHunyuanService("https://example.com/gradio/") + svc := NewHunyuanService("https://example.com/gradio/", "") if svc.endpoint != "https://example.com/gradio" { t.Errorf("expected trailing slash stripped, got %q", svc.endpoint) } @@ -21,6 +21,18 @@ func TestHunyuanServiceEndpoint(t *testing.T) { } } +func TestCustomModelNameConfiguration(t *testing.T) { + svc := NewHunyuanService("https://example.com/gradio", "hunyuan-custom-v1") + if svc.modelName != "hunyuan-custom-v1" { + t.Errorf("expected modelName 'hunyuan-custom-v1', got %q", svc.modelName) + } + + models := svc.ListModels() + if len(models) != 1 || models[0].ID != "hunyuan-custom-v1" { + t.Fatalf("expected model ID 'hunyuan-custom-v1', got %v", models) + } +} + func TestParseGradioStreamData(t *testing.T) { sampleJSON := `[["Hello world", "Thinking process...", null]]` c, r, tc, ok := parseGradioStreamData(sampleJSON) @@ -60,7 +72,7 @@ func TestHunyuanMockedCompletion(t *testing.T) { server := httptest.NewServer(handler) defer server.Close() - svc := NewHunyuanService(server.URL) + svc := NewHunyuanService(server.URL, "hy3") rec := httptest.NewRecorder() req, _ := http.NewRequest("POST", "/v1/chat/completions", nil) @@ -146,7 +158,7 @@ func TestHunyuanToolCallingNonStreaming(t *testing.T) { server := httptest.NewServer(handler) defer server.Close() - svc := NewHunyuanService(server.URL) + svc := NewHunyuanService(server.URL, "hy3") rec := httptest.NewRecorder() req, _ := http.NewRequest("POST", "/v1/chat/completions", nil) @@ -230,7 +242,7 @@ func TestHunyuanReasoningAndToolCallingStreaming(t *testing.T) { server := httptest.NewServer(handler) defer server.Close() - svc := NewHunyuanService(server.URL) + svc := NewHunyuanService(server.URL, "hy3") rec := httptest.NewRecorder() req, _ := http.NewRequest("POST", "/v1/chat/completions", nil) diff --git a/main.go b/main.go index 527340e..dd57320 100644 --- a/main.go +++ b/main.go @@ -375,29 +375,34 @@ func parseGradioStreamData(dataJSON string) (string, string, []ToolCall, bool) { } type HunyuanService struct { - endpoint string - client *http.Client + endpoint string + modelName string + client *http.Client } -func NewHunyuanService(endpoint string) *HunyuanService { +func NewHunyuanService(endpoint string, modelName string) *HunyuanService { cleanEndpoint := strings.TrimRight(endpoint, "/") + if modelName == "" { + modelName = "hy3" + } return &HunyuanService{ - endpoint: cleanEndpoint, - client: &http.Client{Timeout: 300 * time.Second}, + endpoint: cleanEndpoint, + modelName: modelName, + client: &http.Client{Timeout: 300 * time.Second}, } } func (s *HunyuanService) ListModels() []ModelItem { now := time.Now().Unix() return []ModelItem{ - {ID: "hy3", Object: "model", Created: now, OwnedBy: "hunyuan"}, + {ID: s.modelName, Object: "model", Created: now, OwnedBy: "hunyuan"}, } } func (s *HunyuanService) Chat(w http.ResponseWriter, r *http.Request, req ChatCompletionRequest) error { modelName := req.Model if modelName == "" { - modelName = "hy3" + modelName = s.modelName } maxTokens := ResolveMaxTokens(req) @@ -722,6 +727,7 @@ func NewMux(service *HunyuanService) *http.ServeMux { func main() { portFlag := flag.String("port", "8080", "Port to listen on") endpointFlag := flag.String("endpoint", "https://tencent-hy3.hf.space", "Root URL of the Hunyuan Gradio space") + modelFlag := flag.String("model", "hy3", "Exposed model name") uaFlag := flag.String("user-agent", DefaultUserAgent, "Custom User-Agent header") uaShortFlag := flag.String("ua", "", "Alias for -user-agent") flag.Parse() @@ -731,11 +737,12 @@ func main() { ConfiguredUserAgent = *uaShortFlag } - service := NewHunyuanService(*endpointFlag) + service := NewHunyuanService(*endpointFlag, *modelFlag) mux := NewMux(service) fmt.Printf("hygate starting on port %s...\n", *portFlag) fmt.Printf("Target Endpoint: %s\n", service.endpoint) + fmt.Printf("Model Name: %s\n", service.modelName) fmt.Printf("User-Agent: %s\n", ConfiguredUserAgent) fmt.Printf("Endpoints:\n") fmt.Printf(" GET http://localhost:%s/v1/models\n", *portFlag)