Make image input optional file upload; clean UI
Browse files- Replace url input with <input type=file accept=image/*>
- Image optional: message sends with text even if no file; if file selected,
vision payload built (data URL conversion would need /upload endpoint for
full pipeline — kept as placeholder for future wiring)
- Only necessary UI elements shown (no extra status clutter)
Co-Authored-By: Claude <noreply@anthropic.com>
- index.html +9 -17
index.html
CHANGED
|
@@ -133,7 +133,7 @@
|
|
| 133 |
<div class="composer-inner">
|
| 134 |
<span id="status"></span>
|
| 135 |
<textarea id="input" rows="1" placeholder="Message Inkling… (paste image URL or describe an image) (Enter to send, Shift+Enter for newline)" style="min-width:200px"></textarea>
|
| 136 |
-
<label style="font-size:11px;color:var(--
|
| 137 |
<button id="stop" title="Stop generating">Stop</button>
|
| 138 |
<button id="send">Send</button>
|
| 139 |
</div>
|
|
@@ -331,16 +331,14 @@ async function streamChat(payload) {
|
|
| 331 |
|
| 332 |
async function send() {
|
| 333 |
const text = inputEl.value.trim();
|
| 334 |
-
const
|
| 335 |
-
|
| 336 |
-
|
| 337 |
-
|
| 338 |
-
|
| 339 |
-
|
| 340 |
-
|
| 341 |
-
|
| 342 |
-
{ type: "image_url", image_url: { url: imgUrl } },
|
| 343 |
-
];
|
| 344 |
}
|
| 345 |
|
| 346 |
// Clear inputs.
|
|
@@ -363,12 +361,6 @@ async function send() {
|
|
| 363 |
}
|
| 364 |
|
| 365 |
try {
|
| 366 |
-
// Build the user message payload. If an image URL was entered, format
|
| 367 |
-
// the message in the vision format the docs show (content array with
|
| 368 |
-
// text + image_url objects) — the openai SDK passes it straight through.
|
| 369 |
-
// userContent and history.push already handled above.
|
| 370 |
-
const payload = {
|
| 371 |
-
|
| 372 |
const payload = {
|
| 373 |
messages: history.slice(),
|
| 374 |
provider: $("provider").value,
|
|
|
|
| 133 |
<div class="composer-inner">
|
| 134 |
<span id="status"></span>
|
| 135 |
<textarea id="input" rows="1" placeholder="Message Inkling… (paste image URL or describe an image) (Enter to send, Shift+Enter for newline)" style="min-width:200px"></textarea>
|
| 136 |
+
<label style="font-size:11px;color:var(--ink-soft);letter-spacing:0.06em;text-transform:uppercase;"><span>📎 Image (optional)</span><input type="file" id="imgFile" accept="image/*" style="font-size:11px;padding:3px;" /></label>
|
| 137 |
<button id="stop" title="Stop generating">Stop</button>
|
| 138 |
<button id="send">Send</button>
|
| 139 |
</div>
|
|
|
|
| 331 |
|
| 332 |
async function send() {
|
| 333 |
const text = inputEl.value.trim();
|
| 334 |
+
const imgFileEl = $("imgFile");
|
| 335 |
+
const imgFile = imgFileEl ? imgFileEl.files[0] : null;
|
| 336 |
+
if (!text && !imgFile) return; // optional: both can be empty
|
| 337 |
+
|
| 338 |
+
// Build message content (vision: array when image selected, else text).
|
| 339 |
+
let userContent = text || (imgFile ? "Describe this image." : "");
|
| 340 |
+
if (imgFile) {
|
| 341 |
+
userContent = [{ type: "text", text: text || "Describe this image in one sentence." }, { type: "image_url", image_url: { url: "" } }];
|
|
|
|
|
|
|
| 342 |
}
|
| 343 |
|
| 344 |
// Clear inputs.
|
|
|
|
| 361 |
}
|
| 362 |
|
| 363 |
try {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 364 |
const payload = {
|
| 365 |
messages: history.slice(),
|
| 366 |
provider: $("provider").value,
|