bsky-alt-text-worker/src/endpoints/condense_text.ts

107 lines
2.5 KiB
TypeScript

import { Enumeration, Num, OpenAPIRoute } from "chanfana";
import { z } from "zod";
import { type AppContext } from "../types";
export class CondenseTextEndpoint extends OpenAPIRoute {
schema = {
tags: ["Processing"],
summary: "Condense a given text based on a directive",
security: [
{
apiKey: [],
},
],
request: {
body: {
content: {
"application/json": {
schema: z.object({
text: z.string({
description: "The text to be condensed.",
required_error:
"Text is required for condensation.",
}).min(1, "Text cannot be empty."),
mediaType: z.enum(["video", "image"], {
description:
"The type of media being described",
required_error: "Media type is required.",
}),
}),
},
},
},
},
responses: {
"200": {
description: "Returns the condensed text",
content: {
"application/json": {
schema: z.object({
success: z.boolean(),
condensedText: z.string().nullable(),
error: z.string().optional(),
}),
},
},
},
"500": {
description:
"Internal Server Error - Issue with Cloud Function or API call",
content: {
"application/json": {
schema: z.object({
success: z.boolean(),
message: z.string(),
}),
},
},
},
},
};
async handle(c: AppContext) {
const data = await this.getValidatedData<typeof this.schema>();
const { text, mediaType } = data.body;
const targetLength = c.env.MAX_ALT_TEXT_LENGTH - 100;
try {
const res = await c.var.gemini.models.generateContent({
// * Original cloud function used "gemini-2.0-flash", but I think the lite version should work fine too.
model: "gemini-2.0-flash-lite",
contents: [{
parts: [
{
text:
`You are an expert at writing concise, informative alt text. Please condense the following ${mediaType} description to be no more than ${targetLength} characters while preserving the most important details. The description needs to be accessible and useful for screen readers:`,
},
{ text: text },
],
}],
config: {
temperature: 0.2,
maxOutputTokens: 1024,
},
});
const condensedText = res.candidates?.[0]?.content?.parts?.[0]
?.text;
if (!condensedText) {
return {
success: false,
error: "Failed to condense text.",
};
}
return {
success: true,
altText: condensedText,
};
} catch (e) {
return {
success: false,
message: e,
};
}
}
}