@umituz/react-native-ai-groq-provider 1.0.23 → 1.0.25
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/application/use-cases/chat-session.usecase.ts +19 -9
- package/src/application/use-cases/streaming.usecase.ts +13 -7
- package/src/application/use-cases/structured-generation.usecase.ts +17 -5
- package/src/application/use-cases/text-generation.usecase.ts +4 -3
- package/src/domain/entities/error.types.ts +17 -2
- package/src/index.ts +26 -68
- package/src/infrastructure/http/groq-http-client.ts +68 -12
- package/src/infrastructure/http/streaming-client.ts +135 -84
- package/src/infrastructure/telemetry/TelemetryHooks.ts +40 -23
- package/src/infrastructure/utils/calculation.util.ts +46 -14
- package/src/infrastructure/utils/content-mapper.util.ts +1 -1
- package/src/presentation/hooks/use-groq.hook.ts +14 -22
- package/src/providers/ConfigBuilder.ts +2 -73
- package/src/providers/ProviderFactory.ts +7 -62
- package/src/shared/request-builder.ts +8 -4
- package/src/shared/response-handler.ts +81 -0
- package/src/types/react-native-global.d.ts +12 -0
- package/src/application/use-cases/index.ts +0 -19
- package/src/domain/entities/index.ts +0 -7
- package/src/infrastructure/http/index.ts +0 -7
- package/src/infrastructure/telemetry/index.ts +0 -5
- package/src/infrastructure/utils/async/index.ts +0 -6
- package/src/infrastructure/utils/index.ts +0 -8
- package/src/presentation/hooks/index.ts +0 -7
- package/src/presentation/hooks/useGroq.ts +0 -235
- package/src/presentation/hooks/useOperationManager.ts +0 -119
- package/src/presentation/index.ts +0 -6
- package/src/providers/index.ts +0 -16
- package/src/shared/index.ts +0 -16
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
* Builder pattern for Groq configuration
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import type { GroqConfig, GroqGenerationConfig } from "../domain/entities";
|
|
7
|
-
import { DEFAULT_MODELS } from "../domain/entities";
|
|
6
|
+
import type { GroqConfig, GroqGenerationConfig } from "../domain/entities/groq.types";
|
|
7
|
+
import { DEFAULT_MODELS } from "../domain/entities/groq.types";
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Builder for Groq configuration
|
|
@@ -12,41 +12,26 @@ import { DEFAULT_MODELS } from "../domain/entities";
|
|
|
12
12
|
export class ConfigBuilder {
|
|
13
13
|
private config: Partial<GroqConfig> = {};
|
|
14
14
|
|
|
15
|
-
/**
|
|
16
|
-
* Set API key
|
|
17
|
-
*/
|
|
18
15
|
withApiKey(apiKey: string): ConfigBuilder {
|
|
19
16
|
this.config.apiKey = apiKey;
|
|
20
17
|
return this;
|
|
21
18
|
}
|
|
22
19
|
|
|
23
|
-
/**
|
|
24
|
-
* Set base URL
|
|
25
|
-
*/
|
|
26
20
|
withBaseUrl(baseUrl: string): ConfigBuilder {
|
|
27
21
|
this.config.baseUrl = baseUrl;
|
|
28
22
|
return this;
|
|
29
23
|
}
|
|
30
24
|
|
|
31
|
-
/**
|
|
32
|
-
* Set timeout
|
|
33
|
-
*/
|
|
34
25
|
withTimeout(timeoutMs: number): ConfigBuilder {
|
|
35
26
|
this.config.timeoutMs = timeoutMs;
|
|
36
27
|
return this;
|
|
37
28
|
}
|
|
38
29
|
|
|
39
|
-
/**
|
|
40
|
-
* Set default text model
|
|
41
|
-
*/
|
|
42
30
|
withTextModel(model: string): ConfigBuilder {
|
|
43
31
|
this.config.textModel = model;
|
|
44
32
|
return this;
|
|
45
33
|
}
|
|
46
34
|
|
|
47
|
-
/**
|
|
48
|
-
* Build configuration
|
|
49
|
-
*/
|
|
50
35
|
build(): GroqConfig {
|
|
51
36
|
if (!this.config.apiKey) {
|
|
52
37
|
throw new Error("API key is required. Use withApiKey() to set it.");
|
|
@@ -59,13 +44,6 @@ export class ConfigBuilder {
|
|
|
59
44
|
textModel: this.config.textModel || DEFAULT_MODELS.TEXT,
|
|
60
45
|
};
|
|
61
46
|
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Create a new builder instance
|
|
65
|
-
*/
|
|
66
|
-
static create(): ConfigBuilder {
|
|
67
|
-
return new ConfigBuilder();
|
|
68
|
-
}
|
|
69
47
|
}
|
|
70
48
|
|
|
71
49
|
/**
|
|
@@ -74,86 +52,37 @@ export class ConfigBuilder {
|
|
|
74
52
|
export class GenerationConfigBuilder {
|
|
75
53
|
private config: GroqGenerationConfig = {};
|
|
76
54
|
|
|
77
|
-
/**
|
|
78
|
-
* Set temperature
|
|
79
|
-
*/
|
|
80
55
|
withTemperature(temperature: number): GenerationConfigBuilder {
|
|
81
56
|
this.config.temperature = temperature;
|
|
82
57
|
return this;
|
|
83
58
|
}
|
|
84
59
|
|
|
85
|
-
/**
|
|
86
|
-
* Set max tokens
|
|
87
|
-
*/
|
|
88
60
|
withMaxTokens(maxTokens: number): GenerationConfigBuilder {
|
|
89
61
|
this.config.maxTokens = maxTokens;
|
|
90
62
|
return this;
|
|
91
63
|
}
|
|
92
64
|
|
|
93
|
-
/**
|
|
94
|
-
* Set top P
|
|
95
|
-
*/
|
|
96
65
|
withTopP(topP: number): GenerationConfigBuilder {
|
|
97
66
|
this.config.topP = topP;
|
|
98
67
|
return this;
|
|
99
68
|
}
|
|
100
69
|
|
|
101
|
-
/**
|
|
102
|
-
* Set frequency penalty
|
|
103
|
-
*/
|
|
104
70
|
withFrequencyPenalty(penalty: number): GenerationConfigBuilder {
|
|
105
71
|
this.config.frequencyPenalty = penalty;
|
|
106
72
|
return this;
|
|
107
73
|
}
|
|
108
74
|
|
|
109
|
-
/**
|
|
110
|
-
* Set presence penalty
|
|
111
|
-
*/
|
|
112
75
|
withPresencePenalty(penalty: number): GenerationConfigBuilder {
|
|
113
76
|
this.config.presencePenalty = penalty;
|
|
114
77
|
return this;
|
|
115
78
|
}
|
|
116
79
|
|
|
117
|
-
/**
|
|
118
|
-
* Set stop sequences
|
|
119
|
-
*/
|
|
120
80
|
withStop(stop: string[]): GenerationConfigBuilder {
|
|
121
81
|
this.config.stop = stop;
|
|
122
82
|
return this;
|
|
123
83
|
}
|
|
124
84
|
|
|
125
|
-
/**
|
|
126
|
-
* Build configuration
|
|
127
|
-
*/
|
|
128
85
|
build(): GroqGenerationConfig {
|
|
129
86
|
return { ...this.config };
|
|
130
87
|
}
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* Create a new builder instance
|
|
134
|
-
*/
|
|
135
|
-
static create(): GenerationConfigBuilder {
|
|
136
|
-
return new GenerationConfigBuilder();
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* Create a balanced configuration
|
|
141
|
-
*/
|
|
142
|
-
static balanced(): GenerationConfigBuilder {
|
|
143
|
-
return new GenerationConfigBuilder().withTemperature(0.7);
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* Create a creative configuration
|
|
148
|
-
*/
|
|
149
|
-
static creative(): GenerationConfigBuilder {
|
|
150
|
-
return new GenerationConfigBuilder().withTemperature(1.0);
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
/**
|
|
154
|
-
* Create a precise configuration
|
|
155
|
-
*/
|
|
156
|
-
static precise(): GenerationConfigBuilder {
|
|
157
|
-
return new GenerationConfigBuilder().withTemperature(0.3);
|
|
158
|
-
}
|
|
159
88
|
}
|
|
@@ -3,8 +3,7 @@
|
|
|
3
3
|
* Factory for creating configured Groq provider instances
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { groqHttpClient } from "../infrastructure/
|
|
7
|
-
import { ConfigBuilder, GenerationConfigBuilder } from "./ConfigBuilder";
|
|
6
|
+
import { groqHttpClient } from "../infrastructure/http/groq-http-client";
|
|
8
7
|
|
|
9
8
|
/**
|
|
10
9
|
* Provider configuration options
|
|
@@ -16,14 +15,6 @@ export interface ProviderConfig {
|
|
|
16
15
|
defaultModel?: string;
|
|
17
16
|
}
|
|
18
17
|
|
|
19
|
-
/**
|
|
20
|
-
* Provider factory options
|
|
21
|
-
*/
|
|
22
|
-
export interface ProviderFactoryOptions {
|
|
23
|
-
enableTelemetry?: boolean;
|
|
24
|
-
onError?: (error: Error) => void;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
18
|
/**
|
|
28
19
|
* Initialize Groq provider with configuration
|
|
29
20
|
*/
|
|
@@ -37,61 +28,15 @@ export function initializeProvider(config: ProviderConfig): void {
|
|
|
37
28
|
}
|
|
38
29
|
|
|
39
30
|
/**
|
|
40
|
-
*
|
|
31
|
+
* Reset provider configuration
|
|
41
32
|
*/
|
|
42
|
-
export
|
|
43
|
-
|
|
44
|
-
* Create a new provider instance
|
|
45
|
-
*/
|
|
46
|
-
create(config: ProviderConfig): void {
|
|
47
|
-
initializeProvider(config);
|
|
48
|
-
},
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Create provider from environment variables
|
|
52
|
-
*/
|
|
53
|
-
fromEnv(): void {
|
|
54
|
-
const apiKey = process.env.GROQ_API_KEY;
|
|
55
|
-
|
|
56
|
-
if (!apiKey) {
|
|
57
|
-
throw new Error("GROQ_API_KEY environment variable is not set");
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
initializeProvider({
|
|
61
|
-
apiKey,
|
|
62
|
-
baseUrl: process.env.GROQ_BASE_URL,
|
|
63
|
-
timeoutMs: process.env.GROQ_TIMEOUT_MS ? parseInt(process.env.GROQ_TIMEOUT_MS) : undefined,
|
|
64
|
-
});
|
|
65
|
-
},
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Reset provider (clear configuration)
|
|
69
|
-
*/
|
|
70
|
-
reset(): void {
|
|
71
|
-
groqHttpClient.reset();
|
|
72
|
-
},
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Check if provider is initialized
|
|
76
|
-
*/
|
|
77
|
-
isInitialized(): boolean {
|
|
78
|
-
return groqHttpClient.isInitialized();
|
|
79
|
-
},
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Convenience function to initialize provider
|
|
84
|
-
*/
|
|
85
|
-
export function configureProvider(config: ProviderConfig): void {
|
|
86
|
-
providerFactory.create(config);
|
|
33
|
+
export function resetProvider(): void {
|
|
34
|
+
groqHttpClient.reset();
|
|
87
35
|
}
|
|
88
36
|
|
|
89
37
|
/**
|
|
90
|
-
*
|
|
38
|
+
* Check if provider is initialized
|
|
91
39
|
*/
|
|
92
|
-
export function
|
|
93
|
-
|
|
40
|
+
export function isProviderInitialized(): boolean {
|
|
41
|
+
return groqHttpClient.isInitialized();
|
|
94
42
|
}
|
|
95
|
-
|
|
96
|
-
// Re-export builders
|
|
97
|
-
export { ConfigBuilder, GenerationConfigBuilder };
|
|
@@ -7,8 +7,8 @@ import type {
|
|
|
7
7
|
GroqChatRequest,
|
|
8
8
|
GroqGenerationConfig,
|
|
9
9
|
GroqMessage,
|
|
10
|
-
} from "../domain/entities";
|
|
11
|
-
import { DEFAULT_MODELS } from "../domain/entities";
|
|
10
|
+
} from "../domain/entities/groq.types";
|
|
11
|
+
import { DEFAULT_MODELS } from "../domain/entities/groq.types";
|
|
12
12
|
|
|
13
13
|
export interface RequestBuilderOptions {
|
|
14
14
|
model?: string;
|
|
@@ -32,8 +32,12 @@ export class RequestBuilder {
|
|
|
32
32
|
return {
|
|
33
33
|
model,
|
|
34
34
|
messages,
|
|
35
|
-
temperature: generationConfig.temperature
|
|
36
|
-
|
|
35
|
+
temperature: generationConfig.temperature !== undefined
|
|
36
|
+
? generationConfig.temperature
|
|
37
|
+
: defaultTemperature,
|
|
38
|
+
max_tokens: generationConfig.maxTokens !== undefined
|
|
39
|
+
? generationConfig.maxTokens
|
|
40
|
+
: defaultMaxTokens,
|
|
37
41
|
top_p: generationConfig.topP,
|
|
38
42
|
n: generationConfig.n,
|
|
39
43
|
stop: generationConfig.stop,
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Response Handler Utility
|
|
3
|
+
* Handles API response parsing and extraction
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { GroqChatResponse, GroqUsage, GroqFinishReason } from "../domain/entities/groq.types";
|
|
7
|
+
|
|
8
|
+
interface Logger {
|
|
9
|
+
debug: (tag: string, message: string, context?: Record<string, unknown>) => void;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface ResponseHandlerResult {
|
|
13
|
+
content: string;
|
|
14
|
+
usage: {
|
|
15
|
+
promptTokens: number;
|
|
16
|
+
completionTokens: number;
|
|
17
|
+
totalTokens: number;
|
|
18
|
+
};
|
|
19
|
+
finishReason: GroqFinishReason;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export class ResponseHandler {
|
|
23
|
+
/**
|
|
24
|
+
* Extract content from chat completion response
|
|
25
|
+
*/
|
|
26
|
+
static extractContent(response: GroqChatResponse): string {
|
|
27
|
+
if (!response.choices || response.choices.length === 0) {
|
|
28
|
+
return "";
|
|
29
|
+
}
|
|
30
|
+
return response.choices[0].message?.content || "";
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Handle complete response and extract all relevant data
|
|
35
|
+
*/
|
|
36
|
+
static handleResponse(response: GroqChatResponse): ResponseHandlerResult {
|
|
37
|
+
if (!response.choices || response.choices.length === 0) {
|
|
38
|
+
return {
|
|
39
|
+
content: "",
|
|
40
|
+
usage: this.extractUsage(response.usage),
|
|
41
|
+
finishReason: "stop",
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const choice = response.choices[0];
|
|
46
|
+
return {
|
|
47
|
+
content: choice.message?.content || "",
|
|
48
|
+
usage: this.extractUsage(response.usage),
|
|
49
|
+
finishReason: choice.finish_reason || "stop",
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Extract usage information
|
|
55
|
+
*/
|
|
56
|
+
private static extractUsage(usage: GroqUsage): {
|
|
57
|
+
promptTokens: number;
|
|
58
|
+
completionTokens: number;
|
|
59
|
+
totalTokens: number;
|
|
60
|
+
} {
|
|
61
|
+
return {
|
|
62
|
+
promptTokens: usage.prompt_tokens || 0,
|
|
63
|
+
completionTokens: usage.completion_tokens || 0,
|
|
64
|
+
totalTokens: usage.total_tokens || 0,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Log response details
|
|
70
|
+
*/
|
|
71
|
+
static logResponse(logger: Logger, response: GroqChatResponse, apiMs: number): void {
|
|
72
|
+
logger.debug("ResponseHandler", "API response received", {
|
|
73
|
+
model: response.model,
|
|
74
|
+
promptTokens: response.usage.prompt_tokens,
|
|
75
|
+
completionTokens: response.usage.completion_tokens,
|
|
76
|
+
totalTokens: response.usage.total_tokens,
|
|
77
|
+
finishReason: response.choices[0]?.finish_reason,
|
|
78
|
+
apiDuration: `${apiMs}ms`,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Application Layer - Use Cases
|
|
3
|
-
* Business logic orchestrators
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
export { generateText } from "./text-generation.usecase";
|
|
7
|
-
export type { TextGenerationOptions } from "./text-generation.usecase";
|
|
8
|
-
|
|
9
|
-
export { generateStructured } from "./structured-generation.usecase";
|
|
10
|
-
export type { StructuredGenerationOptions } from "./structured-generation.usecase";
|
|
11
|
-
|
|
12
|
-
export { streamText } from "./streaming.usecase";
|
|
13
|
-
export type { StreamingCallbacks, StreamingOptions } from "./streaming.usecase";
|
|
14
|
-
|
|
15
|
-
export {
|
|
16
|
-
chatSessionManager,
|
|
17
|
-
type ChatSession,
|
|
18
|
-
type ChatSendResult,
|
|
19
|
-
} from "./chat-session.usecase";
|
|
@@ -1,235 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* useGroq Hook
|
|
3
|
-
* Main React hook for Groq text generation
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { useState, useCallback, useRef, useMemo } from "react";
|
|
7
|
-
import type { GroqGenerationConfig } from "../../domain/entities";
|
|
8
|
-
import { textGeneration } from "../../infrastructure/services/TextGeneration";
|
|
9
|
-
import { structuredText } from "../../infrastructure/services/StructuredText";
|
|
10
|
-
import { streaming } from "../../infrastructure/services/Streaming";
|
|
11
|
-
import { getUserFriendlyError } from "../../infrastructure/utils/error-mapper.util";
|
|
12
|
-
import { telemetry } from "../../infrastructure/telemetry";
|
|
13
|
-
|
|
14
|
-
export interface UseGroqOptions {
|
|
15
|
-
/** Initial model to use */
|
|
16
|
-
model?: string;
|
|
17
|
-
/** Default generation config */
|
|
18
|
-
generationConfig?: GroqGenerationConfig;
|
|
19
|
-
/** Callback when generation starts */
|
|
20
|
-
onStart?: () => void;
|
|
21
|
-
/** Callback when generation completes */
|
|
22
|
-
onSuccess?: (result: string) => void;
|
|
23
|
-
/** Callback when generation fails */
|
|
24
|
-
onError?: (error: string) => void;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export interface UseGroqReturn {
|
|
28
|
-
/** Loading state */
|
|
29
|
-
isLoading: boolean;
|
|
30
|
-
/** Error message */
|
|
31
|
-
error: string | null;
|
|
32
|
-
/** Generated result */
|
|
33
|
-
result: string | null;
|
|
34
|
-
/** Generate text from a prompt */
|
|
35
|
-
generate: (prompt: string, options?: GroqGenerationConfig) => Promise<string>;
|
|
36
|
-
/** Generate structured JSON output */
|
|
37
|
-
generateJSON: <T = Record<string, unknown>>(
|
|
38
|
-
prompt: string,
|
|
39
|
-
options?: GroqGenerationConfig & { schema?: Record<string, unknown> }
|
|
40
|
-
) => Promise<T>;
|
|
41
|
-
/** Stream text generation */
|
|
42
|
-
stream: (
|
|
43
|
-
prompt: string,
|
|
44
|
-
onChunk: (chunk: string) => void,
|
|
45
|
-
options?: GroqGenerationConfig
|
|
46
|
-
) => Promise<void>;
|
|
47
|
-
/** Reset state */
|
|
48
|
-
reset: () => void;
|
|
49
|
-
/** Clear error */
|
|
50
|
-
clearError: () => void;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Hook for Groq text generation
|
|
55
|
-
* Optimized to prevent unnecessary re-renders and memory leaks
|
|
56
|
-
*/
|
|
57
|
-
export function useGroq(options: UseGroqOptions = {}): UseGroqReturn {
|
|
58
|
-
const [isLoading, setIsLoading] = useState(false);
|
|
59
|
-
const [error, setError] = useState<string | null>(null);
|
|
60
|
-
const [result, setResult] = useState<string | null>(null);
|
|
61
|
-
const abortControllerRef = useRef<AbortController | null>(null);
|
|
62
|
-
|
|
63
|
-
// Memoize options to prevent unnecessary callback recreations
|
|
64
|
-
const stableOptions = useMemo(() => options, [
|
|
65
|
-
options.model,
|
|
66
|
-
options.generationConfig?.temperature,
|
|
67
|
-
options.generationConfig?.maxTokens,
|
|
68
|
-
options.generationConfig?.topP,
|
|
69
|
-
options.onStart,
|
|
70
|
-
options.onSuccess,
|
|
71
|
-
options.onError,
|
|
72
|
-
]);
|
|
73
|
-
|
|
74
|
-
const generate = useCallback(
|
|
75
|
-
async (prompt: string, config?: GroqGenerationConfig): Promise<string> => {
|
|
76
|
-
// Cancel any ongoing request
|
|
77
|
-
if (abortControllerRef.current) {
|
|
78
|
-
abortControllerRef.current.abort();
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
abortControllerRef.current = new AbortController();
|
|
82
|
-
setIsLoading(true);
|
|
83
|
-
setError(null);
|
|
84
|
-
setResult(null);
|
|
85
|
-
|
|
86
|
-
telemetry.log("groq_generate_start", { prompt: prompt.substring(0, 100) });
|
|
87
|
-
stableOptions.onStart?.();
|
|
88
|
-
|
|
89
|
-
try {
|
|
90
|
-
const response = await textGeneration(prompt, {
|
|
91
|
-
model: stableOptions.model,
|
|
92
|
-
generationConfig: { ...stableOptions.generationConfig, ...config },
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
setResult(response);
|
|
96
|
-
stableOptions.onSuccess?.(response);
|
|
97
|
-
telemetry.log("groq_generate_success", { responseLength: response.length });
|
|
98
|
-
|
|
99
|
-
return response;
|
|
100
|
-
} catch (err) {
|
|
101
|
-
const errorMessage = getUserFriendlyError(err);
|
|
102
|
-
setError(errorMessage);
|
|
103
|
-
stableOptions.onError?.(errorMessage);
|
|
104
|
-
telemetry.log("groq_generate_error", { error: errorMessage });
|
|
105
|
-
throw err;
|
|
106
|
-
} finally {
|
|
107
|
-
setIsLoading(false);
|
|
108
|
-
abortControllerRef.current = null;
|
|
109
|
-
}
|
|
110
|
-
},
|
|
111
|
-
[stableOptions]
|
|
112
|
-
);
|
|
113
|
-
|
|
114
|
-
const generateJSON = useCallback(
|
|
115
|
-
async <T = Record<string, unknown>,>(
|
|
116
|
-
prompt: string,
|
|
117
|
-
config?: GroqGenerationConfig & { schema?: Record<string, unknown> }
|
|
118
|
-
): Promise<T> => {
|
|
119
|
-
// Cancel any ongoing request
|
|
120
|
-
if (abortControllerRef.current) {
|
|
121
|
-
abortControllerRef.current.abort();
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
abortControllerRef.current = new AbortController();
|
|
125
|
-
setIsLoading(true);
|
|
126
|
-
setError(null);
|
|
127
|
-
setResult(null);
|
|
128
|
-
|
|
129
|
-
telemetry.log("groq_generate_json_start", { prompt: prompt.substring(0, 100) });
|
|
130
|
-
stableOptions.onStart?.();
|
|
131
|
-
|
|
132
|
-
try {
|
|
133
|
-
const response = await structuredText<T>(prompt, {
|
|
134
|
-
model: stableOptions.model,
|
|
135
|
-
generationConfig: { ...stableOptions.generationConfig, ...config },
|
|
136
|
-
schema: config?.schema,
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
setResult(JSON.stringify(response, null, 2));
|
|
140
|
-
stableOptions.onSuccess?.(JSON.stringify(response, null, 2));
|
|
141
|
-
telemetry.log("groq_generate_json_success");
|
|
142
|
-
|
|
143
|
-
return response;
|
|
144
|
-
} catch (err) {
|
|
145
|
-
const errorMessage = getUserFriendlyError(err);
|
|
146
|
-
setError(errorMessage);
|
|
147
|
-
stableOptions.onError?.(errorMessage);
|
|
148
|
-
telemetry.log("groq_generate_json_error", { error: errorMessage });
|
|
149
|
-
throw err;
|
|
150
|
-
} finally {
|
|
151
|
-
setIsLoading(false);
|
|
152
|
-
abortControllerRef.current = null;
|
|
153
|
-
}
|
|
154
|
-
},
|
|
155
|
-
[stableOptions]
|
|
156
|
-
);
|
|
157
|
-
|
|
158
|
-
const stream = useCallback(
|
|
159
|
-
async (
|
|
160
|
-
prompt: string,
|
|
161
|
-
onChunk: (chunk: string) => void,
|
|
162
|
-
config?: GroqGenerationConfig
|
|
163
|
-
): Promise<void> => {
|
|
164
|
-
// Cancel any ongoing request
|
|
165
|
-
if (abortControllerRef.current) {
|
|
166
|
-
abortControllerRef.current.abort();
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
abortControllerRef.current = new AbortController();
|
|
170
|
-
setIsLoading(true);
|
|
171
|
-
setError(null);
|
|
172
|
-
setResult(null);
|
|
173
|
-
|
|
174
|
-
let fullContent = "";
|
|
175
|
-
|
|
176
|
-
telemetry.log("groq_stream_start", { prompt: prompt.substring(0, 100) });
|
|
177
|
-
stableOptions.onStart?.();
|
|
178
|
-
|
|
179
|
-
try {
|
|
180
|
-
for await (const streamingResult of streaming(prompt, {
|
|
181
|
-
model: stableOptions.model,
|
|
182
|
-
generationConfig: { ...stableOptions.generationConfig, ...config },
|
|
183
|
-
callbacks: {
|
|
184
|
-
onChunk: (c) => {
|
|
185
|
-
fullContent += c;
|
|
186
|
-
onChunk(c);
|
|
187
|
-
},
|
|
188
|
-
},
|
|
189
|
-
})) {
|
|
190
|
-
// Consume the async iterator (streaming is handled via callbacks)
|
|
191
|
-
void streamingResult;
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
setResult(fullContent);
|
|
195
|
-
stableOptions.onSuccess?.(fullContent);
|
|
196
|
-
telemetry.log("groq_stream_success", { contentLength: fullContent.length });
|
|
197
|
-
} catch (err) {
|
|
198
|
-
const errorMessage = getUserFriendlyError(err);
|
|
199
|
-
setError(errorMessage);
|
|
200
|
-
stableOptions.onError?.(errorMessage);
|
|
201
|
-
telemetry.log("groq_stream_error", { error: errorMessage });
|
|
202
|
-
throw err;
|
|
203
|
-
} finally {
|
|
204
|
-
setIsLoading(false);
|
|
205
|
-
abortControllerRef.current = null;
|
|
206
|
-
}
|
|
207
|
-
},
|
|
208
|
-
[stableOptions]
|
|
209
|
-
);
|
|
210
|
-
|
|
211
|
-
const reset = useCallback(() => {
|
|
212
|
-
if (abortControllerRef.current) {
|
|
213
|
-
abortControllerRef.current.abort();
|
|
214
|
-
abortControllerRef.current = null;
|
|
215
|
-
}
|
|
216
|
-
setIsLoading(false);
|
|
217
|
-
setError(null);
|
|
218
|
-
setResult(null);
|
|
219
|
-
}, []);
|
|
220
|
-
|
|
221
|
-
const clearError = useCallback(() => {
|
|
222
|
-
setError(null);
|
|
223
|
-
}, []);
|
|
224
|
-
|
|
225
|
-
return {
|
|
226
|
-
isLoading,
|
|
227
|
-
error,
|
|
228
|
-
result,
|
|
229
|
-
generate,
|
|
230
|
-
generateJSON,
|
|
231
|
-
stream,
|
|
232
|
-
reset,
|
|
233
|
-
clearError,
|
|
234
|
-
};
|
|
235
|
-
}
|