354db0afcb74a0340644e856016238c2d8c07186
groqqer
groqqer is a lightweight, zero-dependency Go OpenAI-compatible API gateway and proxy for the Groq Streamlit chatbot space (https://dromerosm-groq-chatbot.hf.space).
It converts standard OpenAI chat completions and model requests into automated headless browser interactions, providing fast inference with Groq models without requiring an API key.
Features
- OpenAI Compatible API: Exposes standard
/v1/modelsand/v1/chat/completionsendpoints. Drop-in replacement for OpenAI SDKs, Open-WebUI, LiteLLM, LibreChat, and LangChain. - Zero Third-Party Dependencies: Written entirely in pure Go using only the standard library (
net/http,encoding/json,os/exec,crypto/rand, etc.). Includes a built-in RFC 6455 WebSocket CDP client and RFC 1928 SOCKS5 proxy client. - System Prompt Support: Translates developer/system messages into natural instruction framing.
- Streaming & Non-Streaming: Supports Server-Sent Events (
stream: true) with real-time token delivery, as well as 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>responses into OpenAItool_callspayloads withfinish_reason: "tool_calls". - Reasoning Content: Automatically parses
<think>and</think>tags from reasoning models (such as Qwen 3.6/3.8) and streams or populatesreasoning_contentin accordance with OpenAI O-series conventions. - Dynamic Model Discovery: Scrapes active models directly from the Streamlit UI on startup and allows seamless model switching between requests (
qwen/qwen3.6-27b,openai/gpt-oss-120b,openai/gpt-oss-20b,groq/compound, etc.). - Display Isolation via Xvfb: Automatically discovers and spawns a virtual X display (
:100-:199) to keep browser automation completely isolated from host desktop displays. Gracefully falls back to offscreen coordinates if Xvfb is not present. - SOCKS5 Proxy Tunneling: Tunnel browser traffic through SOCKS5 proxies using the
-socksflag orALL_PROXY/SOCKS5_PROXYenvironment variables. - Clean Session Isolation: Automatically clears Streamlit conversation state between requests to prevent cumulative token window exhaustion or stale error states.
Architecture
+---------------------------+
| OpenAI Client / SDK / App |
+---------------------------+
| HTTP POST /v1/chat/completions
v
+---------------------------+
| groqqer |
| (Pure Go Standard Lib) |
+---------------------------+
| RFC 6455 WebSocket CDP
v
+---------------------------+
| Chromium / Chrome |
| (Display :100+ via Xvfb) |
+---------------------------+
| HTTPS
v
+---------------------------+
| Groq Streamlit Space |
| (dromerosm-groq-chatbot) |
+---------------------------+
Requirements
- Linux (x86_64 or aarch64)
- Go 1.20+
- Chromium or Google Chrome installed (
/usr/bin/chromium,/usr/bin/google-chrome, or in$PATH) - (Optional) Xvfb (
xorg-server-xvfb) for display isolation
Installation & Build
Clone or navigate to the repository, then build the binary:
make
The optimized binary will be placed 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 |
llama-3.3-70b-versatile |
Fallback model if request does not specify one |
-browser |
"" |
Custom path to Chromium/Chrome binary |
-xvfb |
true |
Enable virtual X server display isolation |
-no-xvfb |
false |
Disable virtual X server (run offscreen) |
-socks |
"" |
SOCKS5 proxy URL (e.g. socks5://127.0.0.1:1080) |
-user-agent |
(Chrome 133 UA) | Custom browser User-Agent string |
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": 1788869470, "owned_by": "groq"},
{"id": "openai/gpt-oss-120b", "object": "model", "created": 1788869470, "owned_by": "groq"},
{"id": "openai/gpt-oss-20b", "object": "model", "created": 1788869470, "owned_by": "groq"},
{"id": "groq/compound", "object": "model", "created": 1788869470, "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": "qwen/qwen3.6-27b",
"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-9691bbf8-8623-4155-a40f-a00e6b6903ac",
"object": "chat.completion",
"created": 1788869478,
"model": "qwen/qwen3.6-27b",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "The capital of France is Paris.",
"reasoning_content": "Analyze User Input: Question: 'What is the capital of France?'..."
},
"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 with commas."}
],
"stream": true
}'
Output:
data: {"id":"chatcmpl-341d6d05","object":"chat.completion.chunk","created":1788869487,"model":"qwen/qwen3.6-27b","choices":[{"index":0,"delta":{"role":"assistant"}}]}
data: {"id":"chatcmpl-341d6d05","object":"chat.completion.chunk","created":1788869487,"model":"qwen/qwen3.6-27b","choices":[{"index":0,"delta":{"reasoning_content":"Thinking process..."}}]}
data: {"id":"chatcmpl-341d6d05","object":"chat.completion.chunk","created":1788869487,"model":"qwen/qwen3.6-27b","choices":[{"index":0,"delta":{"content":"1, 2, 3,"}}]}
data: {"id":"chatcmpl-341d6d05","object":"chat.completion.chunk","created":1788869487,"model":"qwen/qwen3.6-27b","choices":[{"index":0,"delta":{"content":" 4"}}]}
data: {"id":"chatcmpl-341d6d05","object":"chat.completion.chunk","created":1788869487,"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 current weather in Tokyo?"}
],
"tools": [
{
"type": "function",
"function": {
"name": "get_current_weather",
"description": "Get current weather for a city",
"parameters": {
"type": "object",
"properties": {
"location": {"type": "string", "description": "The city and country, e.g. Tokyo, Japan"}
},
"required": ["location"]
}
}
}
],
"tool_choice": "auto"
}'
Response:
{
"id": "chatcmpl-cb050ba0-2573-403f-a1db-e76cdfb8f99d",
"object": "chat.completion",
"created": 1788869493,
"model": "qwen/qwen3.6-27b",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": null,
"tool_calls": [
{
"id": "call_ff437271",
"type": "function",
"function": {
"name": "get_current_weather",
"arguments": "{\"location\":\"Tokyo, Japan\"}"
}
}
]
},
"finish_reason": "tool_calls"
}
]
}
5. Multi-Turn Tool Response Execution
Once you run your tool locally, send the tool result back 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 current weather in Tokyo?"},
{
"role": "assistant",
"tool_calls": [
{
"id": "call_ff437271",
"type": "function",
"function": {
"name": "get_current_weather",
"arguments": "{\"location\":\"Tokyo, Japan\"}"
}
}
]
},
{
"role": "tool",
"tool_call_id": "call_ff437271",
"name": "get_current_weather",
"content": "{\"temperature\": \"18°C\", \"condition\": \"Sunny\", \"humidity\": \"45%\"}"
}
]
}'
Response:
{
"id": "chatcmpl-aad3ed3e-b401-41b8-9b3b-a9455070def5",
"object": "chat.completion",
"created": 1788869501,
"model": "qwen/qwen3.6-27b",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "It is currently sunny in Tokyo with a temperature of 18°C and 45% humidity."
},
"finish_reason": "stop"
}
]
}
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
Languages
Go
99.8%
Makefile
0.2%