2026-10-12 07:43:34 +03:00
|
|
|
# hygate-c
|
|
|
|
|
|
|
|
|
|
A small, dependency-light C port of the Hygate gateway that exposes a
|
|
|
|
|
**Gradio-hosted Hunyuan model (`hy3`)** behind an **OpenAI-compatible** REST API.
|
|
|
|
|
|
|
|
|
|
It translates OpenAI `chat/completions` requests into Gradio's queue API
|
|
|
|
|
(`POST /gradio_api/call/chat` → `GET /gradio_api/call/chat/{event_id}` SSE
|
|
|
|
|
stream) and translates the Gradio stream back into OpenAI streaming and
|
|
|
|
|
non-streaming responses, including tool calls and reasoning content.
|
|
|
|
|
|
|
|
|
|
## Build
|
|
|
|
|
|
|
|
|
|
Requires `libcurl` and `json-c` (auto-detected via `pkg-config`); falls back
|
|
|
|
|
to `-lcurl -ljson-c` if `pkg-config` is unavailable.
|
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
make # dynamic binary -> bin/hygate
|
|
|
|
|
make static # static binary -> bin/hygate.static
|
|
|
|
|
make clean
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Build is POSIX-portable (Linux, FreeBSD, macOS) and compiles clean with
|
|
|
|
|
`-Wall -Wextra`.
|
|
|
|
|
|
|
|
|
|
## Run
|
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
./bin/hygate [options]
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Options
|
|
|
|
|
|
|
|
|
|
| Flag | Default | Description |
|
|
|
|
|
|------|---------|-------------|
|
|
|
|
|
| `-port <n>` | `8080` | Listen port (binds `0.0.0.0`). |
|
|
|
|
|
| `-endpoint <url>` | `https://tencent-hy3.hf.space` | Upstream Gradio Space base URL (trailing slash trimmed). |
|
|
|
|
|
| `-model <name>` | `hy3` | Model name reported in `/v1/models` and responses. |
|
|
|
|
|
| `-user-agent <ua>` / `-ua <ua>` | built-in Firefox UA | Outgoing `User-Agent`. Empty string => default. |
|
|
|
|
|
| `-max-body <bytes>` | `5242880` (5 MiB) | Maximum request body size. Oversized requests are rejected with `413`. |
|
|
|
|
|
| `-max-conn <n>` | `16` | Maximum concurrent connections (worker threads). Excess connections queue in the kernel listen backlog. |
|
|
|
|
|
|
|
|
|
|
Flag forms: `-key value` or `-key=value`.
|
|
|
|
|
|
|
|
|
|
Example — listen on `9090`, allow 8 MiB bodies, cap at 32 concurrent connections:
|
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
./bin/hygate -port 9090 -max-body 8388608 -max-conn 32
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## Endpoints
|
|
|
|
|
|
|
|
|
|
| Method | Path | Notes |
|
|
|
|
|
|--------|------|-------|
|
|
|
|
|
| `GET` | `/v1/models`, `/models` | Returns the configured model (served locally, no upstream call). |
|
|
|
|
|
| `POST` | `/v1/chat/completions`, `/chat/completions` | OpenAI-style chat completion. Supports `stream`, `tools`/`tool_calls`, and `reasoning_content`. |
|
|
|
|
|
| `OPTIONS` | any of the above | CORS preflight. |
|
|
|
|
|
|
|
|
|
|
CORS is enabled for all origins (`Access-Control-Allow-Origin: *`).
|
|
|
|
|
|
|
|
|
|
## Request / response notes
|
|
|
|
|
|
|
|
|
|
- OpenAI `messages` are mapped into Gradio's `[message, system, history,
|
|
|
|
|
"high", temperature, max_tokens, top_p, null, functions_json]` payload.
|
|
|
|
|
- `max_tokens` / `max_completion_tokens` are honored; defaults to `131072`
|
|
|
|
|
when omitted.
|
|
|
|
|
- Upstream calls use Fibonacci-backoff retries (up to `MAX_RETRIES = 5`,
|
|
|
|
|
300 s timeout).
|
|
|
|
|
|
2026-10-13 20:36:29 +03:00
|
|
|
## Token usage counting
|
|
|
|
|
|
|
|
|
|
Responses include an OpenAI-style `usage` object with `prompt_tokens`,
|
2026-10-14 00:00:02 +03:00
|
|
|
`completion_tokens`, `total_tokens`, and `completion_tokens_details`
|
|
|
|
|
(`reasoning_tokens`). These are computed locally by an **embedded cl100k_base
|
|
|
|
|
BPE tokenizer** (vocabulary data in `tokenizer_data.c`, logic in `tokenizer.c`)
|
|
|
|
|
— no upstream token counts are available from the Gradio backend.
|
2026-10-13 20:36:29 +03:00
|
|
|
|
2026-10-14 00:00:02 +03:00
|
|
|
- `prompt_tokens` sums the active `system` prompt, each message's `content`
|
|
|
|
|
(or individual multi-part content parts), `reasoning_content`, `tool_calls`
|
|
|
|
|
/ `function_call` (`name` and `arguments`), `tool` result wrappers, and any
|
|
|
|
|
request `tools` function definitions (`name`, `description`, `parameters`).
|
2026-10-13 20:36:29 +03:00
|
|
|
- `completion_tokens` sums the assistant `content`, `reasoning_content`, and
|
2026-10-14 00:00:02 +03:00
|
|
|
any emitted `tool_calls` (`name` and `arguments`), with `reasoning_tokens`
|
|
|
|
|
broken out under `completion_tokens_details`.
|
2026-10-13 20:36:29 +03:00
|
|
|
- `total_tokens = prompt_tokens + completion_tokens`.
|
|
|
|
|
|
|
|
|
|
cl100k_base is OpenAI's canonical multilingual tokenizer and is used as the
|
|
|
|
|
best available approximation for Hunyuan; the resulting counts are
|
|
|
|
|
deterministic subword counts and may differ slightly from the exact Hunyuan
|
|
|
|
|
vocabulary. No per-message formatting overhead (the `+3`/priming tokens
|
|
|
|
|
OpenAI applies) is added.
|
|
|
|
|
|
2026-10-12 07:43:34 +03:00
|
|
|
## Security considerations
|
|
|
|
|
|
2026-10-13 20:36:29 +03:00
|
|
|
|
2026-10-12 07:43:34 +03:00
|
|
|
- The server binds all interfaces (`0.0.0.0`) and currently enforces **no
|
|
|
|
|
authentication** — it is an open relay to the configured upstream. Do not
|
|
|
|
|
expose it to untrusted networks without a fronting proxy or auth layer.
|
|
|
|
|
- `-max-body` and `-max-conn` exist to bound resource usage (memory and
|
|
|
|
|
thread count) against abusive clients.
|
|
|
|
|
|
|
|
|
|
## Source layout
|
|
|
|
|
|
|
|
|
|
| File | Role |
|
|
|
|
|
|------|------|
|
|
|
|
|
| `main.c` | Entry point, flag parsing, TCP listen, thread-per-connection with concurrency cap. |
|
|
|
|
|
| `server.c` | HTTP parsing, routing, SSE emitters, libcurl upstream calls, streaming state machine. |
|
|
|
|
|
| `jsonapi.c` | OpenAI <-> Gradio payload translation and stream parsing. |
|
|
|
|
|
| `util.c` | Growable string buffer (`strbuf`), UUID, backoff, helpers. |
|
|
|
|
|
| `hygate.h` | Shared types and declarations. |
|
|
|
|
|
|
|
|
|
|
## Credits
|
|
|
|
|
|
|
|
|
|
Created by Luxferre in 2026, released into the public domain with no warranties.
|