openai-api-tester 0.1.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,58 @@
1
+ Metadata-Version: 2.2
2
+ Name: openai-api-tester
3
+ Version: 0.1.1
4
+ Summary: A tool designed to interact with APIs compatible with OpenAI's format.
5
+ Requires-Python: >=3.12
6
+ Description-Content-Type: text/markdown
7
+ Requires-Dist: fastapi>=0.115
8
+ Requires-Dist: httpx>=0.28.1
9
+ Requires-Dist: jinja2>=3.1
10
+ Requires-Dist: pygments>=2.19
11
+ Requires-Dist: python-multipart>=0.0.20
12
+ Requires-Dist: uvicorn>=0.34
13
+
14
+ # OpenAI API Tester
15
+
16
+ OpenAI API Tester is a tool designed to interact with APIs compatible with OpenAI's format. It uses the [FastAPI framework](https://github.com/fastapi/fastapi) and [HTMX](https://htmx.org) to provide a seamless interface for quickly testing various APIs. Form inputs are stored in the browser's local storage, so you can pick up where you left off.
17
+
18
+ ## Installation
19
+
20
+ To install the necessary dependencies, use the `uv` package manager:
21
+
22
+ ```bash
23
+ uv tool install openai-api-tester
24
+ ```
25
+
26
+ You can also launch the application one-shot:
27
+
28
+ ```bash
29
+ uvx openai-api-tester
30
+ ```
31
+
32
+ ## Deploy on Clever Cloud
33
+
34
+ Install Clever Tools and create a Python application:
35
+
36
+ ```bash
37
+ npm i -g clever-tools
38
+ clever login
39
+
40
+ clever create --type python
41
+ ```
42
+
43
+ Set the environment variables:
44
+
45
+ ```bash
46
+ clever env set CC_RUN_COMMAND "uvx openai-api-tester"
47
+ ```
48
+
49
+ Deploy the application:
50
+
51
+ ```bash
52
+ clever deploy
53
+ clever open
54
+ ```
55
+
56
+ ## License
57
+
58
+ This project is licensed under the MIT License.
@@ -0,0 +1,45 @@
1
+ # OpenAI API Tester
2
+
3
+ OpenAI API Tester is a tool designed to interact with APIs compatible with OpenAI's format. It uses the [FastAPI framework](https://github.com/fastapi/fastapi) and [HTMX](https://htmx.org) to provide a seamless interface for quickly testing various APIs. Form inputs are stored in the browser's local storage, so you can pick up where you left off.
4
+
5
+ ## Installation
6
+
7
+ To install the necessary dependencies, use the `uv` package manager:
8
+
9
+ ```bash
10
+ uv tool install openai-api-tester
11
+ ```
12
+
13
+ You can also launch the application one-shot:
14
+
15
+ ```bash
16
+ uvx openai-api-tester
17
+ ```
18
+
19
+ ## Deploy on Clever Cloud
20
+
21
+ Install Clever Tools and create a Python application:
22
+
23
+ ```bash
24
+ npm i -g clever-tools
25
+ clever login
26
+
27
+ clever create --type python
28
+ ```
29
+
30
+ Set the environment variables:
31
+
32
+ ```bash
33
+ clever env set CC_RUN_COMMAND "uvx openai-api-tester"
34
+ ```
35
+
36
+ Deploy the application:
37
+
38
+ ```bash
39
+ clever deploy
40
+ clever open
41
+ ```
42
+
43
+ ## License
44
+
45
+ This project is licensed under the MIT License.
@@ -0,0 +1,58 @@
1
+ Metadata-Version: 2.2
2
+ Name: openai-api-tester
3
+ Version: 0.1.1
4
+ Summary: A tool designed to interact with APIs compatible with OpenAI's format.
5
+ Requires-Python: >=3.12
6
+ Description-Content-Type: text/markdown
7
+ Requires-Dist: fastapi>=0.115
8
+ Requires-Dist: httpx>=0.28.1
9
+ Requires-Dist: jinja2>=3.1
10
+ Requires-Dist: pygments>=2.19
11
+ Requires-Dist: python-multipart>=0.0.20
12
+ Requires-Dist: uvicorn>=0.34
13
+
14
+ # OpenAI API Tester
15
+
16
+ OpenAI API Tester is a tool designed to interact with APIs compatible with OpenAI's format. It uses the [FastAPI framework](https://github.com/fastapi/fastapi) and [HTMX](https://htmx.org) to provide a seamless interface for quickly testing various APIs. Form inputs are stored in the browser's local storage, so you can pick up where you left off.
17
+
18
+ ## Installation
19
+
20
+ To install the necessary dependencies, use the `uv` package manager:
21
+
22
+ ```bash
23
+ uv tool install openai-api-tester
24
+ ```
25
+
26
+ You can also launch the application one-shot:
27
+
28
+ ```bash
29
+ uvx openai-api-tester
30
+ ```
31
+
32
+ ## Deploy on Clever Cloud
33
+
34
+ Install Clever Tools and create a Python application:
35
+
36
+ ```bash
37
+ npm i -g clever-tools
38
+ clever login
39
+
40
+ clever create --type python
41
+ ```
42
+
43
+ Set the environment variables:
44
+
45
+ ```bash
46
+ clever env set CC_RUN_COMMAND "uvx openai-api-tester"
47
+ ```
48
+
49
+ Deploy the application:
50
+
51
+ ```bash
52
+ clever deploy
53
+ clever open
54
+ ```
55
+
56
+ ## License
57
+
58
+ This project is licensed under the MIT License.
@@ -0,0 +1,13 @@
1
+ README.md
2
+ pyproject.toml
3
+ openai_api_tester.egg-info/PKG-INFO
4
+ openai_api_tester.egg-info/SOURCES.txt
5
+ openai_api_tester.egg-info/dependency_links.txt
6
+ openai_api_tester.egg-info/entry_points.txt
7
+ openai_api_tester.egg-info/requires.txt
8
+ openai_api_tester.egg-info/top_level.txt
9
+ src/server.py
10
+ src/static/favicon.ico
11
+ src/templates/index.html
12
+ src/templates/partials/get-request.html
13
+ src/templates/partials/post-request.html
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ openai-api-tester-test = src.server:main
@@ -0,0 +1,6 @@
1
+ fastapi>=0.115
2
+ httpx>=0.28.1
3
+ jinja2>=3.1
4
+ pygments>=2.19
5
+ python-multipart>=0.0.20
6
+ uvicorn>=0.34
@@ -0,0 +1,24 @@
1
+ [project]
2
+ name = "openai-api-tester"
3
+ version = "0.1.1"
4
+ description = "A tool designed to interact with APIs compatible with OpenAI's format."
5
+ readme = "README.md"
6
+ requires-python = ">=3.12"
7
+ dependencies = [
8
+ "fastapi>=0.115",
9
+ "httpx>=0.28.1",
10
+ "jinja2>=3.1",
11
+ "pygments>=2.19",
12
+ "python-multipart>=0.0.20",
13
+ "uvicorn>=0.34",
14
+ ]
15
+
16
+ [project.scripts]
17
+ openai-api-tester-test = "src.server:main"
18
+
19
+ [tool.setuptools]
20
+ packages = ["src"]
21
+ include-package-data = true
22
+
23
+ [tool.setuptools.package-data]
24
+ "src" = ["templates/*", "templates/partials/*", "static/*"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,96 @@
1
+ import json
2
+ import httpx
3
+ import logging
4
+
5
+ from importlib import resources
6
+ from pathlib import Path
7
+
8
+ from pygments import highlight
9
+ from pygments.lexers import JsonLexer
10
+ from pygments.formatters import HtmlFormatter
11
+
12
+ from fastapi import FastAPI, Request
13
+ from fastapi.staticfiles import StaticFiles
14
+ from fastapi.responses import HTMLResponse
15
+ from jinja2 import Environment, FileSystemLoader
16
+
17
+ logging.basicConfig(level=logging.INFO)
18
+ logger = logging.getLogger(__name__)
19
+
20
+ app = FastAPI(openapi_url="")
21
+
22
+ try:
23
+ package_path = resources.files("src")
24
+ except ModuleNotFoundError:
25
+ package_path = Path(__file__).parent
26
+
27
+ static_path = package_path / "static"
28
+ templates_path = package_path / "templates"
29
+
30
+ app.mount("/static", StaticFiles(directory=str(static_path)), name="static")
31
+
32
+ env = Environment(loader=FileSystemLoader(str(templates_path)))
33
+
34
+ @app.get("/", response_class=HTMLResponse)
35
+ async def home(request: Request) -> HTMLResponse:
36
+ template = env.get_template("index.html")
37
+ return template.render()
38
+
39
+ @app.get("/template/{template_name}", response_class=HTMLResponse)
40
+ async def get_template(template_name: str) -> HTMLResponse:
41
+ return read_html(f"partials/{template_name}.html")
42
+
43
+ @app.post("/api-call", response_class=HTMLResponse)
44
+ async def make_api_call(request: Request) -> HTMLResponse:
45
+ try:
46
+ form = await request.form()
47
+
48
+ headers = {"Content-Type": "application/json"}
49
+ if token := form.get("token"):
50
+ headers["Authorization"] = f"Bearer {token}"
51
+
52
+ async with httpx.AsyncClient(timeout=90.0) as client:
53
+ response = await client.request(
54
+ method=form.get("method", "POST"),
55
+ url=form.get("base_url"),
56
+ headers=headers,
57
+ json=json.loads(form.get("body")) if form.get("method") == "POST" else None
58
+ )
59
+ response.raise_for_status()
60
+ return format_json_response(response.json())
61
+ except httpx.HTTPStatusError as http_err:
62
+ logger.error(f"HTTP error occurred: {http_err.response.status_code} - {http_err.response.text}")
63
+ return f"<div class='error'>HTTP error occurred: {http_err.response.status_code} - {http_err.response.text}</div>"
64
+ except httpx.RequestError as req_err:
65
+ logger.error(f"Request error occurred: {str(req_err)}")
66
+ return f"<div class='error'>Request error occurred: {str(req_err)}</div>"
67
+ except Exception as e:
68
+ logger.error(f"Error during API call: {str(e)}")
69
+ return f"<div class='error'>{str(e)}</div>"
70
+
71
+ def read_html(path: str) -> str:
72
+ template_file = templates_path / path
73
+ with open(template_file, "r") as f:
74
+ return f.read()
75
+
76
+ def format_json_response(data: any) -> str:
77
+ try:
78
+ formatted_json = json.dumps(data, indent=2)
79
+ formatter = HtmlFormatter(style="github-dark")
80
+ highlighted = highlight(formatted_json, JsonLexer(), formatter)
81
+ css = formatter.get_style_defs()
82
+
83
+ return (
84
+ f'<style>{css}</style>'
85
+ f'<div class="response-area" style="white-space: pre;">{highlighted}</div>'
86
+ )
87
+ except Exception as e:
88
+ logger.error(f"Error formatting JSON response: {str(e)}")
89
+ return f'<div class="error">{str(e)}</div>'
90
+
91
+ def main():
92
+ import uvicorn
93
+ uvicorn.run(app, host="0.0.0.0", port=9000)
94
+
95
+ if __name__ == "__main__":
96
+ main()
@@ -0,0 +1,108 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+
4
+ <head>
5
+ <meta charset="UTF-8">
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
+ <meta http-equiv="X-UA-Compatible" content="ie=edge">
8
+ <title>OpenAI API Tester</title>
9
+ <meta property="og:title" content="OpenAI API Tester">
10
+ <meta name="description" content="OpenAI API Explorer">
11
+ <meta name="keywords" content="OpenAI, API, REST, Chat, Completions, Embeddings, Explorer, AI, Artificial Intelligence">
12
+ <meta property="og:description" content="Explore and test OpenAI APIs with ease.">
13
+ <meta property="og:image" content="https://openapi.davlgd.fr/static/images/og-image.webp">
14
+ <meta property="og:url" content="https://openai.davlgd.fr">
15
+ <meta name="twitter:card" content="summary_large_image">
16
+ <meta name="twitter:title" content="OpenAI API Tester">
17
+ <meta name="twitter:description" content="Explore and test OpenAI APIs with ease.">
18
+ <meta name="twitter:image" content="https://openapi.davlgd.fr/static/images/og-image.webp">
19
+ <link rel="icon" href="/static/favicon.ico" type="image/x-icon">
20
+ <link rel="stylesheet" href="/static/css/main.css">
21
+ <link rel="stylesheet" href="/static/css/fa-all.min.css">
22
+ <script src="https://unpkg.com/htmx.org"></script>
23
+ <style></style>
24
+ </head>
25
+
26
+ <body>
27
+ <div class="container">
28
+ <div class="sidebar">
29
+ <h2>Server Configuration</h2>
30
+ <form id="server-config" class="config-form">
31
+ <div class="field">
32
+ <label>Host</label>
33
+ <input type="text" id="host" placeholder="localhost" hx-on="change: localStorage.setItem('host', this.value)">
34
+ </div>
35
+ <div class="field">
36
+ <label>Port (optional)</label>
37
+ <input type="text" id="port" placeholder="11434" hx-on="change: localStorage.setItem('port', this.value)">
38
+ </div>
39
+ <div class="field checkbox">
40
+ <label>
41
+ <input type="checkbox" id="tls" hx-on="change: localStorage.setItem('tls', this.checked)">
42
+ Use HTTPS
43
+ </label>
44
+ </div>
45
+ <div class="field">
46
+ <label>Bearer Token</label>
47
+ <input type="password" id="token" placeholder="Enter your API token if any">
48
+ </div>
49
+ </form>
50
+
51
+ <h2>Endpoints</h2>
52
+ <button class="endpoint-btn" hx-get="/template/get-request" hx-target="#main-form" hx-swap="innerHTML" hx-on="htmx:afterSettle:
53
+ this.classList.add('active');
54
+ document.querySelector('#response').innerHTML = '';
55
+ loadConfigFromLocalStorage();" data-endpoint="/v1/models">
56
+ <span class="method get">GET</span>
57
+ <span>/v1/models</span>
58
+ </button>
59
+ <button class="endpoint-btn" hx-get="/template/post-request" hx-target="#main-form" hx-swap="innerHTML" hx-on="htmx:afterSettle:
60
+ this.classList.add('active');
61
+ document.querySelector('#response').innerHTML = '';
62
+ loadConfigFromLocalStorage();" data-endpoint="/v1/chat/completions">
63
+ <span class="method post">POST</span>
64
+ <span>/v1/chat/completions</span>
65
+ </button>
66
+ <button class="endpoint-btn" hx-get="/template/post-request" hx-target="#main-form" hx-swap="innerHTML" hx-on="htmx:afterSettle:
67
+ this.classList.add('active');
68
+ document.querySelector('#response').innerHTML = '';
69
+ loadConfigFromLocalStorage();" data-endpoint="/v1/embeddings">
70
+ <span class="method post">POST</span>
71
+ <span>/v1/embeddings</span>
72
+ </button>
73
+ </div>
74
+
75
+ <main class="main">
76
+ <form class="request-form" id="requestForm">
77
+ <div class="url-bar">
78
+ <div class="field">
79
+ <div class="col-header">
80
+ <h3>Request URL</h3>
81
+ </div>
82
+ <input type="text" id="display_url" class="request-url" readonly>
83
+ <input type="hidden" name="base_url" id="actual_url">
84
+ <input type="hidden" name="token" id="token_field">
85
+ </div>
86
+ <button class="btn-primary" type="submit" hx-post="/api-call" hx-target="#response" hx-include="closest form"
87
+ hx-on="htmx:beforeRequest:
88
+ this.disabled = true;
89
+ this.querySelector('.btn-text').style.display = 'none';
90
+ this.querySelector('.spinner').style.display = 'block';
91
+ htmx:afterRequest:
92
+ this.disabled = false;
93
+ this.querySelector('.btn-text').style.display = 'block';
94
+ this.querySelector('.spinner').style.display = 'none';
95
+ document.querySelector('.btn-copy').classList.add('visible');">
96
+ <span class="btn-text">Send</span>
97
+ <div class="spinner" style="display: none;"></div>
98
+ </button>
99
+ </div>
100
+ <div id="main-form" hx-get="/template/post-request" hx-trigger="load"></div>
101
+ </form>
102
+ </main>
103
+ </div>
104
+ <footer class="footer"><p>Written with ♥ by <a href="https://davlgd.fr">davlgd</a>. Use this tool with any OpenAI compatible API. It's <a href="https://github.com/davlgd/openai-api-tester" target="_blank">open source software</a>, not affiliated with OpenAI.</p></footer>
105
+ <script type="module" src="/static/js/main.js"></script>
106
+ </body>
107
+
108
+ </html>
@@ -0,0 +1,21 @@
1
+ <div class="cols single">
2
+ <div class="col">
3
+ <div class="col-header">
4
+ <h3>Response</h3>
5
+ <button type="button" class="btn-copy" hx-on="click:
6
+ navigator.clipboard.writeText(document.getElementById('response').innerText);
7
+ this.querySelector('.icon').classList.remove('fa-copy');
8
+ this.querySelector('.icon').classList.add('fa-check');
9
+ setTimeout(() => {
10
+ this.querySelector('.icon').classList.remove('fa-check');
11
+ this.querySelector('.icon').classList.add('fa-copy');
12
+ }, 2000);" class="btn-copy">
13
+ <i class="icon fa fa-copy"></i>
14
+ </button>
15
+ </div>
16
+ <div class="col-content">
17
+ <div id="response" class="json-viewer" hx-indicator="self"></div>
18
+ </div>
19
+ </div>
20
+ </div>
21
+ <input type="hidden" name="method" value="GET">
@@ -0,0 +1,29 @@
1
+ <div class="cols">
2
+ <div class="col">
3
+ <div class="col-header">
4
+ <h3>Request Body</h3>
5
+ </div>
6
+ <div class="col-content">
7
+ <input type="hidden" name="method" value="POST">
8
+ <textarea name="body" class="json-input" spellcheck="false"
9
+ hx-on="blur: localStorage.setItem(document.querySelector('.endpoint-btn.active').getAttribute('data-endpoint') + '-model', this.value)"></textarea>
10
+ </div>
11
+ </div>
12
+ <div class="col">
13
+ <div class="col-header">
14
+ <h3>Response</h3>
15
+ <button type="button" class="btn-copy" hx-on="click:
16
+ navigator.clipboard.writeText(document.getElementById('response').innerText);
17
+ this.querySelector('.icon').classList.remove('fa-copy');
18
+ this.querySelector('.icon').classList.add('fa-check');
19
+ setTimeout(() => {
20
+ this.querySelector('.icon').classList.remove('fa-check');
21
+ this.querySelector('.icon').classList.add('fa-copy');
22
+ }, 2000);" class="btn-copy">
23
+ <i class="icon fa fa-copy"></i>
24
+ </button>
25
+ </div>
26
+ <div class="col-content">
27
+ <div id="response" class="response-area"></div>
28
+ </div>
29
+ </div>