Overview
Current Status
- Project type: Node.js OpenAI-compatible chat completions proxy with a browser chat client.
- Status: backend proxy is working, and
public/chatclient/ now provides a simplified tabbed rich-text workspace with auto-saved draft input, settings, image/audio attachments by upload or link, assistant output rendering, and raw response inspection.
- Verified with
npm test, npm run build, and node --check on the browser chat client modules.
- Build output folder:
C:\Users\a\AppData\Local\Temp\oapix-chatclient-preview-build
What The App Does
- Exposes
POST /v1/chat/completions as a proxy to an OpenAI-compatible upstream base URL.
- Accepts image input as URL, data URL, or raw base64 on
image_url.url.
- Accepts audio input as base64 on
input_audio.data or as input_audio.url.
- Downloads audio URLs, converts them to mp3, base64-encodes them, and forwards them upstream.
- Exposes audio output base64 as a temporary proxy URL on non-stream responses.
- Exposes image data URLs returned by compatible upstreams as temporary proxy URLs on non-stream responses.
- Exposes
GET /v1/media/:mediaId for temporary media retrieval and GET /v1/health for health checks.
- Serves a landing page from
/ and an interactive demo chat client from /chatclient/.
Runtime Notes
- Configure
OPENAI_API_KEY and OPENAI_BASE_URL in the local .env file.
- Media files are stored in memory and expire after
MEDIA_TTL_SECONDS.
- Stream responses are passed through directly and do not get extra proxy media URLs added.
- The build script writes a bundled server file and static assets into the temp build folder.
- Static frontend files are served directly from
public/ with a service worker for cached HTML, CSS, and JS.
- The chat client stores endpoint, model, system prompt, audio toggle, and voice settings in browser local storage.
- The chat client also auto-saves compose draft HTML, link-picker state, and link-based attachments in browser local storage.
Chat Client Status
- Compose tab: contenteditable rich text editor with basic formatting tools and
Ctrl+Enter send.
- Layout: the large intro/header block and Back button were removed, leaving a compact top tab bar.
- Tool row: single-line icon toolbar with settings, add-attachment, and a right-aligned send button.
- Settings panel: endpoint, model, system prompt, audio output, and voice selection.
- Output tab: formatted assistant text plus returned image and audio media.
- Raw Output tab: exact JSON returned by the proxy, plus structured error output on failed requests.
- Attachment flow: image/audio attachments can be added by uploaded file or direct
http(s) link; image files are sent as data URLs, audio files are sent as base64 with format metadata, and links are forwarded as URLs.
- Attachment preview: attachments render as compact mini items, and clicking one opens a larger preview overlay for the selected image or audio.
- Draft flow: editor content and link-based compose state restore automatically when
/chatclient/ is reopened.
- Send behavior: clicking Send switches to the Output tab immediately, and successful requests keep both the editor prompt text and current attachments in place.
Project Structure
oapix/
|-- .env.example # Example environment variables for local setup
|-- .gitignore # Node.js and local-secret ignore rules
|-- package-lock.json # Locked dependency versions
|-- package.json # Scripts, runtime deps, and build deps
|-- doc/
| |-- agent.md # Human-maintained task instructions for agents
| |-- common_mistakes.md # Project-specific pitfalls to avoid
| |-- overview.md # Current project status, structure, and file map
| |-- update.md # Latest finished task summary
| `-- updates.md # Historical task log, newest first
|-- public/
| |-- app.js # Landing-page script and service-worker registration
| |-- index.html # Landing page with proxy overview and links
| |-- styles.css # Landing-page styles
| |-- sw-register.js # Shared service-worker registration helper
| `-- sw.js # Offline cache and timed refresh logic
|-- public/chatclient/
| |-- app.js # Chat client controller, tabs, send flow, draft restore, and local state
| |-- draft.js # Browser-local draft persistence for compose input and link attachments
| |-- index.html # Tabbed chat client shell and settings/output panels
| |-- media.js # Attachment creation from uploads/links, previews, and payload conversion
| |-- preview.js # Large attachment preview overlay controller
| |-- render.js # Attachment list rendering, assistant rendering, and status/toast UI
| |-- richText.js # Safe rich-text rendering helpers for assistant output
| |-- settings.js # Browser-local chat client settings persistence
| `-- styles.css # Chat client workspace styles
|-- scripts/
| `-- build.mjs # Temp-folder build output script
|-- src/
| |-- app.js # Express app factory and error handling
| |-- config.js # Env loading and validation
| |-- server.js # Dependency wiring and server startup
| |-- controllers/
| | |-- chatController.js # Chat proxy request handling
| | `-- mediaController.js # Temporary media download handling
| |-- routes/
| | `-- apiRouter.js # `/v1` routes
| |-- services/
| | |-- audioConversionService.js # Audio URL download and mp3 conversion
| | |-- mediaStore.js # In-memory temporary media storage
| | |-- openAiService.js # Upstream OpenAI-compatible fetch client
| | |-- requestNormalizationService.js # Input media normalization
| | `-- responseNormalizationService.js # Output media normalization
| `-- utils/
| |-- dataUrl.js # Data URL and base64 helpers
| |-- httpError.js # HTTP error shape
| `-- mediaTypes.js # Audio/image MIME helpers
`-- test/
|-- requestNormalization.test.js # Request normalization tests
`-- responseNormalization.test.js# Response normalization tests
Main Commands
npm install
npm start
npm test
npm run build