| name | convex-ai-card-generation |
| description | Generate Pictionary drawing cards using AI (Groq) with fallback to hardcoded libraries. Use when creating new game cards, implementing category-based card selection, or handling AI card generation with graceful degradation. |
| compatibility | Requires Convex actions, Vercel AI SDK, Groq API access, fallback card libraries |
| metadata | [object Object] |
Convex AI Card Generation
Overview
This skill handles AI-powered card generation for PictionAI's Pictionary gameplay. Cards are generated dynamically using Groq LLM with Vercel AI SDK's generateText function, including structured output validation via Zod schemas and automatic fallback to hardcoded card libraries when API limits are reached.
Architecture
Generation Flow
1. Request card for category
↓
2. Check card availability/balance
↓
3. Try Groq (primary) → Fallback to other models → Fallback to hardcoded library
↓
4. Validate with Zod schema
↓
5. Return structured card object { word, description, difficulty, category }
AI Models (Priority Order)
- groq-mixtral-8x7b-instruct (Primary) - Best quality, lower latency
- groq-llama2-70b-chat (Secondary) - If Mixtral unavailable
- groq-llama-3.1-70b (Tertiary) - Fallback option
- Hardcoded Library (Final) - When all API models fail
Key Action
generateCards
Generate one or multiple drawing cards for a specific category with AI.
action generateCards {
args: {
category: "animals" | "objects" | "actions" | "movies" | "sports",
count?: number // Default: 1, Max: 5
}
// Returns:
// {
// cards: Array<{
// word: string,
// description: string,
// difficulty: "easy" | "medium" | "hard",
// category: string
// }>,
// source: "ai" | "fallback" // Indicates if AI or hardcoded
// }
}
Card Data Structure
interface Card {
word: string; // Single word to draw (required)
description: string; // Drawing hints/clues (1-100 chars)
difficulty: "easy" | "medium" | "hard";
category: string; // Category name
created_at?: number; // Timestamp
ai_generated?: boolean; // True if from Groq
}
Supported Categories
- animals - Creatures, pets, wildlife
- objects - Inanimate items, tools, furniture
- actions - Verbs, activities, gestures
- movies - Film titles, characters, scenes
- sports - Sports, games, athletic activities
- food - Dishes, ingredients, cuisine
- technology - Gadgets, software, digital items
Implementation Details
Groq Configuration
const groq = new Groq({
apiKey: env.GROQ_API_KEY, // Environment variable
baseURL: "https://api.groq.com/openai/v1",
});
Zod Schema for Validation
const cardSchema = z.object({
word: z.string().min(1).max(30),
description: z.string().min(10).max(100),
difficulty: z.enum(["easy", "medium", "hard"]),
category: z.string(),
});
const cardsResponseSchema = z.object({
cards: z.array(cardSchema),
});
AI Prompt Template
Generate {count} unique Pictionary drawing cards for the "{category}" category.
For each card, provide:
- word: A single word to draw
- description: A brief hint (1-100 characters)
- difficulty: easy, medium, or hard
- category: {category}
Format as JSON array. Make words creative and diverse.
Fallback Card Libraries
When all AI models fail, the system falls back to hardcoded libraries:
const cardLibraries = {
animals: [
{
word: "elephant",
description: "Large animal with long trunk",
difficulty: "easy",
category: "animals",
},
{
word: "giraffe",
description: "Tall with spotted pattern",
difficulty: "easy",
category: "animals",
},
// ... more animals
],
objects: [
{
word: "bicycle",
description: "Two-wheeled vehicle",
difficulty: "easy",
category: "objects",
},
// ... more objects
],
// ... other categories
};
React Integration
// In game setup, generate initial card
const generateCardsAction = useAction(api.actions.generateCards);
async function setupGameCards(category: string) {
const result = await generateCardsAction({
category,
count: 5, // Generate 5 cards per round
});
console.log(`Cards generated from ${result.source}`);
return result.cards;
}
Error Handling
Graceful Degradation
- API Quota Exceeded → Automatically switch to fallback
- Network Error → Retry once, then use fallback
- Invalid Response → Log error, use fallback
- Schema Validation Fail → Discard AI response, use fallback
Logging
console.log(`Generated cards from ${source} for category: ${category}`);
// source: "ai" or "fallback"
Performance Considerations
- AI Generation: ~500-1000ms per card (includes API latency)
- Fallback Lookup: ~50ms per card
- Caching: Consider caching generated cards per category/session
- Batch Generation: Generate 5-10 cards at game start, not on-demand per turn
Best Practices
Do's
✅ Generate multiple cards at game start (not per turn) ✅ Cache cards for session duration ✅ Log both AI and fallback usage for monitoring ✅ Validate all AI responses against Zod schema ✅ Handle quota errors gracefully
Don'ts
❌ Don't wait for card generation on each turn ❌ Don't expose Groq API key in frontend ❌ Don't retry forever on network errors ❌ Don't mix AI and fallback for same category in single game
Example: Complete Card Setup
// Game initialization
export const initializeGameCards = action({
args: { game_id: v.id("games"), category: v.string() },
handler: async (ctx, args) => {
const generateCards = await ctx.runAction(api.actions.generateCards, {
category: args.category,
count: 10,
});
// Store cards in game doc
await ctx.runMutation(api.mutations.games.storeGameCards, {
game_id: args.game_id,
cards: generateCards.cards,
});
return {
count: generateCards.cards.length,
source: generateCards.source,
};
},
});
See Also
convex/actions/generateCards.ts- Complete action implementation- Groq API docs: https://console.groq.com/docs
- Vercel AI SDK: https://sdk.vercel.ai