{"slug": "a-simple-cli-tool-for-testing-openai-compatible-apis-and-measuring-streaming-it", "title": "A simple CLI tool for testing OpenAI-compatible APIs and measuring streaming performance. It calculates TTFT, generation time, completion tokens, and real-time TPS with optional proxy support.", "summary": "A developer has released a simple command-line tool for testing OpenAI-compatible APIs and measuring streaming performance. The tool calculates time-to-first-token (TTFT), generation time, completion tokens, and real-time tokens per second (TPS), with optional proxy support.", "body_md": "|  | #!/usr/bin/env python3 | \n|  | import json | \n|  | import time | \n|  | import urllib.request | \n|  | import urllib.error | \n|  | def main(): | \n|  | base_url = input(\"Base URL: \").strip().rstrip(\"/\") | \n|  | model = input(\"Model: \").strip() | \n|  | api_key = input(\"API Key: \").strip() | \n|  | proxy = input(\"Proxy (optional): \").strip() | \n|  | prompt = input(\"Prompt: \").strip() | \n|  | url = f\"{base_url}/chat/completions\" | \n|  | payload = { | \n|  | \"model\": model, | \n|  | \"messages\": [ | \n|  | { | \n|  | \"role\": \"user\", | \n|  | \"content\": prompt, | \n|  | } | \n|  | ], | \n|  | \"stream\": True, | \n|  | \"stream_options\": { | \n|  | \"include_usage\": True, | \n|  | }, | \n|  | } | \n|  | data = json.dumps(payload).encode() | \n|  | request = urllib.request.Request( | \n|  | url, | \n|  | data=data, | \n|  | headers={ | \n|  | \"Authorization\": f\"Bearer {api_key}\", | \n|  | \"Content-Type\": \"application/json\", | \n|  | \"Accept\": \"text/event-stream\", | \n|  | }, | \n|  | method=\"POST\", | \n|  | ) | \n|  | # Proxy | \n|  | if proxy: | \n|  | proxy_handler = urllib.request.ProxyHandler({ | \n|  | \"http\": proxy, | \n|  | \"https\": proxy, | \n|  | }) | \n|  | opener = urllib.request.build_opener(proxy_handler) | \n|  | else: | \n|  | opener = urllib.request.build_opener() | \n|  | print() | \n|  | print(\"Connecting...\") | \n|  | print() | \n|  | request_start = time.perf_counter() | \n|  | first_token_time = None | \n|  | last_token_time = None | \n|  | completion_tokens = None | \n|  | try: | \n|  | with opener.open(request, timeout=600) as response: | \n|  | for raw_line in response: | \n|  | line = raw_line.decode(\"utf-8\", errors=\"replace\").strip() | \n|  | if not line.startswith(\"data:\"): | \n|  | continue | \n|  | data_str = line[5:].strip() | \n|  | if data_str == \"[DONE]\": | \n|  | break | \n|  | try: | \n|  | chunk = json.loads(data_str) | \n|  | except json.JSONDecodeError: | \n|  | continue | \n|  | # Usage | \n|  | usage = chunk.get(\"usage\") | \n|  | if usage: | \n|  | completion_tokens = usage.get(\"completion_tokens\") | \n|  | choices = chunk.get(\"choices\", []) | \n|  | if not choices: | \n|  | continue | \n|  | delta = choices[0].get(\"delta\", {}) | \n|  | content = delta.get(\"content\") | \n|  | if content: | \n|  | now = time.perf_counter() | \n|  | if first_token_time is None: | \n|  | first_token_time = now | \n|  | ttft = first_token_time - request_start | \n|  | print( | \n|  | f\"\\n[TTFT: {ttft:.3f}s]\\n\" | \n|  | ) | \n|  | last_token_time = now | \n|  | print(content, end=\"\", flush=True) | \n|  | except urllib.error.HTTPError as e: | \n|  | print(f\"\\nHTTP Error {e.code}:\") | \n|  | print(e.read().decode(errors=\"replace\")) | \n|  | return | \n|  | except Exception as e: | \n|  | print(f\"\\nError: {e}\") | \n|  | return | \n|  | print(\"\\n\") | \n|  | print(\"=\" * 50) | \n|  | if first_token_time is None: | \n|  | print(\"No tokens received.\") | \n|  | return | \n|  | if last_token_time is None: | \n|  | last_token_time = first_token_time | \n|  | generation_time = last_token_time - first_token_time | \n|  | total_time = last_token_time - request_start | \n|  | print(f\"Model: {model}\") | \n|  | print(f\"Completion tokens: {completion_tokens}\") | \n|  | print(f\"TTFT: {first_token_time - request_start:.3f}s\") | \n|  | print(f\"Generation time: {generation_time:.3f}s\") | \n|  | print(f\"Total time: {total_time:.3f}s\") | \n|  | if completion_tokens and generation_time > 0: | \n|  | tps = completion_tokens / generation_time | \n|  | print(f\"TPS: {tps:.2f} tokens/s\") | \n|  | else: | \n|  | print(\"TPS: N/A\") | \n|  | if __name__ == \"__main__\": | \n|  | main() |", "url": "https://wpnews.pro/news/a-simple-cli-tool-for-testing-openai-compatible-apis-and-measuring-streaming-it", "canonical_source": "https://gist.github.com/maanimeisam/6f766b5fbf9f3fdfce49b92b68645b02", "published_at": "2026-09-08 08:46:43+00:00", "updated_at": "2026-09-08 09:03:17.510999+00:00", "lang": "en", "topics": ["developer-tools"], "entities": [], "alternates": {"html": "https://wpnews.pro/news/a-simple-cli-tool-for-testing-openai-compatible-apis-and-measuring-streaming-it", "markdown": "https://wpnews.pro/news/a-simple-cli-tool-for-testing-openai-compatible-apis-and-measuring-streaming-it.md", "text": "https://wpnews.pro/news/a-simple-cli-tool-for-testing-openai-compatible-apis-and-measuring-streaming-it.txt", "jsonld": "https://wpnews.pro/news/a-simple-cli-tool-for-testing-openai-compatible-apis-and-measuring-streaming-it.jsonld"}}