| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>oapix chat client</title> |
| <link rel="stylesheet" href="/chatclient/styles.css"> |
| <script type="module" src="/chatclient/app.js"></script> |
| </head> |
| <body> |
| <main class="client-shell"> |
| <section class="workspace-card"> |
| <div class="top-bar"> |
| <div class="tab-strip" role="tablist" aria-label="Chat client tabs"> |
| <button class="tab-button is-active" type="button" role="tab" aria-selected="true" data-tab="compose"> |
| Compose |
| </button> |
| <button class="tab-button" type="button" role="tab" aria-selected="false" data-tab="output"> |
| Output |
| </button> |
| <button class="tab-button" type="button" role="tab" aria-selected="false" data-tab="raw"> |
| Raw Output |
| </button> |
| </div> |
| </div> |
| <p id="status-line" class="sr-only">Ready.</p> |
|
|
| <section class="tab-panel is-active" role="tabpanel" data-panel="compose"> |
| <article class="editor-card"> |
| <div class="editor-toolbar" aria-label="Text formatting tools"> |
| <button class="format-button" type="button" data-command="bold" aria-label="Bold text"> |
| <strong>B</strong> |
| </button> |
| <button class="format-button" type="button" data-command="italic" aria-label="Italic text"> |
| <em>I</em> |
| </button> |
| <button class="format-button" type="button" data-command="insertUnorderedList" aria-label="Bullet list"> |
| List |
| </button> |
| <button class="format-button" type="button" data-command="removeFormat" aria-label="Clear formatting"> |
| Clear |
| </button> |
| </div> |
|
|
| <div |
| id="editor" |
| class="rich-editor" |
| contenteditable="true" |
| spellcheck="true" |
| data-placeholder="Write the user message here. Use Ctrl+Enter to send." |
| ></div> |
| </article> |
|
|
| <div class="tool-row" aria-label="Request tools"> |
| <button id="settings-toggle" class="tool-button icon-button" type="button" aria-label="Open settings" title="Settings"> |
| <svg viewBox="0 0 24 24" aria-hidden="true"> |
| <path d="M12 8.5A3.5 3.5 0 1 0 12 15.5A3.5 3.5 0 1 0 12 8.5z"></path> |
| <path d="M19.4 13.5a7.5 7.5 0 0 0 .1-1.5a7.5 7.5 0 0 0-.1-1.5l2-1.6l-2-3.4l-2.4 1a7.9 7.9 0 0 0-2.6-1.5L14 2h-4l-.4 3a7.9 7.9 0 0 0-2.6 1.5l-2.4-1l-2 3.4l2 1.6A7.5 7.5 0 0 0 4.5 12a7.5 7.5 0 0 0 .1 1.5l-2 1.6l2 3.4l2.4-1a7.9 7.9 0 0 0 2.6 1.5l.4 3h4l.4-3a7.9 7.9 0 0 0 2.6-1.5l2.4 1l2-3.4z"></path> |
| </svg> |
| </button> |
|
|
| <button id="attachment-trigger" class="tool-button icon-button" type="button" aria-label="Add attachment" title="Add attachment"> |
| <svg viewBox="0 0 24 24" aria-hidden="true"> |
| <path d="M12 5v14"></path> |
| <path d="M5 12h14"></path> |
| </svg> |
| </button> |
|
|
| <button id="send-button" class="send-button icon-button" type="button" aria-label="Send message" title="Send"> |
| <svg viewBox="0 0 24 24" aria-hidden="true"> |
| <path d="M4 12l15-7l-3 7l3 7z"></path> |
| <path d="M10 12h9"></path> |
| </svg> |
| </button> |
|
|
| <input id="attachment-input" type="file" accept="image/*,audio/*" multiple hidden> |
| </div> |
|
|
| <section id="attachment-picker" class="attachment-picker" hidden> |
| <div class="section-head"> |
| <div> |
| <p class="eyebrow">Add Attachment</p> |
| <h3>Choose Source</h3> |
| </div> |
| <p class="section-copy">Use uploaded files or direct links for image and audio inputs.</p> |
| </div> |
|
|
| <div class="picker-mode-row" role="tablist" aria-label="Attachment source options"> |
| <button id="attachment-mode-upload" class="picker-mode-button is-active" type="button" data-mode="upload"> |
| Upload Files |
| </button> |
| <button id="attachment-mode-link" class="picker-mode-button" type="button" data-mode="link"> |
| File Link |
| </button> |
| </div> |
|
|
| <div id="attachment-picker-upload" class="picker-panel is-active"> |
| <p class="picker-copy">Click <strong>Upload Files</strong> above to open the system picker immediately.</p> |
| </div> |
|
|
| <div id="attachment-picker-link" class="picker-panel" hidden> |
| <div class="picker-grid"> |
| <label> |
| <span>Type</span> |
| <select id="attachment-link-type"> |
| <option value="image">Image</option> |
| <option value="audio">Audio</option> |
| </select> |
| </label> |
|
|
| <label class="picker-link-field"> |
| <span>File Link</span> |
| <input id="attachment-link-url" type="url" placeholder="https://example.com/file"> |
| </label> |
| </div> |
|
|
| <button id="attachment-link-add" class="picker-action-button" type="button">Add Link</button> |
| </div> |
| </section> |
|
|
| <section class="attachments-card" aria-labelledby="attachments-heading"> |
| <div class="section-head"> |
| <div> |
| <p class="eyebrow">Attachments</p> |
| <h3 id="attachments-heading">Image and Audio Attachments</h3> |
| </div> |
| <p id="attachment-summary" class="section-copy">No files added.</p> |
| </div> |
| <div id="attachment-list" class="attachment-list"> |
| <p class="empty-state">Add an image or audio file or link to include it with the next request.</p> |
| </div> |
| </section> |
|
|
| <section id="settings-panel" class="settings-panel" hidden> |
| <div class="section-head"> |
| <div> |
| <p class="eyebrow">Settings</p> |
| <h3>Request Options</h3> |
| </div> |
| <p class="section-copy">Endpoint and prompt settings stay local in this browser.</p> |
| </div> |
|
|
| <div class="settings-grid"> |
| <label> |
| <span>Endpoint</span> |
| <input id="endpoint" name="endpoint" type="url"> |
| </label> |
|
|
| <label> |
| <span>Model</span> |
| <input id="model" name="model" type="text" value="gpt-4.1-mini" required> |
| </label> |
|
|
| <label class="settings-wide"> |
| <span>System Prompt</span> |
| <textarea id="system-prompt" name="systemPrompt" rows="4" placeholder="Optional system prompt"></textarea> |
| </label> |
|
|
| <label class="toggle-card"> |
| <span>Audio Output</span> |
| <input id="audio-output" name="audioOutput" type="checkbox" checked> |
| </label> |
|
|
| <label> |
| <span>Voice</span> |
| <select id="voice" name="voice"> |
| <option value="alloy">alloy</option> |
| <option value="ash">ash</option> |
| <option value="ballad">ballad</option> |
| <option value="coral">coral</option> |
| <option value="sage">sage</option> |
| <option value="verse">verse</option> |
| </select> |
| </label> |
| </div> |
| </section> |
| </section> |
|
|
| <section class="tab-panel" role="tabpanel" data-panel="output" hidden> |
| <article class="output-card"> |
| <div class="section-head"> |
| <div> |
| <p class="eyebrow">Assistant Output</p> |
| <h3>Rich Text Page</h3> |
| </div> |
| <p class="section-copy">Rendered response, returned images, and returned audio live here.</p> |
| </div> |
| <div id="response-output" class="response-output"> |
| <p class="empty-state">Send a request to open the assistant response view.</p> |
| </div> |
| </article> |
| </section> |
|
|
| <section class="tab-panel" role="tabpanel" data-panel="raw" hidden> |
| <article class="output-card"> |
| <div class="section-head"> |
| <div> |
| <p class="eyebrow">Debug</p> |
| <h3>Raw Response</h3> |
| </div> |
| <button id="raw-copy-button" class="secondary-button" type="button">Copy Raw</button> |
| </div> |
| <p class="section-copy">This tab shows the exact JSON returned by the proxy.</p> |
| <pre id="raw-json" class="raw-output">{}</pre> |
| </article> |
| </section> |
| </section> |
| </main> |
|
|
| <section id="attachment-preview" class="attachment-preview" hidden> |
| <div class="attachment-preview__backdrop" data-close-preview></div> |
| <article class="attachment-preview__card" role="dialog" aria-modal="true" aria-labelledby="attachment-preview-title"> |
| <div class="attachment-preview__head"> |
| <div> |
| <p class="eyebrow">Attachment Preview</p> |
| <h3 id="attachment-preview-title">Preview</h3> |
| </div> |
| <button id="attachment-preview-close" class="attachment-preview__close" type="button" aria-label="Close preview"> |
| x |
| </button> |
| </div> |
| <div id="attachment-preview-body" class="attachment-preview__body"></div> |
| </article> |
| </section> |
|
|
| <button id="error-toast" class="error-toast" type="button" hidden></button> |
| </body> |
| </html> |
|
|