cardamom
Val Town is a collaborative website to build and scale JavaScript apps.
Deploy APIs, crons, & store data – all from the browser, and deployed in milliseconds.
Viewing readonly version of main branch: v63View latest version
A mobile-friendly web application that captures, parses, and stores recipes from multiple sources including URLs, PDFs, images, and plain text.
- Multi-source Recipe Input: Accept recipes from:
- Web URLs (recipe websites)
- PDF files
- Images (photos of recipes)
- Plain text input
- Intelligent Parsing: Automatically extracts:
- Dish title and description
- Ingredients with precise quantities and units
- Step-by-step cooking instructions
- Cooking metadata (prep time, cook time, servings, difficulty)
- Recipe tags and source information
- Mobile-Friendly: Responsive design optimized for mobile devices
- Recipe Storage: Persistent SQLite storage with full CRUD operations
- Recipe Management: View, edit, delete, and organize saved recipes
- Advanced Features:
- Recipe filtering and search
- Fraction-to-decimal conversion for precise measurements
- Comprehensive error handling and validation
- Real-time parsing feedback
- Frontend: React 18.2.0 with TypeScript, TailwindCSS
- Backend: Hono API framework with TypeScript
- Database: SQLite with normalized schema (recipes + ingredients tables)
- AI: OpenAI GPT-4o-mini for intelligent recipe parsing
- File Processing:
- PDF parsing via
unpdf
library - Image OCR via OpenAI Vision API
- URL content extraction
- PDF parsing via
├── backend/
│ ├── database/
│ │ ├── migrations.ts # Database schema
│ │ └── queries.ts # Database operations
│ ├── routes/
│ │ ├── recipes.ts # Recipe CRUD operations
│ │ └── parse.ts # Recipe parsing endpoints
│ └── index.ts # Main API entry point
├── frontend/
│ ├── components/
│ │ ├── App.tsx # Main app component
│ │ ├── RecipeForm.tsx # Recipe input form
│ │ ├── RecipeList.tsx # Recipe listing
│ │ └── RecipeView.tsx # Individual recipe display
│ ├── index.html # Main HTML template
│ └── index.tsx # Frontend entry point
└── shared/
└── types.ts # Shared TypeScript types
GET /api/recipes
- Get all recipes (supports filtering via query params)?search=term
- Search in recipe titles and descriptions?difficulty=easy|medium|hard
- Filter by difficulty?maxPrepTime=minutes
- Filter by maximum prep time?maxCookTime=minutes
- Filter by maximum cook time?tags=tag1,tag2
- Filter by tags
POST /api/recipes
- Save a new recipeGET /api/recipes/:id
- Get specific recipe by IDPUT /api/recipes/:id
- Update existing recipeDELETE /api/recipes/:id
- Delete recipe
POST /api/parse/url
- Parse recipe from web URLPOST /api/parse/pdf
- Parse recipe from PDF file (base64)POST /api/parse/image
- Parse recipe from image (base64)POST /api/parse/text
- Parse recipe from plain text
GET /api/health
- Health check endpointGET /api/test-delete
- Test endpoint for debugging delete operations
- Access the App: Open the application in your browser
- Add Recipes: Choose from multiple input methods:
- URL: Paste a recipe website URL
- PDF: Upload a PDF file containing a recipe
- Image: Upload a photo of a recipe
- Text: Paste or type recipe text directly
- Review & Edit: The AI will parse the recipe automatically - review and edit as needed
- Save: Add the recipe to your collection
- Manage: View, search, filter, edit, or delete saved recipes
The app uses a normalized SQLite database with two main tables:
id
- Primary keytitle
- Recipe name (required)description
- Optional descriptionservings
,prep_time
,cook_time
- Numeric metadatadifficulty
- Enum: 'easy', 'medium', 'hard'tags
- JSON array of tag stringssource
- Source URL or descriptionimage_url
- Optional recipe image URLsteps
- JSON array of cooking stepscreated_at
,updated_at
- Timestamps
id
- Primary keyrecipe_id
- Foreign key to recipes tablename
- Ingredient name (required)amount
- Quantity as string (required)unit
- Measurement unit (required)notes
- Optional ingredient notesorder_index
- For maintaining ingredient order
- Uses OpenAI GPT-4o-mini for intelligent content extraction
- Handles fractional Unicode characters (¼, ½, ¾) and converts to decimals
- Robust JSON extraction with fallback parsing
- Comprehensive validation and data cleaning
- PDF: Uses
unpdf
library for text extraction - Images: Leverages OpenAI Vision API for OCR
- URLs: Fetches and parses HTML content
- Text: Direct text processing
- Single-page React application with TypeScript
- Component-based architecture with clear separation of concerns
- Mobile-first responsive design
- Real-time error handling and loading states
- Custom CSS animations and styling
- Hono-based REST API with TypeScript
- Normalized database design with proper foreign key relationships
- Comprehensive error handling and validation
- Database migrations with versioned table names
- Performance optimizations with database indexes