Analyze Image

Creates an image analysis task via the Nextcloud OCS Task Processing API and gives the completed result

Script nextcloud Verified

by nextcloud ยท 3/18/2026

The script

Submitted by nextcloud Bun
Verified 57 days ago
1
import createClient, { type Middleware } from "openapi-fetch";
2

3
const TASK_TYPE_ANALYZE_IMAGES = "core:analyze-images";
4
const POLL_INTERVAL_MS = 1000;
5
const DEFAULT_POLL_TIMEOUT_MS = 600_000; // 10 minutes (ensure one cron job finished)
6

7
/**
8
 * Creates an image analysis task via the Nextcloud OCS Task Processing API,
9
 * polls until the task completes, and returns the analysis text.
10
 */
11
export async function main(
12
  ncResource: RT.Nextcloud,
13
  prompt: string,
14
  imageFileIds: number | string | Array<number | string>,
15
  model: string | null = null,
16
  timeout_ms: number = DEFAULT_POLL_TIMEOUT_MS,
17
  interval_ms: number = POLL_INTERVAL_MS,
18
) {
19
  if (timeout_ms < 1) {
20
    timeout_ms = DEFAULT_POLL_TIMEOUT_MS;
21
  }
22
  if (interval_ms < 1) {
23
    interval_ms = POLL_INTERVAL_MS;
24
  }
25
  if (!Array.isArray(imageFileIds)) {
26
    imageFileIds = [imageFileIds];
27
  }
28
  if (imageFileIds.length < 1) {
29
    throw new Error("imageFileIds must be a non-empty array of Nextcloud file IDs");
30
  }
31

32
  const client = createClient({ baseUrl: ncResource.baseUrl }) as any;
33
  const authMiddleware: Middleware = {
34
    async onRequest({ request }) {
35
      request.headers.set(
36
        "Authorization",
37
        `Basic ${btoa(ncResource.userId + ":" + ncResource.token)}`,
38
      );
39
      return request;
40
    },
41
  };
42
  client.use(authMiddleware);
43

44
  // Schedule the image analysis task
45
  const { data: scheduleData, error: scheduleError } = await client.POST(
46
    "/ocs/v2.php/taskprocessing/schedule",
47
    {
48
      params: {
49
        header: {
50
          "OCS-APIRequest": true,
51
        },
52
        query: {
53
          format: "json",
54
        },
55
      },
56
      body: {
57
        type: TASK_TYPE_ANALYZE_IMAGES,
58
        input: {
59
          model: model,
60
          input: prompt,
61
          images: imageFileIds,
62
        },
63
        appId: "windmill",
64
      },
65
    },
66
  );
67

68
  if (scheduleError) {
69
    throw new Error(
70
      `Failed to schedule image analysis task: ${JSON.stringify(scheduleError)}`,
71
    );
72
  }
73
  const taskId = scheduleData?.ocs?.data?.task?.id;
74

75
  // Polls every interval until timeout or a result happens
76
  const deadline = Date.now() + timeout_ms;
77
  while (Date.now() < deadline) {
78
    console.log("Polling task output");
79
    const { data: taskData, error: taskError } = await client.GET(
80
      "/ocs/v2.php/taskprocessing/task/{id}",
81
      {
82
        params: {
83
          header: {
84
            "OCS-APIRequest": true,
85
          },
86
          query: {
87
            format: "json",
88
          },
89
          path: {
90
            id: taskId,
91
          },
92
        },
93
      },
94
    );
95

96
    if (taskError) {
97
      throw new Error(`Failed to get task ${taskId}: ${JSON.stringify(taskError)}`);
98
    }
99
    const task = taskData.ocs?.data?.task;
100
    const status = task.status;
101

102
    if (status === "STATUS_SUCCESSFUL") {
103
      const output = task.output;
104
      if (output && typeof output.output === "string") {
105
        return { analysisText: output.output, taskId };
106
      }
107
      return { analysisText: output, taskId };
108
    }
109

110
    if (status === "STATUS_FAILED" || status === "STATUS_CANCELLED") {
111
      const msg = JSON.stringify(task);
112
      throw new Error(`Image analysis task failed: ${msg}`);
113
    }
114
    if (!["STATUS_SCHEDULED", "STATUS_RUNNING"].includes(status)) {
115
      const msg = JSON.stringify(task);
116
      throw new Error(`Image analysis task failed with unknown status: ${msg}`);
117
    }
118
    await new Promise((r) => setTimeout(r, interval_ms));
119
  }
120

121
  throw new Error(
122
    `Image analysis task did not complete within ${timeout_ms}ms (taskId: ${taskId})`,
123
  );
124
}
125

126