feat: add multi-space support with MicroHERO ZeroGPU default and auto-detection

This commit is contained in:
Luxferre
2026-09-05 16:15:15 +03:00
parent 0da31212b4
commit bb56840d59
3 changed files with 608 additions and 35 deletions
+127 -1
View File
@@ -232,7 +232,7 @@ func TestQwenServiceChatMock(t *testing.T) {
}))
defer mockServer.Close()
svc := NewQwenService(mockServer.URL, "Qwen/Qwen3.8-Flash-Next", "", "", "", "", true)
svc := NewQwenService(mockServer.URL, "Qwen/Qwen3.8-Flash-Next", "chat_response", "", "", "", "", true)
// 1. Test Non-streaming completion
rec := httptest.NewRecorder()
@@ -319,3 +319,129 @@ func TestQwenServiceChatMock(t *testing.T) {
t.Fatalf("expected streamed content, got %q", receivedContent.String())
}
}
func TestParseAssistantTextDirectString(t *testing.T) {
dataJSON := `["Step-by-step reasoning\n</think>\n\nFinal answer here", null]`
text, ok := parseAssistantText(dataJSON)
if !ok {
t.Fatalf("expected successful parse of direct string assistant text")
}
if text != "Step-by-step reasoning\n</think>\n\nFinal answer here" {
t.Fatalf("unexpected text: %q", text)
}
reasoning, content := SeparateReasoningAndContent(text)
if reasoning != "Step-by-step reasoning" {
t.Fatalf("unexpected reasoning: %q", reasoning)
}
if content != "Final answer here" {
t.Fatalf("unexpected content: %q", content)
}
}
func TestQwenServiceChatRespondMock(t *testing.T) {
mockServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/gradio_api/call/respond" && r.Method == http.MethodPost {
w.Header().Set("Content-Type", "application/json")
w.Write([]byte(`{"event_id": "respond_event_456"}`))
return
}
if r.URL.Path == "/gradio_api/call/respond/respond_event_456" && r.Method == http.MethodGet {
w.Header().Set("Content-Type", "text/event-stream")
flusher, _ := w.(http.Flusher)
chunk := `event: complete` + "\n" +
`data: ["Analyzing the problem.\n</think>\n\nThe solution is 42.", null]` + "\n\n"
w.Write([]byte(chunk))
flusher.Flush()
return
}
http.NotFound(w, r)
}))
defer mockServer.Close()
svc := NewQwenService(mockServer.URL, "Qwen/Qwen3.8-27B-Uncensored", "respond", "", "", "", "", true)
// Non-streaming test
rec := httptest.NewRecorder()
req := ChatCompletionRequest{
Model: "qwen3.8-27b",
Messages: []ChatMessage{
{Role: "user", Content: "What is the answer?"},
},
Stream: false,
}
err := svc.Chat(rec, nil, req)
if err != nil {
t.Fatalf("unexpected error in respond non-streaming: %v", err)
}
if rec.Code != http.StatusOK {
t.Fatalf("expected HTTP 200, got %d", rec.Code)
}
var resp ChatCompletionResponse
if err := json.NewDecoder(rec.Body).Decode(&resp); err != nil {
t.Fatalf("failed to decode response: %v", err)
}
if resp.Choices[0].Message.Content != "The solution is 42." {
t.Fatalf("unexpected content: %v", resp.Choices[0].Message.Content)
}
if resp.Choices[0].Message.ReasoningContent != "Analyzing the problem." {
t.Fatalf("unexpected reasoning: %v", resp.Choices[0].Message.ReasoningContent)
}
// Streaming test
recStream := httptest.NewRecorder()
reqStream := ChatCompletionRequest{
Model: "qwen3.8-27b",
Messages: []ChatMessage{
{Role: "user", Content: "What is the answer?"},
},
Stream: true,
}
errStream := svc.Chat(recStream, nil, reqStream)
if errStream != nil {
t.Fatalf("unexpected error in respond streaming: %v", errStream)
}
scanner := bufio.NewScanner(recStream.Body)
var receivedContent strings.Builder
var receivedReasoning strings.Builder
var sawDone bool
for scanner.Scan() {
line := scanner.Text()
if strings.HasPrefix(line, "data: ") {
payload := strings.TrimPrefix(line, "data: ")
if payload == "[DONE]" {
sawDone = true
continue
}
var sResp StreamResponse
if err := json.Unmarshal([]byte(payload), &sResp); err == nil && len(sResp.Choices) > 0 {
delta := sResp.Choices[0].Delta
if delta.ReasoningContent != "" {
receivedReasoning.WriteString(delta.ReasoningContent)
}
if delta.Content != "" {
receivedContent.WriteString(delta.Content)
}
}
}
}
if !sawDone {
t.Fatalf("expected [DONE] in stream")
}
if receivedReasoning.String() != "Analyzing the problem." {
t.Fatalf("unexpected streamed reasoning: %q", receivedReasoning.String())
}
if receivedContent.String() != "The solution is 42." {
t.Fatalf("unexpected streamed content: %q", receivedContent.String())
}
}