@node-llm/core 0.3.0 → 0.4.1
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 +176 -25
- package/dist/chat/Chat.d.ts +26 -1
- package/dist/chat/Chat.d.ts.map +1 -1
- package/dist/chat/Chat.js +83 -1
- package/dist/chat/ChatOptions.d.ts +5 -0
- package/dist/chat/ChatOptions.d.ts.map +1 -1
- package/dist/chat/ChatResponse.d.ts +5 -0
- package/dist/chat/ChatResponse.d.ts.map +1 -1
- package/dist/chat/ChatResponse.js +12 -0
- package/dist/constants.d.ts +7 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +6 -0
- package/dist/embedding/Embedding.d.ts +17 -0
- package/dist/embedding/Embedding.d.ts.map +1 -0
- package/dist/embedding/Embedding.js +24 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/llm.d.ts +11 -1
- package/dist/llm.d.ts.map +1 -1
- package/dist/llm.js +55 -28
- package/dist/providers/Embedding.d.ts +20 -0
- package/dist/providers/Embedding.d.ts.map +1 -0
- package/dist/providers/Embedding.js +1 -0
- package/dist/providers/Provider.d.ts +11 -4
- package/dist/providers/Provider.d.ts.map +1 -1
- package/dist/providers/gemini/Capabilities.d.ts +30 -0
- package/dist/providers/gemini/Capabilities.d.ts.map +1 -0
- package/dist/providers/gemini/Capabilities.js +148 -0
- package/dist/providers/gemini/Chat.d.ts +8 -0
- package/dist/providers/gemini/Chat.d.ts.map +1 -0
- package/dist/providers/gemini/Chat.js +69 -0
- package/dist/providers/gemini/ChatUtils.d.ts +9 -0
- package/dist/providers/gemini/ChatUtils.d.ts.map +1 -0
- package/dist/providers/gemini/ChatUtils.js +83 -0
- package/dist/providers/gemini/Embeddings.d.ts +8 -0
- package/dist/providers/gemini/Embeddings.d.ts.map +1 -0
- package/dist/providers/gemini/Embeddings.js +44 -0
- package/dist/providers/gemini/Errors.d.ts +2 -0
- package/dist/providers/gemini/Errors.d.ts.map +1 -0
- package/dist/providers/gemini/Errors.js +34 -0
- package/dist/providers/gemini/GeminiProvider.d.ts +34 -0
- package/dist/providers/gemini/GeminiProvider.d.ts.map +1 -0
- package/dist/providers/gemini/GeminiProvider.js +55 -0
- package/dist/providers/gemini/Image.d.ts +8 -0
- package/dist/providers/gemini/Image.d.ts.map +1 -0
- package/dist/providers/gemini/Image.js +47 -0
- package/dist/providers/gemini/Models.d.ts +8 -0
- package/dist/providers/gemini/Models.d.ts.map +1 -0
- package/dist/providers/gemini/Models.js +38 -0
- package/dist/providers/gemini/Streaming.d.ts +8 -0
- package/dist/providers/gemini/Streaming.d.ts.map +1 -0
- package/dist/providers/gemini/Streaming.js +70 -0
- package/dist/providers/gemini/Transcription.d.ts +9 -0
- package/dist/providers/gemini/Transcription.d.ts.map +1 -0
- package/dist/providers/gemini/Transcription.js +63 -0
- package/dist/providers/gemini/index.d.ts +11 -0
- package/dist/providers/gemini/index.d.ts.map +1 -0
- package/dist/providers/gemini/index.js +24 -0
- package/dist/providers/gemini/types.d.ts +118 -0
- package/dist/providers/gemini/types.d.ts.map +1 -0
- package/dist/providers/gemini/types.js +1 -0
- package/dist/providers/openai/Capabilities.d.ts +7 -2
- package/dist/providers/openai/Capabilities.d.ts.map +1 -1
- package/dist/providers/openai/Capabilities.js +52 -214
- package/dist/providers/openai/Chat.d.ts.map +1 -1
- package/dist/providers/openai/Chat.js +3 -0
- package/dist/providers/openai/Embedding.d.ts +8 -0
- package/dist/providers/openai/Embedding.d.ts.map +1 -0
- package/dist/providers/openai/Embedding.js +48 -0
- package/dist/providers/openai/ModelDefinitions.d.ts +25 -0
- package/dist/providers/openai/ModelDefinitions.d.ts.map +1 -0
- package/dist/providers/openai/ModelDefinitions.js +211 -0
- package/dist/providers/openai/Moderation.d.ts.map +1 -1
- package/dist/providers/openai/Moderation.js +3 -2
- package/dist/providers/openai/OpenAIProvider.d.ts +7 -0
- package/dist/providers/openai/OpenAIProvider.d.ts.map +1 -1
- package/dist/providers/openai/OpenAIProvider.js +10 -0
- package/dist/providers/openai/Transcription.d.ts.map +1 -1
- package/dist/providers/openai/Transcription.js +5 -4
- package/dist/schema/Schema.d.ts +20 -0
- package/dist/schema/Schema.d.ts.map +1 -0
- package/dist/schema/Schema.js +22 -0
- package/dist/schema/to-json-schema.d.ts +3 -0
- package/dist/schema/to-json-schema.d.ts.map +1 -0
- package/dist/schema/to-json-schema.js +10 -0
- package/dist/utils/Binary.d.ts +12 -0
- package/dist/utils/Binary.d.ts.map +1 -0
- package/dist/utils/Binary.js +71 -0
- package/package.json +3 -2
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { BinaryUtils } from "../../utils/Binary.js";
|
|
2
|
+
export class GeminiChatUtils {
|
|
3
|
+
static async convertMessages(messages) {
|
|
4
|
+
const contents = [];
|
|
5
|
+
const systemInstructionParts = [];
|
|
6
|
+
for (const msg of messages) {
|
|
7
|
+
if (msg.role === "system") {
|
|
8
|
+
if (typeof msg.content === "string") {
|
|
9
|
+
systemInstructionParts.push({ text: msg.content });
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
else if (msg.role === "user" || msg.role === "assistant" || msg.role === "tool") {
|
|
13
|
+
const parts = [];
|
|
14
|
+
if (msg.role === "tool") {
|
|
15
|
+
parts.push({
|
|
16
|
+
functionResponse: {
|
|
17
|
+
name: msg.tool_call_id || "unknown",
|
|
18
|
+
response: { result: msg.content },
|
|
19
|
+
},
|
|
20
|
+
});
|
|
21
|
+
contents.push({ role: "user", parts });
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
const role = msg.role === "assistant" ? "model" : "user";
|
|
25
|
+
if (typeof msg.content === "string" && msg.content) {
|
|
26
|
+
parts.push({ text: msg.content });
|
|
27
|
+
}
|
|
28
|
+
else if (Array.isArray(msg.content)) {
|
|
29
|
+
for (const part of msg.content) {
|
|
30
|
+
if (part.type === "text") {
|
|
31
|
+
parts.push({ text: part.text });
|
|
32
|
+
}
|
|
33
|
+
else if (part.type === "image_url") {
|
|
34
|
+
const binary = await BinaryUtils.toBase64(part.image_url.url);
|
|
35
|
+
if (binary) {
|
|
36
|
+
parts.push({
|
|
37
|
+
inlineData: {
|
|
38
|
+
mimeType: binary.mimeType,
|
|
39
|
+
data: binary.data,
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
else if (part.type === "input_audio") {
|
|
45
|
+
parts.push({
|
|
46
|
+
inlineData: {
|
|
47
|
+
mimeType: `audio/${part.input_audio.format}`,
|
|
48
|
+
data: part.input_audio.data,
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
else if (part.type === "video_url") {
|
|
53
|
+
const binary = await BinaryUtils.toBase64(part.video_url.url);
|
|
54
|
+
if (binary) {
|
|
55
|
+
parts.push({
|
|
56
|
+
inlineData: {
|
|
57
|
+
mimeType: binary.mimeType,
|
|
58
|
+
data: binary.data,
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if (msg.role === "assistant" && msg.tool_calls) {
|
|
66
|
+
for (const call of msg.tool_calls) {
|
|
67
|
+
parts.push({
|
|
68
|
+
functionCall: {
|
|
69
|
+
name: call.function.name,
|
|
70
|
+
args: JSON.parse(call.function.arguments),
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
if (parts.length > 0) {
|
|
76
|
+
contents.push({ role, parts });
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return { contents, systemInstructionParts };
|
|
82
|
+
}
|
|
83
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { EmbeddingRequest, EmbeddingResponse } from "../Embedding.js";
|
|
2
|
+
export declare class GeminiEmbeddings {
|
|
3
|
+
private readonly baseUrl;
|
|
4
|
+
private readonly apiKey;
|
|
5
|
+
constructor(baseUrl: string, apiKey: string);
|
|
6
|
+
execute(request: EmbeddingRequest): Promise<EmbeddingResponse>;
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=Embeddings.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Embeddings.d.ts","sourceRoot":"","sources":["../../../src/providers/gemini/Embeddings.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAItE,qBAAa,gBAAgB;IACf,OAAO,CAAC,QAAQ,CAAC,OAAO;IAAU,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAxC,OAAO,EAAE,MAAM,EAAmB,MAAM,EAAE,MAAM;IAEvE,OAAO,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,iBAAiB,CAAC;CAwCrE"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { handleGeminiError } from "./Errors.js";
|
|
2
|
+
export class GeminiEmbeddings {
|
|
3
|
+
baseUrl;
|
|
4
|
+
apiKey;
|
|
5
|
+
constructor(baseUrl, apiKey) {
|
|
6
|
+
this.baseUrl = baseUrl;
|
|
7
|
+
this.apiKey = apiKey;
|
|
8
|
+
}
|
|
9
|
+
async execute(request) {
|
|
10
|
+
const modelId = request.model || "text-embedding-004";
|
|
11
|
+
const url = `${this.baseUrl}/models/${modelId}:batchEmbedContents?key=${this.apiKey}`;
|
|
12
|
+
const inputs = Array.isArray(request.input) ? request.input : [request.input];
|
|
13
|
+
const payload = {
|
|
14
|
+
requests: inputs.map(text => {
|
|
15
|
+
const item = {
|
|
16
|
+
model: `models/${modelId}`,
|
|
17
|
+
content: {
|
|
18
|
+
parts: [{ text: String(text) }]
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
if (request.dimensions) {
|
|
22
|
+
item.outputDimensionality = request.dimensions;
|
|
23
|
+
}
|
|
24
|
+
return item;
|
|
25
|
+
})
|
|
26
|
+
};
|
|
27
|
+
const response = await fetch(url, {
|
|
28
|
+
method: "POST",
|
|
29
|
+
headers: { "Content-Type": "application/json" },
|
|
30
|
+
body: JSON.stringify(payload)
|
|
31
|
+
});
|
|
32
|
+
if (!response.ok) {
|
|
33
|
+
await handleGeminiError(response, modelId);
|
|
34
|
+
}
|
|
35
|
+
const json = (await response.json());
|
|
36
|
+
const vectors = json.embeddings?.map(e => e.values) || [];
|
|
37
|
+
return {
|
|
38
|
+
model: modelId,
|
|
39
|
+
vectors: vectors,
|
|
40
|
+
input_tokens: 0,
|
|
41
|
+
dimensions: vectors[0]?.length || 0
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Errors.d.ts","sourceRoot":"","sources":["../../../src/providers/gemini/Errors.ts"],"names":[],"mappings":"AASA,wBAAsB,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,CAuC1F"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { BadRequestError, AuthenticationError, RateLimitError, ServerError, ServiceUnavailableError, APIError } from "../../errors/index.js";
|
|
2
|
+
export async function handleGeminiError(response, model) {
|
|
3
|
+
const status = response.status;
|
|
4
|
+
let body;
|
|
5
|
+
let message = `Gemini error (${status})`;
|
|
6
|
+
try {
|
|
7
|
+
body = await response.json();
|
|
8
|
+
if (body?.error?.message) {
|
|
9
|
+
message = body.error.message;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
// If not JSON, use the status text
|
|
14
|
+
body = await response.text().catch(() => "Unknown error");
|
|
15
|
+
message = `Gemini error (${status}): ${body}`;
|
|
16
|
+
}
|
|
17
|
+
const provider = "gemini";
|
|
18
|
+
if (status === 400) {
|
|
19
|
+
throw new BadRequestError(message, body, provider, model);
|
|
20
|
+
}
|
|
21
|
+
if (status === 401 || status === 403) {
|
|
22
|
+
throw new AuthenticationError(message, status, body, provider);
|
|
23
|
+
}
|
|
24
|
+
if (status === 429) {
|
|
25
|
+
throw new RateLimitError(message, body, provider, model);
|
|
26
|
+
}
|
|
27
|
+
if (status === 502 || status === 503 || status === 504) {
|
|
28
|
+
throw new ServiceUnavailableError(message, status, body, provider, model);
|
|
29
|
+
}
|
|
30
|
+
if (status >= 500) {
|
|
31
|
+
throw new ServerError(message, status, body, provider, model);
|
|
32
|
+
}
|
|
33
|
+
throw new APIError(message, status, body, provider, model);
|
|
34
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Provider, ChatRequest, ChatResponse, ModelInfo, ChatChunk, ImageRequest, ImageResponse, TranscriptionRequest, TranscriptionResponse } from "../Provider.js";
|
|
2
|
+
import { EmbeddingRequest, EmbeddingResponse } from "../Embedding.js";
|
|
3
|
+
export interface GeminiProviderOptions {
|
|
4
|
+
apiKey: string;
|
|
5
|
+
baseUrl?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare class GeminiProvider implements Provider {
|
|
8
|
+
private readonly options;
|
|
9
|
+
private readonly baseUrl;
|
|
10
|
+
private readonly chatHandler;
|
|
11
|
+
private readonly streamingHandler;
|
|
12
|
+
private readonly modelsHandler;
|
|
13
|
+
private readonly imageHandler;
|
|
14
|
+
private readonly embeddingHandler;
|
|
15
|
+
private readonly transcriptionHandler;
|
|
16
|
+
capabilities: {
|
|
17
|
+
supportsVision: (model: string) => boolean;
|
|
18
|
+
supportsTools: (model: string) => boolean;
|
|
19
|
+
supportsStructuredOutput: (model: string) => boolean;
|
|
20
|
+
supportsEmbeddings: (model: string) => boolean;
|
|
21
|
+
supportsImageGeneration: (model: string) => boolean;
|
|
22
|
+
supportsTranscription: (model: string) => boolean;
|
|
23
|
+
supportsModeration: (model: string) => boolean;
|
|
24
|
+
getContextWindow: (model: string) => number | null;
|
|
25
|
+
};
|
|
26
|
+
constructor(options: GeminiProviderOptions);
|
|
27
|
+
chat(request: ChatRequest): Promise<ChatResponse>;
|
|
28
|
+
stream(request: ChatRequest): AsyncGenerator<ChatChunk>;
|
|
29
|
+
listModels(): Promise<ModelInfo[]>;
|
|
30
|
+
paint(request: ImageRequest): Promise<ImageResponse>;
|
|
31
|
+
embed(request: EmbeddingRequest): Promise<EmbeddingResponse>;
|
|
32
|
+
transcribe(request: TranscriptionRequest): Promise<TranscriptionResponse>;
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=GeminiProvider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GeminiProvider.d.ts","sourceRoot":"","sources":["../../../src/providers/gemini/GeminiProvider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,YAAY,EAAE,SAAS,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAQrK,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAEtE,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,qBAAa,cAAe,YAAW,QAAQ;IAoBjC,OAAO,CAAC,QAAQ,CAAC,OAAO;IAnBpC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAa;IACzC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAkB;IACnD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAe;IAC7C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAc;IAC3C,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAmB;IACpD,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAsB;IAEpD,YAAY;gCACO,MAAM;+BACP,MAAM;0CACK,MAAM;oCACZ,MAAM;yCACD,MAAM;uCACR,MAAM;oCACT,MAAM;kCACR,MAAM;MAChC;gBAE2B,OAAO,EAAE,qBAAqB;IAUrD,IAAI,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;IAIhD,MAAM,CAAC,OAAO,EAAE,WAAW,GAAG,cAAc,CAAC,SAAS,CAAC;IAIxD,UAAU,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;IAIlC,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC;IAIpD,KAAK,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAI5D,UAAU,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,qBAAqB,CAAC;CAGhF"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { Capabilities } from "./Capabilities.js";
|
|
2
|
+
import { GeminiChat } from "./Chat.js";
|
|
3
|
+
import { GeminiStreaming } from "./Streaming.js";
|
|
4
|
+
import { GeminiModels } from "./Models.js";
|
|
5
|
+
import { GeminiImage } from "./Image.js";
|
|
6
|
+
import { GeminiEmbeddings } from "./Embeddings.js";
|
|
7
|
+
import { GeminiTranscription } from "./Transcription.js";
|
|
8
|
+
export class GeminiProvider {
|
|
9
|
+
options;
|
|
10
|
+
baseUrl;
|
|
11
|
+
chatHandler;
|
|
12
|
+
streamingHandler;
|
|
13
|
+
modelsHandler;
|
|
14
|
+
imageHandler;
|
|
15
|
+
embeddingHandler;
|
|
16
|
+
transcriptionHandler;
|
|
17
|
+
capabilities = {
|
|
18
|
+
supportsVision: (model) => Capabilities.supportsVision(model),
|
|
19
|
+
supportsTools: (model) => Capabilities.supportsTools(model),
|
|
20
|
+
supportsStructuredOutput: (model) => Capabilities.supportsStructuredOutput(model),
|
|
21
|
+
supportsEmbeddings: (model) => Capabilities.supportsEmbeddings(model),
|
|
22
|
+
supportsImageGeneration: (model) => Capabilities.supportsImageGeneration(model),
|
|
23
|
+
supportsTranscription: (model) => Capabilities.supportsTranscription(model),
|
|
24
|
+
supportsModeration: (model) => Capabilities.supportsModeration(model),
|
|
25
|
+
getContextWindow: (model) => Capabilities.getContextWindow(model),
|
|
26
|
+
};
|
|
27
|
+
constructor(options) {
|
|
28
|
+
this.options = options;
|
|
29
|
+
this.baseUrl = options.baseUrl ?? "https://generativelanguage.googleapis.com/v1beta";
|
|
30
|
+
this.chatHandler = new GeminiChat(this.baseUrl, options.apiKey);
|
|
31
|
+
this.streamingHandler = new GeminiStreaming(this.baseUrl, options.apiKey);
|
|
32
|
+
this.modelsHandler = new GeminiModels(this.baseUrl, options.apiKey);
|
|
33
|
+
this.imageHandler = new GeminiImage(this.baseUrl, options.apiKey);
|
|
34
|
+
this.embeddingHandler = new GeminiEmbeddings(this.baseUrl, options.apiKey);
|
|
35
|
+
this.transcriptionHandler = new GeminiTranscription(this.baseUrl, options.apiKey);
|
|
36
|
+
}
|
|
37
|
+
async chat(request) {
|
|
38
|
+
return this.chatHandler.execute(request);
|
|
39
|
+
}
|
|
40
|
+
async *stream(request) {
|
|
41
|
+
yield* this.streamingHandler.execute(request);
|
|
42
|
+
}
|
|
43
|
+
async listModels() {
|
|
44
|
+
return this.modelsHandler.execute();
|
|
45
|
+
}
|
|
46
|
+
async paint(request) {
|
|
47
|
+
return this.imageHandler.execute(request);
|
|
48
|
+
}
|
|
49
|
+
async embed(request) {
|
|
50
|
+
return this.embeddingHandler.execute(request);
|
|
51
|
+
}
|
|
52
|
+
async transcribe(request) {
|
|
53
|
+
return this.transcriptionHandler.execute(request);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { ImageRequest, ImageResponse } from "../Provider.js";
|
|
2
|
+
export declare class GeminiImage {
|
|
3
|
+
private readonly baseUrl;
|
|
4
|
+
private readonly apiKey;
|
|
5
|
+
constructor(baseUrl: string, apiKey: string);
|
|
6
|
+
execute(request: ImageRequest): Promise<ImageResponse>;
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=Image.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Image.d.ts","sourceRoot":"","sources":["../../../src/providers/gemini/Image.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAG7D,qBAAa,WAAW;IACV,OAAO,CAAC,QAAQ,CAAC,OAAO;IAAU,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAxC,OAAO,EAAE,MAAM,EAAmB,MAAM,EAAE,MAAM;IAEvE,OAAO,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC;CA8C7D"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { handleGeminiError } from "./Errors.js";
|
|
2
|
+
export class GeminiImage {
|
|
3
|
+
baseUrl;
|
|
4
|
+
apiKey;
|
|
5
|
+
constructor(baseUrl, apiKey) {
|
|
6
|
+
this.baseUrl = baseUrl;
|
|
7
|
+
this.apiKey = apiKey;
|
|
8
|
+
}
|
|
9
|
+
async execute(request) {
|
|
10
|
+
const modelId = request.model || "imagen-4.0-generate-001";
|
|
11
|
+
const url = `${this.baseUrl}/models/${modelId}:predict?key=${this.apiKey}`;
|
|
12
|
+
if (request.size) {
|
|
13
|
+
console.log(`[Gemini] Ignoring size ${request.size}. Gemini does not support image size customization.`);
|
|
14
|
+
}
|
|
15
|
+
const body = {
|
|
16
|
+
instances: [
|
|
17
|
+
{
|
|
18
|
+
prompt: request.prompt,
|
|
19
|
+
},
|
|
20
|
+
],
|
|
21
|
+
parameters: {
|
|
22
|
+
sampleCount: 1,
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
const response = await fetch(url, {
|
|
26
|
+
method: "POST",
|
|
27
|
+
headers: {
|
|
28
|
+
"Content-Type": "application/json",
|
|
29
|
+
},
|
|
30
|
+
body: JSON.stringify(body),
|
|
31
|
+
});
|
|
32
|
+
if (!response.ok) {
|
|
33
|
+
await handleGeminiError(response, modelId);
|
|
34
|
+
}
|
|
35
|
+
const json = await response.json();
|
|
36
|
+
const imageData = json.predictions?.[0];
|
|
37
|
+
if (!imageData || !imageData.bytesBase64Encoded) {
|
|
38
|
+
throw new Error("Unexpected response format from Gemini image generation API");
|
|
39
|
+
}
|
|
40
|
+
const mimeType = imageData.mimeType || "image/png";
|
|
41
|
+
const base64Data = imageData.bytesBase64Encoded;
|
|
42
|
+
return {
|
|
43
|
+
data: base64Data,
|
|
44
|
+
mime_type: mimeType,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Models.d.ts","sourceRoot":"","sources":["../../../src/providers/gemini/Models.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAI3C,qBAAa,YAAY;IACX,OAAO,CAAC,QAAQ,CAAC,OAAO;IAAU,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAxC,OAAO,EAAE,MAAM,EAAmB,MAAM,EAAE,MAAM;IAEvE,OAAO,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;CAgCtC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Capabilities } from "./Capabilities.js";
|
|
2
|
+
export class GeminiModels {
|
|
3
|
+
baseUrl;
|
|
4
|
+
apiKey;
|
|
5
|
+
constructor(baseUrl, apiKey) {
|
|
6
|
+
this.baseUrl = baseUrl;
|
|
7
|
+
this.apiKey = apiKey;
|
|
8
|
+
}
|
|
9
|
+
async execute() {
|
|
10
|
+
const url = `${this.baseUrl}/models?key=${this.apiKey}`;
|
|
11
|
+
const response = await fetch(url);
|
|
12
|
+
if (!response.ok) {
|
|
13
|
+
const errorText = await response.text();
|
|
14
|
+
throw new Error(`Gemini error (${response.status}): ${errorText}`);
|
|
15
|
+
}
|
|
16
|
+
const json = (await response.json());
|
|
17
|
+
return json.models
|
|
18
|
+
.filter(m => m.supportedGenerationMethods.includes("generateContent"))
|
|
19
|
+
.map((model) => {
|
|
20
|
+
const id = model.name.replace("models/", "");
|
|
21
|
+
return {
|
|
22
|
+
id: id,
|
|
23
|
+
name: model.displayName || Capabilities.formatDisplayName(id),
|
|
24
|
+
provider: "gemini",
|
|
25
|
+
family: Capabilities.getFamily(id),
|
|
26
|
+
context_window: model.inputTokenLimit || Capabilities.getContextWindow(id),
|
|
27
|
+
max_output_tokens: model.outputTokenLimit || Capabilities.getMaxOutputTokens(id),
|
|
28
|
+
modalities: Capabilities.getModalities(id),
|
|
29
|
+
capabilities: Capabilities.getCapabilities(id),
|
|
30
|
+
pricing: Capabilities.getPricing(id),
|
|
31
|
+
metadata: {
|
|
32
|
+
description: model.description,
|
|
33
|
+
version: model.version,
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { ChatRequest, ChatChunk } from "../Provider.js";
|
|
2
|
+
export declare class GeminiStreaming {
|
|
3
|
+
private readonly baseUrl;
|
|
4
|
+
private readonly apiKey;
|
|
5
|
+
constructor(baseUrl: string, apiKey: string);
|
|
6
|
+
execute(request: ChatRequest): AsyncGenerator<ChatChunk>;
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=Streaming.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Streaming.d.ts","sourceRoot":"","sources":["../../../src/providers/gemini/Streaming.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAMxD,qBAAa,eAAe;IACd,OAAO,CAAC,QAAQ,CAAC,OAAO;IAAU,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAxC,OAAO,EAAE,MAAM,EAAmB,MAAM,EAAE,MAAM;IAEtE,OAAO,CAAC,OAAO,EAAE,WAAW,GAAG,cAAc,CAAC,SAAS,CAAC;CAoEhE"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { Capabilities } from "./Capabilities.js";
|
|
2
|
+
import { handleGeminiError } from "./Errors.js";
|
|
3
|
+
import { GeminiChatUtils } from "./ChatUtils.js";
|
|
4
|
+
export class GeminiStreaming {
|
|
5
|
+
baseUrl;
|
|
6
|
+
apiKey;
|
|
7
|
+
constructor(baseUrl, apiKey) {
|
|
8
|
+
this.baseUrl = baseUrl;
|
|
9
|
+
this.apiKey = apiKey;
|
|
10
|
+
}
|
|
11
|
+
async *execute(request) {
|
|
12
|
+
const temperature = Capabilities.normalizeTemperature(request.temperature, request.model);
|
|
13
|
+
const url = `${this.baseUrl}/models/${request.model}:streamGenerateContent?alt=sse&key=${this.apiKey}`;
|
|
14
|
+
const { contents, systemInstructionParts } = await GeminiChatUtils.convertMessages(request.messages);
|
|
15
|
+
const payload = {
|
|
16
|
+
contents,
|
|
17
|
+
generationConfig: {
|
|
18
|
+
temperature: temperature ?? undefined,
|
|
19
|
+
maxOutputTokens: request.max_tokens,
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
if (systemInstructionParts.length > 0) {
|
|
23
|
+
payload.systemInstruction = { parts: systemInstructionParts };
|
|
24
|
+
}
|
|
25
|
+
const response = await fetch(url, {
|
|
26
|
+
method: "POST",
|
|
27
|
+
headers: {
|
|
28
|
+
"Content-Type": "application/json",
|
|
29
|
+
},
|
|
30
|
+
body: JSON.stringify(payload),
|
|
31
|
+
});
|
|
32
|
+
if (!response.ok) {
|
|
33
|
+
await handleGeminiError(response, request.model);
|
|
34
|
+
}
|
|
35
|
+
if (!response.body) {
|
|
36
|
+
throw new Error("No response body for streaming");
|
|
37
|
+
}
|
|
38
|
+
const reader = response.body.getReader();
|
|
39
|
+
const decoder = new TextDecoder();
|
|
40
|
+
let buffer = "";
|
|
41
|
+
while (true) {
|
|
42
|
+
const { value, done } = await reader.read();
|
|
43
|
+
if (done)
|
|
44
|
+
break;
|
|
45
|
+
buffer += decoder.decode(value, { stream: true });
|
|
46
|
+
let lineEnd;
|
|
47
|
+
while ((lineEnd = buffer.indexOf("\n")) !== -1) {
|
|
48
|
+
const line = buffer.substring(0, lineEnd).trim();
|
|
49
|
+
buffer = buffer.substring(lineEnd + 1);
|
|
50
|
+
if (line.startsWith("data: ")) {
|
|
51
|
+
const data = line.substring(6).trim();
|
|
52
|
+
if (!data)
|
|
53
|
+
continue;
|
|
54
|
+
try {
|
|
55
|
+
const json = JSON.parse(data);
|
|
56
|
+
const parts = json.candidates?.[0]?.content?.parts || [];
|
|
57
|
+
for (const part of parts) {
|
|
58
|
+
if (part.text) {
|
|
59
|
+
yield { content: part.text };
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
catch (e) {
|
|
64
|
+
// Ignore parse errors
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { TranscriptionRequest, TranscriptionResponse } from "../Provider.js";
|
|
2
|
+
export declare class GeminiTranscription {
|
|
3
|
+
private readonly baseUrl;
|
|
4
|
+
private readonly apiKey;
|
|
5
|
+
private static readonly DEFAULT_PROMPT;
|
|
6
|
+
constructor(baseUrl: string, apiKey: string);
|
|
7
|
+
execute(request: TranscriptionRequest): Promise<TranscriptionResponse>;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=Transcription.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Transcription.d.ts","sourceRoot":"","sources":["../../../src/providers/gemini/Transcription.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAK7E,qBAAa,mBAAmB;IAGlB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAAU,OAAO,CAAC,QAAQ,CAAC,MAAM;IAFrE,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAA8E;gBAEvF,OAAO,EAAE,MAAM,EAAmB,MAAM,EAAE,MAAM;IAEvE,OAAO,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,qBAAqB,CAAC;CA2D7E"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { handleGeminiError } from "./Errors.js";
|
|
2
|
+
import { BinaryUtils } from "../../utils/Binary.js";
|
|
3
|
+
export class GeminiTranscription {
|
|
4
|
+
baseUrl;
|
|
5
|
+
apiKey;
|
|
6
|
+
static DEFAULT_PROMPT = "Transcribe the provided audio and respond with only the transcript text.";
|
|
7
|
+
constructor(baseUrl, apiKey) {
|
|
8
|
+
this.baseUrl = baseUrl;
|
|
9
|
+
this.apiKey = apiKey;
|
|
10
|
+
}
|
|
11
|
+
async execute(request) {
|
|
12
|
+
const model = request.model || "gemini-2.0-flash";
|
|
13
|
+
const url = `${this.baseUrl}/models/${model}:generateContent?key=${this.apiKey}`;
|
|
14
|
+
const result = await BinaryUtils.toBase64(request.file);
|
|
15
|
+
if (!result) {
|
|
16
|
+
throw new Error(`Failed to load audio file: ${request.file}`);
|
|
17
|
+
}
|
|
18
|
+
const { data: base64Data, mimeType } = result;
|
|
19
|
+
let prompt = GeminiTranscription.DEFAULT_PROMPT;
|
|
20
|
+
if (request.language) {
|
|
21
|
+
prompt += ` Respond in the ${request.language} language.`;
|
|
22
|
+
}
|
|
23
|
+
if (request.prompt) {
|
|
24
|
+
prompt += ` ${request.prompt}`;
|
|
25
|
+
}
|
|
26
|
+
const payload = {
|
|
27
|
+
contents: [
|
|
28
|
+
{
|
|
29
|
+
role: "user",
|
|
30
|
+
parts: [
|
|
31
|
+
{ text: prompt },
|
|
32
|
+
{
|
|
33
|
+
inlineData: {
|
|
34
|
+
mimeType,
|
|
35
|
+
data: base64Data,
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
],
|
|
39
|
+
},
|
|
40
|
+
],
|
|
41
|
+
generationConfig: {
|
|
42
|
+
responseMimeType: "text/plain",
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
const response = await fetch(url, {
|
|
46
|
+
method: "POST",
|
|
47
|
+
headers: {
|
|
48
|
+
"Content-Type": "application/json",
|
|
49
|
+
},
|
|
50
|
+
body: JSON.stringify(payload),
|
|
51
|
+
});
|
|
52
|
+
if (!response.ok) {
|
|
53
|
+
await handleGeminiError(response, model);
|
|
54
|
+
}
|
|
55
|
+
const json = (await response.json());
|
|
56
|
+
const text = json.candidates?.[0]?.content?.parts?.map(p => p.text).join("") || "";
|
|
57
|
+
return {
|
|
58
|
+
text,
|
|
59
|
+
model,
|
|
60
|
+
segments: [], // Gemini's generateContent doesn't return segments by default
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Idempotent registration of the Gemini provider.
|
|
3
|
+
* Automatically called by LLM.configure({ provider: 'gemini' })
|
|
4
|
+
*/
|
|
5
|
+
export declare function registerGeminiProvider(): void;
|
|
6
|
+
/**
|
|
7
|
+
* Alias for registerGeminiProvider for internal use.
|
|
8
|
+
*/
|
|
9
|
+
export declare const ensureGeminiRegistered: typeof registerGeminiProvider;
|
|
10
|
+
export * from "./GeminiProvider.js";
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/providers/gemini/index.ts"],"names":[],"mappings":"AAKA;;;GAGG;AACH,wBAAgB,sBAAsB,SAcrC;AAED;;GAEG;AACH,eAAO,MAAM,sBAAsB,+BAAyB,CAAC;AAE7D,cAAc,qBAAqB,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { providerRegistry } from "../registry.js";
|
|
2
|
+
import { GeminiProvider } from "./GeminiProvider.js";
|
|
3
|
+
let registered = false;
|
|
4
|
+
/**
|
|
5
|
+
* Idempotent registration of the Gemini provider.
|
|
6
|
+
* Automatically called by LLM.configure({ provider: 'gemini' })
|
|
7
|
+
*/
|
|
8
|
+
export function registerGeminiProvider() {
|
|
9
|
+
if (registered)
|
|
10
|
+
return;
|
|
11
|
+
providerRegistry.register("gemini", () => {
|
|
12
|
+
const apiKey = process.env.GEMINI_API_KEY;
|
|
13
|
+
if (!apiKey) {
|
|
14
|
+
throw new Error("GEMINI_API_KEY is not set");
|
|
15
|
+
}
|
|
16
|
+
return new GeminiProvider({ apiKey });
|
|
17
|
+
});
|
|
18
|
+
registered = true;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Alias for registerGeminiProvider for internal use.
|
|
22
|
+
*/
|
|
23
|
+
export const ensureGeminiRegistered = registerGeminiProvider;
|
|
24
|
+
export * from "./GeminiProvider.js";
|