diff --git a/typescript/packages/toolshed/deno.json b/typescript/packages/toolshed/deno.json index 88b5308b9..10c206c88 100644 --- a/typescript/packages/toolshed/deno.json +++ b/typescript/packages/toolshed/deno.json @@ -24,17 +24,15 @@ "nodeModulesDir": "auto", "imports": { "@/": "./", - "@commontools/memory": "../common-memory/lib.ts", "@ai-sdk/amazon-bedrock": "npm:@ai-sdk/amazon-bedrock@^1.1.6", "@ai-sdk/anthropic": "npm:@ai-sdk/anthropic@^1.1.6", "@ai-sdk/cerebras": "npm:@ai-sdk/cerebras@^0.1.8", "@ai-sdk/google-vertex": "npm:@ai-sdk/google-vertex@^2.1.12", - "@std/cli": "jsr:@std/cli@^1.0.12", - "gcp-metadata": "npm:gcp-metadata@6.1.0", "@ai-sdk/groq": "npm:@ai-sdk/groq@^1.1.7", "@ai-sdk/openai": "npm:@ai-sdk/openai@^1.1.9", "@arizeai/openinference-semantic-conventions": "npm:@arizeai/openinference-semantic-conventions@^1.0.0", "@arizeai/openinference-vercel": "npm:@arizeai/openinference-vercel@^2.0.1", + "@commontools/memory": "../common-memory/lib.ts", "@fal-ai/client": "npm:@fal-ai/client@^1.2.2", "@hono/sentry": "npm:@hono/sentry@^1.2.0", "@hono/zod-openapi": "npm:@hono/zod-openapi@^0.18.3", @@ -45,6 +43,7 @@ "@scalar/hono-api-reference": "npm:@scalar/hono-api-reference@^0.5.165", "@sentry/deno": "npm:@sentry/deno@^8.54.0", "@std/assert": "jsr:@std/assert@^1.0.10", + "@std/cli": "jsr:@std/cli@^1.0.12", "@std/crypto": "jsr:@std/crypto@^1.0.3", "@std/dotenv": "jsr:@std/dotenv@^0.225.3", "@std/encoding": "jsr:@std/encoding@^1.0.6", @@ -53,15 +52,17 @@ "@std/path": "jsr:@std/path@^1.0.8", "@vercel/otel": "npm:@vercel/otel@^1.10.1", "ai": "npm:ai@^4.1.34", - "jsonschema": "npm:jsonschema@^1.5.0", + "elevenlabs": "npm:elevenlabs@^1.52.0", + "gcp-metadata": "npm:gcp-metadata@6.1.0", "hono": "npm:hono@^4.7.0", "hono-pino": "npm:hono-pino@^0.7.0", + "jsonschema": "npm:jsonschema@^1.5.0", "merkle-reference": "npm:merkle-reference@^2.0.1", + "mistreevous": "npm:mistreevous@4.2.0", "pino": "npm:pino@^9.6.0", "pino-pretty": "npm:pino-pretty@^13.0.0", "redis": "npm:redis@^4.7.0", "stoker": "npm:stoker@^1.4.2", - "zod": "npm:zod@^3.24.1", - "mistreevous": "npm:mistreevous@4.2.0" + "zod": "npm:zod@^3.24.1" } } diff --git a/typescript/packages/toolshed/deno.lock b/typescript/packages/toolshed/deno.lock index 2d88719bc..f387a764d 100644 --- a/typescript/packages/toolshed/deno.lock +++ b/typescript/packages/toolshed/deno.lock @@ -43,6 +43,7 @@ "npm:@vercel/otel@^1.10.1": "1.10.1_@opentelemetry+api@1.9.0_@opentelemetry+api-logs@0.57.1_@opentelemetry+instrumentation@0.57.1__@opentelemetry+api@1.9.0_@opentelemetry+resources@1.30.1__@opentelemetry+api@1.9.0_@opentelemetry+sdk-logs@0.57.1__@opentelemetry+api@1.9.0_@opentelemetry+sdk-metrics@1.30.1__@opentelemetry+api@1.9.0_@opentelemetry+sdk-trace-base@1.30.1__@opentelemetry+api@1.9.0", "npm:ai@*": "4.1.34_zod@3.24.1", "npm:ai@^4.1.34": "4.1.34_zod@3.24.1", + "npm:elevenlabs@^1.52.0": "1.52.0", "npm:gcp-metadata@6.1.0": "6.1.0", "npm:hono-pino@0.7": "0.7.2_hono@4.7.0_pino@9.6.0", "npm:hono@^4.7.0": "4.7.0", @@ -1342,6 +1343,12 @@ "@opentelemetry/sdk-trace-base" ] }, + "abort-controller@3.0.0": { + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "dependencies": [ + "event-target-shim" + ] + }, "acorn-import-attributes@1.9.5_acorn@8.14.0": { "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", "dependencies": [ @@ -1366,6 +1373,9 @@ "zod" ] }, + "asynckit@0.4.0": { + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, "atomic-sleep@1.0.0": { "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==" }, @@ -1381,6 +1391,27 @@ "buffer-equal-constant-time@1.0.1": { "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" }, + "buffer@6.0.3": { + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dependencies": [ + "base64-js", + "ieee754" + ] + }, + "call-bind-apply-helpers@1.0.2": { + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dependencies": [ + "es-errors", + "function-bind" + ] + }, + "call-bound@1.0.3": { + "integrity": "sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==", + "dependencies": [ + "call-bind-apply-helpers", + "get-intrinsic" + ] + }, "chalk@5.4.1": { "integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==" }, @@ -1393,6 +1424,23 @@ "colorette@2.0.20": { "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==" }, + "combined-stream@1.0.8": { + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": [ + "delayed-stream" + ] + }, + "command-exists@1.2.9": { + "integrity": "sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==" + }, + "cross-spawn@7.0.6": { + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dependencies": [ + "path-key", + "shebang-command", + "which" + ] + }, "dateformat@4.6.3": { "integrity": "sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==" }, @@ -1405,30 +1453,96 @@ "defu@6.1.4": { "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==" }, + "delayed-stream@1.0.0": { + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" + }, "dequal@2.0.3": { "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==" }, "diff-match-patch@1.0.5": { "integrity": "sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw==" }, + "dunder-proto@1.0.1": { + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dependencies": [ + "call-bind-apply-helpers", + "es-errors", + "gopd" + ] + }, "ecdsa-sig-formatter@1.0.11": { "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", "dependencies": [ "safe-buffer" ] }, + "elevenlabs@1.52.0": { + "integrity": "sha512-O4lg1uAV0uMjkdKCbX0ftAFHUrOvqGZbWZXFPeaWPWhtXc46TWqZQpqhUaLnqjqd91Yzjs/4j5yE6n+5bLF/Zw==", + "dependencies": [ + "command-exists", + "execa", + "form-data", + "form-data-encoder", + "formdata-node", + "node-fetch", + "qs", + "readable-stream", + "url-join" + ] + }, "end-of-stream@1.4.4": { "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", "dependencies": [ "once" ] }, + "es-define-property@1.0.1": { + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==" + }, + "es-errors@1.3.0": { + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==" + }, + "es-object-atoms@1.1.1": { + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dependencies": [ + "es-errors" + ] + }, + "es-set-tostringtag@2.1.0": { + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dependencies": [ + "es-errors", + "get-intrinsic", + "has-tostringtag", + "hasown" + ] + }, + "event-target-shim@5.0.1": { + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==" + }, + "events@3.3.0": { + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==" + }, "eventsource-parser@1.1.2": { "integrity": "sha512-v0eOBUbiaFojBu2s2NPBfYUoRR9GjcDNvCXVaqEf5vVfpIAh9f8RCo4vXTP8c63QRKCFwoLpMpTdPwwhEKVgzA==" }, "eventsource-parser@3.0.0": { "integrity": "sha512-T1C0XCUimhxVQzW4zFipdx0SficT651NnkR0ZSH3yQwh+mFMdLfgjABVi4YtMTtaL4s168593DaoaRLMqryavA==" }, + "execa@5.1.1": { + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dependencies": [ + "cross-spawn", + "get-stream", + "human-signals", + "is-stream", + "merge-stream", + "npm-run-path", + "onetime", + "signal-exit", + "strip-final-newline" + ] + }, "extend@3.0.2": { "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" }, @@ -1447,6 +1561,21 @@ "strnum" ] }, + "form-data-encoder@4.0.2": { + "integrity": "sha512-KQVhvhK8ZkWzxKxOr56CPulAhH3dobtuQ4+hNQ+HekH/Wp5gSOafqRAeTphQUJAIk0GBvHZgJ2ZGRWd5kphMuw==" + }, + "form-data@4.0.2": { + "integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==", + "dependencies": [ + "asynckit", + "combined-stream", + "es-set-tostringtag", + "mime-types" + ] + }, + "formdata-node@6.0.3": { + "integrity": "sha512-8e1++BCiTzUno9v5IZ2J6bv4RU+3UKDmqWUQD0MIMVCd9AdhWkO1gw57oo1mNEX1dMq2EGI+FbWz4B92pscSQg==" + }, "function-bind@1.1.2": { "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==" }, @@ -1470,6 +1599,31 @@ "generic-pool@3.9.0": { "integrity": "sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==" }, + "get-intrinsic@1.3.0": { + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dependencies": [ + "call-bind-apply-helpers", + "es-define-property", + "es-errors", + "es-object-atoms", + "function-bind", + "get-proto", + "gopd", + "has-symbols", + "hasown", + "math-intrinsics" + ] + }, + "get-proto@1.0.1": { + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dependencies": [ + "dunder-proto", + "es-object-atoms" + ] + }, + "get-stream@6.0.1": { + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==" + }, "google-auth-library@9.15.1": { "integrity": "sha512-Jb6Z0+nvECVz+2lzSMt9u98UsoakXxA2HGHMCxh+so3n90XgYWkq5dur19JAJV7ONiJY22yBTyJB1TSkvPq9Ng==", "dependencies": [ @@ -1481,6 +1635,9 @@ "jws" ] }, + "gopd@1.2.0": { + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==" + }, "gtoken@7.1.0": { "integrity": "sha512-pCcEwRi+TKpMlxAQObHDQ56KawURgyAf6jtIY046fJ5tIv3zDe/LEIubckAO8fj6JnAxLdmWkUfNyulQ2iKdEw==", "dependencies": [ @@ -1488,6 +1645,15 @@ "jws" ] }, + "has-symbols@1.1.0": { + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==" + }, + "has-tostringtag@1.0.2": { + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dependencies": [ + "has-symbols" + ] + }, "hasown@2.0.2": { "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "dependencies": [ @@ -1518,6 +1684,12 @@ "debug" ] }, + "human-signals@2.1.0": { + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==" + }, + "ieee754@1.2.1": { + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" + }, "import-in-the-middle@1.13.0_acorn@8.14.0": { "integrity": "sha512-YG86SYDtrL/Yu8JgfWb7kjQ0myLeT1whw6fs/ZHFkXFcbk9zJU9lOCsSJHpvaPumU11nN3US7NW6x1YTk+HrUA==", "dependencies": [ @@ -1536,6 +1708,9 @@ "is-stream@2.0.1": { "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==" }, + "isexe@2.0.0": { + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + }, "joycon@3.1.1": { "integrity": "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==" }, @@ -1580,6 +1755,12 @@ "lotto-draw@1.0.2": { "integrity": "sha512-1ih414A35BWpApfNlWAHBKOBLSxTj45crAJ+CMWF/kVY5nx6N22DA1OVF/FWW5WM5CGJbIMRh1O+xe8ukyoQ8Q==" }, + "math-intrinsics@1.1.0": { + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==" + }, + "merge-stream@2.0.0": { + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" + }, "merkle-reference@2.0.1": { "integrity": "sha512-3ZFvCbK10ZO5ZLapSgtB79ut4S6+UDKrjSCAP1Q0T43yZ4CEJDrVjYB4dHg6TGTfqBnCaYyR09Zh4cKJpm+Mqg==", "dependencies": [ @@ -1587,6 +1768,18 @@ "multiformats" ] }, + "mime-db@1.52.0": { + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" + }, + "mime-types@2.1.35": { + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": [ + "mime-db" + ] + }, + "mimic-fn@2.1.0": { + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" + }, "minimist@1.2.8": { "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==" }, @@ -1614,6 +1807,15 @@ "whatwg-url" ] }, + "npm-run-path@4.0.1": { + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dependencies": [ + "path-key" + ] + }, + "object-inspect@1.13.4": { + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==" + }, "on-exit-leak-free@2.1.2": { "integrity": "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==" }, @@ -1623,12 +1825,21 @@ "wrappy" ] }, + "onetime@5.1.2": { + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dependencies": [ + "mimic-fn" + ] + }, "openapi3-ts@4.4.0": { "integrity": "sha512-9asTNB9IkKEzWMcHmVZE7Ts3kC9G7AFHfs8i7caD8HbI76gEjdkId4z/AkP83xdZsH7PLAnnbl47qZkXuxpArw==", "dependencies": [ "yaml" ] }, + "path-key@3.1.1": { + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" + }, "path-parse@1.0.7": { "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, @@ -1678,6 +1889,9 @@ "process-warning@4.0.1": { "integrity": "sha512-3c2LzQ3rY9d0hc1emcsHhfT9Jwz0cChib/QN89oME2R451w5fy3f0afAhERFZAwrbDU43wk12d0ORBpDVME50Q==" }, + "process@0.11.10": { + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==" + }, "protobufjs@7.4.0": { "integrity": "sha512-mRUWCc3KUU4w1jU8sGxICXH/gNS94DvI1gxqDvBzhj1JpcsimQkYiOJfwsPUykUI5ZaspFbSgmBLER8IrQ3tqw==", "dependencies": [ @@ -1702,12 +1916,28 @@ "once" ] }, + "qs@6.14.0": { + "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", + "dependencies": [ + "side-channel" + ] + }, "quick-format-unescaped@4.0.4": { "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==" }, "react@19.0.0": { "integrity": "sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==" }, + "readable-stream@4.7.0": { + "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", + "dependencies": [ + "abort-controller", + "buffer", + "events", + "process", + "string_decoder" + ] + }, "real-require@0.2.0": { "integrity": "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==" }, @@ -1753,9 +1983,57 @@ "semver@7.7.1": { "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==" }, + "shebang-command@2.0.0": { + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dependencies": [ + "shebang-regex" + ] + }, + "shebang-regex@3.0.0": { + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" + }, "shimmer@1.2.1": { "integrity": "sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==" }, + "side-channel-list@1.0.0": { + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "dependencies": [ + "es-errors", + "object-inspect" + ] + }, + "side-channel-map@1.0.1": { + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dependencies": [ + "call-bound", + "es-errors", + "get-intrinsic", + "object-inspect" + ] + }, + "side-channel-weakmap@1.0.2": { + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dependencies": [ + "call-bound", + "es-errors", + "get-intrinsic", + "object-inspect", + "side-channel-map" + ] + }, + "side-channel@1.1.0": { + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "dependencies": [ + "es-errors", + "object-inspect", + "side-channel-list", + "side-channel-map", + "side-channel-weakmap" + ] + }, + "signal-exit@3.0.7": { + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + }, "sonic-boom@4.2.0": { "integrity": "sha512-INb7TM37/mAcsGmc9hyyI6+QR3rR1zVRu36B0NeGXKnOOLiZOfER5SA+N7X7k3yUYRzLWafduTDvJAfDswwEww==", "dependencies": [ @@ -1774,6 +2052,15 @@ "openapi3-ts" ] }, + "string_decoder@1.3.0": { + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": [ + "safe-buffer" + ] + }, + "strip-final-newline@2.0.0": { + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==" + }, "strip-json-comments@3.1.1": { "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==" }, @@ -1820,6 +2107,9 @@ "undici-types@6.20.0": { "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==" }, + "url-join@4.0.1": { + "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==" + }, "use-sync-external-store@1.4.0_react@19.0.0": { "integrity": "sha512-9WXSPC5fMv61vaupRkCKCxsPxBocVnwakBEkMIHHpkTTg6icbJtg6jzgtLDm4bl3cSHAca52rYWih0k4K3PfHw==", "dependencies": [ @@ -1839,6 +2129,12 @@ "webidl-conversions" ] }, + "which@2.0.2": { + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dependencies": [ + "isexe" + ] + }, "wrappy@1.0.2": { "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, @@ -1962,6 +2258,7 @@ "npm:@sentry/deno@^8.54.0", "npm:@vercel/otel@^1.10.1", "npm:ai@^4.1.34", + "npm:elevenlabs@^1.52.0", "npm:gcp-metadata@6.1.0", "npm:hono-pino@0.7", "npm:hono@^4.7.0", diff --git a/typescript/packages/toolshed/env.ts b/typescript/packages/toolshed/env.ts index 366f8f703..a72458d27 100644 --- a/typescript/packages/toolshed/env.ts +++ b/typescript/packages/toolshed/env.ts @@ -30,6 +30,12 @@ const EnvSchema = z.object({ CTTS_AI_LLM_PHOENIX_API_KEY: z.string().default(""), // =========================================================================== + // =========================================================================== + // ElevenLabs API Key + // * /routes/ai/voice + // =========================================================================== + ELEVENLABS_API_KEY: z.string().default(""), + // =========================================================================== // FAL AI API Key // * /routes/ai/img diff --git a/typescript/packages/toolshed/routes/ai/voice/voice.handlers.ts b/typescript/packages/toolshed/routes/ai/voice/voice.handlers.ts index 23f74aa2a..49887bbc5 100644 --- a/typescript/packages/toolshed/routes/ai/voice/voice.handlers.ts +++ b/typescript/packages/toolshed/routes/ai/voice/voice.handlers.ts @@ -24,6 +24,28 @@ interface TranscriptionResult { chunks: TranscriptionChunk[]; } +// ElevenLabs API types +interface ElevenLabsTranscriptionResponse { + text: string; + words?: Array<{ + word: string; + start: number; + end: number; + confidence: number; + }>; + iab_categories?: Record; + audio_events?: Array<{ + type: string; + start: number; + end: number; + }>; + speakers?: Array<{ + speaker_id: string; + start: number; + end: number; + }>; +} + async function generateCacheKey(buffer: ArrayBuffer): Promise { const hashBuffer = await crypto.subtle.digest("SHA-256", buffer); const hashArray = Array.from(new Uint8Array(hashBuffer)); @@ -83,6 +105,21 @@ function formatResponse( } } +// Convert ElevenLabs word data to TranscriptionChunk format +function convertElevenLabsToChunks( + response: ElevenLabsTranscriptionResponse, +): TranscriptionChunk[] { + if (!response.words) { + return []; + } + + return response.words.map((word) => ({ + text: word.word, + timestamp: [word.start, word.end], + confidence: word.confidence, + })); +} + export const transcribeVoice: AppRouteHandler = async ( c, ) => { @@ -129,31 +166,47 @@ export const transcribeVoice: AppRouteHandler = async ( logger.info({ promptSha }, "Cache MISS - Generating new transcription"); + // Get the provider from query params, default to "fal" + const provider = c.req.query("provider") || "fal"; + try { - const audioUrl = await uploadToFAL(audioBuffer, contentType); - logger.info({ audioUrl }, "Audio uploaded to FAL storage"); + let transcription: string; + let chunks: TranscriptionChunk[]; - const result = await fal.subscribe("fal-ai/wizper", { - input: { audio_url: audioUrl }, - }); + if (provider === "elevenlabs") { + logger.info("Using ElevenLabs for transcription"); + const result = await transcribeWithElevenLabs( + audioBuffer, + contentType, + logger, + ); + transcription = result.transcription; + chunks = result.chunks; + } else { + // Default to FAL + logger.info("Using FAL for transcription"); + const audioUrl = await uploadToFAL(audioBuffer, contentType); + logger.info({ audioUrl }, "Audio uploaded to FAL storage"); - if (!result.data?.text) { - logger.error({ result }, "No transcription in response"); - return c.json({ error: "Failed to transcribe audio" }, 400); - } + const result = await fal.subscribe("fal-ai/wizper", { + input: { audio_url: audioUrl }, + }); + + if (!result.data?.text) { + logger.error({ result }, "No transcription in response"); + return c.json({ error: "Failed to transcribe audio" }, 400); + } - const transcription = result.data.text; - const chunks = result.data.chunks as unknown as TranscriptionChunk[] || []; + transcription = result.data.text; + chunks = result.data.chunks as unknown as TranscriptionChunk[] || []; + } logger.info( { chars: transcription.length, chunks: chunks.length }, "Transcription generated successfully", ); - const transcriptionResult = { - transcription, - chunks: chunks as unknown as TranscriptionChunk[], - }; + const transcriptionResult = { transcription, chunks }; await saveTranscriptionToCache(cachePath, transcriptionResult, logger); return c.json( @@ -165,3 +218,62 @@ export const transcribeVoice: AppRouteHandler = async ( return c.json({ error: "Failed to transcribe audio" }, 500); } }; + +async function transcribeWithElevenLabs( + audioBuffer: ArrayBuffer, + contentType: AllowedContentType, + logger: Logger, +): Promise { + if (!env.ELEVENLABS_API_KEY) { + throw new Error("ELEVENLABS_API_KEY is not configured"); + } + + const url = "https://api.elevenlabs.io/v1/speech-to-text"; + + // Create form data with the audio file + const formData = new FormData(); + const file = new File([audioBuffer], "audio.wav", { type: contentType }); + formData.append("file", file); + formData.append("model_id", "scribe_v1"); + formData.append("tag_audio_events", "true"); + formData.append("diarize", "true"); + + // Optional: detect language automatically by not specifying language_code + // formData.append("language_code", "eng"); + + logger.info("Sending request to ElevenLabs API"); + + const response = await fetch(url, { + method: "POST", + headers: { + "xi-api-key": env.ELEVENLABS_API_KEY, + }, + body: formData, + }); + + if (!response.ok) { + const errorText = await response.text(); + logger.error( + { status: response.status, error: errorText }, + "ElevenLabs API error", + ); + throw new Error(`ElevenLabs API error: ${response.status} ${errorText}`); + } + + const data = await response.json() as ElevenLabsTranscriptionResponse; + + if (!data.text) { + throw new Error("No transcription returned from ElevenLabs"); + } + + logger.info({ + textLength: data.text.length, + hasWords: !!data.words, + wordCount: data.words?.length || 0, + }, "ElevenLabs transcription received"); + + return { + transcription: data.text, + chunks: convertElevenLabsToChunks(data), + }; +} diff --git a/typescript/packages/toolshed/routes/ai/voice/voice.routes.ts b/typescript/packages/toolshed/routes/ai/voice/voice.routes.ts index 1f8034f8e..787016e85 100644 --- a/typescript/packages/toolshed/routes/ai/voice/voice.routes.ts +++ b/typescript/packages/toolshed/routes/ai/voice/voice.routes.ts @@ -44,6 +44,10 @@ export const transcribeVoice = createRoute({ .describe( "Type of response: full (default), text (transcription only), or chunks (timestamps only)", ), + provider: z.enum(["fal", "elevenlabs"]).default("fal") + .describe( + "Transcription provider to use: fal (default) or elevenlabs", + ), }), body: { content: {