Voice-first productivity tool for nautical carpentry and yacht interior manufacturing
Focus allows craftspeople to capture verbal notes hands-free in the workshop and uses AI to extract structured To-Do lists, specifically identifying CNC tasks, assembly, and finishing work.
Fully functional! The backend is complete with:
- β Voice transcription working (OpenAI Whisper)
- β AI task extraction working (GPT-4o)
- β Database schema deployed to Railway
- β All API endpoints tested and operational
- β GitHub Pages landing page live at chrisforti.github.io/focus
- π§ React Native mobile app (coming soon)
- Backend: Node.js, Express, TypeScript
- Database: PostgreSQL (Railway) with Drizzle ORM
- AI Pipeline: OpenAI Whisper (STT) + GPT-4o (Task Extraction)
- AI Providers: OpenAI or OpenRouter (supports multiple models)
- Infrastructure: Railway (Deployment), GitHub (Version Control)
- π€ Voice-to-text transcription using OpenAI Whisper
- π€ AI-powered task extraction optimized for boat building
- οΏ½ Flexible AI provider support (OpenAI or OpenRouter)
- π― Multiple model options (GPT-4o, Claude, Llama, etc.)
- οΏ½π Structured To-Do lists with priority and categories
- π·οΈ Automatic categorization (CNC, Assembly, Finishing, Carpentry)
- β Task management with completion tracking
- Node.js 18+ installed
- PostgreSQL database (Railway recommended)
- OpenAI API key OR OpenRouter account (see OPENROUTER.md)
-
Clone the repository
git clone git@github.com:ChrisForti/focus.git cd focus -
Install dependencies
npm install
-
Configure environment variables
cp .env.example .env
Edit
.envand add:DATABASE_URL: Your PostgreSQL connection stringOPENAI_API_KEY: Your OpenAI API keyPORT: Server port (default: 3000)CHAT_MODEL: Model to use (default: gpt-4o)
Important: If you have
OPENAI_API_KEYset in your shell environment (.zshrcor.bashrc), it will override the.envfile. Either unset it or remove it from your shell config.# Check if you have it set echo $OPENAI_API_KEY # If yes, unset before running the server unset OPENAI_API_KEY WHISPER_API_KEY
-
Generate and push database schema
npm run db:generate npm run db:push
-
Start development server
npm run dev
The server will start on http://localhost:3000
projects
id: Serial primary keyname: Project namecreated_at: Timestamp
voice_logs
id: Serial primary keyproject_id: Foreign key to projectstranscript: Full text transcriptioncreated_at: Timestamp
todos
id: Serial primary keylog_id: Foreign key to voice_logstask: Task descriptionis_completed: Boolean (default: false)priority: Enum ('low', 'medium', 'high')category: Text (CNC, Assembly, Finishing, etc.)
GET /health
POST /api/process-voice
Content-Type: multipart/form-data
Body:
- audio: Audio file (mp3, wav, m4a, etc.)
- projectId: (optional) Project ID
Response:
{
"success": true,
"transcript": "Full transcription...",
"logId": 123,
"tasks": [
{
"id": 1,
"task": "Cut transom with CNC router",
"priority": "high",
"category": "CNC",
"isCompleted": false
}
]
}
GET /api/projects
GET /api/todos
PATCH /api/todos/:id
Content-Type: application/json
Body:
{
"isCompleted": true,
"priority": "high",
"category": "CNC"
}
-
Create a new Railway project
- Go to railway.app
- Create a new project
- Add PostgreSQL database
-
Connect GitHub repository
- Link your GitHub repository
- Railway will auto-detect the Node.js project
-
Configure environment variables
- Add
DATABASE_URL(auto-populated by Railway) - Add
OPENAI_API_KEY - Add
NODE_ENV=production
- Add
-
Deploy
- Push to main branch
- Railway will automatically build and deploy
Check the health endpoint:
curl https://your-app.railway.app/healthnpm run buildnpm start# Generate migration files
npm run db:generate
# Push schema to database
npm run db:push
# Open Drizzle Studio (GUI)
npm run db:studiofocus/
βββ src/
β βββ controllers/ # Request handlers
β βββ db/ # Database configuration & schema
β βββ routes/ # API route definitions
β βββ services/ # Business logic (AI, etc.)
β βββ index.ts # Express app entry point
βββ drizzle/ # Generated migration files
βββ uploads/ # Temporary audio file storage
βββ .env # Environment variables (not in git)
βββ .env.example # Environment template
βββ drizzle.config.ts # Drizzle ORM configuration
βββ package.json # Dependencies
βββ tsconfig.json # TypeScript configuration
βββ railway.json # Railway deployment config
# Health check
curl http://localhost:3000/health
# Upload voice recording
curl -X POST http://localhost:3000/api/process-voice \
-F "audio=@./sample.mp3" \
-F "projectId=1"
# Get todos
curl http://localhost:3000/api/todosThe AI is optimized to recognize:
- CNC Operations: cutting, routing, offsets, toolpaths
- Cold-molding: lamination techniques
- Structural Work: transoms, bulkheads, frames
- Assembly: joinery, fitting, installation
- Finishing: varnishing, painting, sanding
- Materials: wood types, epoxy, hardware specifications
"Need to cut the transom with a 6mm offset on the CNC, then sand it down to 220 grit before applying the first coat of varnish"
[
{
"task": "Cut transom with 6mm offset on CNC",
"priority": "high",
"category": "CNC"
},
{
"task": "Sand transom to 220 grit",
"priority": "medium",
"category": "Finishing"
},
{
"task": "Apply first coat of varnish to transom",
"priority": "medium",
"category": "Finishing"
}
]ISC
This is a specialized tool for boat building workflows. Contributions welcome!
Built for craftspeople who work with their hands π¨β