@umituz/web-ai-groq-provider 1.1.13 → 2.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/README.md +154 -72
- package/dist/domains/chat/index.cjs +539 -0
- package/dist/domains/chat/index.cjs.map +1 -0
- package/dist/domains/chat/index.d.cts +322 -0
- package/dist/domains/chat/index.d.ts +322 -0
- package/dist/domains/chat/index.js +531 -0
- package/dist/domains/chat/index.js.map +1 -0
- package/dist/domains/groq/index.cjs +1499 -0
- package/dist/domains/groq/index.cjs.map +1 -0
- package/dist/domains/groq/index.d.cts +561 -0
- package/dist/domains/groq/index.d.ts +561 -0
- package/dist/domains/groq/index.js +1453 -0
- package/dist/domains/groq/index.js.map +1 -0
- package/dist/index.cjs +1993 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +53 -0
- package/dist/index.d.ts +53 -0
- package/dist/index.js +1937 -0
- package/dist/index.js.map +1 -0
- package/dist/text-generation.service-BP4Q_SH0.d.cts +252 -0
- package/dist/text-generation.service-BP4Q_SH0.d.ts +252 -0
- package/package.json +25 -11
- package/src/domains/chat/entities/chat.entities.ts +0 -113
- package/src/domains/chat/entities/index.ts +0 -14
- package/src/domains/chat/hooks/index.ts +0 -5
- package/src/domains/chat/hooks/use-chat.hook.ts +0 -259
- package/src/domains/chat/index.ts +0 -32
- package/src/domains/chat/interfaces/chat.interface.ts +0 -80
- package/src/domains/chat/interfaces/index.ts +0 -10
- package/src/domains/chat/services/chat.service.ts +0 -195
- package/src/domains/chat/services/index.ts +0 -5
- package/src/domains/chat/utils/message-formatter.ts +0 -49
- package/src/domains/groq/constants/error.constants.ts +0 -46
- package/src/domains/groq/constants/groq.constants.ts +0 -68
- package/src/domains/groq/constants/index.ts +0 -20
- package/src/domains/groq/entities/groq.entities.ts +0 -196
- package/src/domains/groq/entities/index.ts +0 -20
- package/src/domains/groq/hooks/index.ts +0 -7
- package/src/domains/groq/hooks/use-groq.hook.ts +0 -232
- package/src/domains/groq/index.ts +0 -72
- package/src/domains/groq/interfaces/groq.interface.ts +0 -77
- package/src/domains/groq/interfaces/index.ts +0 -22
- package/src/domains/groq/services/http-client.service.ts +0 -265
- package/src/domains/groq/services/index.ts +0 -9
- package/src/domains/groq/services/text-generation.service.ts +0 -238
- package/src/domains/groq/utils/cache-manager.util.ts +0 -215
- package/src/domains/groq/utils/debounce.util.ts +0 -268
- package/src/domains/groq/utils/error.util.ts +0 -57
- package/src/domains/groq/utils/groq-error.util.ts +0 -18
- package/src/domains/groq/utils/index.ts +0 -37
- package/src/domains/groq/utils/message.util.ts +0 -57
- package/src/domains/groq/utils/request-deduplicator.util.ts +0 -123
- package/src/domains/groq/utils/request-queue.util.ts +0 -178
- package/src/domains/groq/utils/retry.util.ts +0 -207
- package/src/index.ts +0 -15
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Domain Interfaces Index
|
|
3
|
-
* Subpath: @umituz/web-ai-groq-provider/domain
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
export type {
|
|
7
|
-
TextGenerationOptions,
|
|
8
|
-
StreamingCallbacks,
|
|
9
|
-
StructuredGenerationOptions,
|
|
10
|
-
} from "./groq.interface";
|
|
11
|
-
|
|
12
|
-
export type { IGroqChatService, IGroqHttpClient } from "./groq.interface";
|
|
13
|
-
|
|
14
|
-
// Re-export from entities for convenience
|
|
15
|
-
export type {
|
|
16
|
-
GroqConfig,
|
|
17
|
-
GroqGenerationConfig,
|
|
18
|
-
GroqMessage,
|
|
19
|
-
GroqChatRequest,
|
|
20
|
-
GroqChatResponse,
|
|
21
|
-
GroqChatChunk,
|
|
22
|
-
} from "../entities";
|
|
@@ -1,265 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Groq HTTP Client Service
|
|
3
|
-
* @description Handles all HTTP communication with Groq API with performance optimizations
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import type { IGroqHttpClient } from "../interfaces";
|
|
7
|
-
import type { GroqConfig, GroqChatRequest, GroqChatResponse } from "../entities";
|
|
8
|
-
import { GroqError } from "../utils/groq-error.util";
|
|
9
|
-
import { GroqErrorType, mapHttpStatusToErrorType } from "../constants/error.constants";
|
|
10
|
-
import { DEFAULT_BASE_URL, TIMEOUTS } from "../constants/groq.constants";
|
|
11
|
-
import { requestDeduplicator } from "../utils/request-deduplicator.util";
|
|
12
|
-
import { requestQueue } from "../utils/request-queue.util";
|
|
13
|
-
import { retryManager } from "../utils/retry.util";
|
|
14
|
-
|
|
15
|
-
class GroqHttpClientService implements IGroqHttpClient {
|
|
16
|
-
private config: GroqConfig | null = null;
|
|
17
|
-
private initialized = false;
|
|
18
|
-
private pendingAbortControllers = new Set<AbortController>();
|
|
19
|
-
|
|
20
|
-
initialize(config: GroqConfig): void {
|
|
21
|
-
const apiKey = config.apiKey?.trim();
|
|
22
|
-
|
|
23
|
-
if (!apiKey || apiKey.length < 10) {
|
|
24
|
-
throw new GroqError(
|
|
25
|
-
GroqErrorType.INVALID_API_KEY,
|
|
26
|
-
"API key is required and must be at least 10 characters"
|
|
27
|
-
);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
this.config = {
|
|
31
|
-
apiKey,
|
|
32
|
-
baseUrl: config.baseUrl || DEFAULT_BASE_URL,
|
|
33
|
-
timeoutMs: config.timeoutMs || TIMEOUTS.DEFAULT,
|
|
34
|
-
textModel: config.textModel,
|
|
35
|
-
};
|
|
36
|
-
this.initialized = true;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Cancel all pending requests
|
|
41
|
-
*/
|
|
42
|
-
cancelPendingRequests(): void {
|
|
43
|
-
for (const controller of this.pendingAbortControllers) {
|
|
44
|
-
controller.abort();
|
|
45
|
-
}
|
|
46
|
-
this.pendingAbortControllers.clear();
|
|
47
|
-
requestQueue.cancelAll();
|
|
48
|
-
requestDeduplicator.cancelAll();
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
isInitialized(): boolean {
|
|
52
|
-
return this.initialized && this.config !== null;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
getApiKey(): string {
|
|
56
|
-
if (!this.config) {
|
|
57
|
-
throw new GroqError(
|
|
58
|
-
GroqErrorType.MISSING_CONFIG,
|
|
59
|
-
"Client not initialized"
|
|
60
|
-
);
|
|
61
|
-
}
|
|
62
|
-
return this.config.apiKey;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
setApiKey(apiKey: string): void {
|
|
66
|
-
if (!this.config) {
|
|
67
|
-
throw new GroqError(
|
|
68
|
-
GroqErrorType.MISSING_CONFIG,
|
|
69
|
-
"Client not initialized. Call initialize() first."
|
|
70
|
-
);
|
|
71
|
-
}
|
|
72
|
-
this.config = { ...this.config, apiKey: apiKey.trim() };
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
async postChatCompletion(request: GroqChatRequest): Promise<GroqChatResponse> {
|
|
76
|
-
// Generate deduplication key
|
|
77
|
-
const dedupeKey = requestDeduplicator.generateKey({
|
|
78
|
-
endpoint: "/chat/completions",
|
|
79
|
-
...request,
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
// Execute with deduplication, retry, and queue management
|
|
83
|
-
return requestDeduplicator.execute(dedupeKey, () =>
|
|
84
|
-
retryManager.execute(() =>
|
|
85
|
-
requestQueue.add(
|
|
86
|
-
() => this.request<GroqChatResponse>("/chat/completions", { ...request, stream: false }),
|
|
87
|
-
10 // High priority for user-initiated requests
|
|
88
|
-
)
|
|
89
|
-
)
|
|
90
|
-
);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
async streamChatCompletion(request: GroqChatRequest): Promise<ReadableStream> {
|
|
94
|
-
if (!this.config || !this.initialized) {
|
|
95
|
-
throw new GroqError(
|
|
96
|
-
GroqErrorType.MISSING_CONFIG,
|
|
97
|
-
"Client not initialized. Call initialize() first."
|
|
98
|
-
);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
const url = `${this.config.baseUrl}/chat/completions`;
|
|
102
|
-
const timeout = this.config.timeoutMs || TIMEOUTS.STREAMING;
|
|
103
|
-
|
|
104
|
-
let controller: AbortController | null = null;
|
|
105
|
-
let timeoutId: NodeJS.Timeout | null = null;
|
|
106
|
-
|
|
107
|
-
try {
|
|
108
|
-
controller = new AbortController();
|
|
109
|
-
timeoutId = setTimeout(() => controller?.abort(), timeout);
|
|
110
|
-
|
|
111
|
-
this.pendingAbortControllers.add(controller);
|
|
112
|
-
|
|
113
|
-
const response = await fetch(url, {
|
|
114
|
-
method: "POST",
|
|
115
|
-
headers: {
|
|
116
|
-
"Content-Type": "application/json",
|
|
117
|
-
Authorization: `Bearer ${this.config.apiKey}`,
|
|
118
|
-
},
|
|
119
|
-
body: JSON.stringify({ ...request, stream: true }),
|
|
120
|
-
signal: controller.signal,
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
if (!response.ok) {
|
|
124
|
-
throw new GroqError(
|
|
125
|
-
mapHttpStatusToErrorType(response.status),
|
|
126
|
-
`HTTP ${response.status}: ${response.statusText}`,
|
|
127
|
-
undefined,
|
|
128
|
-
{ status: response.status, url: response.url }
|
|
129
|
-
);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
if (!response.body) {
|
|
133
|
-
throw new GroqError(
|
|
134
|
-
GroqErrorType.NETWORK_ERROR,
|
|
135
|
-
"Response body is null"
|
|
136
|
-
);
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
return response.body;
|
|
140
|
-
} catch (error) {
|
|
141
|
-
throw this.handleRequestError(error);
|
|
142
|
-
} finally {
|
|
143
|
-
if (timeoutId) {
|
|
144
|
-
clearTimeout(timeoutId);
|
|
145
|
-
}
|
|
146
|
-
if (controller) {
|
|
147
|
-
this.pendingAbortControllers.delete(controller);
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
private async request<T>(
|
|
153
|
-
endpoint: string,
|
|
154
|
-
body: unknown,
|
|
155
|
-
signal?: AbortSignal
|
|
156
|
-
): Promise<T> {
|
|
157
|
-
if (!this.config || !this.initialized) {
|
|
158
|
-
throw new GroqError(
|
|
159
|
-
GroqErrorType.MISSING_CONFIG,
|
|
160
|
-
"Client not initialized. Call initialize() first."
|
|
161
|
-
);
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
const url = `${this.config.baseUrl}${endpoint}`;
|
|
165
|
-
const timeout = this.config.timeoutMs || TIMEOUTS.DEFAULT;
|
|
166
|
-
|
|
167
|
-
let controller: AbortController | null = null;
|
|
168
|
-
let timeoutId: NodeJS.Timeout | null = null;
|
|
169
|
-
|
|
170
|
-
try {
|
|
171
|
-
controller = new AbortController();
|
|
172
|
-
timeoutId = setTimeout(() => controller?.abort(), timeout);
|
|
173
|
-
|
|
174
|
-
if (signal) {
|
|
175
|
-
signal.addEventListener("abort", () => controller?.abort());
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
this.pendingAbortControllers.add(controller);
|
|
179
|
-
|
|
180
|
-
const response = await fetch(url, {
|
|
181
|
-
method: "POST",
|
|
182
|
-
headers: {
|
|
183
|
-
"Content-Type": "application/json",
|
|
184
|
-
Authorization: `Bearer ${this.config.apiKey}`,
|
|
185
|
-
},
|
|
186
|
-
body: JSON.stringify(body),
|
|
187
|
-
signal: controller.signal,
|
|
188
|
-
});
|
|
189
|
-
|
|
190
|
-
if (!response.ok) {
|
|
191
|
-
await this.handleErrorResponse(response);
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
return (await response.json()) as T;
|
|
195
|
-
} catch (error) {
|
|
196
|
-
throw this.handleRequestError(error);
|
|
197
|
-
} finally {
|
|
198
|
-
if (timeoutId) {
|
|
199
|
-
clearTimeout(timeoutId);
|
|
200
|
-
}
|
|
201
|
-
if (controller) {
|
|
202
|
-
this.pendingAbortControllers.delete(controller);
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
private async handleErrorResponse(response: Response): Promise<never> {
|
|
208
|
-
let errorMessage = `HTTP ${response.status}`;
|
|
209
|
-
const errorType = mapHttpStatusToErrorType(response.status);
|
|
210
|
-
|
|
211
|
-
try {
|
|
212
|
-
const errorData = (await response.json()) as {
|
|
213
|
-
error?: { message?: string };
|
|
214
|
-
};
|
|
215
|
-
if (errorData.error?.message) {
|
|
216
|
-
errorMessage = errorData.error.message;
|
|
217
|
-
}
|
|
218
|
-
} catch {
|
|
219
|
-
// If parsing fails, use default message
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
throw new GroqError(errorType, errorMessage, undefined, {
|
|
223
|
-
status: response.status,
|
|
224
|
-
url: response.url,
|
|
225
|
-
});
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
private handleRequestError(error: unknown): GroqError {
|
|
229
|
-
if (error instanceof GroqError) {
|
|
230
|
-
return error;
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
if (error instanceof Error) {
|
|
234
|
-
if (error.name === "AbortError") {
|
|
235
|
-
return new GroqError(
|
|
236
|
-
GroqErrorType.ABORT_ERROR,
|
|
237
|
-
"Request was aborted by the client",
|
|
238
|
-
error
|
|
239
|
-
);
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
if (error.name === "TypeError" && error.message.includes("network")) {
|
|
243
|
-
return new GroqError(
|
|
244
|
-
GroqErrorType.NETWORK_ERROR,
|
|
245
|
-
"Network error: Unable to connect to Groq API",
|
|
246
|
-
error
|
|
247
|
-
);
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
return new GroqError(
|
|
252
|
-
GroqErrorType.UNKNOWN_ERROR,
|
|
253
|
-
error instanceof Error ? error.message : "Unknown error occurred",
|
|
254
|
-
error as Error
|
|
255
|
-
);
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
reset(): void {
|
|
259
|
-
this.cancelPendingRequests();
|
|
260
|
-
this.config = null;
|
|
261
|
-
this.initialized = false;
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
export const groqHttpClient = new GroqHttpClientService();
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Infrastructure Services Index
|
|
3
|
-
* Subpath: @umituz/web-ai-groq-provider/services
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
export { groqHttpClient } from "./http-client.service";
|
|
7
|
-
export { textGenerationService } from "./text-generation.service";
|
|
8
|
-
export type { IGroqHttpClient } from "../interfaces";
|
|
9
|
-
export type { IGroqChatService } from "../interfaces";
|
|
@@ -1,238 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Text Generation Service
|
|
3
|
-
* @description Handles text generation using Groq API with caching and performance optimizations
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import type { IGroqChatService } from "../interfaces";
|
|
7
|
-
import type {
|
|
8
|
-
GroqMessage,
|
|
9
|
-
GroqChatRequest,
|
|
10
|
-
TextGenerationOptions,
|
|
11
|
-
StreamingCallbacks,
|
|
12
|
-
StructuredGenerationOptions,
|
|
13
|
-
} from "../interfaces";
|
|
14
|
-
import { groqHttpClient } from "./http-client.service";
|
|
15
|
-
import { GroqError } from "../utils/groq-error.util";
|
|
16
|
-
import { GroqErrorType } from "../constants/error.constants";
|
|
17
|
-
import { DEFAULT_MODELS, DEFAULT_GENERATION_CONFIG } from "../constants/groq.constants";
|
|
18
|
-
import { cacheManager } from "../utils/cache-manager.util";
|
|
19
|
-
|
|
20
|
-
class TextGenerationService implements IGroqChatService {
|
|
21
|
-
private readonly CACHE_TTL = 300000; // 5 minutes
|
|
22
|
-
async generateCompletion(
|
|
23
|
-
prompt: string,
|
|
24
|
-
options: TextGenerationOptions = {}
|
|
25
|
-
): Promise<string> {
|
|
26
|
-
const model = options.model || DEFAULT_MODELS.TEXT;
|
|
27
|
-
|
|
28
|
-
// Check cache first
|
|
29
|
-
const cacheKey = cacheManager.generateKey({
|
|
30
|
-
type: "completion",
|
|
31
|
-
model,
|
|
32
|
-
prompt,
|
|
33
|
-
config: options.generationConfig,
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
const cached = cacheManager.get<string>(cacheKey);
|
|
37
|
-
if (cached !== null) {
|
|
38
|
-
return cached;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const messages: GroqMessage[] = [{ role: "user", content: prompt }];
|
|
42
|
-
const request = this.buildRequest(model, messages, options.generationConfig);
|
|
43
|
-
|
|
44
|
-
const response = await groqHttpClient.postChatCompletion(request);
|
|
45
|
-
const content = response.choices[0]?.message?.content;
|
|
46
|
-
|
|
47
|
-
if (!content) {
|
|
48
|
-
throw new GroqError(
|
|
49
|
-
GroqErrorType.UNKNOWN_ERROR,
|
|
50
|
-
"No content generated from Groq API"
|
|
51
|
-
);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// Cache the result
|
|
55
|
-
cacheManager.set(cacheKey, content);
|
|
56
|
-
|
|
57
|
-
return content;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
async generateChatCompletion(
|
|
61
|
-
messages: GroqMessage[],
|
|
62
|
-
options: TextGenerationOptions = {}
|
|
63
|
-
): Promise<string> {
|
|
64
|
-
const model = options.model || DEFAULT_MODELS.TEXT;
|
|
65
|
-
|
|
66
|
-
// Check cache first
|
|
67
|
-
const cacheKey = cacheManager.generateKey({
|
|
68
|
-
type: "chat",
|
|
69
|
-
model,
|
|
70
|
-
messages,
|
|
71
|
-
config: options.generationConfig,
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
const cached = cacheManager.get<string>(cacheKey);
|
|
75
|
-
if (cached !== null) {
|
|
76
|
-
return cached;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
const request = this.buildRequest(model, messages, options.generationConfig);
|
|
80
|
-
const response = await groqHttpClient.postChatCompletion(request);
|
|
81
|
-
const content = response.choices[0]?.message?.content;
|
|
82
|
-
|
|
83
|
-
if (!content) {
|
|
84
|
-
throw new GroqError(
|
|
85
|
-
GroqErrorType.UNKNOWN_ERROR,
|
|
86
|
-
"No content generated from Groq API"
|
|
87
|
-
);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
// Cache the result
|
|
91
|
-
cacheManager.set(cacheKey, content);
|
|
92
|
-
|
|
93
|
-
return content;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
async generateStructured<T>(
|
|
97
|
-
prompt: string,
|
|
98
|
-
options: StructuredGenerationOptions = {}
|
|
99
|
-
): Promise<T> {
|
|
100
|
-
const model = options.model || DEFAULT_MODELS.TEXT;
|
|
101
|
-
|
|
102
|
-
// Build JSON prompt
|
|
103
|
-
const jsonPrompt = this.buildStructuredPrompt(prompt, options.schema);
|
|
104
|
-
const messages: GroqMessage[] = [{ role: "user", content: jsonPrompt }];
|
|
105
|
-
const request = this.buildRequest(model, messages, {
|
|
106
|
-
...options.generationConfig,
|
|
107
|
-
temperature: 0.1, // Lower temperature for structured output
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
const response = await groqHttpClient.postChatCompletion(request);
|
|
111
|
-
const content = response.choices[0]?.message?.content;
|
|
112
|
-
|
|
113
|
-
if (!content) {
|
|
114
|
-
throw new GroqError(
|
|
115
|
-
GroqErrorType.UNKNOWN_ERROR,
|
|
116
|
-
"No content generated from Groq API"
|
|
117
|
-
);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
// Parse JSON response
|
|
121
|
-
try {
|
|
122
|
-
const jsonMatch = content.match(/```json\n([\s\S]*?)\n```/) ||
|
|
123
|
-
content.match(/\{[\s\S]*\}/);
|
|
124
|
-
const jsonStr = jsonMatch ? jsonMatch[1] || jsonMatch[0] : content;
|
|
125
|
-
const parsed = JSON.parse(jsonStr) as T;
|
|
126
|
-
|
|
127
|
-
return parsed;
|
|
128
|
-
} catch (error) {
|
|
129
|
-
throw new GroqError(
|
|
130
|
-
GroqErrorType.UNKNOWN_ERROR,
|
|
131
|
-
"Failed to parse structured response as JSON",
|
|
132
|
-
error as Error
|
|
133
|
-
);
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
async streamCompletion(
|
|
138
|
-
prompt: string,
|
|
139
|
-
callbacks: StreamingCallbacks,
|
|
140
|
-
options: TextGenerationOptions = {}
|
|
141
|
-
): Promise<void> {
|
|
142
|
-
const model = options.model || DEFAULT_MODELS.TEXT;
|
|
143
|
-
const messages: GroqMessage[] = [{ role: "user", content: prompt }];
|
|
144
|
-
const request = this.buildRequest(model, messages, options.generationConfig);
|
|
145
|
-
|
|
146
|
-
try {
|
|
147
|
-
const stream = await groqHttpClient.streamChatCompletion(request);
|
|
148
|
-
const reader = stream.getReader();
|
|
149
|
-
const decoder = new TextDecoder();
|
|
150
|
-
const contentChunks: string[] = []; // Use array instead of string concatenation
|
|
151
|
-
|
|
152
|
-
while (true) {
|
|
153
|
-
const { done, value } = await reader.read();
|
|
154
|
-
if (done) break;
|
|
155
|
-
|
|
156
|
-
const chunk = decoder.decode(value, { stream: true }); // Optimize with stream option
|
|
157
|
-
const lines = chunk.split("\n").filter(line => line.trim() !== "");
|
|
158
|
-
|
|
159
|
-
for (const line of lines) {
|
|
160
|
-
if (line.startsWith("data: ")) {
|
|
161
|
-
const data = line.slice(6);
|
|
162
|
-
if (data === "[DONE]") continue;
|
|
163
|
-
|
|
164
|
-
try {
|
|
165
|
-
const parsed = JSON.parse(data) as {
|
|
166
|
-
choices?: Array<{ delta?: { content?: string } }>;
|
|
167
|
-
};
|
|
168
|
-
const content = parsed.choices?.[0]?.delta?.content;
|
|
169
|
-
if (content) {
|
|
170
|
-
contentChunks.push(content); // Push to array instead of concatenation
|
|
171
|
-
callbacks.onChunk?.(content);
|
|
172
|
-
}
|
|
173
|
-
} catch {
|
|
174
|
-
// Skip invalid JSON chunks
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
// Join chunks at the end - more efficient than repeated concatenation
|
|
181
|
-
const fullContent = contentChunks.join('');
|
|
182
|
-
callbacks.onComplete?.(fullContent);
|
|
183
|
-
} catch (error) {
|
|
184
|
-
callbacks.onError?.(error as Error);
|
|
185
|
-
throw error;
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
private buildRequest(
|
|
190
|
-
model: string,
|
|
191
|
-
messages: GroqMessage[],
|
|
192
|
-
config?: TextGenerationOptions["generationConfig"]
|
|
193
|
-
): GroqChatRequest {
|
|
194
|
-
return {
|
|
195
|
-
model,
|
|
196
|
-
messages,
|
|
197
|
-
temperature: config?.temperature ?? DEFAULT_GENERATION_CONFIG.temperature,
|
|
198
|
-
max_tokens: config?.maxTokens ?? DEFAULT_GENERATION_CONFIG.maxTokens,
|
|
199
|
-
top_p: config?.topP ?? DEFAULT_GENERATION_CONFIG.topP,
|
|
200
|
-
n: config?.n,
|
|
201
|
-
stop: config?.stop,
|
|
202
|
-
frequency_penalty: config?.frequencyPenalty,
|
|
203
|
-
presence_penalty: config?.presencePenalty,
|
|
204
|
-
};
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
private buildStructuredPrompt(
|
|
208
|
-
prompt: string,
|
|
209
|
-
schema?: Record<string, unknown>
|
|
210
|
-
): string {
|
|
211
|
-
let structuredPrompt = `Please generate a JSON response for the following request.\n\n`;
|
|
212
|
-
|
|
213
|
-
if (schema) {
|
|
214
|
-
structuredPrompt += `Expected JSON schema:\n${JSON.stringify(schema, null, 2)}\n\n`;
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
structuredPrompt += `Request:\n${prompt}\n\n`;
|
|
218
|
-
structuredPrompt += `Respond only with valid JSON, formatted as:\n\`\`\`json\n{...}\n\`\`\``;
|
|
219
|
-
|
|
220
|
-
return structuredPrompt;
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
export const textGenerationService = new TextGenerationService();
|
|
225
|
-
|
|
226
|
-
/**
|
|
227
|
-
* Clear all cached responses
|
|
228
|
-
*/
|
|
229
|
-
export function clearGenerationCache(): void {
|
|
230
|
-
cacheManager.clear();
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
/**
|
|
234
|
-
* Get cache statistics
|
|
235
|
-
*/
|
|
236
|
-
export function getCacheStats() {
|
|
237
|
-
return cacheManager.getStats();
|
|
238
|
-
}
|