@umituz/react-native-ai-generation-content 1.17.31 → 1.17.34

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umituz/react-native-ai-generation-content",
3
- "version": "1.17.31",
3
+ "version": "1.17.34",
4
4
  "description": "Provider-agnostic AI generation orchestration for React Native",
5
5
  "main": "src/index.ts",
6
6
  "types": "src/index.ts",
@@ -58,7 +58,8 @@ export function FilterChips({
58
58
  [tokens],
59
59
  );
60
60
 
61
- const visibleTypes = types.filter((t) => availableTypes.includes(t.id));
61
+ const safeAvailableTypes = availableTypes ?? [];
62
+ const visibleTypes = types.filter((t) => safeAvailableTypes.includes(t.id));
62
63
 
63
64
  return (
64
65
  <View style={[styles.container, style]}>
@@ -0,0 +1,326 @@
1
+ /**
2
+ * Flashcard Generation Service
3
+ * AI-powered flashcard generation for educational content
4
+ */
5
+
6
+ import type {
7
+ GenerationRequest,
8
+ GenerationResult,
9
+ GenerationStatus,
10
+ PhotoGenerationInput,
11
+ DirectExecutionResult,
12
+ } from "../domain/entities";
13
+
14
+ export interface FlashcardGenerationRequest {
15
+ topic: string;
16
+ difficulty: "beginner" | "intermediate" | "advanced";
17
+ count: number;
18
+ language?: string;
19
+ format?: "qa" | "definition" | "fill_blank" | "multiple_choice";
20
+ context?: string;
21
+ tags?: string[];
22
+ includeImages?: boolean;
23
+ }
24
+
25
+ export interface GeneratedFlashcard {
26
+ id: string;
27
+ front: string;
28
+ back: string;
29
+ difficulty: "easy" | "medium" | "hard";
30
+ tags: string[];
31
+ source: "ai_generated";
32
+ generationRequest: FlashcardGenerationRequest;
33
+ confidence: number; // 0-1 score
34
+ createdAt?: string;
35
+ }
36
+
37
+ export interface FlashcardGenerationResult {
38
+ success: boolean;
39
+ flashcards: GeneratedFlashcard[];
40
+ creditsUsed: number;
41
+ tokensUsed: number;
42
+ processingTime: number; // milliseconds
43
+ error?: string;
44
+ requestId: string;
45
+ }
46
+
47
+ export class FlashcardGenerationService {
48
+ private static instance: FlashcardGenerationService;
49
+
50
+ static getInstance(): FlashcardGenerationService {
51
+ if (!FlashcardGenerationService.instance) {
52
+ FlashcardGenerationService.instance = new FlashcardGenerationService();
53
+ }
54
+ return FlashcardGenerationService.instance;
55
+ }
56
+
57
+ /**
58
+ * Generate flashcards using AI
59
+ */
60
+ async generateFlashcards(
61
+ request: FlashcardGenerationRequest,
62
+ ): Promise<FlashcardGenerationResult> {
63
+ try {
64
+ const startTime = Date.now();
65
+
66
+ // Create AI generation prompt
67
+ const prompt = this.buildFlashcardPrompt(request);
68
+
69
+ // Use the AI generation orchestrator
70
+ const generationRequest: GenerationRequest = {
71
+ prompt,
72
+ type: "text_to_text" as any,
73
+ options: {
74
+ maxTokens: this.calculateMaxTokens(request.count),
75
+ temperature: 0.7,
76
+ language: request.language || "en",
77
+ },
78
+ };
79
+
80
+ const result = await this.executeGeneration(generationRequest);
81
+
82
+ // Parse AI response into flashcards
83
+ const flashcards = this.parseFlashcardsFromResult(result, request);
84
+ const processingTime = Date.now() - startTime;
85
+
86
+ return {
87
+ success: true,
88
+ flashcards,
89
+ creditsUsed: request.count * 2, // 2 credits per flashcard
90
+ tokensUsed: result.metadata?.tokensUsed || 0,
91
+ processingTime,
92
+ requestId: result.jobId || `req_${Date.now()}`,
93
+ };
94
+ } catch (error) {
95
+ return {
96
+ success: false,
97
+ flashcards: [],
98
+ creditsUsed: 0,
99
+ tokensUsed: 0,
100
+ processingTime: 0,
101
+ error: error instanceof Error ? error.message : "Unknown error",
102
+ requestId: "",
103
+ };
104
+ }
105
+ }
106
+
107
+ /**
108
+ * Validate generated flashcard content
109
+ */
110
+ async validateFlashcard(
111
+ front: string,
112
+ back: string,
113
+ ): Promise<{
114
+ accuracy: number;
115
+ relevance: number;
116
+ clarity: number;
117
+ completeness: number;
118
+ overall: number;
119
+ }> {
120
+ // Simple validation heuristic
121
+ const frontLength = front.length;
122
+ const backLength = back.length;
123
+
124
+ const accuracy = this.calculateAccuracy(front, back);
125
+ const relevance = this.calculateRelevance(front, back);
126
+ const clarity = this.calculateClarity(front, back);
127
+ const completeness = this.calculateCompleteness(front, back);
128
+ const overall = (accuracy + relevance + clarity + completeness) / 4;
129
+
130
+ return {
131
+ accuracy,
132
+ relevance,
133
+ clarity,
134
+ completeness,
135
+ overall,
136
+ };
137
+ }
138
+
139
+ private buildFlashcardPrompt(request: FlashcardGenerationRequest): string {
140
+ const qualityMap = {
141
+ beginner:
142
+ "simple, clear language appropriate for learners just starting out",
143
+ intermediate:
144
+ "moderate complexity with some technical terms expected to be known",
145
+ advanced:
146
+ "complex content with specialized terminology and nuanced concepts",
147
+ };
148
+
149
+ const formatInstructions = {
150
+ qa: "Format as Question-Answer pairs",
151
+ definition: "Format as Term-Definition pairs",
152
+ fill_blank: "Format as Fill-in-the-blank exercises",
153
+ multiple_choice:
154
+ "Format as Multiple Choice questions with one correct answer",
155
+ };
156
+
157
+ return `Generate ${request.count} educational flashcards about "${request.topic}".
158
+
159
+ Topic Context: ${request.context || "General learning"}
160
+ Difficulty Level: ${request.difficulty} - ${qualityMap[request.difficulty]}
161
+ Format: ${request.format || "qa"} - ${formatInstructions[request.format || "qa"]}
162
+ Language: ${request.language || "English"}
163
+ Tags to include: ${request.tags?.join(", ") || "auto-generated"}
164
+
165
+ Requirements:
166
+ - Questions should be clear and concise
167
+ - Answers should be accurate and comprehensive
168
+ - Content should be age and difficulty appropriate
169
+ - Include relevant educational context
170
+ - Make it engaging and memorable
171
+
172
+ Output format: JSON array with structure:
173
+ [
174
+ {
175
+ "front": "Question text here",
176
+ "back": "Answer text here",
177
+ "difficulty": "easy|medium|hard",
178
+ "tags": ["tag1", "tag2"]
179
+ }
180
+ ]`;
181
+ }
182
+
183
+ private calculateMaxTokens(count: number): number {
184
+ // Estimate ~50 tokens per flashcard + overhead
185
+ return Math.max(count * 50, 200);
186
+ }
187
+
188
+ private async executeGeneration(request: GenerationRequest): Promise<any> {
189
+ // This would integrate with the actual AI generation orchestrator
190
+ // For now, return mock result
191
+ await new Promise((resolve) => setTimeout(resolve, 2000));
192
+
193
+ return {
194
+ success: true,
195
+ result: this.generateMockContent(request.options?.maxTokens || 200),
196
+ metadata: {
197
+ tokensUsed: request.options?.maxTokens || 200,
198
+ processingTime: 2000,
199
+ },
200
+ jobId: `job_${Date.now()}`,
201
+ };
202
+ }
203
+
204
+ private generateMockContent(maxTokens: number): string {
205
+ const mockFlashcards = [
206
+ {
207
+ front: "What is photosynthesis?",
208
+ back: "The process by which plants convert sunlight, water, and carbon dioxide into glucose and oxygen.",
209
+ difficulty: "medium",
210
+ tags: ["biology", "science", "plants"],
211
+ },
212
+ {
213
+ front: "Define gravity",
214
+ back: "A fundamental force that attracts objects with mass toward each other.",
215
+ difficulty: "easy",
216
+ tags: ["physics", "science", "forces"],
217
+ },
218
+ {
219
+ front: "What is the formula for water?",
220
+ back: "H₂O",
221
+ difficulty: "easy",
222
+ tags: ["chemistry", "science", "molecules"],
223
+ },
224
+ ];
225
+
226
+ return JSON.stringify(mockFlashcards.slice(0, Math.floor(maxTokens / 100)));
227
+ }
228
+
229
+ private parseFlashcardsFromResult(
230
+ result: any,
231
+ request: FlashcardGenerationRequest,
232
+ ): GeneratedFlashcard[] {
233
+ try {
234
+ let flashcards: any[];
235
+
236
+ if (typeof result.result === "string") {
237
+ flashcards = JSON.parse(result.result);
238
+ } else if (Array.isArray(result.result)) {
239
+ flashcards = result.result;
240
+ } else {
241
+ throw new Error("Invalid AI response format");
242
+ }
243
+
244
+ return flashcards.map((item, index) => ({
245
+ id: `generated_${Date.now()}_${index}`,
246
+ front: item.front || "",
247
+ back: item.back || "",
248
+ difficulty: item.difficulty || "medium",
249
+ tags: Array.isArray(item.tags)
250
+ ? item.tags
251
+ : item.tags
252
+ ? [item.tags]
253
+ : [],
254
+ source: "ai_generated" as const,
255
+ generationRequest: request,
256
+ confidence: 0.8 + Math.random() * 0.2, // 0.8-1.0
257
+ createdAt: new Date().toISOString(),
258
+ }));
259
+ } catch (error) {
260
+ console.error("Failed to parse AI response:", error);
261
+ return [];
262
+ }
263
+ }
264
+
265
+ private calculateAccuracy(front: string, back: string): number {
266
+ // Simple heuristics for accuracy assessment
267
+ let score = 0.5; // Base score
268
+
269
+ // Check for reasonable length
270
+ if (front.length >= 5 && front.length <= 200) score += 0.2;
271
+ if (back.length >= 10 && back.length <= 500) score += 0.2;
272
+
273
+ // Check for balanced content
274
+ const frontWords = front.split(/\s+/).length;
275
+ const backWords = back.split(/\s+/).length;
276
+ if (backWords >= frontWords * 0.5 && backWords <= frontWords * 3)
277
+ score += 0.1;
278
+
279
+ return Math.min(score, 1.0);
280
+ }
281
+
282
+ private calculateRelevance(front: string, back: string): number {
283
+ // Simple relevance check
284
+ let score = 0.6; // Base score
285
+
286
+ // Check for educational content indicators
287
+ const educationalTerms = [
288
+ "define",
289
+ "explain",
290
+ "describe",
291
+ "what is",
292
+ "how does",
293
+ "formula",
294
+ "process",
295
+ "function",
296
+ ];
297
+ const hasEducationalTerms = educationalTerms.some(
298
+ (term) =>
299
+ front.toLowerCase().includes(term) || back.toLowerCase().includes(term),
300
+ );
301
+
302
+ if (hasEducationalTerms) score += 0.3;
303
+ if (front.includes("?") || front.toLowerCase().includes("what is"))
304
+ score += 0.1;
305
+
306
+ return Math.min(score, 1.0);
307
+ }
308
+
309
+ private calculateClarity(front: string, back: string): number {
310
+ let score = 0.5; // Base score
311
+
312
+ // Check for clear structure
313
+ if (front.trim().endsWith("?")) score += 0.2;
314
+ if (!front.includes("...") && !back.includes("...")) score += 0.2;
315
+ if (!/[A-Z]{2,}/.test(front)) score += 0.1; // Not too many caps
316
+
317
+ return Math.min(score, 1.0);
318
+ }
319
+
320
+ private calculateCompleteness(front: string, back: string): number {
321
+ const frontScore = Math.min(front.length / 20, 1.0); // Ideal 20 chars
322
+ const backScore = Math.min(back.length / 50, 1.0); // Ideal 50 chars
323
+
324
+ return (frontScore + backScore) / 2;
325
+ }
326
+ }
@@ -0,0 +1,154 @@
1
+ /**
2
+ * Flashcard Generation Hooks
3
+ * React hooks for AI-powered flashcard generation
4
+ */
5
+
6
+ import React from "react";
7
+ import type {
8
+ FlashcardGenerationRequest,
9
+ GeneratedFlashcard,
10
+ FlashcardGenerationResult,
11
+ } from "../domains/flashcard-generation/FlashcardGenerationService";
12
+
13
+ export interface UseFlashcardGenerationResult {
14
+ generateFlashcards: (
15
+ request: FlashcardGenerationRequest,
16
+ ) => Promise<FlashcardGenerationResult>;
17
+ isGenerating: boolean;
18
+ result: FlashcardGenerationResult | null;
19
+ error: string | null;
20
+ }
21
+
22
+ export const useFlashcardGeneration = (): UseFlashcardGenerationResult => {
23
+ const [isGenerating, setIsGenerating] = React.useState(false);
24
+ const [result, setResult] = React.useState<FlashcardGenerationResult | null>(
25
+ null,
26
+ );
27
+ const [error, setError] = React.useState<string | null>(null);
28
+
29
+ const generateFlashcards = React.useCallback(
30
+ async (
31
+ request: FlashcardGenerationRequest,
32
+ ): Promise<FlashcardGenerationResult> => {
33
+ try {
34
+ setIsGenerating(true);
35
+ setError(null);
36
+
37
+ // This would use the actual FlashcardGenerationService
38
+ // For now, mock the implementation
39
+ await new Promise((resolve) => setTimeout(resolve, 2000));
40
+
41
+ const flashcards: GeneratedFlashcard[] = [];
42
+ for (let i = 0; i < request.count; i++) {
43
+ flashcards.push({
44
+ id: `generated_${Date.now()}_${i}`,
45
+ front: `Mock question ${i + 1} about ${request.topic}`,
46
+ back: `Mock answer ${i + 1} for ${request.topic}`,
47
+ difficulty: i % 3 === 0 ? "easy" : i % 3 === 1 ? "medium" : "hard",
48
+ tags: [
49
+ ...(request.tags || []),
50
+ request.topic.toLowerCase().replace(/\s+/g, "_"),
51
+ ],
52
+ source: "ai_generated",
53
+ generationRequest: request,
54
+ confidence: 0.8 + Math.random() * 0.2,
55
+ createdAt: new Date().toISOString(),
56
+ });
57
+ }
58
+
59
+ const generationResult: FlashcardGenerationResult = {
60
+ success: true,
61
+ flashcards,
62
+ creditsUsed: request.count * 2,
63
+ tokensUsed: request.count * 100,
64
+ processingTime: 2000,
65
+ requestId: `req_${Date.now()}`,
66
+ };
67
+
68
+ setResult(generationResult);
69
+ return generationResult;
70
+ } catch (err) {
71
+ const errorMessage =
72
+ err instanceof Error ? err.message : "Generation failed";
73
+ setError(errorMessage);
74
+ setIsGenerating(false);
75
+
76
+ return {
77
+ success: false,
78
+ flashcards: [],
79
+ creditsUsed: 0,
80
+ tokensUsed: 0,
81
+ processingTime: 0,
82
+ error: errorMessage,
83
+ requestId: `req_${Date.now()}`,
84
+ };
85
+ } finally {
86
+ setIsGenerating(false);
87
+ }
88
+ },
89
+ [],
90
+ );
91
+
92
+ const reset = React.useCallback(() => {
93
+ setResult(null);
94
+ setError(null);
95
+ setIsGenerating(false);
96
+ }, []);
97
+
98
+ return {
99
+ generateFlashcards,
100
+ isGenerating,
101
+ result,
102
+ error,
103
+ reset,
104
+ };
105
+ };
106
+
107
+ export interface UseFlashcardValidationResult {
108
+ validateFlashcard: (
109
+ front: string,
110
+ back: string,
111
+ ) => Promise<{
112
+ accuracy: number;
113
+ relevance: number;
114
+ clarity: number;
115
+ completeness: number;
116
+ overall: number;
117
+ }>;
118
+ isValidating: boolean;
119
+ }
120
+
121
+ export const useFlashcardValidation = (): UseFlashcardValidationResult => {
122
+ const [isValidating, setIsValidating] = React.useState(false);
123
+
124
+ const validateFlashcard = React.useCallback(
125
+ async (front: string, back: string) => {
126
+ setIsValidating(true);
127
+
128
+ // Mock validation - in production would use actual service
129
+ await new Promise((resolve) => setTimeout(resolve, 500));
130
+
131
+ const accuracy = Math.min(1, front.length / 10);
132
+ const relevance = Math.min(1, back.length / 25);
133
+ const clarity = Math.min(1, 1 - front.split(/\s+/).length / 20);
134
+ const completeness = Math.min(1, back.length / 50);
135
+ const overall = (accuracy + relevance + clarity + completeness) / 4;
136
+
137
+ setIsValidating(false);
138
+
139
+ return {
140
+ accuracy,
141
+ relevance,
142
+ clarity,
143
+ completeness,
144
+ overall,
145
+ };
146
+ },
147
+ [],
148
+ );
149
+
150
+ return {
151
+ validateFlashcard,
152
+ isValidating,
153
+ };
154
+ };