diff --git a/README.md b/README.md index 23392f0..ab405ab 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ Welcome to CodeQuest, the quiz game that's more addictive than trying to fix a b - 🎊 **Confetti**: Celebrate your achievements with a rainbow of confetti! - 🏆 **Score Sharing**: Brag about your big brain energy on social media - 📱 **Responsive Design**: Looks great on everything from your smartwatch to your smart fridge +- 🧙‍♂️ **Question Generation**: Generate question creation prompts to use with your favorite LLM! ## 🎭 Question Features (The Real Stars of the Show) @@ -29,6 +30,35 @@ Welcome to CodeQuest, the quiz game that's more addictive than trying to fix a b Check out `example-question.md` for a comprehensive example of all these features in action! +## 🧙‍♂️ Question Generation (Let AI Do the Heavy Lifting) + +Too busy debugging to craft questions? Fear not! We've conjured up a magical script to help you generate question prompts faster than you can say "Stack Overflow": + +1. Wave your wand (or just type in your terminal): + ``` + bun run question-prompt + ``` + +2. Answer the mystical prompt asking how many questions you desire (choose wisely, young wizard!) + +3. Behold as a perfectly crafted prompt materializes before your eyes! + +4. Feed this prompt to your favorite AI familiar (we recommend Claude 3.5 Sonnet or GPT-4o for best results) and watch in awe as it conjures up quiz questions that would make even Merlin jealous. + +5. Copy the AI-generated questions into new `.md` files in your `src/questions/` directory, and voilà! Your quiz just got a whole lot smarter. + +Want to save your prompt for later? Use the `-o` flag: +``` +bun run question-prompt -o prompt.md +``` + +Need a helping hand? Just ask: +``` +bun run question-prompt -h +``` + +Remember, with great power comes great responsibility. Use this feature wisely, and may your questions be ever engaging and your quizzes eternally awesome! 🧙‍♂️✨ + ## 🚀 Quick Start Guide (No Rocket Science Degree Required) 1. Clone this repo: diff --git a/bun.lockb b/bun.lockb index 9decafb..6665b14 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/package.json b/package.json index 8943691..6faf565 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,8 @@ "build": "tsc -b && vite build", "lint": "eslint .", "lint:fix": "eslint . --fix", - "preview": "vite preview" + "preview": "vite preview", + "question-prompt": "node question-prompt.cjs" }, "dependencies": { "@radix-ui/react-alert-dialog": "1.1.1", @@ -28,22 +29,24 @@ "clsx": "2.1.1", "gray-matter": "^4.0.3", "lucide-react": "0.408.0", - "marked": "^13.0.2", + "marked": "13.0.2", "react": "18.3.1", "react-confetti": "6.1.0", "react-dom": "18.3.1", "shiki": "1.10.3", "tailwind-merge": "2.4.0", "tailwindcss-animate": "1.0.7", - "yaml": "^2.4.5" + "yaml": "2.4.5" }, "devDependencies": { "@antfu/eslint-config": "2.23.0", + "@inquirer/prompts": "5.2.0", "@types/node": "20.14.11", "@types/react": "18.3.3", "@types/react-dom": "18.3.0", "@vitejs/plugin-react": "4.3.1", "autoprefixer": "10.4.19", + "commander": "12.1.0", "eslint": "9.7.0", "postcss": "8.4.39", "tailwindcss": "3.4.6", diff --git a/question-prompt.cjs b/question-prompt.cjs new file mode 100644 index 0000000..0418f7d --- /dev/null +++ b/question-prompt.cjs @@ -0,0 +1,121 @@ +const fs = require('node:fs').promises; +const path = require('node:path'); +const process = require('node:process'); +const { program } = require('commander'); +const { number } = require('@inquirer/prompts'); + +async function readFiles(dir) { + const files = await fs.readdir(dir); + return Promise.all( + files.map(async (file) => { + const content = await fs.readFile(path.join(dir, file), 'utf8'); + return { name: file, content }; + }), + ); +} + +async function generatePrompt(numQuestions) { + try { + const questionsDir = path.join(__dirname, 'src', 'questions'); + const existingQuestions = await readFiles(questionsDir); + const exampleQuestion = await fs.readFile(path.join(__dirname, 'example-question.md'), 'utf8'); + + return ` +You are an expert quiz creator for the CodeQuest project. Your task is to create ${numQuestions} new question(s) for our fun, engaging and playful quiz game. Here are the guidelines: + +1. Each question should be in Markdown format, similar to the example provided below. +2. Questions should increase in difficulty as they progress. +3. The title and description should be fun, descriptive and engaging. Use alliterations and wordplay to make them stand out. +3. Use the following features where appropriate: + - Markdown formatting (bold, italics, code blocks, lists etc.) + - Multiple choice answers + - Time limits (optional) + - Difficulty levels (Beginner, Intermediate, Expert) (optional) + - Hints + - Explanations + +4. The structure should be exactly as follows: + --- + title: [Question Title] + description: [Brief description] + level: [number, determines order] + correctAnswer: [number, 1-based index of correct answer] + difficulty: [Beginner/Intermediate/Expert] + timeLimit: [optional, in seconds] + --- + + ## Context + + ### Introduction + [Optional: Only include if necessary to understand the question] + + ### Question + [The actual question goes here] + + ### Outro + [Optional: Include only to provide additional resources or information] + + ## Answers + - [Answer option 1] + - [Answer option 2] + - [Answer option 3] + - [Answer option 4] + + ## Explanation + [Detailed explanation of the correct answer] + + ## Hint + [Optional hint for the question] + +5. Prefer short answer options, but use code fences for longer code snippets if necessary. +6. Ensure questions are relevant to coding, technology, or related fields. +7. Be creative and make the questions engaging! + +Here's an example question for reference: + +${exampleQuestion} + +Now, based on the existing questions and this example, please create ${numQuestions} new question(s). Ensure they fit well with the existing set and increase in difficulty appropriately. + +Existing questions for context: +${existingQuestions.map(q => q.content).join('\n\n')} +`; + } + catch (error) { + console.error('Error generating prompt:', error); + } +} + +async function main() { + program + .option('-o, --output ', 'output file') + .helpOption('-h, --help', 'display help for command') + .parse(process.argv); + + const options = program.opts(); + + if (options.help) { + program.outputHelp(); + process.exit(0); + } + + try { + const numQuestions = await number({ message: 'How many questions do you want to generate?' }, { min: 1, max: 5 }); + const prompt = await generatePrompt(numQuestions); + + if (options.output) { + await fs.writeFile(options.output, prompt); + // eslint-disable-next-line no-console + console.log(`Prompt written to ${options.output}`); + } + else { + process.stdout.write(prompt); + } + } + catch (error) { + console.error('An error occurred:', error); + process.exit(1); + } +} + +main();