# groqqer `groqqer` is a lightweight, zero-dependency Go OpenAI-compatible API gateway and proxy for the Groq Streamlit space (`https://dromerosm-groq-chatbot.hf.space`). It connects directly to Streamlit's binary WebSocket engine (`/_stcore/stream`) using a pure Go Protobuf wire-format encoder/decoder. It requires **no browser**, **no Chromium**, and **no Xvfb**, allowing it to run smoothly on minimal headless servers and low-resource containers. ## Key features - **Direct WebSocket Protobuf protocol**: communicates directly with Streamlit's internal engine over RFC 6455 WebSockets and Protocol Buffers wire format. - **Completely headless and zero dependencies**: written entirely in pure Go using only the standard library (`net/http`, `crypto/tls`, `encoding/binary`, `encoding/json`, etc.). No Chromium, Chrome, Xvfb, Puppeteer, or external Go modules required. - **Sub-second latency**: bypasses browser rendering and DOM parsing entirely, delivering responses with minimal overhead. - **OpenAI-compatible API**: exposes standard `/v1/models` and `/v1/chat/completions` endpoints. Drop-in replacement for OpenAI SDKs, LiteLLM, Open-WebUI, LibreChat, and LangChain. - **System prompt support**: formats developer/system instructions cleanly for the target model. - **Streaming and non-streaming**: supports Server-Sent Events (`stream: true`) with real-time token streaming and synchronous JSON responses. - **Tool and function calling**: fully supports OpenAI `tools`, `tool_choice`, and multi-turn execution (`role: "tool"`). Automatically injects schemas and parses `` outputs into standard OpenAI `tool_calls` payloads with `finish_reason: "tool_calls"`. - **Reasoning content**: extracts `` and `` tags from reasoning models (e.g., Qwen 3.6/3.8) and streams or populates `reasoning_content` following OpenAI O-series conventions. - **Dynamic model discovery and switching**: discovers active models directly from the Streamlit space on startup and allows seamless model switching between requests (`qwen/qwen3.6-27b`, `openai/gpt-oss-120b`, `openai/gpt-oss-20b`, `groq/compound`, etc.). - **SOCKS5 proxy support**: native pure Go SOCKS5 proxy client supporting authentication (`-socks` flag or `ALL_PROXY` / `SOCKS5_PROXY` environment variables). ## Architecture ``` +---------------------------+ | OpenAI Client / SDK / App | +---------------------------+ | HTTP POST /v1/chat/completions v +---------------------------+ | groqqer | | (Pure Go Standard Lib) | | RFC 6455 WS + Protobuf | +---------------------------+ | WSS (TLS WebSocket) v +---------------------------+ | Groq Streamlit Space | | (dromerosm-groq-chatbot) | +---------------------------+ ``` ## Requirements - Linux, macOS, or Windows - Go 1.20+ (for building from source) - No browser or graphics packages needed ## Installation and build Clone or navigate to the repository, then build the binary: ```bash make ``` The optimized binary will be created at `bin/groqqer`. ## Running the server Start the gateway with default settings: ```bash ./bin/groqqer -port 8080 ``` ### CLI flags | Flag | Default | Description | |------|---------|-------------| | `-port` | `8080` | HTTP server listening port | | `-target` | `https://dromerosm-groq-chatbot.hf.space` | Target Groq Streamlit space URL | | `-default-model` | `qwen/qwen3.6-27b` | Fallback model if request does not specify one | | `-socks` | `""` | SOCKS5 proxy URL (e.g. `socks5://127.0.0.1:1080`) | | `-user-agent` | *(Chrome UA)* | Custom User-Agent string | *(Note: legacy flags `-browser`, `-xvfb`, and `-headless` are retained for backward compatibility but are ignored, as groqqer operates completely headless via direct WebSocket).* ## API usage examples ### 1. List available models ```bash curl -s http://127.0.0.1:8080/v1/models ``` **Response:** ```json { "object": "list", "data": [ {"id": "qwen/qwen3.6-27b", "object": "model", "created": 1788870683, "owned_by": "groq"}, {"id": "qwen/qwen3.8-27b", "object": "model", "created": 1788870683, "owned_by": "groq"}, {"id": "openai/gpt-oss-120b", "object": "model", "created": 1788870683, "owned_by": "groq"}, {"id": "openai/gpt-oss-20b", "object": "model", "created": 1788870683, "owned_by": "groq"}, {"id": "groq/compound", "object": "model", "created": 1788870683, "owned_by": "groq"}, {"id": "groq/compound-mini", "object": "model", "created": 1788870683, "owned_by": "groq"}, {"id": "allam-2-7b", "object": "model", "created": 1788870683, "owned_by": "groq"} ] } ``` --- ### 2. Chat completion (non-streaming) ```bash curl -s -X POST http://127.0.0.1:8080/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{ "model": "openai/gpt-oss-20b", "messages": [ {"role": "system", "content": "You are a concise assistant. Reply in one sentence."}, {"role": "user", "content": "What is the capital of France?"} ] }' ``` **Response:** ```json { "id": "chatcmpl-893498c9-2808-4bec-8c6a-2a0352ed69e9", "object": "chat.completion", "created": 1788870700, "model": "openai/gpt-oss-20b", "choices": [ { "index": 0, "message": { "role": "assistant", "content": "The capital of France is Paris." }, "finish_reason": "stop" } ], "usage": { "prompt_tokens": 0, "completion_tokens": 0, "total_tokens": 0 } } ``` --- ### 3. Streaming chat completion (SSE) ```bash curl -N -s -X POST http://127.0.0.1:8080/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{ "model": "qwen/qwen3.6-27b", "messages": [ {"role": "user", "content": "Count from 1 to 4 separated by commas."} ], "stream": true }' ``` **Output:** ``` data: {"id":"chatcmpl-7a06d0fb","object":"chat.completion.chunk","created":1788870705,"model":"qwen/qwen3.6-27b","choices":[{"index":0,"delta":{"role":"assistant"}}]} data: {"id":"chatcmpl-7a06d0fb","object":"chat.completion.chunk","created":1788870705,"model":"qwen/qwen3.6-27b","choices":[{"index":0,"delta":{"reasoning_content":"Thinking process..."}}]} data: {"id":"chatcmpl-7a06d0fb","object":"chat.completion.chunk","created":1788870705,"model":"qwen/qwen3.6-27b","choices":[{"index":0,"delta":{"content":"1,"}}]} data: {"id":"chatcmpl-7a06d0fb","object":"chat.completion.chunk","created":1788870705,"model":"qwen/qwen3.6-27b","choices":[{"index":0,"delta":{"content":" 2,"}}]} data: {"id":"chatcmpl-7a06d0fb","object":"chat.completion.chunk","created":1788870705,"model":"qwen/qwen3.6-27b","choices":[{"index":0,"delta":{"content":" 3,"}}]} data: {"id":"chatcmpl-7a06d0fb","object":"chat.completion.chunk","created":1788870705,"model":"qwen/qwen3.6-27b","choices":[{"index":0,"delta":{"content":" 4"}}]} data: {"id":"chatcmpl-7a06d0fb","object":"chat.completion.chunk","created":1788870705,"model":"qwen/qwen3.6-27b","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]} data: [DONE] ``` --- ### 4. Tool and function calling ```bash curl -s -X POST http://127.0.0.1:8080/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{ "model": "qwen/qwen3.6-27b", "messages": [ {"role": "user", "content": "What is the weather in Tokyo right now?"} ], "tools": [ { "type": "function", "function": { "name": "get_current_weather", "description": "Get current weather for a city", "parameters": { "type": "object", "properties": { "location": {"type": "string", "description": "City and country"} }, "required": ["location"] } } } ], "tool_choice": "required" }' ``` **Response:** ```json { "id": "chatcmpl-29f63b3b-7ab6-444c-8579-49f906007d43", "object": "chat.completion", "created": 1788870711, "model": "qwen/qwen3.6-27b", "choices": [ { "index": 0, "message": { "role": "assistant", "content": null, "reasoning_content": "The user is asking for the current weather in Tokyo...", "tool_calls": [ { "id": "call_163e8f97", "type": "function", "function": { "name": "get_current_weather", "arguments": "{\"location\":\"Tokyo\"}" } } ] }, "finish_reason": "tool_calls" } ] } ``` --- ### 5. Multi-turn tool response execution Send back the tool execution results using `role: "tool"`: ```bash curl -s -X POST http://127.0.0.1:8080/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{ "model": "qwen/qwen3.6-27b", "messages": [ {"role": "user", "content": "What is the weather in Tokyo right now?"}, { "role": "assistant", "tool_calls": [ { "id": "call_163e8f97", "type": "function", "function": { "name": "get_current_weather", "arguments": "{\"location\":\"Tokyo\"}" } } ] }, { "role": "tool", "tool_call_id": "call_163e8f97", "name": "get_current_weather", "content": "{\"temperature\": \"19°C\", \"weather\": \"Sunny with clear skies\"}" } ] }' ``` **Response:** ```json { "id": "chatcmpl-23354bba-33c7-45be-8807-9c84243037b8", "object": "chat.completion", "created": 1788870718, "model": "qwen/qwen3.6-27b", "choices": [ { "index": 0, "message": { "role": "assistant", "content": "It's currently 19°C and sunny with clear skies in Tokyo" }, "finish_reason": "stop" } ] } ``` --- ### 6. Python OpenAI SDK example ```python from openai import OpenAI client = OpenAI( base_url="http://127.0.0.1:8080/v1", api_key="not-needed" ) response = client.chat.completions.create( model="qwen/qwen3.6-27b", messages=[ {"role": "system", "content": "You are a helpful coding assistant."}, {"role": "user", "content": "Write a Python function to reverse a string."} ] ) print(response.choices[0].message.content) ``` ## License Created by Luxferre in 2026, released into the public domain with no warranties.