Files
hygate-c/README.md
T
2026-10-13 20:36:29 +03:00

112 lines
4.3 KiB
Markdown

# 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).
## Token usage counting
Responses include an OpenAI-style `usage` object with `prompt_tokens`,
`completion_tokens`, and `total_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.
- `prompt_tokens` sums each message's `content` (or multi-part content
parts), `reasoning_content`, and any `tool_calls` function `name` /
`arguments`.
- `completion_tokens` sums the assistant `content`, `reasoning_content`, and
any emitted `tool_calls`.
- `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.
## Security considerations
- 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.