@umituz/react-native-ai-gemini-provider 3.0.18 → 3.0.19
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 +1 -1
- package/src/domain/entities/gemini.types.ts +45 -0
- package/src/domain/entities/models.ts +6 -0
- package/src/index.ts +6 -0
- package/src/infrastructure/services/ChatSession.ts +54 -0
- package/src/infrastructure/services/GeminiClient.ts +41 -5
- package/src/infrastructure/services/index.ts +1 -0
package/package.json
CHANGED
|
@@ -111,3 +111,48 @@ export interface GeminiUsageMetadata {
|
|
|
111
111
|
/** Total number of tokens used */
|
|
112
112
|
totalTokenCount?: number;
|
|
113
113
|
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Safety setting for a single harm category
|
|
117
|
+
*/
|
|
118
|
+
export interface GeminiSafetySetting {
|
|
119
|
+
category: GeminiHarmCategory;
|
|
120
|
+
threshold: GeminiHarmBlockThreshold;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Inline data part for binary content (images, audio)
|
|
125
|
+
*/
|
|
126
|
+
export interface GeminiInlineDataPart {
|
|
127
|
+
inlineData: { mimeType: string; data: string };
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* A message part that can be text or inline data
|
|
132
|
+
*/
|
|
133
|
+
export type GeminiMessagePart = GeminiPart | GeminiInlineDataPart;
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Options for creating a generative model instance
|
|
137
|
+
*/
|
|
138
|
+
export interface GeminiModelOptions {
|
|
139
|
+
model?: string;
|
|
140
|
+
systemInstruction?: string;
|
|
141
|
+
safetySettings?: GeminiSafetySetting[];
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Configuration for a chat session
|
|
146
|
+
*/
|
|
147
|
+
export interface GeminiChatConfig {
|
|
148
|
+
/** Model name override */
|
|
149
|
+
model?: string;
|
|
150
|
+
/** System instruction for the model */
|
|
151
|
+
systemInstruction?: string;
|
|
152
|
+
/** Safety settings (defaults to BLOCK_NONE for all categories) */
|
|
153
|
+
safetySettings?: GeminiSafetySetting[];
|
|
154
|
+
/** Generation config (temperature, maxOutputTokens, etc.) */
|
|
155
|
+
generationConfig?: GeminiGenerationConfig;
|
|
156
|
+
/** Initial conversation history */
|
|
157
|
+
history?: GeminiContent[];
|
|
158
|
+
}
|
|
@@ -6,6 +6,10 @@ export const GEMINI_MODELS = {
|
|
|
6
6
|
TEXT: {
|
|
7
7
|
/** Lightweight flash model for fast text generation */
|
|
8
8
|
FLASH_LITE: "gemini-2.5-flash-lite",
|
|
9
|
+
/** Balanced flash model for general use */
|
|
10
|
+
FLASH: "gemini-2.5-flash",
|
|
11
|
+
/** Premium model for complex tasks */
|
|
12
|
+
PRO: "gemini-2.5-pro",
|
|
9
13
|
},
|
|
10
14
|
} as const;
|
|
11
15
|
|
|
@@ -15,4 +19,6 @@ export const GEMINI_MODELS = {
|
|
|
15
19
|
export const DEFAULT_MODELS = {
|
|
16
20
|
/** Default model for text generation */
|
|
17
21
|
TEXT: GEMINI_MODELS.TEXT.FLASH_LITE,
|
|
22
|
+
/** Default model for chat sessions */
|
|
23
|
+
CHAT: GEMINI_MODELS.TEXT.FLASH,
|
|
18
24
|
} as const;
|
package/src/index.ts
CHANGED
|
@@ -11,6 +11,11 @@ export type {
|
|
|
11
11
|
GeminiHarmBlockThreshold,
|
|
12
12
|
GeminiContent,
|
|
13
13
|
GeminiPart,
|
|
14
|
+
GeminiInlineDataPart,
|
|
15
|
+
GeminiMessagePart,
|
|
16
|
+
GeminiSafetySetting,
|
|
17
|
+
GeminiModelOptions,
|
|
18
|
+
GeminiChatConfig,
|
|
14
19
|
GeminiResponse,
|
|
15
20
|
GeminiCandidate,
|
|
16
21
|
GeminiFinishReason,
|
|
@@ -29,6 +34,7 @@ export {
|
|
|
29
34
|
|
|
30
35
|
// Services
|
|
31
36
|
export { geminiClient } from "./infrastructure/services/GeminiClient";
|
|
37
|
+
export { createChatSession } from "./infrastructure/services/ChatSession";
|
|
32
38
|
export { textGeneration } from "./infrastructure/services/TextGeneration";
|
|
33
39
|
export { structuredText } from "./infrastructure/services/StructuredText";
|
|
34
40
|
export { streaming } from "./infrastructure/services/Streaming";
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { ChatSession as SdkChatSession, Part } from "@google/generative-ai";
|
|
2
|
+
import { geminiClient } from "./GeminiClient";
|
|
3
|
+
import { DEFAULT_MODELS } from "../../domain/entities";
|
|
4
|
+
import type {
|
|
5
|
+
GeminiChatConfig,
|
|
6
|
+
GeminiContent,
|
|
7
|
+
GeminiMessagePart,
|
|
8
|
+
} from "../../domain/entities";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Creates a Gemini chat session with full support for system instructions,
|
|
12
|
+
* safety settings, generation config, and multi-turn conversation history.
|
|
13
|
+
*
|
|
14
|
+
* Usage:
|
|
15
|
+
* ```ts
|
|
16
|
+
* const session = createChatSession({
|
|
17
|
+
* model: "gemini-2.5-flash",
|
|
18
|
+
* systemInstruction: "You are a helpful assistant.",
|
|
19
|
+
* generationConfig: { temperature: 0.7, maxOutputTokens: 512 },
|
|
20
|
+
* history: geminiHistory,
|
|
21
|
+
* });
|
|
22
|
+
*
|
|
23
|
+
* const text = await session.send([{ text: "Hello" }]);
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export function createChatSession(config: GeminiChatConfig = {}) {
|
|
27
|
+
const model = geminiClient.getModel({
|
|
28
|
+
model: config.model ?? DEFAULT_MODELS.CHAT,
|
|
29
|
+
systemInstruction: config.systemInstruction,
|
|
30
|
+
safetySettings: config.safetySettings,
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
const historyForChat = (config.history ?? []).map((turn) => ({
|
|
34
|
+
role: turn.role === "model" ? ("model" as const) : ("user" as const),
|
|
35
|
+
parts: turn.parts as Part[],
|
|
36
|
+
}));
|
|
37
|
+
|
|
38
|
+
const chat: SdkChatSession = model.startChat({
|
|
39
|
+
history: historyForChat,
|
|
40
|
+
...(config.generationConfig && { generationConfig: config.generationConfig }),
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
return {
|
|
44
|
+
/**
|
|
45
|
+
* Send a message and return the full response text.
|
|
46
|
+
* Accepts text parts and/or inline data parts (images, audio).
|
|
47
|
+
*/
|
|
48
|
+
async send(parts: GeminiMessagePart[]): Promise<string> {
|
|
49
|
+
const result = await chat.sendMessage(parts as Part[]);
|
|
50
|
+
if (!result.response) throw new Error("No response from Gemini SDK");
|
|
51
|
+
return result.response.text();
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
}
|
|
@@ -1,11 +1,25 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
GoogleGenerativeAI,
|
|
3
|
+
HarmCategory,
|
|
4
|
+
HarmBlockThreshold,
|
|
5
|
+
type GenerativeModel,
|
|
6
|
+
type SafetySetting,
|
|
7
|
+
} from "@google/generative-ai";
|
|
2
8
|
import { DEFAULT_MODELS } from "../../domain/entities";
|
|
3
|
-
import type { GeminiConfig } from "../../domain/entities";
|
|
9
|
+
import type { GeminiConfig, GeminiModelOptions } from "../../domain/entities";
|
|
4
10
|
|
|
5
11
|
const DEFAULT_CONFIG: Partial<GeminiConfig> = {
|
|
6
12
|
textModel: DEFAULT_MODELS.TEXT,
|
|
7
13
|
};
|
|
8
14
|
|
|
15
|
+
/** All categories set to BLOCK_NONE */
|
|
16
|
+
const PERMISSIVE_SAFETY: SafetySetting[] = [
|
|
17
|
+
{ category: HarmCategory.HARM_CATEGORY_HARASSMENT, threshold: HarmBlockThreshold.BLOCK_NONE },
|
|
18
|
+
{ category: HarmCategory.HARM_CATEGORY_HATE_SPEECH, threshold: HarmBlockThreshold.BLOCK_NONE },
|
|
19
|
+
{ category: HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT, threshold: HarmBlockThreshold.BLOCK_NONE },
|
|
20
|
+
{ category: HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT, threshold: HarmBlockThreshold.BLOCK_NONE },
|
|
21
|
+
];
|
|
22
|
+
|
|
9
23
|
class GeminiClient {
|
|
10
24
|
private client: GoogleGenerativeAI | null = null;
|
|
11
25
|
private config: GeminiConfig | null = null;
|
|
@@ -35,18 +49,40 @@ class GeminiClient {
|
|
|
35
49
|
return this.client;
|
|
36
50
|
}
|
|
37
51
|
|
|
38
|
-
|
|
52
|
+
/**
|
|
53
|
+
* Returns a GenerativeModel configured with optional safety settings and system instruction.
|
|
54
|
+
* When no safety settings are provided, defaults to BLOCK_NONE for all categories.
|
|
55
|
+
*/
|
|
56
|
+
getModel(modelNameOrOptions?: string | GeminiModelOptions): GenerativeModel {
|
|
39
57
|
if (!this.client || !this.initialized) {
|
|
40
58
|
throw new Error("Gemini client not initialized. Call initialize() first.");
|
|
41
59
|
}
|
|
42
60
|
|
|
43
|
-
|
|
61
|
+
// Normalize args
|
|
62
|
+
const opts: GeminiModelOptions =
|
|
63
|
+
typeof modelNameOrOptions === "string"
|
|
64
|
+
? { model: modelNameOrOptions }
|
|
65
|
+
: modelNameOrOptions ?? {};
|
|
66
|
+
|
|
67
|
+
const effectiveModel = opts.model || this.config?.textModel || DEFAULT_MODELS.TEXT;
|
|
44
68
|
|
|
45
69
|
if (!effectiveModel.startsWith("gemini-")) {
|
|
46
70
|
throw new Error('Model name must start with "gemini-"');
|
|
47
71
|
}
|
|
48
72
|
|
|
49
|
-
|
|
73
|
+
// Map package safety settings to SDK format
|
|
74
|
+
const sdkSafety: SafetySetting[] = opts.safetySettings
|
|
75
|
+
? opts.safetySettings.map((s) => ({
|
|
76
|
+
category: s.category as unknown as HarmCategory,
|
|
77
|
+
threshold: s.threshold as unknown as HarmBlockThreshold,
|
|
78
|
+
}))
|
|
79
|
+
: PERMISSIVE_SAFETY;
|
|
80
|
+
|
|
81
|
+
return this.client.getGenerativeModel({
|
|
82
|
+
model: effectiveModel,
|
|
83
|
+
...(opts.systemInstruction && { systemInstruction: opts.systemInstruction }),
|
|
84
|
+
safetySettings: sdkSafety,
|
|
85
|
+
});
|
|
50
86
|
}
|
|
51
87
|
|
|
52
88
|
reset(): void {
|