Translate Text
One script reply has been approved by the moderators Verified

Creates a translation task via the Nextcloud OCS Task Processing API, polls until task completes, and returns the translated text.

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

3
type Nextcloud = {
4
  baseUrl: string,
5
  userId: string,
6
  token: string
7
};
8

9
const TASK_TYPE_TRANSLATE = "core:text2text:translate";
10
const POLL_INTERVAL_MS = 1000;
11
const DEFAULT_POLL_TIMEOUT_MS = 600_000; // 10 minutes (ensure one cron job finished)
12

13
/**
14
 * Creates a translation task via the Nextcloud OCS Task Processing API,
15
 * polls until the task completes, and returns the translated text.
16
 */
17
export async function main(
18
  ncResource: Nextcloud,
19
  text: string,
20
  targetLanguage: string,
21
  originLanguage: string | null = null,
22
  model: string | null = null,
23
  timeout_ms: number = DEFAULT_POLL_TIMEOUT_MS,
24
  interval_ms: number = POLL_INTERVAL_MS,
25
) {
26
  const client = createClient({ baseUrl: ncResource.baseUrl }) as any;
27
  const authMiddleware: Middleware = {
28
    async onRequest({ request, options }) {
29
      request.headers.set("Authorization", `Basic ${btoa(ncResource.userId + ':' + ncResource.token)}`);
30
      return request;
31
    },
32
  };
33
  client.use(authMiddleware);
34

35
  const input: Record<string, string> = {
36
    input: text,
37
    target_language: targetLanguage,
38
  };
39
  if (originLanguage !== null && originLanguage !== "") {
40
    input.origin_language = originLanguage;
41
  }
42
  if (model !== null && model !== "") {
43
    input.model = model
44
  }
45

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

66
  if (scheduleError) {
67
    throw new Error(`Failed to schedule translation task: ${JSON.stringify(scheduleError)}`);
68
  }
69
  const taskId = scheduleData?.ocs?.data?.task?.id;
70

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

92
    if (taskError) {
93
      throw new Error(`Failed to get task ${taskId}: ${JSON.stringify(taskError)}`);
94
    }
95
    const task = taskData.ocs?.data?.task;
96
    const status = task.status;
97

98
    if (status === "STATUS_SUCCESSFUL") {
99
      const output = task.output;
100
      if (output && typeof output.output === "string") {
101
        return { translatedText: output.output, taskId };
102
      }
103
      return { translatedText: output, taskId };
104
    }
105

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

117
  throw new Error(
118
    `Translation task did not complete within ${timeout_ms}ms (taskId: ${taskId})`,
119
  );
120
}
121