@umituz/web-ai-groq-provider 1.1.7 → 1.1.8
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/domains/chat/hooks/use-chat.hook.ts +121 -73
- package/src/domains/chat/services/chat.service.ts +67 -14
- package/src/domains/groq/hooks/use-groq.hook.ts +46 -36
- package/src/domains/groq/services/http-client.service.ts +91 -32
- package/src/domains/groq/services/text-generation.service.ts +54 -4
- package/src/domains/groq/utils/cache-manager.util.ts +215 -0
- package/src/domains/groq/utils/debounce.util.ts +268 -0
- package/src/domains/groq/utils/index.ts +15 -1
- package/src/domains/groq/utils/request-deduplicator.util.ts +123 -0
- package/src/domains/groq/utils/request-queue.util.ts +178 -0
- package/src/domains/groq/utils/retry.util.ts +207 -0
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* useChat Hook
|
|
3
|
-
* @description Main React hook for chat functionality
|
|
3
|
+
* @description Main React hook for chat functionality with performance optimizations
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { useState, useCallback, useEffect } from "react";
|
|
6
|
+
import { useState, useCallback, useEffect, useRef } from "react";
|
|
7
7
|
import type {
|
|
8
8
|
ChatMessage,
|
|
9
9
|
ChatConfig,
|
|
@@ -19,7 +19,7 @@ const MESSAGE_ID_PREFIX = "msg-";
|
|
|
19
19
|
const MESSAGE_ID_USER_SUFFIX = "user";
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
|
-
* Hook for chat functionality with AI integration
|
|
22
|
+
* Hook for chat functionality with AI integration and performance optimizations
|
|
23
23
|
*/
|
|
24
24
|
export function useChat(options: UseChatOptions): UseChatReturn {
|
|
25
25
|
const {
|
|
@@ -37,6 +37,11 @@ export function useChat(options: UseChatOptions): UseChatReturn {
|
|
|
37
37
|
const [isTyping, setIsTyping] = useState(false);
|
|
38
38
|
const [error, setError] = useState<string | null>(null);
|
|
39
39
|
|
|
40
|
+
// Refs for deduplication and callback tracking
|
|
41
|
+
const pendingMessageRef = useRef<string | null>(null);
|
|
42
|
+
const optionsRef = useRef(options);
|
|
43
|
+
optionsRef.current = options;
|
|
44
|
+
|
|
40
45
|
// Initialize chat service config
|
|
41
46
|
useEffect(() => {
|
|
42
47
|
if (config) {
|
|
@@ -44,6 +49,13 @@ export function useChat(options: UseChatOptions): UseChatReturn {
|
|
|
44
49
|
}
|
|
45
50
|
}, [config]);
|
|
46
51
|
|
|
52
|
+
// Cleanup on unmount
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
return () => {
|
|
55
|
+
pendingMessageRef.current = null;
|
|
56
|
+
};
|
|
57
|
+
}, []);
|
|
58
|
+
|
|
47
59
|
// Load messages from storage on mount
|
|
48
60
|
useEffect(() => {
|
|
49
61
|
if (!storage) return;
|
|
@@ -60,7 +72,7 @@ export function useChat(options: UseChatOptions): UseChatReturn {
|
|
|
60
72
|
void loadMessages();
|
|
61
73
|
}, [conversationId, storage]);
|
|
62
74
|
|
|
63
|
-
// Save message to storage
|
|
75
|
+
// Save message to storage (stable reference)
|
|
64
76
|
const saveToStorage = useCallback(
|
|
65
77
|
async (message: ChatMessage) => {
|
|
66
78
|
if (!autoSave || !storage) return;
|
|
@@ -74,16 +86,47 @@ export function useChat(options: UseChatOptions): UseChatReturn {
|
|
|
74
86
|
[conversationId, storage, autoSave]
|
|
75
87
|
);
|
|
76
88
|
|
|
77
|
-
//
|
|
89
|
+
// Batch save messages to storage
|
|
90
|
+
const saveMessagesToStorage = useCallback(
|
|
91
|
+
async (messagesToSave: ChatMessage[]) => {
|
|
92
|
+
if (!autoSave || !storage || messagesToSave.length === 0) return;
|
|
93
|
+
|
|
94
|
+
try {
|
|
95
|
+
// Try batch save if supported
|
|
96
|
+
if ('saveMessages' in storage) {
|
|
97
|
+
await (storage as any).saveMessages(conversationId, messagesToSave);
|
|
98
|
+
} else {
|
|
99
|
+
// Fallback to individual saves in parallel
|
|
100
|
+
await Promise.all(
|
|
101
|
+
messagesToSave.map(msg => storage.saveMessage(conversationId, msg))
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
} catch (err) {
|
|
105
|
+
// Silently fail
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
[conversationId, storage, autoSave]
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
// Send message with deduplication and functional updates
|
|
78
112
|
const sendMessage = useCallback(
|
|
79
113
|
async (text: string, type?: ChatMessage["type"]): Promise<void> => {
|
|
80
114
|
if (!text.trim() || isLoading) return;
|
|
81
115
|
|
|
116
|
+
// Prevent duplicate messages
|
|
117
|
+
if (pendingMessageRef.current === text) {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
pendingMessageRef.current = text;
|
|
82
122
|
setIsLoading(true);
|
|
83
123
|
setError(null);
|
|
84
124
|
|
|
125
|
+
// Get latest callbacks from ref
|
|
126
|
+
const currentOptions = optionsRef.current;
|
|
127
|
+
|
|
85
128
|
try {
|
|
86
|
-
// Create user message
|
|
129
|
+
// Create user message
|
|
87
130
|
const userMessage: ChatMessage = {
|
|
88
131
|
id: `${MESSAGE_ID_PREFIX}${Date.now()}-${MESSAGE_ID_USER_SUFFIX}`,
|
|
89
132
|
sender: "user",
|
|
@@ -92,102 +135,107 @@ export function useChat(options: UseChatOptions): UseChatReturn {
|
|
|
92
135
|
type: type || "text",
|
|
93
136
|
};
|
|
94
137
|
|
|
95
|
-
//
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
138
|
+
// Use functional update to avoid stale closure
|
|
139
|
+
setMessages(prev => {
|
|
140
|
+
const updated = [...prev, userMessage];
|
|
141
|
+
saveToStorage(userMessage);
|
|
142
|
+
currentOptions.onMessageSent?.(userMessage);
|
|
143
|
+
return updated;
|
|
144
|
+
});
|
|
100
145
|
|
|
101
146
|
// Generate AI response
|
|
102
147
|
setIsTyping(true);
|
|
148
|
+
|
|
149
|
+
// Get current messages for context
|
|
150
|
+
const contextForAI = messages; // Use closure messages, not functional update
|
|
151
|
+
|
|
103
152
|
const aiResponse = await chatService.generateAIResponse(
|
|
104
153
|
conversationId,
|
|
105
154
|
text,
|
|
106
|
-
|
|
155
|
+
contextForAI
|
|
107
156
|
);
|
|
108
157
|
|
|
109
|
-
//
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
158
|
+
// Use functional update for AI response
|
|
159
|
+
setMessages(prev => {
|
|
160
|
+
const updated = [...prev, aiResponse];
|
|
161
|
+
saveToStorage(aiResponse);
|
|
162
|
+
currentOptions.onAIResponse?.(aiResponse);
|
|
163
|
+
return updated;
|
|
164
|
+
});
|
|
116
165
|
} catch (err) {
|
|
117
166
|
const errorMessage =
|
|
118
167
|
err instanceof Error ? err.message : "Failed to send message";
|
|
119
168
|
setError(errorMessage);
|
|
120
|
-
onError?.(errorMessage);
|
|
169
|
+
currentOptions.onError?.(errorMessage);
|
|
121
170
|
} finally {
|
|
122
171
|
setIsLoading(false);
|
|
123
172
|
setIsTyping(false);
|
|
173
|
+
pendingMessageRef.current = null;
|
|
124
174
|
}
|
|
125
175
|
},
|
|
126
|
-
[
|
|
127
|
-
conversationId,
|
|
128
|
-
messages,
|
|
129
|
-
isLoading,
|
|
130
|
-
saveToStorage,
|
|
131
|
-
onMessageSent,
|
|
132
|
-
onAIResponse,
|
|
133
|
-
onError,
|
|
134
|
-
]
|
|
176
|
+
[conversationId, isLoading, saveToStorage, messages]
|
|
135
177
|
);
|
|
136
178
|
|
|
137
|
-
// Regenerate last AI response
|
|
179
|
+
// Regenerate last AI response with functional updates
|
|
138
180
|
const regenerate = useCallback(async (): Promise<void> => {
|
|
139
|
-
|
|
181
|
+
// Use functional update to get latest messages
|
|
182
|
+
setMessages(currentMessages => {
|
|
183
|
+
if (currentMessages.length === 0 || isLoading) {
|
|
184
|
+
return currentMessages;
|
|
185
|
+
}
|
|
140
186
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
187
|
+
const lastUserMessage = [...currentMessages]
|
|
188
|
+
.reverse()
|
|
189
|
+
.find((m) => m.sender === "user");
|
|
144
190
|
|
|
145
|
-
|
|
191
|
+
if (!lastUserMessage) return currentMessages;
|
|
146
192
|
|
|
147
|
-
|
|
148
|
-
|
|
193
|
+
// Async operation - need to handle differently
|
|
194
|
+
setIsLoading(true);
|
|
195
|
+
setError(null);
|
|
196
|
+
|
|
197
|
+
const currentOptions = optionsRef.current;
|
|
149
198
|
|
|
150
|
-
try {
|
|
151
199
|
// Remove last AI message if exists
|
|
152
|
-
const messagesWithoutAI =
|
|
153
|
-
(m, i) => !(i ===
|
|
200
|
+
const messagesWithoutAI = currentMessages.filter(
|
|
201
|
+
(m, i) => !(i === currentMessages.length - 1 && m.sender === "assistant")
|
|
154
202
|
);
|
|
155
203
|
|
|
156
|
-
|
|
204
|
+
// Trigger async update
|
|
205
|
+
(async () => {
|
|
206
|
+
try {
|
|
207
|
+
// Generate new response
|
|
208
|
+
setIsTyping(true);
|
|
209
|
+
const aiResponse = await chatService.generateAIResponse(
|
|
210
|
+
conversationId,
|
|
211
|
+
lastUserMessage.content,
|
|
212
|
+
messagesWithoutAI.slice(0, -1)
|
|
213
|
+
);
|
|
157
214
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
);
|
|
215
|
+
// Update messages with new response
|
|
216
|
+
setMessages(prev => {
|
|
217
|
+
const lastIsAI = prev.length > 0 && prev[prev.length - 1].sender === "assistant";
|
|
218
|
+
const base = lastIsAI ? prev.slice(0, -1) : prev;
|
|
219
|
+
return [...base, aiResponse];
|
|
220
|
+
});
|
|
165
221
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
}, [
|
|
184
|
-
conversationId,
|
|
185
|
-
messages,
|
|
186
|
-
isLoading,
|
|
187
|
-
saveToStorage,
|
|
188
|
-
onAIResponse,
|
|
189
|
-
onError,
|
|
190
|
-
]);
|
|
222
|
+
// Save to storage
|
|
223
|
+
await saveToStorage(aiResponse);
|
|
224
|
+
currentOptions.onAIResponse?.(aiResponse);
|
|
225
|
+
} catch (err) {
|
|
226
|
+
const errorMessage =
|
|
227
|
+
err instanceof Error ? err.message : "Failed to regenerate";
|
|
228
|
+
setError(errorMessage);
|
|
229
|
+
currentOptions.onError?.(errorMessage);
|
|
230
|
+
} finally {
|
|
231
|
+
setIsLoading(false);
|
|
232
|
+
setIsTyping(false);
|
|
233
|
+
}
|
|
234
|
+
})();
|
|
235
|
+
|
|
236
|
+
return messagesWithoutAI;
|
|
237
|
+
});
|
|
238
|
+
}, [conversationId, isLoading, saveToStorage]);
|
|
191
239
|
|
|
192
240
|
// Clear all messages
|
|
193
241
|
const clearMessages = useCallback(() => {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Chat Service
|
|
3
|
-
* @description Core chat logic with AI integration
|
|
3
|
+
* @description Core chat logic with AI integration and performance optimizations
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import type {
|
|
@@ -17,6 +17,7 @@ import type {
|
|
|
17
17
|
import { textGenerationService } from "../../groq/services";
|
|
18
18
|
import { messageFormatter } from "../utils/message-formatter";
|
|
19
19
|
import { DEFAULT_MODELS } from "../../groq/constants";
|
|
20
|
+
import { cacheManager } from "../../groq/utils/cache-manager.util";
|
|
20
21
|
|
|
21
22
|
const DEFAULT_CONFIG: ChatConfig = {
|
|
22
23
|
temperature: 0.8,
|
|
@@ -27,13 +28,20 @@ const DEFAULT_CONFIG: ChatConfig = {
|
|
|
27
28
|
|
|
28
29
|
class ChatService implements IChatService {
|
|
29
30
|
private config: ChatConfig = DEFAULT_CONFIG;
|
|
31
|
+
private systemPromptCache = new Map<string, string>();
|
|
32
|
+
private readonly PROMPT_CACHE_KEY_PREFIX = "system-prompt";
|
|
33
|
+
private readonly RESPONSE_CACHE_TTL = 300000; // 5 minutes
|
|
30
34
|
|
|
31
35
|
initialize(config: ChatConfig): void {
|
|
32
36
|
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
37
|
+
// Clear system prompt cache when config changes
|
|
38
|
+
this.clearSystemPromptCache();
|
|
33
39
|
}
|
|
34
40
|
|
|
35
41
|
updateConfig(config: Partial<ChatConfig>): void {
|
|
36
42
|
this.config = { ...this.config, ...config };
|
|
43
|
+
// Clear system prompt cache when config changes
|
|
44
|
+
this.clearSystemPromptCache();
|
|
37
45
|
}
|
|
38
46
|
|
|
39
47
|
async sendMessage(input: SendMessageInput): Promise<SendMessageResult> {
|
|
@@ -74,7 +82,7 @@ class ChatService implements IChatService {
|
|
|
74
82
|
context: ChatMessage[] = []
|
|
75
83
|
): Promise<ChatMessage> {
|
|
76
84
|
try {
|
|
77
|
-
// Build system prompt from config
|
|
85
|
+
// Build system prompt from config (with caching)
|
|
78
86
|
const systemPrompt = this.buildSystemPrompt();
|
|
79
87
|
|
|
80
88
|
// Format messages for Groq
|
|
@@ -89,17 +97,34 @@ class ChatService implements IChatService {
|
|
|
89
97
|
content: userMessage,
|
|
90
98
|
});
|
|
91
99
|
|
|
92
|
-
//
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
100
|
+
// Check cache for response
|
|
101
|
+
const cacheKey = cacheManager.generateKey({
|
|
102
|
+
companionId,
|
|
103
|
+
userMessage,
|
|
104
|
+
context: context.map(m => ({ sender: m.sender, content: m.content })),
|
|
105
|
+
config: {
|
|
106
|
+
temperature: this.config.temperature,
|
|
107
|
+
maxTokens: this.config.maxTokens,
|
|
108
|
+
},
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
const cachedResponse = cacheManager.get<string>(cacheKey);
|
|
112
|
+
const response = cachedResponse ||
|
|
113
|
+
await textGenerationService.generateChatCompletion(
|
|
114
|
+
groqMessages,
|
|
115
|
+
{
|
|
116
|
+
model: DEFAULT_MODELS.TEXT,
|
|
117
|
+
generationConfig: {
|
|
118
|
+
temperature: this.config.temperature,
|
|
119
|
+
maxTokens: this.config.maxTokens,
|
|
120
|
+
},
|
|
121
|
+
}
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
// Cache the response if it wasn't cached
|
|
125
|
+
if (!cachedResponse) {
|
|
126
|
+
cacheManager.set(cacheKey, response);
|
|
127
|
+
}
|
|
103
128
|
|
|
104
129
|
// Format response as chat message
|
|
105
130
|
const aiMessage: ChatMessage = {
|
|
@@ -107,6 +132,7 @@ class ChatService implements IChatService {
|
|
|
107
132
|
metadata: {
|
|
108
133
|
companionId,
|
|
109
134
|
model: DEFAULT_MODELS.TEXT,
|
|
135
|
+
cached: !!cachedResponse,
|
|
110
136
|
},
|
|
111
137
|
};
|
|
112
138
|
|
|
@@ -122,11 +148,38 @@ class ChatService implements IChatService {
|
|
|
122
148
|
|
|
123
149
|
private buildSystemPrompt(): string {
|
|
124
150
|
const language = this.config.language || "tr";
|
|
125
|
-
const
|
|
151
|
+
const customPrompt = this.config.systemPrompt;
|
|
152
|
+
|
|
153
|
+
// Generate cache key
|
|
154
|
+
const cacheKey = `${this.PROMPT_CACHE_KEY_PREFIX}-${language}-${customPrompt?.length || 0}`;
|
|
155
|
+
|
|
156
|
+
// Check cache
|
|
157
|
+
if (this.systemPromptCache.has(cacheKey)) {
|
|
158
|
+
return this.systemPromptCache.get(cacheKey)!;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Build prompt
|
|
162
|
+
const basePrompt = customPrompt || this.getDefaultPrompt(language);
|
|
163
|
+
|
|
164
|
+
// Cache it
|
|
165
|
+
this.systemPromptCache.set(cacheKey, basePrompt);
|
|
126
166
|
|
|
127
167
|
return basePrompt;
|
|
128
168
|
}
|
|
129
169
|
|
|
170
|
+
private clearSystemPromptCache(): void {
|
|
171
|
+
this.systemPromptCache.clear();
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Clear all cached data (system prompts and response cache)
|
|
176
|
+
*/
|
|
177
|
+
clearCache(): void {
|
|
178
|
+
this.clearSystemPromptCache();
|
|
179
|
+
// Note: Response cache is managed by textGenerationService
|
|
180
|
+
// Export cache clearing function from there if needed
|
|
181
|
+
}
|
|
182
|
+
|
|
130
183
|
private getDefaultPrompt(language: string): string {
|
|
131
184
|
if (language === "tr") {
|
|
132
185
|
return `Sen samimi, eğlenceli ve ilgi çekici bir AI companionsın. Türkçe konuşuyorsun.
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* useGroq Hook
|
|
3
|
-
* @description Main React hook for Groq text generation
|
|
3
|
+
* @description Main React hook for Groq text generation with performance optimizations
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { useState, useCallback, useMemo } from "react";
|
|
6
|
+
import { useState, useCallback, useMemo, useRef, useEffect } from "react";
|
|
7
7
|
import type { GroqGenerationConfig } from "../interfaces";
|
|
8
8
|
import type { TextGenerationOptions, StreamingCallbacks } from "../interfaces";
|
|
9
9
|
import { textGenerationService } from "../services";
|
|
10
10
|
import { GroqError } from "../utils/groq-error.util";
|
|
11
11
|
import { getUserFriendlyError } from "../utils/error.util";
|
|
12
12
|
import { DEFAULT_MODELS } from "../constants";
|
|
13
|
+
import { groqHttpClient } from "../services/http-client.service";
|
|
13
14
|
|
|
14
15
|
export interface UseGroqOptions {
|
|
15
16
|
/** Initial model to use */
|
|
@@ -51,46 +52,54 @@ export interface UseGroqReturn {
|
|
|
51
52
|
}
|
|
52
53
|
|
|
53
54
|
/**
|
|
54
|
-
* Hook for Groq text generation
|
|
55
|
+
* Hook for Groq text generation with performance optimizations
|
|
55
56
|
*/
|
|
56
57
|
export function useGroq(options: UseGroqOptions = {}): UseGroqReturn {
|
|
57
58
|
const [isLoading, setIsLoading] = useState(false);
|
|
58
59
|
const [error, setError] = useState<string | null>(null);
|
|
59
60
|
const [result, setResult] = useState<string | null>(null);
|
|
60
61
|
|
|
61
|
-
//
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
options.
|
|
69
|
-
options.
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
]
|
|
62
|
+
// Use ref for callbacks to avoid stale closures and unstable references
|
|
63
|
+
const optionsRef = useRef(options);
|
|
64
|
+
optionsRef.current = options;
|
|
65
|
+
|
|
66
|
+
// Memoize only the stable configuration values (not callbacks)
|
|
67
|
+
const stableConfig = useMemo(
|
|
68
|
+
() => ({
|
|
69
|
+
model: options.model,
|
|
70
|
+
generationConfig: options.generationConfig,
|
|
71
|
+
}),
|
|
72
|
+
[options.model, options.generationConfig?.temperature, options.generationConfig?.maxTokens, options.generationConfig?.topP]
|
|
73
73
|
);
|
|
74
74
|
|
|
75
|
+
// Cleanup pending requests on unmount
|
|
76
|
+
useEffect(() => {
|
|
77
|
+
return () => {
|
|
78
|
+
groqHttpClient.cancelPendingRequests();
|
|
79
|
+
};
|
|
80
|
+
}, []);
|
|
81
|
+
|
|
75
82
|
const generate = useCallback(
|
|
76
83
|
async (prompt: string, config?: GroqGenerationConfig): Promise<string> => {
|
|
77
84
|
setIsLoading(true);
|
|
78
85
|
setError(null);
|
|
79
86
|
setResult(null);
|
|
80
87
|
|
|
81
|
-
|
|
88
|
+
// Use ref to get latest callbacks without adding to dependencies
|
|
89
|
+
const currentOptions = optionsRef.current;
|
|
90
|
+
currentOptions.onStart?.();
|
|
82
91
|
|
|
83
92
|
try {
|
|
84
93
|
const response = await textGenerationService.generateCompletion(prompt, {
|
|
85
|
-
model:
|
|
94
|
+
model: stableConfig.model,
|
|
86
95
|
generationConfig: {
|
|
87
|
-
...
|
|
96
|
+
...stableConfig.generationConfig,
|
|
88
97
|
...config,
|
|
89
98
|
},
|
|
90
99
|
});
|
|
91
100
|
|
|
92
101
|
setResult(response);
|
|
93
|
-
|
|
102
|
+
currentOptions.onSuccess?.(response);
|
|
94
103
|
|
|
95
104
|
return response;
|
|
96
105
|
} catch (err) {
|
|
@@ -98,14 +107,14 @@ export function useGroq(options: UseGroqOptions = {}): UseGroqReturn {
|
|
|
98
107
|
err instanceof Error ? err : new Error("Unknown error")
|
|
99
108
|
);
|
|
100
109
|
setError(errorMessage);
|
|
101
|
-
|
|
110
|
+
currentOptions.onError?.(errorMessage);
|
|
102
111
|
|
|
103
112
|
throw err;
|
|
104
113
|
} finally {
|
|
105
114
|
setIsLoading(false);
|
|
106
115
|
}
|
|
107
116
|
},
|
|
108
|
-
[
|
|
117
|
+
[stableConfig]
|
|
109
118
|
);
|
|
110
119
|
|
|
111
120
|
const generateJSON = useCallback(
|
|
@@ -117,13 +126,14 @@ export function useGroq(options: UseGroqOptions = {}): UseGroqReturn {
|
|
|
117
126
|
setError(null);
|
|
118
127
|
setResult(null);
|
|
119
128
|
|
|
120
|
-
|
|
129
|
+
const currentOptions = optionsRef.current;
|
|
130
|
+
currentOptions.onStart?.();
|
|
121
131
|
|
|
122
132
|
try {
|
|
123
133
|
const response = await textGenerationService.generateStructured<T>(prompt, {
|
|
124
|
-
model:
|
|
134
|
+
model: stableConfig.model,
|
|
125
135
|
generationConfig: {
|
|
126
|
-
...
|
|
136
|
+
...stableConfig.generationConfig,
|
|
127
137
|
...config,
|
|
128
138
|
},
|
|
129
139
|
schema: config?.schema,
|
|
@@ -131,7 +141,7 @@ export function useGroq(options: UseGroqOptions = {}): UseGroqReturn {
|
|
|
131
141
|
|
|
132
142
|
const jsonString = JSON.stringify(response, null, 2);
|
|
133
143
|
setResult(jsonString);
|
|
134
|
-
|
|
144
|
+
currentOptions.onSuccess?.(jsonString);
|
|
135
145
|
|
|
136
146
|
return response;
|
|
137
147
|
} catch (err) {
|
|
@@ -139,14 +149,14 @@ export function useGroq(options: UseGroqOptions = {}): UseGroqReturn {
|
|
|
139
149
|
err instanceof Error ? err : new Error("Unknown error")
|
|
140
150
|
);
|
|
141
151
|
setError(errorMessage);
|
|
142
|
-
|
|
152
|
+
currentOptions.onError?.(errorMessage);
|
|
143
153
|
|
|
144
154
|
throw err;
|
|
145
155
|
} finally {
|
|
146
156
|
setIsLoading(false);
|
|
147
157
|
}
|
|
148
158
|
},
|
|
149
|
-
[
|
|
159
|
+
[stableConfig]
|
|
150
160
|
);
|
|
151
161
|
|
|
152
162
|
const stream = useCallback(
|
|
@@ -159,19 +169,19 @@ export function useGroq(options: UseGroqOptions = {}): UseGroqReturn {
|
|
|
159
169
|
setError(null);
|
|
160
170
|
setResult(null);
|
|
161
171
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
172
|
+
const contentChunks: string[] = [];
|
|
173
|
+
const currentOptions = optionsRef.current;
|
|
174
|
+
currentOptions.onStart?.();
|
|
165
175
|
|
|
166
176
|
try {
|
|
167
177
|
const callbacks: StreamingCallbacks = {
|
|
168
178
|
onChunk: (c) => {
|
|
169
|
-
|
|
179
|
+
contentChunks.push(c); // Use array accumulation
|
|
170
180
|
onChunk(c);
|
|
171
181
|
},
|
|
172
182
|
onComplete: (text) => {
|
|
173
183
|
setResult(text);
|
|
174
|
-
|
|
184
|
+
currentOptions.onSuccess?.(text);
|
|
175
185
|
},
|
|
176
186
|
};
|
|
177
187
|
|
|
@@ -179,9 +189,9 @@ export function useGroq(options: UseGroqOptions = {}): UseGroqReturn {
|
|
|
179
189
|
prompt,
|
|
180
190
|
callbacks,
|
|
181
191
|
{
|
|
182
|
-
model:
|
|
192
|
+
model: stableConfig.model,
|
|
183
193
|
generationConfig: {
|
|
184
|
-
...
|
|
194
|
+
...stableConfig.generationConfig,
|
|
185
195
|
...config,
|
|
186
196
|
},
|
|
187
197
|
}
|
|
@@ -194,14 +204,14 @@ export function useGroq(options: UseGroqOptions = {}): UseGroqReturn {
|
|
|
194
204
|
err instanceof Error ? err : new Error("Unknown error")
|
|
195
205
|
);
|
|
196
206
|
setError(errorMessage);
|
|
197
|
-
|
|
207
|
+
currentOptions.onError?.(errorMessage);
|
|
198
208
|
|
|
199
209
|
throw err;
|
|
200
210
|
} finally {
|
|
201
211
|
setIsLoading(false);
|
|
202
212
|
}
|
|
203
213
|
},
|
|
204
|
-
[
|
|
214
|
+
[stableConfig]
|
|
205
215
|
);
|
|
206
216
|
|
|
207
217
|
const reset = useCallback(() => {
|