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 & 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/modelsand/v1/chat/completionsendpoints. 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 & Non-Streaming: Supports Server-Sent Events (
stream: true) with real-time token streaming and synchronous JSON responses. - Tool / Function Calling: Fully supports OpenAI
tools,tool_choice, and multi-turn execution (role: "tool"). Automatically injects schemas and parses<tool_call>outputs into standard OpenAItool_callspayloads withfinish_reason: "tool_calls". - Reasoning Content: Extracts
<think>and</think>tags from reasoning models (e.g., Qwen 3.6/3.8) and streams or populatesreasoning_contentfollowing OpenAI O-series conventions. - Dynamic Model Discovery & 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 (
-socksflag orALL_PROXY/SOCKS5_PROXYenvironment 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 / Windows
- Go 1.20+ (for building from source)
- No browser or graphics packages needed.
Installation & Build
Clone or navigate to the repository, then build the binary:
make
The optimized binary will be created at bin/groqqer.
Running the Server
Start the gateway with default settings:
./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
curl -s http://127.0.0.1:8080/v1/models
Response:
{
"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)
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:
{
"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)
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 / Function Calling
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:
{
"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":
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:
{
"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
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
MIT License