A production-ready Node.js backend service that transforms unstructured meeting notes into actionable insights using AI. Built with enterprise-grade architecture and robust error handling.
This service accepts meeting notes (via file upload or raw text) and uses Google Gemini AI to extract:
- Summary: 2-3 sentence meeting overview
- Key Decisions: List of important decisions made
- Action Items: Structured tasks with owners and deadlines
βββ config/ # Centralized configuration management
β βββ app.js # Main app configuration
βββ controllers/ # Business logic layer
β βββ meetingController.js
βββ middleware/ # Reusable middleware components
β βββ upload.js # File upload handling
β βββ errorHandler.js # Error handling middleware
βββ routes/ # API route definitions
β βββ api.js
βββ services/ # External service integrations
β βββ llmService.js # AI/LLM service
βββ utils/ # Utility functions
β βββ helpers.js
βββ samples/ # Sample meeting notes files
β βββ team-sync.txt
β βββ project-meeting.txt
βββ server.js # Application entry point
- Triple Input Support: File upload (.txt), JSON body, OR plain text body
- AI-Powered Extraction: Google Gemini integration with prompt engineering
- Robust Error Handling: Comprehensive API error management
- Input Validation: File type, size, and content validation
- Security First: Secure file handling and input sanitization
- Production Ready: Environment configuration and health checks
- Clean Architecture: Separation of concerns with modular design
- Node.js (v16 or higher)
- npm or yarn
- Google Gemini API key
- Clone the repository
git clone https://github.com/deep-priyo/meeting-insights-api
cd meeting-insights-api- Install dependencies
npm install- Environment Setup
Create a
.envfile in the root directory:
# Required
GEMINI_API_KEY=your_gemini_api_key_here
# Optional
PORT=3000
NODE_ENV=development- Start the server
# Development
npm run dev
# Production
npm startThe server will start on http://localhost:3000
GET /api/healthResponse:
{
"status": "OK",
"timestamp": "2024-01-20T10:30:00.000Z",
"service": "Server is running"
}POST /api/process-meetingInput Options:
Option 1: File Upload
- Content-Type:
multipart/form-data - Field:
file(must be .txt file, max 10MB)
Option 2: JSON Body
- Content-Type:
application/json - Body:
{"text": "your meeting notes here"}
Option 3: Plain Text Body
- Content-Type:
text/plain - Body: Raw text directly in request body
Response Format:
{
"summary": "2-3 sentence meeting summary",
"decisions": [
"Decision 1",
"Decision 2"
],
"actionItems": [
{
"task": "Task description",
"owner": "Person name or null",
"due": "Deadline or null"
}
]
}curl -X GET http://localhost:3000/api/healthcurl -X POST http://localhost:3000/api/process-meeting \
-F "file=@samples/team-sync.txt"curl -X POST http://localhost:3000/api/process-meeting \
-H "Content-Type: application/json" \
-d '{
"text": "Team Sync β May 26\n\n- We will launch the new product on June 10.\n- Ravi to prepare onboarding docs by June 5.\n- Priya will follow up with logistics team on packaging delay.\n- Beta users requested a mobile-first dashboard."
}'curl -X POST http://localhost:3000/api/process-meeting \
-H "Content-Type: text/plain" \
-d "Team Sync β May 26
- We will launch the new product on June 10.
- Ravi to prepare onboarding docs by June 5.
- Priya will follow up with logistics team on packaging delay.
- Beta users requested a mobile-first dashboard."- Set method to
POST - URL:
http://localhost:3000/api/process-meeting - Body β form-data
- Key:
file(select File type) - Value: Choose
samples/team-sync.txt
- Set method to
POST - URL:
http://localhost:3000/api/process-meeting - Headers:
Content-Type: application/json - Body β raw β JSON:
{
"text": "Team Sync β May 26\n\n- We'll launch the new product on June 10.\n- Ravi to prepare onboarding docs by June 5.\n- Priya will follow up with logistics team on packaging delay.\n- Beta users requested a mobile-first dashboard."
}- Set method to
POST - URL:
http://localhost:3000/api/process-meeting - Headers:
Content-Type: text/plain - Body β raw β Text:
Team Sync β May 26
- We'll launch the new product on June 10.
- Ravi to prepare onboarding docs by June 5.
- Priya will follow up with logistics team on packaging delay.
- Beta users requested a mobile-first dashboard.
Team Sync β May 26
- We'll launch the new product on June 10.
- Ravi to prepare onboarding docs by June 5.
- Priya will follow up with logistics team on packaging delay.
- Beta users requested a mobile-first dashboard.
- Decision: Move to mobile-first approach for next sprint.
Expected Output:
{
"summary": "The team confirmed the product launch on June 10, assigned onboarding preparation and logistics follow-up, and decided to implement mobile-first dashboard based on beta user feedback.",
"decisions": [
"Launch set for June 10",
"Move to mobile-first approach for next sprint",
"Need mobile-first dashboard for beta users"
],
"actionItems": [
{
"task": "Prepare onboarding docs",
"owner": "Ravi",
"due": "June 5"
},
{
"task": "Follow up with logistics team on packaging delay",
"owner": "Priya",
"due": null
}
]
}Project Kickoff Meeting - January 15
Attendees: Sarah (PM), Mike (Dev), Lisa (Design), Tom (QA)
Key Points:
- Project deadline set for March 31st
- Sarah will create project timeline by January 20th
- Mike to set up development environment by January 18th
- Lisa needs design mockups ready by February 1st
- Tom will prepare testing strategy document
- Decision: Use React for frontend framework
- Decision: Weekly standups every Tuesday at 10 AM
- Budget approved: $50,000
Expected Output:
{
"summary": "Project kickoff meeting established March 31st deadline, assigned initial setup tasks to team members, and made key technical and process decisions including React framework adoption and weekly standups.",
"decisions": [
"Project deadline set for March 31st",
"Use React for frontend framework",
"Weekly standups every Tuesday at 10 AM",
"Budget approved: $50,000"
],
"actionItems": [
{
"task": "Create project timeline",
"owner": "Sarah",
"due": "January 20th"
},
{
"task": "Set up development environment",
"owner": "Mike",
"due": "January 18th"
},
{
"task": "Design mockups ready",
"owner": "Lisa",
"due": "February 1st"
},
{
"task": "Prepare testing strategy document",
"owner": "Tom",
"due": null
}
]
}The API provides comprehensive error handling with appropriate HTTP status codes:
400 Bad Request- Invalid input, file type, or size issues401 Unauthorized- Invalid or missing Gemini API key429 Too Many Requests- API quota exceeded or rate limiting500 Internal Server Error- Unexpected server errors502 Bad Gateway- AI service returned invalid response504 Gateway Timeout- AI service timeout
{
"error": "File size too large. Maximum size is 10MB."
}GEMINI_API_KEY- Your Google Gemini API key (required)GOOGLE_API_KEY- Alternative API key variable namePORT- Server port (default: 3000)NODE_ENV- Environment setting (development/production)
- File size: 10MB maximum
- Text input: 50,000 characters maximum
- Supported formats: .txt files only
- AI model: gemini-2.5-flash
- Production-Ready Architecture: Proper separation of concerns with MVC pattern
- Comprehensive Validation: Multi-layer input validation and sanitization
- Robust Error Handling: Meaningful error messages with proper HTTP codes
- Flexible Input Methods: Support for both file uploads and raw text
- AI Response Validation: Validates and sanitizes AI responses before returning
- Security First: File type validation, size limits, and secure middleware
- Configuration Management: Environment-based setup for different deployments
- express
- multer
- cors
- helmet
- dotenv
- @google/generative-ai
{
"nodemon": "^3.0.2"
}npm start # Start production server
npm run dev # Start development server with nodemon
npm test # Run tests (when implemented)- Proper error handling and logging
- Input validation and sanitization
- Security middleware implementation
Built with β€οΈ by Priyadeep β making meetings productive again!