@kuralle-syrinx/gemini 2.1.1 → 3.0.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/package.json +2 -2
- package/src/index.test.ts +39 -0
- package/src/index.ts +3 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kuralle-syrinx/gemini",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"types": "./src/index.ts",
|
|
9
9
|
"dependencies": {
|
|
10
10
|
"@google/genai": "^1.0.0",
|
|
11
|
-
"@kuralle-syrinx/core": "
|
|
11
|
+
"@kuralle-syrinx/core": "3.0.0"
|
|
12
12
|
},
|
|
13
13
|
"devDependencies": {
|
|
14
14
|
"typescript": "^5.7.0",
|
package/src/index.test.ts
CHANGED
|
@@ -73,4 +73,43 @@ describe("GeminiTTSPlugin", () => {
|
|
|
73
73
|
bus.stop();
|
|
74
74
|
await started;
|
|
75
75
|
});
|
|
76
|
+
|
|
77
|
+
it("sends the raw text to Gemini by default (no hardcoded persona lead-in)", async () => {
|
|
78
|
+
generateContent.mockResolvedValue({
|
|
79
|
+
candidates: [{ content: { parts: [{ inlineData: { mimeType: "audio/pcm", data: Buffer.from(new Uint8Array([1, 2, 3, 4])).toString("base64") } }] } }],
|
|
80
|
+
});
|
|
81
|
+
const bus = new PipelineBusImpl();
|
|
82
|
+
const started = bus.start();
|
|
83
|
+
const plugin = new GeminiTTSPlugin();
|
|
84
|
+
await plugin.initialize(bus, { api_key: "test-gemini-key" });
|
|
85
|
+
bus.push(Route.Main, { kind: "tts.done", contextId: "t1", timestampMs: Date.now(), text: "Add Biology 101." });
|
|
86
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
87
|
+
|
|
88
|
+
expect(generateContent).toHaveBeenCalledTimes(1);
|
|
89
|
+
const arg = generateContent.mock.calls[0]![0] as { contents: Array<{ parts: Array<{ text: string }> }> };
|
|
90
|
+
expect(arg.contents[0]!.parts[0]!.text).toBe("Add Biology 101.");
|
|
91
|
+
|
|
92
|
+
await plugin.close();
|
|
93
|
+
bus.stop();
|
|
94
|
+
await started;
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it("prepends a configured instruction lead-in when provided", async () => {
|
|
98
|
+
generateContent.mockResolvedValue({
|
|
99
|
+
candidates: [{ content: { parts: [{ inlineData: { mimeType: "audio/pcm", data: Buffer.from(new Uint8Array([1, 2, 3, 4])).toString("base64") } }] } }],
|
|
100
|
+
});
|
|
101
|
+
const bus = new PipelineBusImpl();
|
|
102
|
+
const started = bus.start();
|
|
103
|
+
const plugin = new GeminiTTSPlugin();
|
|
104
|
+
await plugin.initialize(bus, { api_key: "test-gemini-key", instruction: "Read aloud warmly" });
|
|
105
|
+
bus.push(Route.Main, { kind: "tts.done", contextId: "t2", timestampMs: Date.now(), text: "Hi." });
|
|
106
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
107
|
+
|
|
108
|
+
const arg = generateContent.mock.calls[0]![0] as { contents: Array<{ parts: Array<{ text: string }> }> };
|
|
109
|
+
expect(arg.contents[0]!.parts[0]!.text).toBe("Read aloud warmly: Hi.");
|
|
110
|
+
|
|
111
|
+
await plugin.close();
|
|
112
|
+
bus.stop();
|
|
113
|
+
await started;
|
|
114
|
+
});
|
|
76
115
|
});
|
package/src/index.ts
CHANGED
|
@@ -59,6 +59,7 @@ export class GeminiTTSPlugin implements VoicePlugin {
|
|
|
59
59
|
private apiKey: string = "";
|
|
60
60
|
private model: string = DEFAULT_MODEL;
|
|
61
61
|
private voiceName: string = DEFAULT_VOICE;
|
|
62
|
+
private instruction = "";
|
|
62
63
|
private timeoutMs = 45_000;
|
|
63
64
|
private abortController: AbortController | null = null;
|
|
64
65
|
private textByContextId = new Map<string, string>();
|
|
@@ -71,6 +72,7 @@ export class GeminiTTSPlugin implements VoicePlugin {
|
|
|
71
72
|
this.apiKey = requireStringConfig(config, "api_key");
|
|
72
73
|
this.model = optionalStringConfig(config, "model") ?? DEFAULT_MODEL;
|
|
73
74
|
this.voiceName = optionalStringConfig(config, "voice_name") ?? DEFAULT_VOICE;
|
|
75
|
+
this.instruction = optionalStringConfig(config, "instruction") ?? "";
|
|
74
76
|
this.timeoutMs = readPositiveInteger(config["timeout_ms"], 45_000);
|
|
75
77
|
this.retryConfig = readRetryConfig(config);
|
|
76
78
|
assertAudioFormat(this.audioFormat);
|
|
@@ -171,7 +173,7 @@ export class GeminiTTSPlugin implements VoicePlugin {
|
|
|
171
173
|
const response = await withTimeout(
|
|
172
174
|
client.models.generateContent({
|
|
173
175
|
model: this.model,
|
|
174
|
-
contents: [{ parts: [{ text:
|
|
176
|
+
contents: [{ parts: [{ text: this.instruction ? `${this.instruction}: ${text}` : text }] }],
|
|
175
177
|
config: {
|
|
176
178
|
responseModalities: ["AUDIO"],
|
|
177
179
|
speechConfig: {
|