chore: rename project and all references to qorona
This commit is contained in:
@@ -1,8 +1,8 @@
|
|||||||
all: q38max
|
all: qorona
|
||||||
|
|
||||||
q38max:
|
qorona:
|
||||||
mkdir -p bin
|
mkdir -p bin
|
||||||
go build -trimpath -ldflags="-s -w" -o bin/q38max main.go
|
go build -trimpath -ldflags="-s -w" -o bin/qorona main.go
|
||||||
|
|
||||||
test:
|
test:
|
||||||
go test -v ./...
|
go test -v ./...
|
||||||
@@ -10,4 +10,4 @@ test:
|
|||||||
clean:
|
clean:
|
||||||
rm -rf bin
|
rm -rf bin
|
||||||
|
|
||||||
.PHONY: all q38max test clean
|
.PHONY: all qorona test clean
|
||||||
|
|||||||
@@ -1,15 +1,16 @@
|
|||||||
# q38max
|
# qorona
|
||||||
|
|
||||||
Standalone, zero-dependency OpenAI-compatible proxy gateway in Go for the **Qwen 3.8 Max** model (`Qwen/Qwen3.8-Max`) hosted on Hugging Face Spaces (`harpreetsahota-qwen38-max-openlogo-demo.hf.space`).
|
Standalone, zero-dependency OpenAI-compatible proxy gateway in Go for the **Qwen 3.8 Max** model (`Qwen/Qwen3.8-Max`) hosted on Hugging Face Spaces (`harpreetsahota-qwen38-max-openlogo-demo.hf.space`).
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
`q38max` reverse-engineers the FiftyOne plugin backend operator interface of the Hugging Face space and transforms it into a standard, production-ready OpenAI API endpoint (`/v1/chat/completions` and `/v1/models`).
|
`qorona` reverse-engineers the FiftyOne plugin backend operator interface of the Hugging Face space and transforms it into a standard, production-ready OpenAI API endpoint (`/v1/chat/completions` and `/v1/models`).
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|
||||||
- **OpenAI Standard Compatibility**: Full drop-in replacement for OpenAI API clients (Curl, Python `openai`, LangChain, LiteLLM, Open-WebUI).
|
- **OpenAI Standard Compatibility**: Full drop-in replacement for OpenAI API clients (Curl, Python `openai`, LangChain, LiteLLM, Open-WebUI).
|
||||||
- **Zero External Dependencies**: Pure standard library Go implementation (`net/http`, `encoding/json`, `crypto/rand`, `time`).
|
- **Zero External Dependencies**: Pure standard library Go implementation (`net/http`, `encoding/json`, `crypto/rand`, `time`).
|
||||||
|
- **Fully Headless & Browserless**: No Chromium, Playwright, or X11 required. Runs directly on bare servers, containers, or embedded systems.
|
||||||
- **Live Streaming SSE & Reasoning**: Streams real-time tokens with separation of reasoning content (`delta.reasoning_content`) and message content (`delta.content`).
|
- **Live Streaming SSE & Reasoning**: Streams real-time tokens with separation of reasoning content (`delta.reasoning_content`) and message content (`delta.content`).
|
||||||
- **Function / Tool Calling Interception**: Supports OpenAI `tools` specification, system prompt tool schema injection, and stateful streaming interception of tool calls (`delta.tool_calls` and `finish_reason: "tool_calls"`).
|
- **Function / Tool Calling Interception**: Supports OpenAI `tools` specification, system prompt tool schema injection, and stateful streaming interception of tool calls (`delta.tool_calls` and `finish_reason: "tool_calls"`).
|
||||||
- **Session Lifecycle Management**: Thread-safe automatic session creation (`/__session/start`), periodic background heartbeats (`/__session/heartbeat`), and auto-reconnect recovery.
|
- **Session Lifecycle Management**: Thread-safe automatic session creation (`/__session/start`), periodic background heartbeats (`/__session/heartbeat`), and auto-reconnect recovery.
|
||||||
@@ -21,7 +22,7 @@ Standalone, zero-dependency OpenAI-compatible proxy gateway in Go for the **Qwen
|
|||||||
|
|
||||||
```
|
```
|
||||||
+---------------------------+ OpenAI HTTP / SSE +------------------------+
|
+---------------------------+ OpenAI HTTP / SSE +------------------------+
|
||||||
| Client (Python / Curl / | ===========================> | q38max Gateway |
|
| Client (Python / Curl / | ===========================> | qorona Gateway |
|
||||||
| OpenAI SDK / Open-WebUI) | | (localhost:8080) |
|
| OpenAI SDK / Open-WebUI) | | (localhost:8080) |
|
||||||
+---------------------------+ +------------------------+
|
+---------------------------+ +------------------------+
|
||||||
|
|
|
|
||||||
@@ -48,14 +49,14 @@ Standalone, zero-dependency OpenAI-compatible proxy gateway in Go for the **Qwen
|
|||||||
|
|
||||||
### Build
|
### Build
|
||||||
```bash
|
```bash
|
||||||
make q38max
|
make qorona
|
||||||
```
|
```
|
||||||
|
|
||||||
Binary is output to `bin/q38max`.
|
Binary is output to `bin/qorona`.
|
||||||
|
|
||||||
### Run
|
### Run
|
||||||
```bash
|
```bash
|
||||||
./bin/q38max -port 8080
|
./bin/qorona -port 8080
|
||||||
```
|
```
|
||||||
|
|
||||||
### CLI Flags
|
### CLI Flags
|
||||||
@@ -84,7 +85,7 @@ curl http://localhost:8080/v1/models
|
|||||||
curl -X POST http://localhost:8080/v1/chat/completions \
|
curl -X POST http://localhost:8080/v1/chat/completions \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
-d '{
|
-d '{
|
||||||
"model": "qwen-3.8-max",
|
"model": "qorona",
|
||||||
"messages": [
|
"messages": [
|
||||||
{"role": "user", "content": "What is the capital of Germany? Answer in 1 word."}
|
{"role": "user", "content": "What is the capital of Germany? Answer in 1 word."}
|
||||||
],
|
],
|
||||||
@@ -98,7 +99,7 @@ curl -X POST http://localhost:8080/v1/chat/completions \
|
|||||||
curl -N -X POST http://localhost:8080/v1/chat/completions \
|
curl -N -X POST http://localhost:8080/v1/chat/completions \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
-d '{
|
-d '{
|
||||||
"model": "qwen-3.8-max",
|
"model": "qorona",
|
||||||
"messages": [
|
"messages": [
|
||||||
{"role": "user", "content": "Calculate 25 * 25 and explain in one sentence."}
|
{"role": "user", "content": "Calculate 25 * 25 and explain in one sentence."}
|
||||||
],
|
],
|
||||||
@@ -113,7 +114,7 @@ curl -N -X POST http://localhost:8080/v1/chat/completions \
|
|||||||
curl -X POST http://localhost:8080/v1/chat/completions \
|
curl -X POST http://localhost:8080/v1/chat/completions \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
-d '{
|
-d '{
|
||||||
"model": "qwen-3.8-max",
|
"model": "qorona",
|
||||||
"messages": [
|
"messages": [
|
||||||
{"role": "user", "content": "What is the weather in Berlin?"}
|
{"role": "user", "content": "What is the weather in Berlin?"}
|
||||||
],
|
],
|
||||||
@@ -147,7 +148,7 @@ client = OpenAI(
|
|||||||
)
|
)
|
||||||
|
|
||||||
response = client.chat.completions.create(
|
response = client.chat.completions.create(
|
||||||
model="qwen-3.8-max",
|
model="qorona",
|
||||||
messages=[
|
messages=[
|
||||||
{"role": "user", "content": "Write a short haiku about computers."}
|
{"role": "user", "content": "Write a short haiku about computers."}
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// q38max: Standalone OpenAI-compatible gateway for Qwen 3.8 Max HuggingFace Spaces
|
// qorona: Standalone OpenAI-compatible gateway for Qwen 3.8 Max HuggingFace Spaces
|
||||||
// Created by Luxferre in 2026, released into the public domain
|
// Created by Luxferre in 2026, released into the public domain
|
||||||
|
|
||||||
package main
|
package main
|
||||||
@@ -1086,7 +1086,7 @@ func PrepareConversation(req ChatCompletionRequest) (history []map[string]interf
|
|||||||
// Main Gateway Service
|
// Main Gateway Service
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
type Q38Gateway struct {
|
type QoronaGateway struct {
|
||||||
spaceURL string
|
spaceURL string
|
||||||
samplePath string
|
samplePath string
|
||||||
modelID string
|
modelID string
|
||||||
@@ -1094,7 +1094,7 @@ type Q38Gateway struct {
|
|||||||
sessionMgr *FiftyOneSessionManager
|
sessionMgr *FiftyOneSessionManager
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewQ38Gateway(spaceURL string, samplePath string, modelID string, timeout time.Duration) *Q38Gateway {
|
func NewQoronaGateway(spaceURL string, samplePath string, modelID string, timeout time.Duration) *QoronaGateway {
|
||||||
tr := &http.Transport{
|
tr := &http.Transport{
|
||||||
MaxIdleConns: 100,
|
MaxIdleConns: 100,
|
||||||
MaxIdleConnsPerHost: 20,
|
MaxIdleConnsPerHost: 20,
|
||||||
@@ -1104,7 +1104,7 @@ func NewQ38Gateway(spaceURL string, samplePath string, modelID string, timeout t
|
|||||||
Transport: tr,
|
Transport: tr,
|
||||||
Timeout: timeout,
|
Timeout: timeout,
|
||||||
}
|
}
|
||||||
return &Q38Gateway{
|
return &QoronaGateway{
|
||||||
spaceURL: strings.TrimRight(spaceURL, "/"),
|
spaceURL: strings.TrimRight(spaceURL, "/"),
|
||||||
samplePath: samplePath,
|
samplePath: samplePath,
|
||||||
modelID: modelID,
|
modelID: modelID,
|
||||||
@@ -1113,7 +1113,7 @@ func NewQ38Gateway(spaceURL string, samplePath string, modelID string, timeout t
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gw *Q38Gateway) HandleModels(w http.ResponseWriter, r *http.Request) {
|
func (gw *QoronaGateway) HandleModels(w http.ResponseWriter, r *http.Request) {
|
||||||
EnableCORS(w)
|
EnableCORS(w)
|
||||||
if r.Method == http.MethodOptions {
|
if r.Method == http.MethodOptions {
|
||||||
w.WriteHeader(http.StatusNoContent)
|
w.WriteHeader(http.StatusNoContent)
|
||||||
@@ -1130,6 +1130,18 @@ func (gw *Q38Gateway) HandleModels(w http.ResponseWriter, r *http.Request) {
|
|||||||
Created: now,
|
Created: now,
|
||||||
OwnedBy: "qwen",
|
OwnedBy: "qwen",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
ID: "qorona",
|
||||||
|
Object: "model",
|
||||||
|
Created: now,
|
||||||
|
OwnedBy: "qwen",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "qwen-3.8-max",
|
||||||
|
Object: "model",
|
||||||
|
Created: now,
|
||||||
|
OwnedBy: "qwen",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
ID: "qwen3.8-max",
|
ID: "qwen3.8-max",
|
||||||
Object: "model",
|
Object: "model",
|
||||||
@@ -1155,7 +1167,7 @@ func (gw *Q38Gateway) HandleModels(w http.ResponseWriter, r *http.Request) {
|
|||||||
json.NewEncoder(w).Encode(resp)
|
json.NewEncoder(w).Encode(resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gw *Q38Gateway) HandleChatCompletions(w http.ResponseWriter, r *http.Request) {
|
func (gw *QoronaGateway) HandleChatCompletions(w http.ResponseWriter, r *http.Request) {
|
||||||
EnableCORS(w)
|
EnableCORS(w)
|
||||||
if r.Method == http.MethodOptions {
|
if r.Method == http.MethodOptions {
|
||||||
w.WriteHeader(http.StatusNoContent)
|
w.WriteHeader(http.StatusNoContent)
|
||||||
@@ -1599,7 +1611,7 @@ func main() {
|
|||||||
ConfiguredToken = *hfToken
|
ConfiguredToken = *hfToken
|
||||||
}
|
}
|
||||||
|
|
||||||
gw := NewQ38Gateway(*spaceURL, *samplePath, *modelID, time.Duration(*timeoutSec)*time.Second)
|
gw := NewQoronaGateway(*spaceURL, *samplePath, *modelID, time.Duration(*timeoutSec)*time.Second)
|
||||||
|
|
||||||
mux := http.NewServeMux()
|
mux := http.NewServeMux()
|
||||||
|
|
||||||
@@ -1613,28 +1625,28 @@ func main() {
|
|||||||
mux.HandleFunc("/__health", func(w http.ResponseWriter, r *http.Request) {
|
mux.HandleFunc("/__health", func(w http.ResponseWriter, r *http.Request) {
|
||||||
EnableCORS(w)
|
EnableCORS(w)
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
w.Write([]byte(`{"status":"ok","gateway":"q38max"}`))
|
w.Write([]byte(`{"status":"ok","gateway":"qorona"}`))
|
||||||
})
|
})
|
||||||
mux.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
|
mux.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
|
||||||
EnableCORS(w)
|
EnableCORS(w)
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
w.Write([]byte(`{"status":"ok","gateway":"q38max"}`))
|
w.Write([]byte(`{"status":"ok","gateway":"qorona"}`))
|
||||||
})
|
})
|
||||||
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
EnableCORS(w)
|
EnableCORS(w)
|
||||||
if r.URL.Path == "/" {
|
if r.URL.Path == "/" {
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
w.Write([]byte(`{"service":"q38max","description":"OpenAI-compatible gateway for Qwen 3.8 Max","models_endpoint":"/v1/models","completions_endpoint":"/v1/chat/completions"}`))
|
w.Write([]byte(`{"service":"qorona","description":"OpenAI-compatible gateway for Qwen 3.8 Max","models_endpoint":"/v1/models","completions_endpoint":"/v1/chat/completions"}`))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
http.NotFound(w, r)
|
http.NotFound(w, r)
|
||||||
})
|
})
|
||||||
|
|
||||||
addr := fmt.Sprintf(":%d", *port)
|
addr := fmt.Sprintf(":%d", *port)
|
||||||
log.Printf("[q38max] Listening on http://localhost%s (Upstream: %s)", addr, *spaceURL)
|
log.Printf("[qorona] Listening on http://localhost%s (Upstream: %s)", addr, *spaceURL)
|
||||||
log.Printf("[q38max] OpenAI compatible endpoints: http://localhost%s/v1/chat/completions", addr)
|
log.Printf("[qorona] OpenAI compatible endpoints: http://localhost%s/v1/chat/completions", addr)
|
||||||
|
|
||||||
if err := http.ListenAndServe(addr, mux); err != nil {
|
if err := http.ListenAndServe(addr, mux); err != nil {
|
||||||
log.Fatalf("[q38max] Server failed: %v", err)
|
log.Fatalf("[qorona] Server failed: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Unit and integration tests for q38max
|
// Unit and integration tests for qorona
|
||||||
// Created by Luxferre in 2026, released into the public domain
|
// Created by Luxferre in 2026, released into the public domain
|
||||||
|
|
||||||
package main
|
package main
|
||||||
@@ -86,7 +86,7 @@ func TestPrepareConversation(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestModelsHandler(t *testing.T) {
|
func TestModelsHandler(t *testing.T) {
|
||||||
gw := NewQ38Gateway("https://mock.hf.space", "/dummy/path.jpg", "qwen-3.8-max", 5*time.Second)
|
gw := NewQoronaGateway("https://mock.hf.space", "/dummy/path.jpg", "qwen-3.8-max", 5*time.Second)
|
||||||
|
|
||||||
req := httptest.NewRequest("GET", "/v1/models", nil)
|
req := httptest.NewRequest("GET", "/v1/models", nil)
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
@@ -108,12 +108,12 @@ func TestModelsHandler(t *testing.T) {
|
|||||||
|
|
||||||
found := false
|
found := false
|
||||||
for _, m := range res.Data {
|
for _, m := range res.Data {
|
||||||
if m.ID == "qwen-3.8-max" {
|
if m.ID == "qorona" || m.ID == "qwen-3.8-max" {
|
||||||
found = true
|
found = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !found {
|
if !found {
|
||||||
t.Fatalf("qwen-3.8-max not found in models list")
|
t.Fatalf("model not found in models list")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -12,7 +12,7 @@ echo "=== 2. Testing Non-Streaming Chat Completion ==="
|
|||||||
curl -s -X POST "${BASE_URL}/v1/chat/completions" \
|
curl -s -X POST "${BASE_URL}/v1/chat/completions" \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
-d '{
|
-d '{
|
||||||
"model": "qwen-3.8-max",
|
"model": "qorona",
|
||||||
"messages": [
|
"messages": [
|
||||||
{"role": "user", "content": "What is the capital of Italy? Answer in 1 word."}
|
{"role": "user", "content": "What is the capital of Italy? Answer in 1 word."}
|
||||||
],
|
],
|
||||||
@@ -25,7 +25,7 @@ echo "=== 3. Testing Streaming SSE Completion (with reasoning) ==="
|
|||||||
curl -N -s -X POST "${BASE_URL}/v1/chat/completions" \
|
curl -N -s -X POST "${BASE_URL}/v1/chat/completions" \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
-d '{
|
-d '{
|
||||||
"model": "qwen-3.8-max",
|
"model": "qorona",
|
||||||
"messages": [
|
"messages": [
|
||||||
{"role": "user", "content": "Calculate 25 * 25 and explain briefly in one sentence."}
|
{"role": "user", "content": "Calculate 25 * 25 and explain briefly in one sentence."}
|
||||||
],
|
],
|
||||||
@@ -39,7 +39,7 @@ echo "=== 4. Testing Function/Tool Calling ==="
|
|||||||
curl -s -X POST "${BASE_URL}/v1/chat/completions" \
|
curl -s -X POST "${BASE_URL}/v1/chat/completions" \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
-d '{
|
-d '{
|
||||||
"model": "qwen-3.8-max",
|
"model": "qorona",
|
||||||
"messages": [
|
"messages": [
|
||||||
{"role": "user", "content": "What is the weather in Berlin?"}
|
{"role": "user", "content": "What is the weather in Berlin?"}
|
||||||
],
|
],
|
||||||
@@ -64,4 +64,4 @@ curl -s -X POST "${BASE_URL}/v1/chat/completions" \
|
|||||||
}' | jq .
|
}' | jq .
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "=== All integration tests finished successfully! ==="
|
echo "=== All qorona integration tests finished successfully! ==="
|
||||||
|
|||||||
Reference in New Issue
Block a user