@tanstack/openai-base 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +121 -0
- package/dist/esm/adapters/chat-completions-text.d.ts +49 -21
- package/dist/esm/adapters/chat-completions-text.js +476 -68
- package/dist/esm/adapters/chat-completions-text.js.map +1 -1
- package/dist/esm/adapters/chat-completions-tool-converter.d.ts +8 -4
- package/dist/esm/adapters/chat-completions-tool-converter.js.map +1 -1
- package/dist/esm/adapters/responses-text.d.ts +46 -33
- package/dist/esm/adapters/responses-text.js +657 -142
- package/dist/esm/adapters/responses-text.js.map +1 -1
- package/dist/esm/index.d.ts +2 -9
- package/dist/esm/index.js +4 -16
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/tools/apply-patch-tool.d.ts +2 -2
- package/dist/esm/tools/apply-patch-tool.js.map +1 -1
- package/dist/esm/tools/code-interpreter-tool.d.ts +3 -2
- package/dist/esm/tools/code-interpreter-tool.js.map +1 -1
- package/dist/esm/tools/computer-use-tool.d.ts +2 -2
- package/dist/esm/tools/computer-use-tool.js.map +1 -1
- package/dist/esm/tools/custom-tool.d.ts +2 -2
- package/dist/esm/tools/custom-tool.js.map +1 -1
- package/dist/esm/tools/file-search-tool.d.ts +2 -2
- package/dist/esm/tools/file-search-tool.js.map +1 -1
- package/dist/esm/tools/function-tool.d.ts +2 -2
- package/dist/esm/tools/function-tool.js.map +1 -1
- package/dist/esm/tools/image-generation-tool.d.ts +3 -2
- package/dist/esm/tools/image-generation-tool.js.map +1 -1
- package/dist/esm/tools/local-shell-tool.d.ts +3 -2
- package/dist/esm/tools/local-shell-tool.js.map +1 -1
- package/dist/esm/tools/mcp-tool.d.ts +3 -2
- package/dist/esm/tools/mcp-tool.js.map +1 -1
- package/dist/esm/tools/shell-tool.d.ts +2 -2
- package/dist/esm/tools/shell-tool.js.map +1 -1
- package/dist/esm/tools/web-search-preview-tool.d.ts +2 -2
- package/dist/esm/tools/web-search-preview-tool.js.map +1 -1
- package/dist/esm/tools/web-search-tool.d.ts +2 -2
- package/dist/esm/tools/web-search-tool.js.map +1 -1
- package/package.json +6 -6
- package/src/adapters/chat-completions-text.ts +601 -117
- package/src/adapters/chat-completions-tool-converter.ts +9 -5
- package/src/adapters/responses-text.ts +865 -210
- package/src/index.ts +2 -12
- package/src/tools/apply-patch-tool.ts +2 -2
- package/src/tools/code-interpreter-tool.ts +4 -2
- package/src/tools/computer-use-tool.ts +2 -2
- package/src/tools/custom-tool.ts +2 -2
- package/src/tools/file-search-tool.ts +3 -3
- package/src/tools/function-tool.ts +2 -2
- package/src/tools/image-generation-tool.ts +4 -2
- package/src/tools/local-shell-tool.ts +4 -2
- package/src/tools/mcp-tool.ts +4 -2
- package/src/tools/shell-tool.ts +2 -2
- package/src/tools/web-search-preview-tool.ts +2 -2
- package/src/tools/web-search-tool.ts +2 -2
- package/dist/esm/adapters/image.d.ts +0 -32
- package/dist/esm/adapters/image.js +0 -89
- package/dist/esm/adapters/image.js.map +0 -1
- package/dist/esm/adapters/summarize.d.ts +0 -28
- package/dist/esm/adapters/summarize.js +0 -112
- package/dist/esm/adapters/summarize.js.map +0 -1
- package/dist/esm/adapters/transcription.d.ts +0 -34
- package/dist/esm/adapters/transcription.js +0 -131
- package/dist/esm/adapters/transcription.js.map +0 -1
- package/dist/esm/adapters/tts.d.ts +0 -26
- package/dist/esm/adapters/tts.js +0 -78
- package/dist/esm/adapters/tts.js.map +0 -1
- package/dist/esm/adapters/video.d.ts +0 -72
- package/dist/esm/adapters/video.js +0 -238
- package/dist/esm/adapters/video.js.map +0 -1
- package/dist/esm/types/config.d.ts +0 -4
- package/dist/esm/utils/client.d.ts +0 -3
- package/dist/esm/utils/client.js +0 -8
- package/dist/esm/utils/client.js.map +0 -1
- package/src/adapters/image.ts +0 -158
- package/src/adapters/summarize.ts +0 -174
- package/src/adapters/transcription.ts +0 -194
- package/src/adapters/tts.ts +0 -124
- package/src/adapters/video.ts +0 -385
- package/src/types/config.ts +0 -5
- package/src/utils/client.ts +0 -8
package/src/index.ts
CHANGED
|
@@ -1,24 +1,14 @@
|
|
|
1
1
|
export { makeStructuredOutputCompatible } from './utils/schema-converter'
|
|
2
|
-
export { createOpenAICompatibleClient } from './utils/client'
|
|
3
|
-
export type { OpenAICompatibleClientConfig } from './types/config'
|
|
4
2
|
export * from './tools/index'
|
|
5
|
-
export {
|
|
3
|
+
export { OpenAIBaseChatCompletionsTextAdapter } from './adapters/chat-completions-text'
|
|
6
4
|
export {
|
|
7
5
|
convertFunctionToolToChatCompletionsFormat,
|
|
8
6
|
convertToolsToChatCompletionsFormat,
|
|
9
7
|
type ChatCompletionFunctionTool,
|
|
10
8
|
} from './adapters/chat-completions-tool-converter'
|
|
11
|
-
export {
|
|
9
|
+
export { OpenAIBaseResponsesTextAdapter } from './adapters/responses-text'
|
|
12
10
|
export {
|
|
13
11
|
convertFunctionToolToResponsesFormat,
|
|
14
12
|
convertToolsToResponsesFormat,
|
|
15
13
|
type ResponsesFunctionTool,
|
|
16
14
|
} from './adapters/responses-tool-converter'
|
|
17
|
-
export { OpenAICompatibleImageAdapter } from './adapters/image'
|
|
18
|
-
export {
|
|
19
|
-
OpenAICompatibleSummarizeAdapter,
|
|
20
|
-
type ChatStreamCapable,
|
|
21
|
-
} from './adapters/summarize'
|
|
22
|
-
export { OpenAICompatibleTranscriptionAdapter } from './adapters/transcription'
|
|
23
|
-
export { OpenAICompatibleTTSAdapter } from './adapters/tts'
|
|
24
|
-
export { OpenAICompatibleVideoAdapter } from './adapters/video'
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import type { ApplyPatchTool as ApplyPatchToolConfig } from 'openai/resources/responses/responses'
|
|
2
2
|
import type { Tool } from '@tanstack/ai'
|
|
3
3
|
|
|
4
|
-
export type ApplyPatchToolConfig
|
|
4
|
+
export type { ApplyPatchToolConfig }
|
|
5
5
|
|
|
6
6
|
/** @deprecated Renamed to `ApplyPatchToolConfig`. Will be removed in a future release. */
|
|
7
7
|
export type ApplyPatchTool = ApplyPatchToolConfig
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import type { Tool as SDKTool } from 'openai/resources/responses/responses'
|
|
1
2
|
import type { Tool } from '@tanstack/ai'
|
|
2
|
-
import type OpenAI from 'openai'
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
type CodeInterpreterToolConfig = SDKTool.CodeInterpreter
|
|
5
|
+
|
|
6
|
+
export type { CodeInterpreterToolConfig }
|
|
5
7
|
|
|
6
8
|
/** @deprecated Renamed to `CodeInterpreterToolConfig`. Will be removed in a future release. */
|
|
7
9
|
export type CodeInterpreterTool = CodeInterpreterToolConfig
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import type { ComputerTool as ComputerUseToolConfig } from 'openai/resources/responses/responses'
|
|
2
2
|
import type { Tool } from '@tanstack/ai'
|
|
3
3
|
|
|
4
|
-
export type ComputerUseToolConfig
|
|
4
|
+
export type { ComputerUseToolConfig }
|
|
5
5
|
|
|
6
6
|
/** @deprecated Renamed to `ComputerUseToolConfig`. Will be removed in a future release. */
|
|
7
7
|
export type ComputerUseTool = ComputerUseToolConfig
|
package/src/tools/custom-tool.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import type { CustomTool as CustomToolConfig } from 'openai/resources/responses/responses'
|
|
2
2
|
import type { Tool } from '@tanstack/ai'
|
|
3
3
|
|
|
4
|
-
export type CustomToolConfig
|
|
4
|
+
export type { CustomToolConfig }
|
|
5
5
|
|
|
6
6
|
/** @deprecated Renamed to `CustomToolConfig`. Will be removed in a future release. */
|
|
7
7
|
export type CustomTool = CustomToolConfig
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import type { FileSearchTool as FileSearchToolConfig } from 'openai/resources/responses/responses'
|
|
2
2
|
import type { Tool } from '@tanstack/ai'
|
|
3
3
|
|
|
4
|
+
export type { FileSearchToolConfig }
|
|
5
|
+
|
|
4
6
|
const validateMaxNumResults = (maxNumResults: number | undefined) => {
|
|
5
7
|
if (
|
|
6
8
|
maxNumResults !== undefined &&
|
|
@@ -10,8 +12,6 @@ const validateMaxNumResults = (maxNumResults: number | undefined) => {
|
|
|
10
12
|
}
|
|
11
13
|
}
|
|
12
14
|
|
|
13
|
-
export type FileSearchToolConfig = OpenAI.Responses.FileSearchTool
|
|
14
|
-
|
|
15
15
|
/** @deprecated Renamed to `FileSearchToolConfig`. Will be removed in a future release. */
|
|
16
16
|
export type FileSearchTool = FileSearchToolConfig
|
|
17
17
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { makeStructuredOutputCompatible } from '../utils/schema-converter'
|
|
2
|
+
import type { FunctionTool as FunctionToolConfig } from 'openai/resources/responses/responses'
|
|
2
3
|
import type { JSONSchema, Tool } from '@tanstack/ai'
|
|
3
|
-
import type OpenAI from 'openai'
|
|
4
4
|
|
|
5
|
-
export type FunctionToolConfig
|
|
5
|
+
export type { FunctionToolConfig }
|
|
6
6
|
|
|
7
7
|
/** @deprecated Renamed to `FunctionToolConfig`. Will be removed in a future release. */
|
|
8
8
|
export type FunctionTool = FunctionToolConfig
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import type { Tool as SDKTool } from 'openai/resources/responses/responses'
|
|
2
2
|
import type { Tool } from '@tanstack/ai'
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
type ImageGenerationToolConfig = SDKTool.ImageGeneration
|
|
5
|
+
|
|
6
|
+
export type { ImageGenerationToolConfig }
|
|
5
7
|
|
|
6
8
|
/** @deprecated Renamed to `ImageGenerationToolConfig`. Will be removed in a future release. */
|
|
7
9
|
export type ImageGenerationTool = ImageGenerationToolConfig
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import type { Tool as SDKTool } from 'openai/resources/responses/responses'
|
|
2
2
|
import type { Tool } from '@tanstack/ai'
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
type LocalShellToolConfig = SDKTool.LocalShell
|
|
5
|
+
|
|
6
|
+
export type { LocalShellToolConfig }
|
|
5
7
|
|
|
6
8
|
/** @deprecated Renamed to `LocalShellToolConfig`. Will be removed in a future release. */
|
|
7
9
|
export type LocalShellTool = LocalShellToolConfig
|
package/src/tools/mcp-tool.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import type { Tool as SDKTool } from 'openai/resources/responses/responses'
|
|
2
2
|
import type { Tool } from '@tanstack/ai'
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
type MCPToolConfig = SDKTool.Mcp
|
|
5
|
+
|
|
6
|
+
export type { MCPToolConfig }
|
|
5
7
|
|
|
6
8
|
/** @deprecated Renamed to `MCPToolConfig`. Will be removed in a future release. */
|
|
7
9
|
export type MCPTool = MCPToolConfig
|
package/src/tools/shell-tool.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import type { FunctionShellTool as ShellToolConfig } from 'openai/resources/responses/responses'
|
|
2
2
|
import type { Tool } from '@tanstack/ai'
|
|
3
3
|
|
|
4
|
-
export type ShellToolConfig
|
|
4
|
+
export type { ShellToolConfig }
|
|
5
5
|
|
|
6
6
|
/** @deprecated Renamed to `ShellToolConfig`. Will be removed in a future release. */
|
|
7
7
|
export type ShellTool = ShellToolConfig
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import type { WebSearchPreviewTool as WebSearchPreviewToolConfig } from 'openai/resources/responses/responses'
|
|
2
2
|
import type { Tool } from '@tanstack/ai'
|
|
3
3
|
|
|
4
|
-
export type WebSearchPreviewToolConfig
|
|
4
|
+
export type { WebSearchPreviewToolConfig }
|
|
5
5
|
|
|
6
6
|
/** @deprecated Renamed to `WebSearchPreviewToolConfig`. Will be removed in a future release. */
|
|
7
7
|
export type WebSearchPreviewTool = WebSearchPreviewToolConfig
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import type { WebSearchTool as WebSearchToolConfig } from 'openai/resources/responses/responses'
|
|
2
2
|
import type { Tool } from '@tanstack/ai'
|
|
3
3
|
|
|
4
|
-
export type WebSearchToolConfig
|
|
4
|
+
export type { WebSearchToolConfig }
|
|
5
5
|
|
|
6
6
|
/** @deprecated Renamed to `WebSearchToolConfig`. Will be removed in a future release. */
|
|
7
7
|
export type WebSearchTool = WebSearchToolConfig
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { BaseImageAdapter } from '@tanstack/ai/adapters';
|
|
2
|
-
import { ImageGenerationOptions, ImageGenerationResult } from '@tanstack/ai';
|
|
3
|
-
import { default as OpenAI_SDK } from 'openai';
|
|
4
|
-
import { OpenAICompatibleClientConfig } from '../types/config.js';
|
|
5
|
-
/**
|
|
6
|
-
* OpenAI-Compatible Image Generation Adapter
|
|
7
|
-
*
|
|
8
|
-
* A generalized base class for providers that implement OpenAI-compatible image
|
|
9
|
-
* generation APIs. Providers like OpenAI, Grok, and others can extend this class
|
|
10
|
-
* and only need to:
|
|
11
|
-
* - Set `baseURL` in the config
|
|
12
|
-
* - Lock the generic type parameters to provider-specific types
|
|
13
|
-
* - Override validation or request building methods for provider-specific constraints
|
|
14
|
-
*
|
|
15
|
-
* All methods that validate inputs, build requests, or transform responses are
|
|
16
|
-
* `protected` so subclasses can override them.
|
|
17
|
-
*/
|
|
18
|
-
export declare class OpenAICompatibleImageAdapter<TModel extends string, TProviderOptions extends object = Record<string, any>, TModelProviderOptionsByName extends Record<string, any> = Record<string, any>, TModelSizeByName extends Record<string, string> = Record<string, string>> extends BaseImageAdapter<TModel, TProviderOptions, TModelProviderOptionsByName, TModelSizeByName> {
|
|
19
|
-
readonly kind: "image";
|
|
20
|
-
readonly name: string;
|
|
21
|
-
protected client: OpenAI_SDK;
|
|
22
|
-
constructor(config: OpenAICompatibleClientConfig, model: TModel, name?: string);
|
|
23
|
-
generateImages(options: ImageGenerationOptions<TProviderOptions>): Promise<ImageGenerationResult>;
|
|
24
|
-
protected buildRequest(options: ImageGenerationOptions<TProviderOptions>): OpenAI_SDK.Images.ImageGenerateParams;
|
|
25
|
-
protected transformResponse(model: string, response: OpenAI_SDK.Images.ImagesResponse): ImageGenerationResult;
|
|
26
|
-
protected validatePrompt(options: {
|
|
27
|
-
prompt: string;
|
|
28
|
-
model: string;
|
|
29
|
-
}): void;
|
|
30
|
-
protected validateImageSize(_model: string, _size: string | undefined): void;
|
|
31
|
-
protected validateNumberOfImages(_model: string, numberOfImages: number | undefined): void;
|
|
32
|
-
}
|
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
import { BaseImageAdapter } from "@tanstack/ai/adapters";
|
|
2
|
-
import { toRunErrorPayload } from "@tanstack/ai/adapter-internals";
|
|
3
|
-
import { generateId } from "@tanstack/ai-utils";
|
|
4
|
-
import { createOpenAICompatibleClient } from "../utils/client.js";
|
|
5
|
-
class OpenAICompatibleImageAdapter extends BaseImageAdapter {
|
|
6
|
-
constructor(config, model, name = "openai-compatible") {
|
|
7
|
-
super(model, {});
|
|
8
|
-
this.kind = "image";
|
|
9
|
-
this.name = name;
|
|
10
|
-
this.client = createOpenAICompatibleClient(config);
|
|
11
|
-
}
|
|
12
|
-
async generateImages(options) {
|
|
13
|
-
const { model, prompt, numberOfImages, size } = options;
|
|
14
|
-
this.validatePrompt({ prompt, model });
|
|
15
|
-
this.validateImageSize(model, size);
|
|
16
|
-
this.validateNumberOfImages(model, numberOfImages);
|
|
17
|
-
const request = this.buildRequest(options);
|
|
18
|
-
try {
|
|
19
|
-
options.logger.request(
|
|
20
|
-
`activity=image provider=${this.name} model=${model} n=${request.n ?? 1} size=${request.size ?? "default"}`,
|
|
21
|
-
{ provider: this.name, model }
|
|
22
|
-
);
|
|
23
|
-
const response = await this.client.images.generate({
|
|
24
|
-
...request,
|
|
25
|
-
stream: false
|
|
26
|
-
});
|
|
27
|
-
return this.transformResponse(model, response);
|
|
28
|
-
} catch (error) {
|
|
29
|
-
options.logger.errors(`${this.name}.generateImages fatal`, {
|
|
30
|
-
error: toRunErrorPayload(error, `${this.name}.generateImages failed`),
|
|
31
|
-
source: `${this.name}.generateImages`
|
|
32
|
-
});
|
|
33
|
-
throw error;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
buildRequest(options) {
|
|
37
|
-
const { model, prompt, numberOfImages, size, modelOptions } = options;
|
|
38
|
-
return {
|
|
39
|
-
model,
|
|
40
|
-
prompt,
|
|
41
|
-
n: numberOfImages ?? 1,
|
|
42
|
-
size,
|
|
43
|
-
...modelOptions
|
|
44
|
-
};
|
|
45
|
-
}
|
|
46
|
-
transformResponse(model, response) {
|
|
47
|
-
const images = (response.data ?? []).flatMap(
|
|
48
|
-
(item) => {
|
|
49
|
-
const revisedPrompt = item.revised_prompt;
|
|
50
|
-
if (item.b64_json) {
|
|
51
|
-
return [{ b64Json: item.b64_json, revisedPrompt }];
|
|
52
|
-
}
|
|
53
|
-
if (item.url) {
|
|
54
|
-
return [{ url: item.url, revisedPrompt }];
|
|
55
|
-
}
|
|
56
|
-
return [];
|
|
57
|
-
}
|
|
58
|
-
);
|
|
59
|
-
return {
|
|
60
|
-
id: generateId(this.name),
|
|
61
|
-
model,
|
|
62
|
-
images,
|
|
63
|
-
usage: response.usage ? {
|
|
64
|
-
inputTokens: response.usage.input_tokens,
|
|
65
|
-
outputTokens: response.usage.output_tokens,
|
|
66
|
-
totalTokens: response.usage.total_tokens
|
|
67
|
-
} : void 0
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
validatePrompt(options) {
|
|
71
|
-
if (options.prompt.length === 0) {
|
|
72
|
-
throw new Error("Prompt cannot be empty.");
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
validateImageSize(_model, _size) {
|
|
76
|
-
}
|
|
77
|
-
validateNumberOfImages(_model, numberOfImages) {
|
|
78
|
-
if (numberOfImages === void 0) return;
|
|
79
|
-
if (numberOfImages < 1) {
|
|
80
|
-
throw new Error(
|
|
81
|
-
`Number of images must be at least 1. Requested: ${numberOfImages}`
|
|
82
|
-
);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
export {
|
|
87
|
-
OpenAICompatibleImageAdapter
|
|
88
|
-
};
|
|
89
|
-
//# sourceMappingURL=image.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"image.js","sources":["../../../src/adapters/image.ts"],"sourcesContent":["import { BaseImageAdapter } from '@tanstack/ai/adapters'\nimport { toRunErrorPayload } from '@tanstack/ai/adapter-internals'\nimport { generateId } from '@tanstack/ai-utils'\nimport { createOpenAICompatibleClient } from '../utils/client'\nimport type {\n GeneratedImage,\n ImageGenerationOptions,\n ImageGenerationResult,\n} from '@tanstack/ai'\nimport type OpenAI_SDK from 'openai'\nimport type { OpenAICompatibleClientConfig } from '../types/config'\n\n/**\n * OpenAI-Compatible Image Generation Adapter\n *\n * A generalized base class for providers that implement OpenAI-compatible image\n * generation APIs. Providers like OpenAI, Grok, and others can extend this class\n * and only need to:\n * - Set `baseURL` in the config\n * - Lock the generic type parameters to provider-specific types\n * - Override validation or request building methods for provider-specific constraints\n *\n * All methods that validate inputs, build requests, or transform responses are\n * `protected` so subclasses can override them.\n */\nexport class OpenAICompatibleImageAdapter<\n TModel extends string,\n TProviderOptions extends object = Record<string, any>,\n TModelProviderOptionsByName extends Record<string, any> = Record<string, any>,\n TModelSizeByName extends Record<string, string> = Record<string, string>,\n> extends BaseImageAdapter<\n TModel,\n TProviderOptions,\n TModelProviderOptionsByName,\n TModelSizeByName\n> {\n readonly kind = 'image' as const\n readonly name: string\n\n protected client: OpenAI_SDK\n\n constructor(\n config: OpenAICompatibleClientConfig,\n model: TModel,\n name: string = 'openai-compatible',\n ) {\n super(model, {})\n this.name = name\n this.client = createOpenAICompatibleClient(config)\n }\n\n async generateImages(\n options: ImageGenerationOptions<TProviderOptions>,\n ): Promise<ImageGenerationResult> {\n const { model, prompt, numberOfImages, size } = options\n\n // Validate inputs\n this.validatePrompt({ prompt, model })\n this.validateImageSize(model, size)\n this.validateNumberOfImages(model, numberOfImages)\n\n // Build request based on model type\n const request = this.buildRequest(options)\n\n try {\n options.logger.request(\n `activity=image provider=${this.name} model=${model} n=${request.n ?? 1} size=${request.size ?? 'default'}`,\n { provider: this.name, model },\n )\n const response = await this.client.images.generate({\n ...request,\n stream: false,\n })\n\n return this.transformResponse(model, response)\n } catch (error: unknown) {\n // Narrow before logging: raw SDK errors can carry request metadata\n // (including auth headers) which we must never surface to user loggers.\n options.logger.errors(`${this.name}.generateImages fatal`, {\n error: toRunErrorPayload(error, `${this.name}.generateImages failed`),\n source: `${this.name}.generateImages`,\n })\n throw error\n }\n }\n\n protected buildRequest(\n options: ImageGenerationOptions<TProviderOptions>,\n ): OpenAI_SDK.Images.ImageGenerateParams {\n const { model, prompt, numberOfImages, size, modelOptions } = options\n\n return {\n model,\n prompt,\n n: numberOfImages ?? 1,\n size: size as OpenAI_SDK.Images.ImageGenerateParams['size'],\n ...modelOptions,\n }\n }\n\n protected transformResponse(\n model: string,\n response: OpenAI_SDK.Images.ImagesResponse,\n ): ImageGenerationResult {\n const images: Array<GeneratedImage> = (response.data ?? []).flatMap(\n (item): Array<GeneratedImage> => {\n const revisedPrompt = item.revised_prompt\n if (item.b64_json) {\n return [{ b64Json: item.b64_json, revisedPrompt }]\n }\n if (item.url) {\n return [{ url: item.url, revisedPrompt }]\n }\n return []\n },\n )\n\n return {\n id: generateId(this.name),\n model,\n images,\n usage: response.usage\n ? {\n inputTokens: response.usage.input_tokens,\n outputTokens: response.usage.output_tokens,\n totalTokens: response.usage.total_tokens,\n }\n : undefined,\n }\n }\n\n protected validatePrompt(options: { prompt: string; model: string }): void {\n if (options.prompt.length === 0) {\n throw new Error('Prompt cannot be empty.')\n }\n }\n\n protected validateImageSize(_model: string, _size: string | undefined): void {\n // Default: no size validation — subclasses can override\n }\n\n protected validateNumberOfImages(\n _model: string,\n numberOfImages: number | undefined,\n ): void {\n if (numberOfImages === undefined) return\n\n // The base adapter only enforces \"must be at least 1\". Per-provider /\n // per-model upper bounds vary widely (some support 4, some 10, some\n // unlimited), so concrete adapter subclasses are expected to override\n // this method with a model-specific cap.\n if (numberOfImages < 1) {\n throw new Error(\n `Number of images must be at least 1. Requested: ${numberOfImages}`,\n )\n }\n }\n}\n"],"names":[],"mappings":";;;;AAyBO,MAAM,qCAKH,iBAKR;AAAA,EAMA,YACE,QACA,OACA,OAAe,qBACf;AACA,UAAM,OAAO,EAAE;AAVjB,SAAS,OAAO;AAWd,SAAK,OAAO;AACZ,SAAK,SAAS,6BAA6B,MAAM;AAAA,EACnD;AAAA,EAEA,MAAM,eACJ,SACgC;AAChC,UAAM,EAAE,OAAO,QAAQ,gBAAgB,SAAS;AAGhD,SAAK,eAAe,EAAE,QAAQ,MAAA,CAAO;AACrC,SAAK,kBAAkB,OAAO,IAAI;AAClC,SAAK,uBAAuB,OAAO,cAAc;AAGjD,UAAM,UAAU,KAAK,aAAa,OAAO;AAEzC,QAAI;AACF,cAAQ,OAAO;AAAA,QACb,2BAA2B,KAAK,IAAI,UAAU,KAAK,MAAM,QAAQ,KAAK,CAAC,SAAS,QAAQ,QAAQ,SAAS;AAAA,QACzG,EAAE,UAAU,KAAK,MAAM,MAAA;AAAA,MAAM;AAE/B,YAAM,WAAW,MAAM,KAAK,OAAO,OAAO,SAAS;AAAA,QACjD,GAAG;AAAA,QACH,QAAQ;AAAA,MAAA,CACT;AAED,aAAO,KAAK,kBAAkB,OAAO,QAAQ;AAAA,IAC/C,SAAS,OAAgB;AAGvB,cAAQ,OAAO,OAAO,GAAG,KAAK,IAAI,yBAAyB;AAAA,QACzD,OAAO,kBAAkB,OAAO,GAAG,KAAK,IAAI,wBAAwB;AAAA,QACpE,QAAQ,GAAG,KAAK,IAAI;AAAA,MAAA,CACrB;AACD,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEU,aACR,SACuC;AACvC,UAAM,EAAE,OAAO,QAAQ,gBAAgB,MAAM,iBAAiB;AAE9D,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA,GAAG,kBAAkB;AAAA,MACrB;AAAA,MACA,GAAG;AAAA,IAAA;AAAA,EAEP;AAAA,EAEU,kBACR,OACA,UACuB;AACvB,UAAM,UAAiC,SAAS,QAAQ,CAAA,GAAI;AAAA,MAC1D,CAAC,SAAgC;AAC/B,cAAM,gBAAgB,KAAK;AAC3B,YAAI,KAAK,UAAU;AACjB,iBAAO,CAAC,EAAE,SAAS,KAAK,UAAU,eAAe;AAAA,QACnD;AACA,YAAI,KAAK,KAAK;AACZ,iBAAO,CAAC,EAAE,KAAK,KAAK,KAAK,eAAe;AAAA,QAC1C;AACA,eAAO,CAAA;AAAA,MACT;AAAA,IAAA;AAGF,WAAO;AAAA,MACL,IAAI,WAAW,KAAK,IAAI;AAAA,MACxB;AAAA,MACA;AAAA,MACA,OAAO,SAAS,QACZ;AAAA,QACE,aAAa,SAAS,MAAM;AAAA,QAC5B,cAAc,SAAS,MAAM;AAAA,QAC7B,aAAa,SAAS,MAAM;AAAA,MAAA,IAE9B;AAAA,IAAA;AAAA,EAER;AAAA,EAEU,eAAe,SAAkD;AACzE,QAAI,QAAQ,OAAO,WAAW,GAAG;AAC/B,YAAM,IAAI,MAAM,yBAAyB;AAAA,IAC3C;AAAA,EACF;AAAA,EAEU,kBAAkB,QAAgB,OAAiC;AAAA,EAE7E;AAAA,EAEU,uBACR,QACA,gBACM;AACN,QAAI,mBAAmB,OAAW;AAMlC,QAAI,iBAAiB,GAAG;AACtB,YAAM,IAAI;AAAA,QACR,mDAAmD,cAAc;AAAA,MAAA;AAAA,IAErE;AAAA,EACF;AACF;"}
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { BaseSummarizeAdapter } from '@tanstack/ai/adapters';
|
|
2
|
-
import { StreamChunk, SummarizationOptions, SummarizationResult, TextOptions } from '@tanstack/ai';
|
|
3
|
-
/**
|
|
4
|
-
* Minimal interface for a text adapter that supports chatStream.
|
|
5
|
-
* This allows the summarize adapter to work with any OpenAI-compatible
|
|
6
|
-
* text adapter without tight coupling to a specific implementation.
|
|
7
|
-
*/
|
|
8
|
-
export interface ChatStreamCapable<TProviderOptions extends object> {
|
|
9
|
-
chatStream: (options: TextOptions<TProviderOptions>) => AsyncIterable<StreamChunk>;
|
|
10
|
-
}
|
|
11
|
-
/**
|
|
12
|
-
* OpenAI-Compatible Summarize Adapter
|
|
13
|
-
*
|
|
14
|
-
* A thin wrapper around a text adapter that adds summarization-specific prompting.
|
|
15
|
-
* Delegates all API calls to the provided text adapter.
|
|
16
|
-
*
|
|
17
|
-
* Subclasses or instantiators provide a text adapter (or factory) at construction
|
|
18
|
-
* time, allowing any OpenAI-compatible provider to get summarization for free by
|
|
19
|
-
* reusing its text adapter.
|
|
20
|
-
*/
|
|
21
|
-
export declare class OpenAICompatibleSummarizeAdapter<TModel extends string, TProviderOptions extends object = Record<string, any>> extends BaseSummarizeAdapter<TModel, TProviderOptions> {
|
|
22
|
-
readonly name: string;
|
|
23
|
-
private textAdapter;
|
|
24
|
-
constructor(textAdapter: ChatStreamCapable<TProviderOptions>, model: TModel, name?: string);
|
|
25
|
-
summarize(options: SummarizationOptions): Promise<SummarizationResult>;
|
|
26
|
-
summarizeStream(options: SummarizationOptions): AsyncIterable<StreamChunk>;
|
|
27
|
-
protected buildSummarizationPrompt(options: SummarizationOptions): string;
|
|
28
|
-
}
|
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
import { BaseSummarizeAdapter } from "@tanstack/ai/adapters";
|
|
2
|
-
import { toRunErrorPayload } from "@tanstack/ai/adapter-internals";
|
|
3
|
-
import { generateId } from "@tanstack/ai-utils";
|
|
4
|
-
class OpenAICompatibleSummarizeAdapter extends BaseSummarizeAdapter {
|
|
5
|
-
constructor(textAdapter, model, name = "openai-compatible") {
|
|
6
|
-
super({}, model);
|
|
7
|
-
this.name = name;
|
|
8
|
-
this.textAdapter = textAdapter;
|
|
9
|
-
}
|
|
10
|
-
async summarize(options) {
|
|
11
|
-
const systemPrompt = this.buildSummarizationPrompt(options);
|
|
12
|
-
let summary = "";
|
|
13
|
-
const id = generateId(this.name);
|
|
14
|
-
let model = options.model;
|
|
15
|
-
let usage = { promptTokens: 0, completionTokens: 0, totalTokens: 0 };
|
|
16
|
-
options.logger.request(
|
|
17
|
-
`activity=summarize provider=${this.name} model=${options.model} text-length=${options.text.length} maxLength=${options.maxLength ?? "unset"}`,
|
|
18
|
-
{ provider: this.name, model: options.model }
|
|
19
|
-
);
|
|
20
|
-
try {
|
|
21
|
-
for await (const chunk of this.textAdapter.chatStream({
|
|
22
|
-
model: options.model,
|
|
23
|
-
messages: [{ role: "user", content: options.text }],
|
|
24
|
-
systemPrompts: [systemPrompt],
|
|
25
|
-
maxTokens: options.maxLength,
|
|
26
|
-
temperature: 0.3,
|
|
27
|
-
logger: options.logger
|
|
28
|
-
})) {
|
|
29
|
-
if (chunk.type === "TEXT_MESSAGE_CONTENT") {
|
|
30
|
-
if (chunk.content) {
|
|
31
|
-
summary = chunk.content;
|
|
32
|
-
} else if (chunk.delta) {
|
|
33
|
-
summary += chunk.delta;
|
|
34
|
-
}
|
|
35
|
-
model = chunk.model || model;
|
|
36
|
-
}
|
|
37
|
-
if (chunk.type === "RUN_FINISHED") {
|
|
38
|
-
if (chunk.usage) {
|
|
39
|
-
usage = chunk.usage;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
if (chunk.type === "RUN_ERROR") {
|
|
43
|
-
const message = (chunk.error && typeof chunk.error.message === "string" ? chunk.error.message : null) ?? "Summarization failed";
|
|
44
|
-
const code = chunk.error && typeof chunk.error.code === "string" ? chunk.error.code : void 0;
|
|
45
|
-
const err = new Error(message);
|
|
46
|
-
if (code) {
|
|
47
|
-
;
|
|
48
|
-
err.code = code;
|
|
49
|
-
}
|
|
50
|
-
throw err;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
} catch (error) {
|
|
54
|
-
options.logger.errors(`${this.name}.summarize fatal`, {
|
|
55
|
-
error: toRunErrorPayload(error, `${this.name}.summarize failed`),
|
|
56
|
-
source: `${this.name}.summarize`
|
|
57
|
-
});
|
|
58
|
-
throw error;
|
|
59
|
-
}
|
|
60
|
-
return { id, model, summary, usage };
|
|
61
|
-
}
|
|
62
|
-
async *summarizeStream(options) {
|
|
63
|
-
const systemPrompt = this.buildSummarizationPrompt(options);
|
|
64
|
-
options.logger.request(
|
|
65
|
-
`activity=summarizeStream provider=${this.name} model=${options.model} text-length=${options.text.length} maxLength=${options.maxLength ?? "unset"}`,
|
|
66
|
-
{ provider: this.name, model: options.model }
|
|
67
|
-
);
|
|
68
|
-
try {
|
|
69
|
-
yield* this.textAdapter.chatStream({
|
|
70
|
-
model: options.model,
|
|
71
|
-
messages: [{ role: "user", content: options.text }],
|
|
72
|
-
systemPrompts: [systemPrompt],
|
|
73
|
-
maxTokens: options.maxLength,
|
|
74
|
-
temperature: 0.3,
|
|
75
|
-
logger: options.logger
|
|
76
|
-
});
|
|
77
|
-
} catch (error) {
|
|
78
|
-
options.logger.errors(`${this.name}.summarizeStream fatal`, {
|
|
79
|
-
error: toRunErrorPayload(error, `${this.name}.summarizeStream failed`),
|
|
80
|
-
source: `${this.name}.summarizeStream`
|
|
81
|
-
});
|
|
82
|
-
throw error;
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
buildSummarizationPrompt(options) {
|
|
86
|
-
let prompt = "You are a professional summarizer. ";
|
|
87
|
-
switch (options.style) {
|
|
88
|
-
case "bullet-points":
|
|
89
|
-
prompt += "Provide a summary in bullet point format. ";
|
|
90
|
-
break;
|
|
91
|
-
case "paragraph":
|
|
92
|
-
prompt += "Provide a summary in paragraph format. ";
|
|
93
|
-
break;
|
|
94
|
-
case "concise":
|
|
95
|
-
prompt += "Provide a very concise summary in 1-2 sentences. ";
|
|
96
|
-
break;
|
|
97
|
-
default:
|
|
98
|
-
prompt += "Provide a clear and concise summary. ";
|
|
99
|
-
}
|
|
100
|
-
if (options.focus && options.focus.length > 0) {
|
|
101
|
-
prompt += `Focus on the following aspects: ${options.focus.join(", ")}. `;
|
|
102
|
-
}
|
|
103
|
-
if (options.maxLength) {
|
|
104
|
-
prompt += `Keep the summary under ${options.maxLength} tokens. `;
|
|
105
|
-
}
|
|
106
|
-
return prompt;
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
export {
|
|
110
|
-
OpenAICompatibleSummarizeAdapter
|
|
111
|
-
};
|
|
112
|
-
//# sourceMappingURL=summarize.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"summarize.js","sources":["../../../src/adapters/summarize.ts"],"sourcesContent":["import { BaseSummarizeAdapter } from '@tanstack/ai/adapters'\nimport { toRunErrorPayload } from '@tanstack/ai/adapter-internals'\nimport { generateId } from '@tanstack/ai-utils'\nimport type {\n StreamChunk,\n SummarizationOptions,\n SummarizationResult,\n TextOptions,\n} from '@tanstack/ai'\n\n/**\n * Minimal interface for a text adapter that supports chatStream.\n * This allows the summarize adapter to work with any OpenAI-compatible\n * text adapter without tight coupling to a specific implementation.\n */\nexport interface ChatStreamCapable<TProviderOptions extends object> {\n chatStream: (\n options: TextOptions<TProviderOptions>,\n ) => AsyncIterable<StreamChunk>\n}\n\n/**\n * OpenAI-Compatible Summarize Adapter\n *\n * A thin wrapper around a text adapter that adds summarization-specific prompting.\n * Delegates all API calls to the provided text adapter.\n *\n * Subclasses or instantiators provide a text adapter (or factory) at construction\n * time, allowing any OpenAI-compatible provider to get summarization for free by\n * reusing its text adapter.\n */\nexport class OpenAICompatibleSummarizeAdapter<\n TModel extends string,\n TProviderOptions extends object = Record<string, any>,\n> extends BaseSummarizeAdapter<TModel, TProviderOptions> {\n readonly name: string\n\n private textAdapter: ChatStreamCapable<TProviderOptions>\n\n constructor(\n textAdapter: ChatStreamCapable<TProviderOptions>,\n model: TModel,\n name: string = 'openai-compatible',\n ) {\n super({}, model)\n this.name = name\n this.textAdapter = textAdapter\n }\n\n async summarize(options: SummarizationOptions): Promise<SummarizationResult> {\n const systemPrompt = this.buildSummarizationPrompt(options)\n\n let summary = ''\n const id = generateId(this.name)\n let model = options.model\n let usage = { promptTokens: 0, completionTokens: 0, totalTokens: 0 }\n\n options.logger.request(\n `activity=summarize provider=${this.name} model=${options.model} text-length=${options.text.length} maxLength=${options.maxLength ?? 'unset'}`,\n { provider: this.name, model: options.model },\n )\n\n try {\n for await (const chunk of this.textAdapter.chatStream({\n model: options.model,\n messages: [{ role: 'user', content: options.text }],\n systemPrompts: [systemPrompt],\n maxTokens: options.maxLength,\n temperature: 0.3,\n logger: options.logger,\n } satisfies TextOptions<TProviderOptions>)) {\n if (chunk.type === 'TEXT_MESSAGE_CONTENT') {\n if (chunk.content) {\n summary = chunk.content\n } else if (chunk.delta) {\n // Append delta only when present — a content-less chunk with no\n // delta would otherwise concat literal `'undefined'`.\n summary += chunk.delta\n }\n model = chunk.model || model\n }\n if (chunk.type === 'RUN_FINISHED') {\n if (chunk.usage) {\n usage = chunk.usage\n }\n }\n // Surface failures: the underlying chatStream emits RUN_ERROR instead\n // of throwing, so without this branch summarize() would return an\n // empty summary and pretend a failed run succeeded.\n if (chunk.type === 'RUN_ERROR') {\n const message =\n (chunk.error && typeof chunk.error.message === 'string'\n ? chunk.error.message\n : null) ?? 'Summarization failed'\n const code =\n chunk.error && typeof chunk.error.code === 'string'\n ? chunk.error.code\n : undefined\n const err = new Error(message)\n if (code) {\n ;(err as Error & { code?: string }).code = code\n }\n throw err\n }\n }\n } catch (error: unknown) {\n // Narrow before logging: raw SDK errors can carry request metadata\n // (including auth headers) which we must never surface to user loggers.\n options.logger.errors(`${this.name}.summarize fatal`, {\n error: toRunErrorPayload(error, `${this.name}.summarize failed`),\n source: `${this.name}.summarize`,\n })\n throw error\n }\n\n return { id, model, summary, usage }\n }\n\n async *summarizeStream(\n options: SummarizationOptions,\n ): AsyncIterable<StreamChunk> {\n const systemPrompt = this.buildSummarizationPrompt(options)\n\n options.logger.request(\n `activity=summarizeStream provider=${this.name} model=${options.model} text-length=${options.text.length} maxLength=${options.maxLength ?? 'unset'}`,\n { provider: this.name, model: options.model },\n )\n\n try {\n yield* this.textAdapter.chatStream({\n model: options.model,\n messages: [{ role: 'user', content: options.text }],\n systemPrompts: [systemPrompt],\n maxTokens: options.maxLength,\n temperature: 0.3,\n logger: options.logger,\n } satisfies TextOptions<TProviderOptions>)\n } catch (error: unknown) {\n options.logger.errors(`${this.name}.summarizeStream fatal`, {\n error: toRunErrorPayload(error, `${this.name}.summarizeStream failed`),\n source: `${this.name}.summarizeStream`,\n })\n throw error\n }\n }\n\n protected buildSummarizationPrompt(options: SummarizationOptions): string {\n let prompt = 'You are a professional summarizer. '\n\n switch (options.style) {\n case 'bullet-points':\n prompt += 'Provide a summary in bullet point format. '\n break\n case 'paragraph':\n prompt += 'Provide a summary in paragraph format. '\n break\n case 'concise':\n prompt += 'Provide a very concise summary in 1-2 sentences. '\n break\n default:\n prompt += 'Provide a clear and concise summary. '\n }\n\n if (options.focus && options.focus.length > 0) {\n prompt += `Focus on the following aspects: ${options.focus.join(', ')}. `\n }\n\n if (options.maxLength) {\n prompt += `Keep the summary under ${options.maxLength} tokens. `\n }\n\n return prompt\n }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { BaseTranscriptionAdapter } from '@tanstack/ai/adapters';
|
|
2
|
-
import { TranscriptionOptions, TranscriptionResult } from '@tanstack/ai';
|
|
3
|
-
import { default as OpenAI_SDK } from 'openai';
|
|
4
|
-
import { OpenAICompatibleClientConfig } from '../types/config.js';
|
|
5
|
-
/**
|
|
6
|
-
* OpenAI-Compatible Transcription (Speech-to-Text) Adapter
|
|
7
|
-
*
|
|
8
|
-
* A generalized base class for providers that implement OpenAI-compatible audio
|
|
9
|
-
* transcription APIs. Providers can extend this class and only need to:
|
|
10
|
-
* - Set `baseURL` in the config
|
|
11
|
-
* - Lock the generic type parameters to provider-specific types
|
|
12
|
-
* - Override audio handling or response mapping methods as needed
|
|
13
|
-
*
|
|
14
|
-
* All methods that handle audio input or map response formats are `protected`
|
|
15
|
-
* so subclasses can override them.
|
|
16
|
-
*/
|
|
17
|
-
export declare class OpenAICompatibleTranscriptionAdapter<TModel extends string, TProviderOptions extends object = Record<string, any>> extends BaseTranscriptionAdapter<TModel, TProviderOptions> {
|
|
18
|
-
readonly name: string;
|
|
19
|
-
protected client: OpenAI_SDK;
|
|
20
|
-
constructor(config: OpenAICompatibleClientConfig, model: TModel, name?: string);
|
|
21
|
-
transcribe(options: TranscriptionOptions<TProviderOptions>): Promise<TranscriptionResult>;
|
|
22
|
-
protected prepareAudioFile(audio: string | File | Blob | ArrayBuffer): File;
|
|
23
|
-
/**
|
|
24
|
-
* Checks that the global `File` constructor is available.
|
|
25
|
-
* Throws a descriptive error in environments that lack it (e.g. Node < 20).
|
|
26
|
-
*/
|
|
27
|
-
private ensureFileSupport;
|
|
28
|
-
/**
|
|
29
|
-
* Whether the adapter should default to verbose_json when no response format is specified.
|
|
30
|
-
* Override in provider-specific subclasses for model-specific behavior.
|
|
31
|
-
*/
|
|
32
|
-
protected shouldDefaultToVerbose(_model: string): boolean;
|
|
33
|
-
protected mapResponseFormat(format?: 'json' | 'text' | 'srt' | 'verbose_json' | 'vtt'): OpenAI_SDK.Audio.TranscriptionCreateParams['response_format'];
|
|
34
|
-
}
|
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
import { BaseTranscriptionAdapter } from "@tanstack/ai/adapters";
|
|
2
|
-
import { toRunErrorPayload } from "@tanstack/ai/adapter-internals";
|
|
3
|
-
import { generateId, base64ToArrayBuffer } from "@tanstack/ai-utils";
|
|
4
|
-
import { createOpenAICompatibleClient } from "../utils/client.js";
|
|
5
|
-
class OpenAICompatibleTranscriptionAdapter extends BaseTranscriptionAdapter {
|
|
6
|
-
constructor(config, model, name = "openai-compatible") {
|
|
7
|
-
super(model, {});
|
|
8
|
-
this.name = name;
|
|
9
|
-
this.client = createOpenAICompatibleClient(config);
|
|
10
|
-
}
|
|
11
|
-
async transcribe(options) {
|
|
12
|
-
const { model, audio, language, prompt, responseFormat, modelOptions } = options;
|
|
13
|
-
const file = this.prepareAudioFile(audio);
|
|
14
|
-
const request = {
|
|
15
|
-
model,
|
|
16
|
-
file,
|
|
17
|
-
language,
|
|
18
|
-
prompt,
|
|
19
|
-
response_format: this.mapResponseFormat(responseFormat),
|
|
20
|
-
...modelOptions
|
|
21
|
-
};
|
|
22
|
-
const useVerbose = responseFormat === "verbose_json" || !responseFormat && this.shouldDefaultToVerbose(model);
|
|
23
|
-
try {
|
|
24
|
-
options.logger.request(
|
|
25
|
-
`activity=transcription provider=${this.name} model=${model} verbose=${useVerbose}`,
|
|
26
|
-
{ provider: this.name, model }
|
|
27
|
-
);
|
|
28
|
-
if (useVerbose) {
|
|
29
|
-
const response = await this.client.audio.transcriptions.create({
|
|
30
|
-
...request,
|
|
31
|
-
response_format: "verbose_json"
|
|
32
|
-
});
|
|
33
|
-
return {
|
|
34
|
-
id: generateId(this.name),
|
|
35
|
-
model,
|
|
36
|
-
text: response.text,
|
|
37
|
-
language: response.language,
|
|
38
|
-
duration: response.duration,
|
|
39
|
-
segments: response.segments?.map(
|
|
40
|
-
(seg) => ({
|
|
41
|
-
id: seg.id,
|
|
42
|
-
start: seg.start,
|
|
43
|
-
end: seg.end,
|
|
44
|
-
text: seg.text,
|
|
45
|
-
// The OpenAI SDK types `avg_logprob` as `number`, so call Math.exp
|
|
46
|
-
// directly. Previously this was guarded with `seg.avg_logprob ?`
|
|
47
|
-
// which treated `0` (perfect-confidence) as missing.
|
|
48
|
-
confidence: Math.exp(seg.avg_logprob)
|
|
49
|
-
})
|
|
50
|
-
),
|
|
51
|
-
words: response.words?.map((w) => ({
|
|
52
|
-
word: w.word,
|
|
53
|
-
start: w.start,
|
|
54
|
-
end: w.end
|
|
55
|
-
}))
|
|
56
|
-
};
|
|
57
|
-
} else {
|
|
58
|
-
const response = await this.client.audio.transcriptions.create(request);
|
|
59
|
-
return {
|
|
60
|
-
id: generateId(this.name),
|
|
61
|
-
model,
|
|
62
|
-
text: typeof response === "string" ? response : response.text,
|
|
63
|
-
language
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
} catch (error) {
|
|
67
|
-
options.logger.errors(`${this.name}.transcribe fatal`, {
|
|
68
|
-
error: toRunErrorPayload(error, `${this.name}.transcribe failed`),
|
|
69
|
-
source: `${this.name}.transcribe`
|
|
70
|
-
});
|
|
71
|
-
throw error;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
prepareAudioFile(audio) {
|
|
75
|
-
if (typeof File !== "undefined" && audio instanceof File) {
|
|
76
|
-
return audio;
|
|
77
|
-
}
|
|
78
|
-
if (typeof Blob !== "undefined" && audio instanceof Blob) {
|
|
79
|
-
this.ensureFileSupport();
|
|
80
|
-
return new File([audio], "audio.mp3", {
|
|
81
|
-
type: audio.type || "audio/mpeg"
|
|
82
|
-
});
|
|
83
|
-
}
|
|
84
|
-
if (typeof ArrayBuffer !== "undefined" && audio instanceof ArrayBuffer) {
|
|
85
|
-
this.ensureFileSupport();
|
|
86
|
-
return new File([audio], "audio.mp3", { type: "audio/mpeg" });
|
|
87
|
-
}
|
|
88
|
-
if (typeof audio === "string") {
|
|
89
|
-
this.ensureFileSupport();
|
|
90
|
-
if (audio.startsWith("data:")) {
|
|
91
|
-
const parts = audio.split(",");
|
|
92
|
-
const header = parts[0];
|
|
93
|
-
const base64Data = parts[1] || "";
|
|
94
|
-
const mimeMatch = header?.match(/data:([^;]+)/);
|
|
95
|
-
const mimeType = mimeMatch?.[1] || "audio/mpeg";
|
|
96
|
-
const bytes2 = base64ToArrayBuffer(base64Data);
|
|
97
|
-
const extension = mimeType.split("/")[1] || "mp3";
|
|
98
|
-
return new File([bytes2], `audio.${extension}`, { type: mimeType });
|
|
99
|
-
}
|
|
100
|
-
const bytes = base64ToArrayBuffer(audio);
|
|
101
|
-
return new File([bytes], "audio.mp3", { type: "audio/mpeg" });
|
|
102
|
-
}
|
|
103
|
-
throw new Error("Invalid audio input type");
|
|
104
|
-
}
|
|
105
|
-
/**
|
|
106
|
-
* Checks that the global `File` constructor is available.
|
|
107
|
-
* Throws a descriptive error in environments that lack it (e.g. Node < 20).
|
|
108
|
-
*/
|
|
109
|
-
ensureFileSupport() {
|
|
110
|
-
if (typeof File === "undefined") {
|
|
111
|
-
throw new Error(
|
|
112
|
-
"`File` is not available in this environment. Use Node.js 20 or newer, or pass a File object directly."
|
|
113
|
-
);
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
/**
|
|
117
|
-
* Whether the adapter should default to verbose_json when no response format is specified.
|
|
118
|
-
* Override in provider-specific subclasses for model-specific behavior.
|
|
119
|
-
*/
|
|
120
|
-
shouldDefaultToVerbose(_model) {
|
|
121
|
-
return false;
|
|
122
|
-
}
|
|
123
|
-
mapResponseFormat(format) {
|
|
124
|
-
if (!format) return "json";
|
|
125
|
-
return format;
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
export {
|
|
129
|
-
OpenAICompatibleTranscriptionAdapter
|
|
130
|
-
};
|
|
131
|
-
//# sourceMappingURL=transcription.js.map
|