@umituz/react-native-ai-groq-provider 1.0.24 → 1.0.26
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 +62 -14
- package/src/application/use-cases/streaming.usecase.ts +13 -7
- package/src/application/use-cases/structured-generation.usecase.ts +27 -10
- package/src/application/use-cases/text-generation.usecase.ts +4 -3
- package/src/domain/entities/error.types.ts +17 -2
- package/src/index.ts +24 -66
- package/src/infrastructure/http/groq-http-client.ts +68 -12
- package/src/infrastructure/http/streaming-client.ts +139 -87
- package/src/infrastructure/telemetry/TelemetryHooks.ts +39 -19
- package/src/infrastructure/utils/calculation.util.ts +59 -63
- package/src/infrastructure/utils/content-mapper.util.ts +1 -1
- package/src/presentation/hooks/use-groq.hook.ts +58 -41
- package/src/providers/ConfigBuilder.ts +2 -73
- package/src/providers/ProviderFactory.ts +7 -62
- package/src/shared/request-builder.ts +29 -10
- package/src/shared/response-handler.ts +93 -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,10 +3,12 @@
|
|
|
3
3
|
* Main React hook for Groq text generation
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { useState, useCallback,
|
|
7
|
-
import type { GroqGenerationConfig } from "../../domain/entities";
|
|
8
|
-
import { generateText
|
|
9
|
-
import {
|
|
6
|
+
import { useState, useCallback, useRef } from "react";
|
|
7
|
+
import type { GroqGenerationConfig } from "../../domain/entities/groq.types";
|
|
8
|
+
import { generateText } from "../../application/use-cases/text-generation.usecase";
|
|
9
|
+
import { generateStructured } from "../../application/use-cases/structured-generation.usecase";
|
|
10
|
+
import { streamText } from "../../application/use-cases/streaming.usecase";
|
|
11
|
+
import { getUserFriendlyError } from "../../infrastructure/utils/error-mapper.util";
|
|
10
12
|
|
|
11
13
|
export interface UseGroqOptions {
|
|
12
14
|
model?: string;
|
|
@@ -39,24 +41,30 @@ export function useGroq(options: UseGroqOptions = {}): UseGroqReturn {
|
|
|
39
41
|
const [error, setError] = useState<string | null>(null);
|
|
40
42
|
const [result, setResult] = useState<string | null>(null);
|
|
41
43
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
44
|
+
// Use refs to avoid unnecessary re-creates and JSON.stringify
|
|
45
|
+
const optionsRef = useRef(options);
|
|
46
|
+
const callbacksRef = useRef({
|
|
47
|
+
onStart: options.onStart,
|
|
48
|
+
onSuccess: options.onSuccess,
|
|
49
|
+
onError: options.onError,
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
// Update refs when options change
|
|
53
|
+
if (options.model !== optionsRef.current.model) {
|
|
54
|
+
optionsRef.current.model = options.model;
|
|
55
|
+
}
|
|
56
|
+
if (options.generationConfig !== optionsRef.current.generationConfig) {
|
|
57
|
+
optionsRef.current.generationConfig = options.generationConfig;
|
|
58
|
+
}
|
|
59
|
+
if (options.onStart !== callbacksRef.current.onStart) {
|
|
60
|
+
callbacksRef.current.onStart = options.onStart;
|
|
61
|
+
}
|
|
62
|
+
if (options.onSuccess !== callbacksRef.current.onSuccess) {
|
|
63
|
+
callbacksRef.current.onSuccess = options.onSuccess;
|
|
64
|
+
}
|
|
65
|
+
if (options.onError !== callbacksRef.current.onError) {
|
|
66
|
+
callbacksRef.current.onError = options.onError;
|
|
67
|
+
}
|
|
60
68
|
|
|
61
69
|
const generate = useCallback(
|
|
62
70
|
async (prompt: string, config?: GroqGenerationConfig): Promise<string> => {
|
|
@@ -64,27 +72,30 @@ export function useGroq(options: UseGroqOptions = {}): UseGroqReturn {
|
|
|
64
72
|
setError(null);
|
|
65
73
|
setResult(null);
|
|
66
74
|
|
|
67
|
-
|
|
75
|
+
callbacksRef.current.onStart?.();
|
|
68
76
|
|
|
69
77
|
try {
|
|
70
78
|
const response = await generateText(prompt, {
|
|
71
|
-
model:
|
|
72
|
-
generationConfig: {
|
|
79
|
+
model: optionsRef.current.model,
|
|
80
|
+
generationConfig: {
|
|
81
|
+
...optionsRef.current.generationConfig,
|
|
82
|
+
...config,
|
|
83
|
+
},
|
|
73
84
|
});
|
|
74
85
|
|
|
75
86
|
setResult(response);
|
|
76
|
-
|
|
87
|
+
callbacksRef.current.onSuccess?.(response);
|
|
77
88
|
return response;
|
|
78
89
|
} catch (err) {
|
|
79
90
|
const errorMessage = getUserFriendlyError(err);
|
|
80
91
|
setError(errorMessage);
|
|
81
|
-
|
|
92
|
+
callbacksRef.current.onError?.(errorMessage);
|
|
82
93
|
throw err;
|
|
83
94
|
} finally {
|
|
84
95
|
setIsLoading(false);
|
|
85
96
|
}
|
|
86
97
|
},
|
|
87
|
-
[
|
|
98
|
+
[] // No deps - uses refs
|
|
88
99
|
);
|
|
89
100
|
|
|
90
101
|
const generateJSON = useCallback(
|
|
@@ -96,29 +107,32 @@ export function useGroq(options: UseGroqOptions = {}): UseGroqReturn {
|
|
|
96
107
|
setError(null);
|
|
97
108
|
setResult(null);
|
|
98
109
|
|
|
99
|
-
|
|
110
|
+
callbacksRef.current.onStart?.();
|
|
100
111
|
|
|
101
112
|
try {
|
|
102
113
|
const response = await generateStructured<T>(prompt, {
|
|
103
|
-
model:
|
|
104
|
-
generationConfig: {
|
|
114
|
+
model: optionsRef.current.model,
|
|
115
|
+
generationConfig: {
|
|
116
|
+
...optionsRef.current.generationConfig,
|
|
117
|
+
...config,
|
|
118
|
+
},
|
|
105
119
|
schema: config?.schema,
|
|
106
120
|
});
|
|
107
121
|
|
|
108
122
|
const jsonStr = JSON.stringify(response, null, 2);
|
|
109
123
|
setResult(jsonStr);
|
|
110
|
-
|
|
124
|
+
callbacksRef.current.onSuccess?.(jsonStr);
|
|
111
125
|
return response;
|
|
112
126
|
} catch (err) {
|
|
113
127
|
const errorMessage = getUserFriendlyError(err);
|
|
114
128
|
setError(errorMessage);
|
|
115
|
-
|
|
129
|
+
callbacksRef.current.onError?.(errorMessage);
|
|
116
130
|
throw err;
|
|
117
131
|
} finally {
|
|
118
132
|
setIsLoading(false);
|
|
119
133
|
}
|
|
120
134
|
},
|
|
121
|
-
[
|
|
135
|
+
[] // No deps - uses refs
|
|
122
136
|
);
|
|
123
137
|
|
|
124
138
|
const stream = useCallback(
|
|
@@ -133,32 +147,35 @@ export function useGroq(options: UseGroqOptions = {}): UseGroqReturn {
|
|
|
133
147
|
|
|
134
148
|
let fullContent = "";
|
|
135
149
|
|
|
136
|
-
|
|
150
|
+
callbacksRef.current.onStart?.();
|
|
137
151
|
|
|
138
152
|
try {
|
|
139
153
|
for await (const chunk of streamText(prompt, {
|
|
140
|
-
model:
|
|
141
|
-
generationConfig: {
|
|
154
|
+
model: optionsRef.current.model,
|
|
155
|
+
generationConfig: {
|
|
156
|
+
...optionsRef.current.generationConfig,
|
|
157
|
+
...config,
|
|
158
|
+
},
|
|
142
159
|
callbacks: { onChunk: (c) => {
|
|
143
160
|
fullContent += c;
|
|
144
161
|
onChunk(c);
|
|
145
162
|
}},
|
|
146
163
|
})) {
|
|
147
|
-
|
|
164
|
+
fullContent += chunk;
|
|
148
165
|
}
|
|
149
166
|
|
|
150
167
|
setResult(fullContent);
|
|
151
|
-
|
|
168
|
+
callbacksRef.current.onSuccess?.(fullContent);
|
|
152
169
|
} catch (err) {
|
|
153
170
|
const errorMessage = getUserFriendlyError(err);
|
|
154
171
|
setError(errorMessage);
|
|
155
|
-
|
|
172
|
+
callbacksRef.current.onError?.(errorMessage);
|
|
156
173
|
throw err;
|
|
157
174
|
} finally {
|
|
158
175
|
setIsLoading(false);
|
|
159
176
|
}
|
|
160
177
|
},
|
|
161
|
-
[
|
|
178
|
+
[] // No deps - uses refs
|
|
162
179
|
);
|
|
163
180
|
|
|
164
181
|
const reset = useCallback(() => {
|
|
@@ -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;
|
|
@@ -29,17 +29,36 @@ export class RequestBuilder {
|
|
|
29
29
|
defaultMaxTokens = 1024,
|
|
30
30
|
} = options;
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
const request: GroqChatRequest = {
|
|
33
33
|
model,
|
|
34
34
|
messages,
|
|
35
|
-
temperature: generationConfig.temperature
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
presence_penalty: generationConfig.presencePenalty,
|
|
35
|
+
temperature: generationConfig.temperature !== undefined
|
|
36
|
+
? generationConfig.temperature
|
|
37
|
+
: defaultTemperature,
|
|
38
|
+
max_tokens: generationConfig.maxTokens !== undefined
|
|
39
|
+
? generationConfig.maxTokens
|
|
40
|
+
: defaultMaxTokens,
|
|
42
41
|
};
|
|
42
|
+
|
|
43
|
+
// Only include defined optional properties
|
|
44
|
+
// Map camelCase to snake_case for API
|
|
45
|
+
if (generationConfig.topP !== undefined) {
|
|
46
|
+
request.top_p = generationConfig.topP;
|
|
47
|
+
}
|
|
48
|
+
if (generationConfig.n !== undefined) {
|
|
49
|
+
request.n = generationConfig.n;
|
|
50
|
+
}
|
|
51
|
+
if (generationConfig.stop !== undefined) {
|
|
52
|
+
request.stop = generationConfig.stop;
|
|
53
|
+
}
|
|
54
|
+
if (generationConfig.frequencyPenalty !== undefined) {
|
|
55
|
+
request.frequency_penalty = generationConfig.frequencyPenalty;
|
|
56
|
+
}
|
|
57
|
+
if (generationConfig.presencePenalty !== undefined) {
|
|
58
|
+
request.presence_penalty = generationConfig.presencePenalty;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return request;
|
|
43
62
|
}
|
|
44
63
|
|
|
45
64
|
static buildPromptRequest(
|
|
@@ -0,0 +1,93 @@
|
|
|
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
|
+
isEnabled?: () => boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface ResponseHandlerResult {
|
|
14
|
+
content: string;
|
|
15
|
+
usage: {
|
|
16
|
+
promptTokens: number;
|
|
17
|
+
completionTokens: number;
|
|
18
|
+
totalTokens: number;
|
|
19
|
+
};
|
|
20
|
+
finishReason: GroqFinishReason;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export class ResponseHandler {
|
|
24
|
+
/**
|
|
25
|
+
* Extract content from chat completion response
|
|
26
|
+
*/
|
|
27
|
+
static extractContent(response: GroqChatResponse): string {
|
|
28
|
+
const choices = response.choices;
|
|
29
|
+
if (!choices || choices.length === 0) {
|
|
30
|
+
return "";
|
|
31
|
+
}
|
|
32
|
+
return choices[0].message?.content || "";
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Handle complete response and extract all relevant data
|
|
37
|
+
*/
|
|
38
|
+
static handleResponse(response: GroqChatResponse): ResponseHandlerResult {
|
|
39
|
+
const choices = response.choices;
|
|
40
|
+
|
|
41
|
+
if (!choices || choices.length === 0) {
|
|
42
|
+
return {
|
|
43
|
+
content: "",
|
|
44
|
+
usage: this.extractUsage(response.usage),
|
|
45
|
+
finishReason: "stop",
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const choice = choices[0];
|
|
50
|
+
return {
|
|
51
|
+
content: choice.message?.content || "",
|
|
52
|
+
usage: this.extractUsage(response.usage),
|
|
53
|
+
finishReason: choice.finish_reason || "stop",
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Extract usage information
|
|
59
|
+
*/
|
|
60
|
+
private static extractUsage(usage: GroqUsage): {
|
|
61
|
+
promptTokens: number;
|
|
62
|
+
completionTokens: number;
|
|
63
|
+
totalTokens: number;
|
|
64
|
+
} {
|
|
65
|
+
return {
|
|
66
|
+
promptTokens: usage.prompt_tokens || 0,
|
|
67
|
+
completionTokens: usage.completion_tokens || 0,
|
|
68
|
+
totalTokens: usage.total_tokens || 0,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Log response details (only if logger is enabled)
|
|
74
|
+
*/
|
|
75
|
+
static logResponse(logger: Logger, response: GroqChatResponse, apiMs: number): void {
|
|
76
|
+
// Early return if logging is disabled
|
|
77
|
+
if (logger.isEnabled && !logger.isEnabled()) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const choices = response.choices;
|
|
82
|
+
const firstChoice = choices?.[0];
|
|
83
|
+
|
|
84
|
+
logger.debug("ResponseHandler", "API response received", {
|
|
85
|
+
model: response.model,
|
|
86
|
+
promptTokens: response.usage.prompt_tokens,
|
|
87
|
+
completionTokens: response.usage.completion_tokens,
|
|
88
|
+
totalTokens: response.usage.total_tokens,
|
|
89
|
+
finishReason: firstChoice?.finish_reason,
|
|
90
|
+
apiDuration: `${apiMs}ms`,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
}
|
|
@@ -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";
|