Shih-hungg commited on
Commit
afdd8ce
·
1 Parent(s): 5a88b6d

Update readme

Browse files
README.md CHANGED
@@ -1,4 +1,15 @@
1
- This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
 
 
 
 
 
 
 
 
 
 
 
2
 
3
  ## Getting Started
4
 
@@ -18,16 +29,175 @@ Open [http://localhost:3000](http://localhost:3000) with your browser to see the
18
 
19
  You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
20
 
21
- This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
22
 
23
- ## Learn More
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
 
25
- To learn more about Next.js, take a look at the following resources:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
 
27
- - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
28
- - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
29
 
30
- You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
 
 
 
31
 
32
  ## Deploy on Vercel
33
 
 
1
+ # QuizFlash 🚀
2
+
3
+ An intelligent quiz generation platform powered by AI that creates customizable educational questions from any source material.
4
+
5
+ ## Features
6
+
7
+ - **Multiple Question Types**: Support for multiple choice, cloze (fill-in-the-blank), grammar check, reading comprehension, and essay questions
8
+ - **AI-Powered Generation**: Uses OpenAI GPT-4 to generate high-quality, educational questions
9
+ - **Configurable Parameters**: Each question type has customizable difficulty levels and specific parameters
10
+ - **Source Material Support**: Generate questions based on your own text content
11
+ - **Real-time Question Bank**: Build and manage a collection of generated questions
12
+ - **Modern UI**: Clean, responsive interface built with Next.js and Tailwind CSS
13
 
14
  ## Getting Started
15
 
 
29
 
30
  You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
31
 
32
+ ## System Architecture
33
 
34
+ ```mermaid
35
+ graph TD
36
+ A["🔧 Question Config<br/>(questionConfig.ts)"] --> B["📋 Parameter Form<br/>(QuestionParameterForm)"]
37
+ B --> C["🎛️ Parameter Input<br/>(ParameterInput)"]
38
+ C --> D["👤 User Input<br/>(UI Interaction)"]
39
+ D --> E["📊 Parameters Object<br/>(QuestionParameters)"]
40
+
41
+ E --> F["🎯 Question Type<br/>Selection"]
42
+ F --> G["📝 Source Material<br/>(Optional)"]
43
+
44
+ E --> H["🚀 Generate Question<br/>(API Call)"]
45
+ G --> H
46
+
47
+ H --> I["🤖 AI Generation<br/>(OpenAI API)"]
48
+
49
+ I --> J["📄 Prompt Templates<br/>(quiz-generation.ts)"]
50
+ J --> K["🔄 Template Rendering<br/>(renderTemplate)"]
51
+ K --> L["📤 Final Prompt<br/>(to AI Model)"]
52
+
53
+ L --> M["🧠 AI Processing<br/>(GPT-4 Mini)"]
54
+ M --> N["📋 Zod Schema<br/>Validation"]
55
+ N --> O["✅ Structured Response<br/>(JSON Object)"]
56
+
57
+ O --> P["💾 Question Bank<br/>(State Management)"]
58
+ P --> Q["🎴 Question Card<br/>(UI Component)"]
59
+
60
+ Q --> R["👁️ User Display<br/>(Question Bank UI)"]
61
+
62
+ subgraph "Configuration Layer"
63
+ A
64
+ B
65
+ C
66
+ end
67
+
68
+ subgraph "User Interaction Layer"
69
+ D
70
+ E
71
+ F
72
+ G
73
+ end
74
+
75
+ subgraph "API Processing Layer"
76
+ H
77
+ I
78
+ J
79
+ K
80
+ L
81
+ end
82
+
83
+ subgraph "AI Generation Layer"
84
+ M
85
+ N
86
+ O
87
+ end
88
+
89
+ subgraph "Display Layer"
90
+ P
91
+ Q
92
+ R
93
+ end
94
+
95
+ style A fill:#e1f5fe
96
+ style J fill:#fff3e0
97
+ style Q fill:#f3e5f5
98
+ style M fill:#e8f5e8
99
+ ```
100
+
101
+ ### Flow Description
102
+
103
+ #### 1. Configuration Layer
104
+ - **Question Config**: Abstract configuration system that defines parameter schemas for each question type
105
+ - **Parameter Form**: Dynamically renders form fields based on the configuration
106
+ - **Parameter Input**: Reusable input components (select, range, input, checkbox)
107
+
108
+ #### 2. User Interaction Layer
109
+ - **User Input**: Users interact with dynamically generated parameter forms
110
+ - **Parameters Object**: Collects user preferences (difficulty, number of options, etc.)
111
+ - **Question Type Selection**: Users choose from available question types
112
+ - **Source Material**: Optional text input to provide context for questions
113
+
114
+ #### 3. API Processing Layer
115
+ - **Generate Question**: API endpoint processes the generation request
116
+ - **Prompt Templates**: Pre-defined, configurable templates for each question type
117
+ - **Template Rendering**: Dynamic substitution of user parameters into prompt templates
118
+ - **Final Prompt**: Complete, contextualized prompt ready for AI processing
119
+
120
+ #### 4. AI Generation Layer
121
+ - **AI Processing**: OpenAI GPT-4 Mini generates questions based on the prompt
122
+ - **Zod Schema Validation**: Ensures AI responses match expected structure
123
+ - **Structured Response**: Clean, validated JSON object containing question data
124
+
125
+ #### 5. Display Layer
126
+ - **Question Bank**: State management for storing and organizing generated questions
127
+ - **Question Card**: UI components for rendering individual questions
128
+ - **User Display**: Final question bank interface with selection and management features
129
+
130
+ ### Key Architecture Benefits
131
+
132
+ - **🔧 Configurable**: Adding new question types requires only configuration changes
133
+ - **♻️ Reusable**: Components work across all question types
134
+ - **🛡️ Type-Safe**: Full TypeScript support throughout the entire flow
135
+ - **📦 Modular**: Clean separation of concerns between layers
136
+ - **🚀 Scalable**: Easy to extend with new features and question types
137
 
138
+ ## Tech Stack
139
+
140
+ - **Frontend**: Next.js 14, React, TypeScript, Tailwind CSS
141
+ - **AI Integration**: OpenAI GPT-4 Mini, Vercel AI SDK
142
+ - **Validation**: Zod schema validation
143
+ - **Styling**: Tailwind CSS with dark mode support
144
+ - **State Management**: React hooks and context
145
+
146
+ ## Project Structure
147
+
148
+ ```
149
+ src/
150
+ ├── app/ # Next.js App Router
151
+ │ ├── api/ # API routes
152
+ │ │ ├── chat/ # Chat functionality
153
+ │ │ ├── generate-question/ # Single question generation
154
+ │ │ └── generate-quiz/ # Multiple question generation
155
+ │ └── page.tsx # Main application page
156
+ ├── components/ # React components
157
+ │ ├── QuestionParameterForm.tsx # Dynamic parameter form
158
+ │ └── ParameterInput.tsx # Reusable input components
159
+ ├── types/ # TypeScript type definitions
160
+ │ ├── quiz.ts # Core quiz types
161
+ │ └── questionConfig.ts # Configuration types and schemas
162
+ └── prompts/ # AI prompt templates
163
+ └── quiz-generation.ts # Question generation prompts
164
+ ```
165
+
166
+ ## Adding New Question Types
167
+
168
+ Thanks to the abstract configuration system, adding new question types is incredibly simple:
169
+
170
+ 1. Add configuration to `src/types/questionConfig.ts`:
171
+ ```typescript
172
+ 'your-new-type': {
173
+ id: 'your-new-type',
174
+ parameters: [
175
+ {
176
+ key: 'difficulty',
177
+ label: 'Difficulty Level',
178
+ type: 'select',
179
+ defaultValue: 'intermediate',
180
+ options: [
181
+ { value: 'beginner', label: 'Beginner' },
182
+ { value: 'intermediate', label: 'Intermediate' },
183
+ { value: 'advanced', label: 'Advanced' },
184
+ ],
185
+ },
186
+ // Add more parameters as needed
187
+ ],
188
+ }
189
+ ```
190
+
191
+ 2. That's it! No component modifications required. The UI will automatically render the appropriate form fields.
192
+
193
+ ## Learn More
194
 
195
+ To learn more about the technologies used:
 
196
 
197
+ - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API
198
+ - [Vercel AI SDK](https://sdk.vercel.ai/docs) - AI integration toolkit
199
+ - [OpenAI API](https://platform.openai.com/docs) - AI model documentation
200
+ - [Tailwind CSS](https://tailwindcss.com/docs) - utility-first CSS framework
201
 
202
  ## Deploy on Vercel
203
 
src/components/ParameterInput.tsx ADDED
@@ -0,0 +1,96 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 'use client';
2
+
3
+ import { ParameterConfig } from '@/types/questionConfig';
4
+
5
+ interface ParameterInputProps {
6
+ config: ParameterConfig;
7
+ value: any;
8
+ onChange: (value: any) => void;
9
+ }
10
+
11
+ export default function ParameterInput({ config, value, onChange }: ParameterInputProps) {
12
+ const { key, label, type, options, min, max, step, placeholder, helpText } = config;
13
+
14
+ const currentValue = value ?? config.defaultValue;
15
+
16
+ const baseInputClasses = "w-full p-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500";
17
+
18
+ switch (type) {
19
+ case 'select':
20
+ return (
21
+ <div>
22
+ <label className="block text-sm font-medium mb-2">{label}</label>
23
+ <select
24
+ value={currentValue}
25
+ onChange={(e) => {
26
+ const val = options?.find(opt => opt.value.toString() === e.target.value)?.value;
27
+ onChange(val);
28
+ }}
29
+ className={baseInputClasses}
30
+ >
31
+ {options?.map((option) => (
32
+ <option key={option.value.toString()} value={option.value.toString()}>
33
+ {option.label}
34
+ </option>
35
+ ))}
36
+ </select>
37
+ </div>
38
+ );
39
+
40
+ case 'range':
41
+ return (
42
+ <div>
43
+ <label className="block text-sm font-medium mb-2">{label}</label>
44
+ <input
45
+ type="range"
46
+ min={min}
47
+ max={max}
48
+ step={step}
49
+ value={currentValue}
50
+ onChange={(e) => onChange(parseInt(e.target.value))}
51
+ className="w-full"
52
+ />
53
+ <div className="text-center text-sm text-gray-600">
54
+ {currentValue} {helpText}
55
+ </div>
56
+ </div>
57
+ );
58
+
59
+ case 'input':
60
+ return (
61
+ <div>
62
+ <label className="block text-sm font-medium mb-2">{label}</label>
63
+ <input
64
+ type="text"
65
+ value={currentValue || ''}
66
+ placeholder={placeholder}
67
+ onChange={(e) => onChange(e.target.value)}
68
+ className={baseInputClasses}
69
+ />
70
+ {helpText && (
71
+ <div className="text-xs text-gray-500 mt-1">{helpText}</div>
72
+ )}
73
+ </div>
74
+ );
75
+
76
+ case 'checkbox':
77
+ return (
78
+ <div className="flex items-center">
79
+ <input
80
+ type="checkbox"
81
+ id={key}
82
+ checked={currentValue || false}
83
+ onChange={(e) => onChange(e.target.checked)}
84
+ className="mr-2"
85
+ />
86
+ <label htmlFor={key} className="text-sm font-medium">{label}</label>
87
+ {helpText && (
88
+ <div className="text-xs text-gray-500 ml-2">{helpText}</div>
89
+ )}
90
+ </div>
91
+ );
92
+
93
+ default:
94
+ return null;
95
+ }
96
+ }
src/components/QuestionParameterForm.tsx CHANGED
@@ -1,6 +1,8 @@
1
  'use client';
2
 
3
  import { QuestionType, QuestionParameters } from '@/types/quiz';
 
 
4
 
5
  interface QuestionParameterFormProps {
6
  questionType: QuestionType;
@@ -17,194 +19,19 @@ export default function QuestionParameterForm({
17
  onParametersChange({ ...parameters, [key]: value });
18
  };
19
 
20
- switch (questionType.id) {
21
- case 'multiple-choice':
22
- return (
23
- <div className="space-y-4">
24
- <div>
25
- <label className="block text-sm font-medium mb-2">Difficulty Level</label>
26
- <select
27
- value={parameters.difficulty || 'intermediate'}
28
- onChange={(e) => updateParameter('difficulty', e.target.value)}
29
- className="w-full p-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500"
30
- >
31
- <option value="beginner">Beginner</option>
32
- <option value="intermediate">Intermediate</option>
33
- <option value="advanced">Advanced</option>
34
- </select>
35
- </div>
36
- <div>
37
- <label className="block text-sm font-medium mb-2">Number of Options</label>
38
- <select
39
- value={parameters.numOptions || 4}
40
- onChange={(e) => updateParameter('numOptions', parseInt(e.target.value))}
41
- className="w-full p-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500"
42
- >
43
- <option value={3}>3 Options</option>
44
- <option value={4}>4 Options</option>
45
- <option value={5}>5 Options</option>
46
- </select>
47
- </div>
48
- </div>
49
- );
50
-
51
- case 'cloze':
52
- return (
53
- <div className="space-y-4">
54
- <div>
55
- <label className="block text-sm font-medium mb-2">Target Part of Speech</label>
56
- <select
57
- value={parameters.partOfSpeech || 'any'}
58
- onChange={(e) => updateParameter('partOfSpeech', e.target.value)}
59
- className="w-full p-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500"
60
- >
61
- <option value="any">Any</option>
62
- <option value="noun">Nouns</option>
63
- <option value="verb">Verbs</option>
64
- <option value="adjective">Adjectives</option>
65
- <option value="adverb">Adverbs</option>
66
- </select>
67
- </div>
68
- <div>
69
- <label className="block text-sm font-medium mb-2">Number of Blanks</label>
70
- <input
71
- type="range"
72
- min="1"
73
- max="5"
74
- value={parameters.numBlanks || 1}
75
- onChange={(e) => updateParameter('numBlanks', parseInt(e.target.value))}
76
- className="w-full"
77
- />
78
- <div className="text-center text-sm text-gray-600">{parameters.numBlanks || 1} blank(s)</div>
79
- </div>
80
- </div>
81
- );
82
-
83
- case 'grammar':
84
- return (
85
- <div className="space-y-4">
86
- <div>
87
- <label className="block text-sm font-medium mb-2">Difficulty Level</label>
88
- <select
89
- value={parameters.difficulty || 'intermediate'}
90
- onChange={(e) => updateParameter('difficulty', e.target.value)}
91
- className="w-full p-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500"
92
- >
93
- <option value="beginner">Beginner</option>
94
- <option value="intermediate">Intermediate</option>
95
- <option value="advanced">Advanced</option>
96
- </select>
97
- </div>
98
- <div>
99
- <label className="block text-sm font-medium mb-2">Grammar Focus</label>
100
- <select
101
- value={parameters.grammarFocus || 'any'}
102
- onChange={(e) => updateParameter('grammarFocus', e.target.value)}
103
- className="w-full p-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500"
104
- >
105
- <option value="any">Any Grammar Rule</option>
106
- <option value="verb-tenses">Verb Tenses</option>
107
- <option value="subject-verb">Subject-Verb Agreement</option>
108
- <option value="punctuation">Punctuation</option>
109
- <option value="sentence-structure">Sentence Structure</option>
110
- </select>
111
- </div>
112
- </div>
113
- );
114
 
115
- case 'reading-comp':
116
- return (
117
- <div className="space-y-4">
118
- <div>
119
- <label className="block text-sm font-medium mb-2">Difficulty Level</label>
120
- <select
121
- value={parameters.difficulty || 'intermediate'}
122
- onChange={(e) => updateParameter('difficulty', e.target.value)}
123
- className="w-full p-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500"
124
- >
125
- <option value="beginner">Beginner</option>
126
- <option value="intermediate">Intermediate</option>
127
- <option value="advanced">Advanced</option>
128
- </select>
129
- </div>
130
- <div>
131
- <label className="block text-sm font-medium mb-2">Question Focus</label>
132
- <select
133
- value={parameters.focus || 'comprehension'}
134
- onChange={(e) => updateParameter('focus', e.target.value)}
135
- className="w-full p-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500"
136
- >
137
- <option value="comprehension">General Comprehension</option>
138
- <option value="inference">Making Inferences</option>
139
- <option value="main-idea">Main Ideas</option>
140
- <option value="details">Supporting Details</option>
141
- <option value="vocabulary">Vocabulary in Context</option>
142
- </select>
143
- </div>
144
- </div>
145
- );
146
-
147
- case 'essay':
148
- return (
149
- <div className="space-y-4">
150
- <div>
151
- <label className="block text-sm font-medium mb-2">Difficulty Level</label>
152
- <select
153
- value={parameters.difficulty || 'intermediate'}
154
- onChange={(e) => updateParameter('difficulty', e.target.value)}
155
- className="w-full p-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500"
156
- >
157
- <option value="beginner">Beginner</option>
158
- <option value="intermediate">Intermediate</option>
159
- <option value="advanced">Advanced</option>
160
- </select>
161
- </div>
162
- <div>
163
- <label className="block text-sm font-medium mb-2">Essay Type</label>
164
- <select
165
- value={parameters.essayType || 'argumentative'}
166
- onChange={(e) => updateParameter('essayType', e.target.value)}
167
- className="w-full p-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500"
168
- >
169
- <option value="argumentative">Argumentative</option>
170
- <option value="descriptive">Descriptive</option>
171
- <option value="narrative">Narrative</option>
172
- <option value="expository">Expository</option>
173
- <option value="compare-contrast">Compare & Contrast</option>
174
- </select>
175
- </div>
176
- <div>
177
- <label className="block text-sm font-medium mb-2">Word Count Range</label>
178
- <select
179
- value={parameters.wordCount || '300-500'}
180
- onChange={(e) => updateParameter('wordCount', e.target.value)}
181
- className="w-full p-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500"
182
- >
183
- <option value="150-250">150-250 words</option>
184
- <option value="300-500">300-500 words</option>
185
- <option value="500-750">500-750 words</option>
186
- <option value="750-1000">750-1000 words</option>
187
- </select>
188
- </div>
189
- </div>
190
- );
191
-
192
- default:
193
- return (
194
- <div className="space-y-4">
195
- <div>
196
- <label className="block text-sm font-medium mb-2">Difficulty Level</label>
197
- <select
198
- value={parameters.difficulty || 'intermediate'}
199
- onChange={(e) => updateParameter('difficulty', e.target.value)}
200
- className="w-full p-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500"
201
- >
202
- <option value="beginner">Beginner</option>
203
- <option value="intermediate">Intermediate</option>
204
- <option value="advanced">Advanced</option>
205
- </select>
206
- </div>
207
- </div>
208
- );
209
- }
210
  }
 
1
  'use client';
2
 
3
  import { QuestionType, QuestionParameters } from '@/types/quiz';
4
+ import { questionTypeConfigs, defaultQuestionTypeConfig } from '@/types/questionConfig';
5
+ import ParameterInput from './ParameterInput';
6
 
7
  interface QuestionParameterFormProps {
8
  questionType: QuestionType;
 
19
  onParametersChange({ ...parameters, [key]: value });
20
  };
21
 
22
+ // Get configuration for this question type, fallback to default
23
+ const config = questionTypeConfigs[questionType.id] || defaultQuestionTypeConfig;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
 
25
+ return (
26
+ <div className="space-y-4">
27
+ {config.parameters.map((paramConfig) => (
28
+ <ParameterInput
29
+ key={paramConfig.key}
30
+ config={paramConfig}
31
+ value={parameters[paramConfig.key]}
32
+ onChange={(value) => updateParameter(paramConfig.key, value)}
33
+ />
34
+ ))}
35
+ </div>
36
+ );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
37
  }
src/types/questionConfig.ts ADDED
@@ -0,0 +1,204 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ export type ParameterType = 'select' | 'range' | 'input' | 'checkbox';
2
+
3
+ export interface ParameterOption {
4
+ value: string | number;
5
+ label: string;
6
+ }
7
+
8
+ export interface ParameterConfig {
9
+ key: string;
10
+ label: string;
11
+ type: ParameterType;
12
+ defaultValue?: any;
13
+ options?: ParameterOption[];
14
+ min?: number;
15
+ max?: number;
16
+ step?: number;
17
+ placeholder?: string;
18
+ helpText?: string;
19
+ }
20
+
21
+ export interface QuestionTypeConfig {
22
+ id: string;
23
+ parameters: ParameterConfig[];
24
+ }
25
+
26
+ // Configuration for each question type
27
+ export const questionTypeConfigs: Record<string, QuestionTypeConfig> = {
28
+ 'multiple-choice': {
29
+ id: 'multiple-choice',
30
+ parameters: [
31
+ {
32
+ key: 'difficulty',
33
+ label: 'Difficulty Level',
34
+ type: 'select',
35
+ defaultValue: 'intermediate',
36
+ options: [
37
+ { value: 'beginner', label: 'Beginner' },
38
+ { value: 'intermediate', label: 'Intermediate' },
39
+ { value: 'advanced', label: 'Advanced' },
40
+ ],
41
+ },
42
+ {
43
+ key: 'numOptions',
44
+ label: 'Number of Options',
45
+ type: 'select',
46
+ defaultValue: 4,
47
+ options: [
48
+ { value: 3, label: '3 Options' },
49
+ { value: 4, label: '4 Options' },
50
+ { value: 5, label: '5 Options' },
51
+ ],
52
+ },
53
+ ],
54
+ },
55
+
56
+ 'cloze': {
57
+ id: 'cloze',
58
+ parameters: [
59
+ {
60
+ key: 'partOfSpeech',
61
+ label: 'Target Part of Speech',
62
+ type: 'select',
63
+ defaultValue: 'any',
64
+ options: [
65
+ { value: 'any', label: 'Any' },
66
+ { value: 'noun', label: 'Nouns' },
67
+ { value: 'verb', label: 'Verbs' },
68
+ { value: 'adjective', label: 'Adjectives' },
69
+ { value: 'adverb', label: 'Adverbs' },
70
+ ],
71
+ },
72
+ {
73
+ key: 'numBlanks',
74
+ label: 'Number of Blanks',
75
+ type: 'range',
76
+ defaultValue: 1,
77
+ min: 1,
78
+ max: 5,
79
+ step: 1,
80
+ helpText: 'blank(s)',
81
+ },
82
+ ],
83
+ },
84
+
85
+ 'grammar': {
86
+ id: 'grammar',
87
+ parameters: [
88
+ {
89
+ key: 'difficulty',
90
+ label: 'Difficulty Level',
91
+ type: 'select',
92
+ defaultValue: 'intermediate',
93
+ options: [
94
+ { value: 'beginner', label: 'Beginner' },
95
+ { value: 'intermediate', label: 'Intermediate' },
96
+ { value: 'advanced', label: 'Advanced' },
97
+ ],
98
+ },
99
+ {
100
+ key: 'grammarFocus',
101
+ label: 'Grammar Focus',
102
+ type: 'select',
103
+ defaultValue: 'any',
104
+ options: [
105
+ { value: 'any', label: 'Any Grammar Rule' },
106
+ { value: 'verb-tenses', label: 'Verb Tenses' },
107
+ { value: 'subject-verb', label: 'Subject-Verb Agreement' },
108
+ { value: 'punctuation', label: 'Punctuation' },
109
+ { value: 'sentence-structure', label: 'Sentence Structure' },
110
+ ],
111
+ },
112
+ ],
113
+ },
114
+
115
+ 'reading-comp': {
116
+ id: 'reading-comp',
117
+ parameters: [
118
+ {
119
+ key: 'difficulty',
120
+ label: 'Difficulty Level',
121
+ type: 'select',
122
+ defaultValue: 'intermediate',
123
+ options: [
124
+ { value: 'beginner', label: 'Beginner' },
125
+ { value: 'intermediate', label: 'Intermediate' },
126
+ { value: 'advanced', label: 'Advanced' },
127
+ ],
128
+ },
129
+ {
130
+ key: 'focus',
131
+ label: 'Question Focus',
132
+ type: 'select',
133
+ defaultValue: 'comprehension',
134
+ options: [
135
+ { value: 'comprehension', label: 'General Comprehension' },
136
+ { value: 'inference', label: 'Making Inferences' },
137
+ { value: 'main-idea', label: 'Main Ideas' },
138
+ { value: 'details', label: 'Supporting Details' },
139
+ { value: 'vocabulary', label: 'Vocabulary in Context' },
140
+ ],
141
+ },
142
+ ],
143
+ },
144
+
145
+ 'essay': {
146
+ id: 'essay',
147
+ parameters: [
148
+ {
149
+ key: 'difficulty',
150
+ label: 'Difficulty Level',
151
+ type: 'select',
152
+ defaultValue: 'intermediate',
153
+ options: [
154
+ { value: 'beginner', label: 'Beginner' },
155
+ { value: 'intermediate', label: 'Intermediate' },
156
+ { value: 'advanced', label: 'Advanced' },
157
+ ],
158
+ },
159
+ {
160
+ key: 'essayType',
161
+ label: 'Essay Type',
162
+ type: 'select',
163
+ defaultValue: 'argumentative',
164
+ options: [
165
+ { value: 'argumentative', label: 'Argumentative' },
166
+ { value: 'descriptive', label: 'Descriptive' },
167
+ { value: 'narrative', label: 'Narrative' },
168
+ { value: 'expository', label: 'Expository' },
169
+ { value: 'compare-contrast', label: 'Compare & Contrast' },
170
+ ],
171
+ },
172
+ {
173
+ key: 'wordCount',
174
+ label: 'Word Count Range',
175
+ type: 'select',
176
+ defaultValue: '300-500',
177
+ options: [
178
+ { value: '150-250', label: '150-250 words' },
179
+ { value: '300-500', label: '300-500 words' },
180
+ { value: '500-750', label: '500-750 words' },
181
+ { value: '750-1000', label: '750-1000 words' },
182
+ ],
183
+ },
184
+ ],
185
+ },
186
+ };
187
+
188
+ // Default configuration for unknown question types
189
+ export const defaultQuestionTypeConfig: QuestionTypeConfig = {
190
+ id: 'default',
191
+ parameters: [
192
+ {
193
+ key: 'difficulty',
194
+ label: 'Difficulty Level',
195
+ type: 'select',
196
+ defaultValue: 'intermediate',
197
+ options: [
198
+ { value: 'beginner', label: 'Beginner' },
199
+ { value: 'intermediate', label: 'Intermediate' },
200
+ { value: 'advanced', label: 'Advanced' },
201
+ ],
202
+ },
203
+ ],
204
+ };