feat(modality)!: SnapOtter 2.0 phase 3 modality framework: media/doc engines, pool routing, display modes (#218)

This commit is contained in:
SnapOtter
2026-06-13 10:18:39 +08:00
parent c451b939c7
commit d647d8ed19
99 changed files with 4380 additions and 1813 deletions
+160
View File
@@ -1,3 +1,4 @@
import { IMAGE_INPUTS } from "./modality.js";
import type { CategoryInfo, SocialMediaPreset, Tool } from "./types.js";
export const CATEGORIES: CategoryInfo[] = [
@@ -20,6 +21,9 @@ export const TOOLS: Tool[] = [
category: "essentials",
icon: "Maximize2",
route: "/resize",
modality: "image",
acceptedInputs: IMAGE_INPUTS,
executionHint: "fast",
},
{
id: "crop",
@@ -28,6 +32,9 @@ export const TOOLS: Tool[] = [
category: "essentials",
icon: "Crop",
route: "/crop",
modality: "image",
acceptedInputs: IMAGE_INPUTS,
executionHint: "fast",
},
{
id: "rotate",
@@ -36,6 +43,9 @@ export const TOOLS: Tool[] = [
category: "essentials",
icon: "RotateCw",
route: "/rotate",
modality: "image",
acceptedInputs: IMAGE_INPUTS,
executionHint: "fast",
},
{
id: "convert",
@@ -44,6 +54,9 @@ export const TOOLS: Tool[] = [
category: "essentials",
icon: "FileOutput",
route: "/convert",
modality: "image",
acceptedInputs: IMAGE_INPUTS,
executionHint: "fast",
},
{
id: "compress",
@@ -52,6 +65,9 @@ export const TOOLS: Tool[] = [
category: "essentials",
icon: "Minimize2",
route: "/compress",
modality: "image",
acceptedInputs: IMAGE_INPUTS,
executionHint: "fast",
},
// Optimization
{
@@ -62,6 +78,9 @@ export const TOOLS: Tool[] = [
category: "optimization",
icon: "Globe",
route: "/optimize-for-web",
modality: "image",
acceptedInputs: IMAGE_INPUTS,
executionHint: "fast",
},
{
id: "strip-metadata",
@@ -70,6 +89,9 @@ export const TOOLS: Tool[] = [
category: "optimization",
icon: "ShieldOff",
route: "/strip-metadata",
modality: "image",
acceptedInputs: IMAGE_INPUTS,
executionHint: "fast",
},
{
id: "edit-metadata",
@@ -78,6 +100,9 @@ export const TOOLS: Tool[] = [
category: "optimization",
icon: "PenLine",
route: "/edit-metadata",
modality: "image",
acceptedInputs: IMAGE_INPUTS,
executionHint: "fast",
},
{
id: "bulk-rename",
@@ -86,6 +111,9 @@ export const TOOLS: Tool[] = [
category: "optimization",
icon: "FilePen",
route: "/bulk-rename",
modality: "image",
acceptedInputs: IMAGE_INPUTS,
executionHint: "fast",
},
{
id: "image-to-pdf",
@@ -94,6 +122,9 @@ export const TOOLS: Tool[] = [
category: "optimization",
icon: "FileText",
route: "/image-to-pdf",
modality: "image",
acceptedInputs: IMAGE_INPUTS,
executionHint: "fast",
},
{
id: "favicon",
@@ -102,6 +133,9 @@ export const TOOLS: Tool[] = [
category: "optimization",
icon: "AppWindow",
route: "/favicon",
modality: "image",
acceptedInputs: IMAGE_INPUTS,
executionHint: "fast",
},
// Adjustments
{
@@ -111,6 +145,9 @@ export const TOOLS: Tool[] = [
category: "adjustments",
icon: "SlidersHorizontal",
route: "/adjust-colors",
modality: "image",
acceptedInputs: IMAGE_INPUTS,
executionHint: "fast",
},
{
id: "sharpening",
@@ -119,6 +156,9 @@ export const TOOLS: Tool[] = [
category: "adjustments",
icon: "Focus",
route: "/sharpening",
modality: "image",
acceptedInputs: IMAGE_INPUTS,
executionHint: "fast",
},
{
id: "replace-color",
@@ -127,6 +167,9 @@ export const TOOLS: Tool[] = [
category: "adjustments",
icon: "Pipette",
route: "/replace-color",
modality: "image",
acceptedInputs: IMAGE_INPUTS,
executionHint: "fast",
},
{
id: "color-blindness",
@@ -135,6 +178,9 @@ export const TOOLS: Tool[] = [
category: "adjustments",
icon: "Eye",
route: "/color-blindness",
modality: "image",
acceptedInputs: IMAGE_INPUTS,
executionHint: "fast",
},
// AI Tools
{
@@ -144,6 +190,9 @@ export const TOOLS: Tool[] = [
category: "ai",
icon: "Eraser",
route: "/remove-background",
modality: "image",
acceptedInputs: IMAGE_INPUTS,
executionHint: "long",
},
{
id: "upscale",
@@ -152,6 +201,9 @@ export const TOOLS: Tool[] = [
category: "ai",
icon: "ZoomIn",
route: "/upscale",
modality: "image",
acceptedInputs: IMAGE_INPUTS,
executionHint: "long",
},
{
id: "erase-object",
@@ -160,6 +212,9 @@ export const TOOLS: Tool[] = [
category: "ai",
icon: "Wand",
route: "/erase-object",
modality: "image",
acceptedInputs: IMAGE_INPUTS,
executionHint: "long",
},
{
id: "ocr",
@@ -168,6 +223,9 @@ export const TOOLS: Tool[] = [
category: "ai",
icon: "ScanText",
route: "/ocr",
modality: "image",
acceptedInputs: IMAGE_INPUTS,
executionHint: "long",
},
{
id: "blur-faces",
@@ -176,6 +234,9 @@ export const TOOLS: Tool[] = [
category: "ai",
icon: "EyeOff",
route: "/blur-faces",
modality: "image",
acceptedInputs: IMAGE_INPUTS,
executionHint: "long",
},
{
id: "smart-crop",
@@ -184,6 +245,9 @@ export const TOOLS: Tool[] = [
category: "ai",
icon: "Crosshair",
route: "/smart-crop",
modality: "image",
acceptedInputs: IMAGE_INPUTS,
executionHint: "long",
},
{
id: "image-enhancement",
@@ -192,6 +256,9 @@ export const TOOLS: Tool[] = [
category: "ai",
icon: "Sparkles",
route: "/image-enhancement",
modality: "image",
acceptedInputs: IMAGE_INPUTS,
executionHint: "fast", // pure sharp/CV; optional deepEnhance defers to noise-removal
},
{
id: "enhance-faces",
@@ -200,6 +267,9 @@ export const TOOLS: Tool[] = [
category: "ai",
icon: "ScanFace",
route: "/enhance-faces",
modality: "image",
acceptedInputs: IMAGE_INPUTS,
executionHint: "long",
},
{
id: "colorize",
@@ -208,6 +278,9 @@ export const TOOLS: Tool[] = [
category: "ai",
icon: "Palette",
route: "/colorize",
modality: "image",
acceptedInputs: IMAGE_INPUTS,
executionHint: "long",
},
{
id: "noise-removal",
@@ -216,6 +289,9 @@ export const TOOLS: Tool[] = [
category: "ai",
icon: "AudioLines",
route: "/noise-removal",
modality: "image",
acceptedInputs: IMAGE_INPUTS,
executionHint: "long",
},
{
id: "red-eye-removal",
@@ -224,6 +300,9 @@ export const TOOLS: Tool[] = [
category: "ai",
icon: "ScanEye",
route: "/red-eye-removal",
modality: "image",
acceptedInputs: IMAGE_INPUTS,
executionHint: "long",
},
{
id: "restore-photo",
@@ -232,6 +311,9 @@ export const TOOLS: Tool[] = [
category: "ai",
icon: "Undo2",
route: "/restore-photo",
modality: "image",
acceptedInputs: IMAGE_INPUTS,
executionHint: "long",
},
{
id: "passport-photo",
@@ -240,6 +322,9 @@ export const TOOLS: Tool[] = [
category: "ai",
icon: "UserCheck",
route: "/passport-photo",
modality: "image",
acceptedInputs: IMAGE_INPUTS,
executionHint: "long",
},
{
id: "content-aware-resize",
@@ -248,6 +333,9 @@ export const TOOLS: Tool[] = [
category: "ai",
icon: "Scaling",
route: "/content-aware-resize",
modality: "image",
acceptedInputs: IMAGE_INPUTS,
executionHint: "long",
},
{
id: "ai-canvas-expand",
@@ -256,6 +344,9 @@ export const TOOLS: Tool[] = [
category: "ai",
icon: "Expand",
route: "/ai-canvas-expand",
modality: "image",
acceptedInputs: IMAGE_INPUTS,
executionHint: "long",
},
{
id: "transparency-fixer",
@@ -264,6 +355,9 @@ export const TOOLS: Tool[] = [
category: "ai",
icon: "ShieldCheck",
route: "/transparency-fixer",
modality: "image",
acceptedInputs: IMAGE_INPUTS,
executionHint: "long",
},
// Watermark & Overlay
{
@@ -273,6 +367,9 @@ export const TOOLS: Tool[] = [
category: "watermark",
icon: "Type",
route: "/watermark-text",
modality: "image",
acceptedInputs: IMAGE_INPUTS,
executionHint: "fast",
},
{
id: "watermark-image",
@@ -281,6 +378,9 @@ export const TOOLS: Tool[] = [
category: "watermark",
icon: "Image",
route: "/watermark-image",
modality: "image",
acceptedInputs: IMAGE_INPUTS,
executionHint: "fast",
},
{
id: "text-overlay",
@@ -289,6 +389,9 @@ export const TOOLS: Tool[] = [
category: "watermark",
icon: "TextCursorInput",
route: "/text-overlay",
modality: "image",
acceptedInputs: IMAGE_INPUTS,
executionHint: "fast",
},
{
id: "compose",
@@ -297,6 +400,9 @@ export const TOOLS: Tool[] = [
category: "watermark",
icon: "Layers",
route: "/compose",
modality: "image",
acceptedInputs: IMAGE_INPUTS,
executionHint: "fast",
},
{
id: "meme-generator",
@@ -305,6 +411,9 @@ export const TOOLS: Tool[] = [
category: "watermark",
icon: "Laugh",
route: "/meme-generator",
modality: "image",
acceptedInputs: IMAGE_INPUTS,
executionHint: "fast",
},
// Utilities
{
@@ -314,6 +423,9 @@ export const TOOLS: Tool[] = [
category: "utilities",
icon: "Info",
route: "/info",
modality: "image",
acceptedInputs: IMAGE_INPUTS,
executionHint: "fast",
},
{
id: "compare",
@@ -322,6 +434,9 @@ export const TOOLS: Tool[] = [
category: "utilities",
icon: "Columns2",
route: "/compare",
modality: "image",
acceptedInputs: IMAGE_INPUTS,
executionHint: "fast",
},
{
id: "find-duplicates",
@@ -330,6 +445,9 @@ export const TOOLS: Tool[] = [
category: "utilities",
icon: "Copy",
route: "/find-duplicates",
modality: "image",
acceptedInputs: IMAGE_INPUTS,
executionHint: "fast",
},
{
id: "color-palette",
@@ -338,6 +456,9 @@ export const TOOLS: Tool[] = [
category: "utilities",
icon: "Droplets",
route: "/color-palette",
modality: "image",
acceptedInputs: IMAGE_INPUTS,
executionHint: "fast",
},
{
id: "qr-generate",
@@ -346,6 +467,9 @@ export const TOOLS: Tool[] = [
category: "utilities",
icon: "QrCode",
route: "/qr-generate",
modality: "image",
acceptedInputs: IMAGE_INPUTS,
executionHint: "fast",
},
{
id: "html-to-image",
@@ -354,6 +478,9 @@ export const TOOLS: Tool[] = [
category: "utilities",
icon: "Globe",
route: "/html-to-image",
modality: "image",
acceptedInputs: IMAGE_INPUTS,
executionHint: "fast",
},
{
id: "barcode-read",
@@ -362,6 +489,9 @@ export const TOOLS: Tool[] = [
category: "utilities",
icon: "ScanLine",
route: "/barcode-read",
modality: "image",
acceptedInputs: IMAGE_INPUTS,
executionHint: "fast",
},
{
id: "image-to-base64",
@@ -370,6 +500,9 @@ export const TOOLS: Tool[] = [
category: "utilities",
icon: "Code",
route: "/image-to-base64",
modality: "image",
acceptedInputs: IMAGE_INPUTS,
executionHint: "fast",
},
// Layout & Composition
{
@@ -379,6 +512,9 @@ export const TOOLS: Tool[] = [
category: "layout",
icon: "LayoutGrid",
route: "/collage",
modality: "image",
acceptedInputs: IMAGE_INPUTS,
executionHint: "fast",
},
{
id: "stitch",
@@ -387,6 +523,9 @@ export const TOOLS: Tool[] = [
category: "layout",
icon: "Columns2",
route: "/stitch",
modality: "image",
acceptedInputs: IMAGE_INPUTS,
executionHint: "fast",
},
{
id: "split",
@@ -395,6 +534,9 @@ export const TOOLS: Tool[] = [
category: "layout",
icon: "Grid3x3",
route: "/split",
modality: "image",
acceptedInputs: IMAGE_INPUTS,
executionHint: "fast",
},
{
id: "border",
@@ -403,6 +545,9 @@ export const TOOLS: Tool[] = [
category: "layout",
icon: "Frame",
route: "/border",
modality: "image",
acceptedInputs: IMAGE_INPUTS,
executionHint: "fast",
},
{
id: "beautify",
@@ -411,6 +556,9 @@ export const TOOLS: Tool[] = [
category: "layout",
icon: "ImagePlus",
route: "/beautify",
modality: "image",
acceptedInputs: IMAGE_INPUTS,
executionHint: "fast",
},
// Format & Conversion
{
@@ -420,6 +568,9 @@ export const TOOLS: Tool[] = [
category: "format",
icon: "FileImage",
route: "/svg-to-raster",
modality: "image",
acceptedInputs: [".svg", ".svgz"],
executionHint: "fast",
},
{
id: "vectorize",
@@ -428,6 +579,9 @@ export const TOOLS: Tool[] = [
category: "format",
icon: "PenTool",
route: "/vectorize",
modality: "image",
acceptedInputs: IMAGE_INPUTS,
executionHint: "fast",
},
{
id: "gif-tools",
@@ -437,6 +591,9 @@ export const TOOLS: Tool[] = [
category: "format",
icon: "Film",
route: "/gif-tools",
modality: "image",
acceptedInputs: IMAGE_INPUTS,
executionHint: "fast",
},
{
id: "pdf-to-image",
@@ -445,6 +602,9 @@ export const TOOLS: Tool[] = [
category: "format",
icon: "BookImage",
route: "/pdf-to-image",
modality: "image",
acceptedInputs: IMAGE_INPUTS,
executionHint: "fast",
},
];
+14
View File
@@ -49,6 +49,12 @@ export const ar: TranslationKeys = {
format: "التنسيق والتحويل",
ai: "أدوات AI",
},
modalities: {
image: "Image",
video: "Video",
audio: "Audio",
documentsAndFiles: "Documents & Files",
},
tools: {
resize: {
name: "تغيير الحجم",
@@ -271,6 +277,14 @@ export const ar: TranslationKeys = {
description: "ربط عدة أدوات في سير عمل واحد",
},
processing: { canceled: "Processing canceled" },
mediaPlayer: {
unsupported: "Your browser does not support this media format.",
},
documentView: {
loadFailed: "Failed to load document.",
previousPage: "Previous page",
nextPage: "Next page",
},
},
toolSettings: {
compress: {
+14
View File
@@ -49,6 +49,12 @@ export const de: TranslationKeys = {
format: "Format & Konvertierung",
ai: "AI-Werkzeuge",
},
modalities: {
image: "Image",
video: "Video",
audio: "Audio",
documentsAndFiles: "Documents & Files",
},
tools: {
resize: {
name: "Groesse aendern",
@@ -276,6 +282,14 @@ export const de: TranslationKeys = {
description: "Mehrere Werkzeuge zu einem Workflow verketten",
},
processing: { canceled: "Processing canceled" },
mediaPlayer: {
unsupported: "Your browser does not support this media format.",
},
documentView: {
loadFailed: "Failed to load document.",
previousPage: "Previous page",
nextPage: "Next page",
},
},
toolSettings: {
compress: {
+14
View File
@@ -47,6 +47,12 @@ export const en = {
format: "Format & Conversion",
ai: "AI Tools",
},
modalities: {
image: "Image",
video: "Video",
audio: "Audio",
documentsAndFiles: "Documents & Files",
},
tools: {
resize: {
name: "Resize",
@@ -228,6 +234,14 @@ export const en = {
},
pipeline: { name: "Pipeline Builder", description: "Chain multiple tools into a workflow" },
processing: { canceled: "Processing canceled" },
mediaPlayer: {
unsupported: "Your browser does not support this media format.",
},
documentView: {
loadFailed: "Failed to load document.",
previousPage: "Previous page",
nextPage: "Next page",
},
},
toolSettings: {
compress: {
+14
View File
@@ -49,6 +49,12 @@ export const es: TranslationKeys = {
format: "Formato y conversion",
ai: "Herramientas de AI",
},
modalities: {
image: "Image",
video: "Video",
audio: "Audio",
documentsAndFiles: "Documents & Files",
},
tools: {
resize: {
name: "Redimensionar",
@@ -261,6 +267,14 @@ export const es: TranslationKeys = {
description: "Encadena multiples herramientas en un flujo de trabajo",
},
processing: { canceled: "Processing canceled" },
mediaPlayer: {
unsupported: "Your browser does not support this media format.",
},
documentView: {
loadFailed: "Failed to load document.",
previousPage: "Previous page",
nextPage: "Next page",
},
},
toolSettings: {
compress: {
+14
View File
@@ -49,6 +49,12 @@ export const fr: TranslationKeys = {
format: "Format et conversion",
ai: "Outils AI",
},
modalities: {
image: "Image",
video: "Video",
audio: "Audio",
documentsAndFiles: "Documents & Files",
},
tools: {
resize: {
name: "Redimensionner",
@@ -277,6 +283,14 @@ export const fr: TranslationKeys = {
description: "Enchainez plusieurs outils dans un flux de travail",
},
processing: { canceled: "Processing canceled" },
mediaPlayer: {
unsupported: "Your browser does not support this media format.",
},
documentView: {
loadFailed: "Failed to load document.",
previousPage: "Previous page",
nextPage: "Next page",
},
},
toolSettings: {
compress: {
+14
View File
@@ -49,6 +49,12 @@ export const hi: TranslationKeys = {
format: "फॉर्मेट और कन्वर्शन",
ai: "AI टूल्स",
},
modalities: {
image: "Image",
video: "Video",
audio: "Audio",
documentsAndFiles: "Documents & Files",
},
tools: {
resize: {
name: "रीसाइज़",
@@ -268,6 +274,14 @@ export const hi: TranslationKeys = {
description: "कई टूल्स को एक वर्कफ्लो में चेन करें",
},
processing: { canceled: "Processing canceled" },
mediaPlayer: {
unsupported: "Your browser does not support this media format.",
},
documentView: {
loadFailed: "Failed to load document.",
previousPage: "Previous page",
nextPage: "Next page",
},
},
toolSettings: {
compress: {
+14
View File
@@ -49,6 +49,12 @@ export const id: TranslationKeys = {
format: "Format & Konversi",
ai: "Alat AI",
},
modalities: {
image: "Image",
video: "Video",
audio: "Audio",
documentsAndFiles: "Documents & Files",
},
tools: {
resize: {
name: "Ubah Ukuran",
@@ -276,6 +282,14 @@ export const id: TranslationKeys = {
description: "Rangkai beberapa alat menjadi alur kerja",
},
processing: { canceled: "Processing canceled" },
mediaPlayer: {
unsupported: "Your browser does not support this media format.",
},
documentView: {
loadFailed: "Failed to load document.",
previousPage: "Previous page",
nextPage: "Next page",
},
},
toolSettings: {
compress: {
+14
View File
@@ -49,6 +49,12 @@ export const it: TranslationKeys = {
format: "Formato e conversione",
ai: "Strumenti IA",
},
modalities: {
image: "Image",
video: "Video",
audio: "Audio",
documentsAndFiles: "Documents & Files",
},
tools: {
resize: {
name: "Ridimensiona",
@@ -275,6 +281,14 @@ export const it: TranslationKeys = {
description: "Concatena piu strumenti in un flusso di lavoro",
},
processing: { canceled: "Processing canceled" },
mediaPlayer: {
unsupported: "Your browser does not support this media format.",
},
documentView: {
loadFailed: "Failed to load document.",
previousPage: "Previous page",
nextPage: "Next page",
},
},
toolSettings: {
compress: {
+14
View File
@@ -49,6 +49,12 @@ export const ja: TranslationKeys = {
format: "フォーマットと変換",
ai: "AIツール",
},
modalities: {
image: "Image",
video: "Video",
audio: "Audio",
documentsAndFiles: "Documents & Files",
},
tools: {
resize: {
name: "リサイズ",
@@ -236,6 +242,14 @@ export const ja: TranslationKeys = {
},
pipeline: { name: "Pipelineビルダー", description: "複数のツールをワークフローに連結" },
processing: { canceled: "Processing canceled" },
mediaPlayer: {
unsupported: "Your browser does not support this media format.",
},
documentView: {
loadFailed: "Failed to load document.",
previousPage: "Previous page",
nextPage: "Next page",
},
},
toolSettings: {
compress: {
+14
View File
@@ -49,6 +49,12 @@ export const ko: TranslationKeys = {
format: "포맷 및 변환",
ai: "AI 도구",
},
modalities: {
image: "Image",
video: "Video",
audio: "Audio",
documentsAndFiles: "Documents & Files",
},
tools: {
resize: {
name: "리사이즈",
@@ -223,6 +229,14 @@ export const ko: TranslationKeys = {
},
pipeline: { name: "Pipeline 빌더", description: "여러 도구를 워크플로로 연결" },
processing: { canceled: "Processing canceled" },
mediaPlayer: {
unsupported: "Your browser does not support this media format.",
},
documentView: {
loadFailed: "Failed to load document.",
previousPage: "Previous page",
nextPage: "Next page",
},
},
toolSettings: {
compress: {
+14
View File
@@ -49,6 +49,12 @@ export const nl: TranslationKeys = {
format: "Formaat & Conversie",
ai: "AI-tools",
},
modalities: {
image: "Image",
video: "Video",
audio: "Audio",
documentsAndFiles: "Documents & Files",
},
tools: {
resize: {
name: "Formaat wijzigen",
@@ -276,6 +282,14 @@ export const nl: TranslationKeys = {
description: "Meerdere tools koppelen tot een workflow",
},
processing: { canceled: "Processing canceled" },
mediaPlayer: {
unsupported: "Your browser does not support this media format.",
},
documentView: {
loadFailed: "Failed to load document.",
previousPage: "Previous page",
nextPage: "Next page",
},
},
toolSettings: {
compress: {
+14
View File
@@ -49,6 +49,12 @@ export const pl: TranslationKeys = {
format: "Format i konwersja",
ai: "Narzędzia AI",
},
modalities: {
image: "Image",
video: "Video",
audio: "Audio",
documentsAndFiles: "Documents & Files",
},
tools: {
resize: {
name: "Zmiana rozmiaru",
@@ -277,6 +283,14 @@ export const pl: TranslationKeys = {
description: "Łączenie wielu narzędzi w przepływ pracy",
},
processing: { canceled: "Processing canceled" },
mediaPlayer: {
unsupported: "Your browser does not support this media format.",
},
documentView: {
loadFailed: "Failed to load document.",
previousPage: "Previous page",
nextPage: "Next page",
},
},
toolSettings: {
compress: {
+14
View File
@@ -49,6 +49,12 @@ export const ptBR: TranslationKeys = {
format: "Formato e conversao",
ai: "Ferramentas de AI",
},
modalities: {
image: "Image",
video: "Video",
audio: "Audio",
documentsAndFiles: "Documents & Files",
},
tools: {
resize: {
name: "Redimensionar",
@@ -274,6 +280,14 @@ export const ptBR: TranslationKeys = {
description: "Encadeie varias ferramentas em um fluxo de trabalho",
},
processing: { canceled: "Processing canceled" },
mediaPlayer: {
unsupported: "Your browser does not support this media format.",
},
documentView: {
loadFailed: "Failed to load document.",
previousPage: "Previous page",
nextPage: "Next page",
},
},
toolSettings: {
compress: {
+14
View File
@@ -49,6 +49,12 @@ export const ru: TranslationKeys = {
format: "Формат и конвертация",
ai: "AI-инструменты",
},
modalities: {
image: "Image",
video: "Video",
audio: "Audio",
documentsAndFiles: "Documents & Files",
},
tools: {
resize: {
name: "Изменение размера",
@@ -276,6 +282,14 @@ export const ru: TranslationKeys = {
description: "Объединение нескольких инструментов в рабочий процесс",
},
processing: { canceled: "Processing canceled" },
mediaPlayer: {
unsupported: "Your browser does not support this media format.",
},
documentView: {
loadFailed: "Failed to load document.",
previousPage: "Previous page",
nextPage: "Next page",
},
},
toolSettings: {
compress: {
+14
View File
@@ -49,6 +49,12 @@ export const sv: TranslationKeys = {
format: "Format & Konvertering",
ai: "AI-verktyg",
},
modalities: {
image: "Image",
video: "Video",
audio: "Audio",
documentsAndFiles: "Documents & Files",
},
tools: {
resize: {
name: "Andra storlek",
@@ -274,6 +280,14 @@ export const sv: TranslationKeys = {
description: "Kedja samman flera verktyg till ett arbetsflode",
},
processing: { canceled: "Processing canceled" },
mediaPlayer: {
unsupported: "Your browser does not support this media format.",
},
documentView: {
loadFailed: "Failed to load document.",
previousPage: "Previous page",
nextPage: "Next page",
},
},
toolSettings: {
compress: {
+14
View File
@@ -49,6 +49,12 @@ export const th: TranslationKeys = {
format: "รูปแบบและการแปลง",
ai: "เครื่องมือ AI",
},
modalities: {
image: "Image",
video: "Video",
audio: "Audio",
documentsAndFiles: "Documents & Files",
},
tools: {
resize: {
name: "ปรับขนาด",
@@ -269,6 +275,14 @@ export const th: TranslationKeys = {
description: "เชื่อมต่อหลายเครื่องมือเป็นขั้นตอนทำงาน",
},
processing: { canceled: "Processing canceled" },
mediaPlayer: {
unsupported: "Your browser does not support this media format.",
},
documentView: {
loadFailed: "Failed to load document.",
previousPage: "Previous page",
nextPage: "Next page",
},
},
toolSettings: {
compress: {
+14
View File
@@ -49,6 +49,12 @@ export const tr: TranslationKeys = {
format: "Biçim ve Dönüştürme",
ai: "AI Araçları",
},
modalities: {
image: "Image",
video: "Video",
audio: "Audio",
documentsAndFiles: "Documents & Files",
},
tools: {
resize: {
name: "Boyutlandır",
@@ -277,6 +283,14 @@ export const tr: TranslationKeys = {
description: "Birden fazla aracı bir iş akışında zincirleyin",
},
processing: { canceled: "Processing canceled" },
mediaPlayer: {
unsupported: "Your browser does not support this media format.",
},
documentView: {
loadFailed: "Failed to load document.",
previousPage: "Previous page",
nextPage: "Next page",
},
},
toolSettings: {
compress: {
+14
View File
@@ -49,6 +49,12 @@ export const uk: TranslationKeys = {
format: "Формат і конвертація",
ai: "AI-інструменти",
},
modalities: {
image: "Image",
video: "Video",
audio: "Audio",
documentsAndFiles: "Documents & Files",
},
tools: {
resize: {
name: "Зміна розміру",
@@ -276,6 +282,14 @@ export const uk: TranslationKeys = {
description: "Об'єднання кількох інструментів у робочий процес",
},
processing: { canceled: "Processing canceled" },
mediaPlayer: {
unsupported: "Your browser does not support this media format.",
},
documentView: {
loadFailed: "Failed to load document.",
previousPage: "Previous page",
nextPage: "Next page",
},
},
toolSettings: {
compress: {
+14
View File
@@ -49,6 +49,12 @@ export const vi: TranslationKeys = {
format: "Định dạng & Chuyển đổi",
ai: "Công cụ AI",
},
modalities: {
image: "Image",
video: "Video",
audio: "Audio",
documentsAndFiles: "Documents & Files",
},
tools: {
resize: {
name: "Thay đổi kích thước",
@@ -277,6 +283,14 @@ export const vi: TranslationKeys = {
description: "Kết nối nhiều công cụ thành một quy trình làm việc",
},
processing: { canceled: "Processing canceled" },
mediaPlayer: {
unsupported: "Your browser does not support this media format.",
},
documentView: {
loadFailed: "Failed to load document.",
previousPage: "Previous page",
nextPage: "Next page",
},
},
toolSettings: {
compress: {
+14
View File
@@ -49,6 +49,12 @@ export const zhCN: TranslationKeys = {
format: "格式与转换",
ai: "AI 工具",
},
modalities: {
image: "Image",
video: "Video",
audio: "Audio",
documentsAndFiles: "Documents & Files",
},
tools: {
resize: {
name: "调整大小",
@@ -223,6 +229,14 @@ export const zhCN: TranslationKeys = {
},
pipeline: { name: "Pipeline 构建器", description: "将多个工具串联为工作流" },
processing: { canceled: "Processing canceled" },
mediaPlayer: {
unsupported: "Your browser does not support this media format.",
},
documentView: {
loadFailed: "Failed to load document.",
previousPage: "Previous page",
nextPage: "Next page",
},
},
toolSettings: {
compress: {
+14
View File
@@ -49,6 +49,12 @@ export const zhTW: TranslationKeys = {
format: "格式與轉換",
ai: "AI工具",
},
modalities: {
image: "Image",
video: "Video",
audio: "Audio",
documentsAndFiles: "Documents & Files",
},
tools: {
resize: {
name: "調整大小",
@@ -222,6 +228,14 @@ export const zhTW: TranslationKeys = {
},
pipeline: { name: "Pipeline建構器", description: "將多個工具串聯為工作流程" },
processing: { canceled: "Processing canceled" },
mediaPlayer: {
unsupported: "Your browser does not support this media format.",
},
documentView: {
loadFailed: "Failed to load document.",
previousPage: "Previous page",
nextPage: "Next page",
},
},
toolSettings: {
compress: {
+1
View File
@@ -4,5 +4,6 @@ export * from "./analytics/types.js";
export * from "./constants.js";
export * from "./features.js";
export * from "./i18n/index.js";
export * from "./modality.js";
export * from "./permissions.js";
export * from "./types.js";
+137
View File
@@ -0,0 +1,137 @@
export type Modality = "image" | "video" | "audio" | "document" | "file";
export interface ModalityInfo {
id: Modality;
name: string;
icon: string; // lucide icon name, same convention as CategoryInfo
color: string;
}
// Five modality values in code; "document" and "file" group as one
// "Documents & Files" area in the UI (see spec 4.5).
export const MODALITIES: ModalityInfo[] = [
{ id: "image", name: "Image", icon: "Image", color: "#3B82F6" },
{ id: "video", name: "Video", icon: "Video", color: "#EF4444" },
{ id: "audio", name: "Audio", icon: "AudioLines", color: "#10B981" },
{ id: "document", name: "Documents", icon: "FileText", color: "#8B5CF6" },
{ id: "file", name: "Files", icon: "FileArchive", color: "#F59E0B" },
];
// Which BullMQ pool a modality's tools run on. AI tools override to "ai"
// at enqueue time regardless of modality.
export const MODALITY_POOL: Record<Modality, "image" | "media" | "docs"> = {
image: "image",
video: "media",
audio: "media",
document: "docs",
file: "docs",
};
// Default accepted input extensions per modality (with dots; drives the
// file picker accept attribute and docs). Tools may narrow this.
export const IMAGE_INPUTS = [
".jpg",
".jpeg",
".png",
".webp",
".gif",
".bmp",
".tiff",
".tif",
".avif",
".heic",
".heif",
".svg",
".svgz",
".ico",
".jxl",
".jp2",
".psd",
".tga",
".exr",
".hdr",
".dng",
".cr2",
".nef",
".arw",
".orf",
".rw2",
".ppm",
".pgm",
".pbm",
".qoi",
".dds",
".fits",
".dpx",
".apng",
".cur",
".eps",
];
export const VIDEO_INPUTS = [
".mp4",
".mov",
".webm",
".mkv",
".avi",
".m4v",
".mts",
".m2ts",
".3gp",
".flv",
".wmv",
".mpg",
".mpeg",
".ts",
".ogv",
];
export const AUDIO_INPUTS = [
".mp3",
".wav",
".flac",
".aac",
".m4a",
".ogg",
".opus",
".wma",
".aiff",
".amr",
".ac3",
];
export const DOCUMENT_INPUTS = [
".pdf",
".docx",
".doc",
".xlsx",
".xls",
".pptx",
".ppt",
".odt",
".ods",
".odp",
".rtf",
".txt",
".md",
".html",
".epub",
".mobi",
".azw3",
];
export const FILE_INPUTS = [".csv", ".json", ".xml", ".yaml", ".yml", ".zip"];
export function detectModalityFromMime(mime: string): Modality {
if (mime.startsWith("image/")) return "image";
if (mime.startsWith("video/")) return "video";
if (mime.startsWith("audio/")) return "audio";
if (
mime === "application/pdf" ||
mime.includes("officedocument") ||
mime.includes("msword") ||
mime.includes("ms-excel") ||
mime.includes("ms-powerpoint") ||
mime === "application/epub+zip" ||
mime.startsWith("text/html")
) {
return "document";
}
return "file";
}
+6
View File
@@ -1,3 +1,5 @@
import type { Modality } from "./modality.js";
export interface Tool {
id: string;
name: string;
@@ -5,6 +7,10 @@ export interface Tool {
category: ToolCategory;
icon: string;
route: string;
modality: Modality;
acceptedInputs: string[];
executionHint: "fast" | "long";
maxInputSizeMB?: number;
shortcut?: string;
disabled?: boolean;
experimental?: boolean;