Skip to content

Commit 42f9d44

Browse files
authored
Merge pull request #57 from 10play/wait-for-image
Wait for image
2 parents d2db8bf + 0b3b6a3 commit 42f9d44

File tree

2 files changed

+54
-4
lines changed

2 files changed

+54
-4
lines changed

widget/hooks/useWebSocketMessages.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -259,8 +259,7 @@ export function useWebSocketMessages({ serverUrl, onGitMessage }: UseWebSocketMe
259259
currentPromptIdRef.current = null;
260260
setCurrentParts([]);
261261

262-
// Send prompt immediately with local file paths
263-
// The server runs on the same machine and can read simulator temp files directly
262+
// Upload images to the server first, then send the prompt with server-side paths
264263
const imagePaths = images && images.length > 0
265264
? images.map((img) => img.uri)
266265
: undefined;

widget/services/websocket.ts

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,7 @@ export class WebSocketClient {
351351
this.setStatus("disconnected");
352352
}
353353

354-
sendPrompt(content: string, imagePaths?: string[]): void {
354+
async sendPrompt(content: string, imagePaths?: string[]): Promise<void> {
355355
if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
356356
this.options.onError(new Error("Not connected"));
357357
return;
@@ -364,13 +364,64 @@ export class WebSocketClient {
364364
};
365365

366366
if (imagePaths && imagePaths.length > 0) {
367-
message.imagePaths = imagePaths;
367+
try {
368+
console.log("[expo-air] Uploading", imagePaths.length, "image(s) to:", this.getUploadUrl());
369+
const serverPaths = await this.uploadImages(imagePaths);
370+
console.log("[expo-air] Upload returned paths:", serverPaths);
371+
if (serverPaths.length > 0) {
372+
message.imagePaths = serverPaths;
373+
}
374+
} catch (error) {
375+
console.error("[expo-air] Image upload failed:", error);
376+
}
368377
}
369378

370379
this.ws.send(JSON.stringify(message));
371380
this.setStatus("sending");
372381
}
373382

383+
private getUploadUrl(): string {
384+
let url = this.options.url;
385+
// ws:// → http://, wss:// → https://
386+
if (url.startsWith("wss://")) url = "https://" + url.slice(6);
387+
else if (url.startsWith("ws://")) url = "http://" + url.slice(5);
388+
// Insert /upload before the query string
389+
const qIndex = url.indexOf("?");
390+
if (qIndex >= 0) {
391+
return url.slice(0, qIndex) + "/upload" + url.slice(qIndex);
392+
}
393+
return url + "/upload";
394+
}
395+
396+
private async uploadImages(localPaths: string[]): Promise<string[]> {
397+
const uploadUrl = this.getUploadUrl();
398+
399+
const formData = new FormData();
400+
for (const path of localPaths) {
401+
const uri = path.startsWith("file://") ? path : `file://${path}`;
402+
const ext = path.split(".").pop()?.toLowerCase() || "jpg";
403+
const mimeType = ext === "png" ? "image/png" : "image/jpeg";
404+
formData.append("images", {
405+
uri,
406+
type: mimeType,
407+
name: `image.${ext}`,
408+
} as unknown as Blob);
409+
}
410+
411+
const response = await fetch(uploadUrl, {
412+
method: "POST",
413+
body: formData,
414+
});
415+
416+
if (!response.ok) {
417+
const text = await response.text().catch(() => "");
418+
throw new Error(`Upload failed: ${response.status} ${text}`);
419+
}
420+
421+
const result = await response.json();
422+
return result.paths || [];
423+
}
424+
374425
requestNewSession(): void {
375426
if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
376427
this.options.onError(new Error("Not connected"));

0 commit comments

Comments
 (0)