From 292e53c9c76d4e02efa4990b5d62868a197d39c7 Mon Sep 17 00:00:00 2001 From: Ku6epXBOCTuK Date: Thu, 10 Sep 2026 08:21:20 +0500 Subject: [PATCH] feat: update tools types --- web/src/lib/i18n/en.ts | 2 + web/src/lib/i18n/ru.ts | 2 + web/src/lib/registry-new/types.ts | 89 ++++++++++++++++++++++++++----- 3 files changed, 80 insertions(+), 13 deletions(-) diff --git a/web/src/lib/i18n/en.ts b/web/src/lib/i18n/en.ts index 1d25e42..cb9dbf3 100644 --- a/web/src/lib/i18n/en.ts +++ b/web/src/lib/i18n/en.ts @@ -112,6 +112,8 @@ export const en: Dict = { }, errors: { noImageRun: "This tool does not process images", + sourceRequired: "Upload an image first", + textRequired: "Enter text first", workerFailed: "Worker execution failed", workerUnavailable: "Worker is unavailable", notFound: "Tool not found", diff --git a/web/src/lib/i18n/ru.ts b/web/src/lib/i18n/ru.ts index 5d12f55..35e05f8 100644 --- a/web/src/lib/i18n/ru.ts +++ b/web/src/lib/i18n/ru.ts @@ -113,6 +113,8 @@ export const ru: Dict = { }, errors: { noImageRun: "Этот инструмент не обрабатывает изображения", + sourceRequired: "Сначала загрузите изображение", + textRequired: "Сначала введите текст", workerFailed: "Ошибка исполнения в воркере", workerUnavailable: "Воркер недоступен", notFound: "Инструмент не найден", diff --git a/web/src/lib/registry-new/types.ts b/web/src/lib/registry-new/types.ts index 4b5b6f4..c041568 100644 --- a/web/src/lib/registry-new/types.ts +++ b/web/src/lib/registry-new/types.ts @@ -2,6 +2,7 @@ import type { CategoryId } from "../preview/categories"; import type { ToolSchema } from "../registry-schema"; import type { PixelImage } from "../core/types"; import type { OutputMime } from "../core/io"; +import { ToolError } from "../core/errors"; /** Формат скачивания, отличный от PNG (bmp/jpeg/webp). */ export interface OutputFormat { @@ -10,10 +11,37 @@ export interface OutputFormat { qualityParamId?: string; } +/** Чем управляется инструмент. `image` — требуется входное изображение. */ +export const INPUT_MODES = { + image: "image", + text: "text", + none: "none", +} as const; +export type InputMode = (typeof INPUT_MODES)[keyof typeof INPUT_MODES]; + +/** Тип результата: картинка (по умолчанию), большой текст или короткий вердикт. */ +export const RESULT_KINDS = { + image: "image", + text: "text", + verdict: "verdict", +} as const; +export type ResultKind = (typeof RESULT_KINDS)[keyof typeof RESULT_KINDS]; + +/** Единый вход инструмента. `source`/`text` присутствуют строго по `input`. */ +export interface ToolContext

{ + params: P; + source?: PixelImage; + text?: string; +} + +export type ToolResult = PixelImage | string; + /** * Инструмент нового registry: полностью типизирован на `Params`, схема — - * обязательна (единый источник дефолтов/валидации/UI). Старого `ParamDef[]` - * нет — это отдельная система от старого UI. + * обязательна (единый источник дефолтов/валидации/UI). У каждого инструмента + * ровно один метод `run(ctx)`; контракт входа декларируется через `input` + * (обязательное поле), а результат — через `result`. Отдельных методов + * `generate`/`runFromText`/`toText`/`textToText` нет. */ export type ToolEntry

> = { id: string; @@ -21,20 +49,55 @@ export type ToolEntry

> = { description: string; category: CategoryId; schema: ToolSchema

; + /** Чем управляется инструмент: входным изображением, текстом или ничем. */ + input: InputMode; + /** Тип результата: картинка (по умолчанию), большой текст или короткий вердикт. */ + result?: ResultKind; + /** Единственный метод исполнения — и для генераторов, и для трансформаторов. */ + run(ctx: ToolContext

): Promise | ToolResult; /** Требует DOM (canvas/document); превью-executor запускает напрямую, не в worker. */ domOnly?: boolean; - /** Чем управляется инструмент: файлом (по умолчанию), текстом или ничем (генератор). */ - input?: "file" | "text" | "none"; - /** Тип результата: картинка (по умолчанию), большой текст или короткий вердикт. */ - result?: "image" | "text" | "verdict"; - /** Применение к входному изображению. Для чистых генераторов отсутствует. */ - run?(img: PixelImage, params: P): Promise | PixelImage; - generate?(params: P): Promise | PixelImage; - toText?(img: PixelImage, params: P): Promise | string; - runFromText?(text: string, params: P): Promise | PixelImage; - textToText?(text: string): Promise | string; - preview?(img: PixelImage, params: P): Promise | PixelImage; /** Формат/качество скачивания результата; по умолчанию — PNG. */ output?: OutputFormat; icon?: string; }; + +/** Гарантирует наличие входного изображения для трансформаторов. */ +export function requireSource

(ctx: ToolContext

): PixelImage { + if (!ctx.source) { + throw new ToolError("errors.sourceRequired"); + } + return ctx.source; +} + +/** Гарантирует наличие текстового входа для text-инструментов. */ +export function requireText

(ctx: ToolContext

): string { + if (!ctx.text?.trim()) { + throw new ToolError("errors.textRequired"); + } + return ctx.text; +} + +/** + * Обёртка для image-to-image инструментов: подставляет `src` и `params` + * из контекста. Позволяет оставить тело инструмента в виде `(img, p) => …`. + */ +export function imgTool

( + fn: (img: PixelImage, params: P) => ToolResult, +): (ctx: ToolContext

) => ToolResult { + return (ctx) => fn(requireSource(ctx), ctx.params); +} + +/** Обёртка для генераторов: инструменту нужны только параметры. */ +export function genTool

( + fn: (params: P) => ToolResult, +): (ctx: ToolContext

) => ToolResult { + return (ctx) => fn(ctx.params); +} + +/** Обёртка для text-to-image инструментов: подставляет `text` и `params`. */ +export function textGen

( + fn: (text: string, params: P) => ToolResult, +): (ctx: ToolContext

) => ToolResult { + return (ctx) => fn(requireText(ctx), ctx.params); +} \ No newline at end of file