Hermes is a full-stack application that lets you query your PostgreSQL database using natural language. Think of it as "Perplexity for your data" - ask questions like "What's our revenue this quarter?" and get answers with beautiful visualizations.
- π£οΈ Natural Language Queries - Ask questions in plain English
- π Smart Visualizations - Automatically chooses charts, tables, or text based on the data
- π AI-Powered SQL Generation - Uses OpenAI GPT-4 to convert questions to SQL
- π Interactive Charts - Bar, line, area, and pie charts using Recharts
- π‘οΈ Secure - Read-only queries only, no data modification
- π³ Docker Ready - Easy deployment with Docker Compose
- Frontend: Next.js 15 with React, TypeScript, Tailwind CSS, Recharts
- Backend: Clojure with Ring, Reitit, next.jdbc
- Database: PostgreSQL 16
- AI: OpenAI GPT-4o for text-to-SQL
- Docker and Docker Compose
- OpenAI API key
- (For local dev) Node.js 20+, Clojure CLI tools
# Copy environment file
cp .env.example .env
# Edit .env and add your OpenAI API key
# OPENAI_API_KEY=sk-your-key-hereDevelopment Mode (just the database):
# Start PostgreSQL with seed data
docker compose -f docker-compose.dev.yml up -d
# Wait for database to be ready
docker compose -f docker-compose.dev.yml logs -f postgresThen run the backend and frontend locally (see Development section below).
Production Mode (everything in Docker):
# Start all services
docker compose up -d
# View logs
docker compose logs -f- Frontend: http://localhost:3000
- Backend API: http://localhost:3001
- Start the database:
docker compose -f docker-compose.dev.yml up -d- Start the Clojure backend:
cd backend
# Set environment variables
export OPENAI_API_KEY=sk-your-key-here
export DB_HOST=localhost
export DB_PORT=5432
export DB_NAME=hermes
export DB_USER=hermes
export DB_PASSWORD=hermes
# Run the backend
clojure -M:run- Start the Next.js frontend:
cd frontend
# Create local env file
cp .env.local.example .env.local
# Install dependencies and run
npm install
npm run devHermes/
βββ frontend/ # Next.js frontend
β βββ src/
β β βββ app/ # Next.js app router
β β βββ components/ # React components
β β βββ lib/ # API client & utilities
β βββ Dockerfile
βββ backend/ # Clojure backend
β βββ src/hermes/
β β βββ core.clj # Main entry point
β β βββ api.clj # HTTP API handlers
β β βββ db.clj # Database operations
β β βββ ai.clj # OpenAI integration
β βββ deps.edn # Clojure dependencies
β βββ Dockerfile
βββ db/ # Database files
β βββ init.sql # Schema creation
β βββ seed.sql # Demo data
βββ docker-compose.yml # Production compose
βββ docker-compose.dev.yml # Development compose
βββ README.md
The seed data includes a realistic business scenario with:
- 7 Departments: Sales, Engineering, Marketing, Support, etc.
- 31 Employees: With roles, salaries, and performance scores
- 30 Products: Software licenses, cloud services, support plans
- 100 Customers: Across enterprise, mid-market, and SMB segments
- 1,000+ Orders: Spanning all of 2024 with realistic distribution
- Support Tickets: Throughout the year
- Marketing Campaigns: Various channels and metrics
- Expenses: Monthly recurring and one-time costs
Try asking:
- "What's our total revenue for 2024?"
- "Show me monthly revenue trends"
- "Who are our top 5 sales representatives by revenue?"
- "Which products have the highest profit margins?"
- "How many support tickets are still open?"
- "What's the average order value by customer segment?"
- "Show me the marketing campaign ROI"
- "Which department has the highest expenses?"
- "Who are our enterprise customers?"
- "What's the customer satisfaction score trend?"
| Method | Path | Description |
|---|---|---|
| GET | /api/health |
Health check |
| GET | /api/schema |
Get database schema |
| GET | /api/tables |
List all tables |
| POST | /api/query |
Execute natural language query |
POST /api/query
{
"question": "What's our total revenue?"
}{
"success": true,
"question": "What's our total revenue?",
"sql": "SELECT SUM(total) as total_revenue FROM orders WHERE status = 'delivered'",
"explanation": "Summing all delivered order totals",
"visualization": "number",
"data": [{"total_revenue": 2847392.50}],
"row_count": 1,
"answer": "Your total revenue from delivered orders is $2,847,392.50.",
"insights": ["Revenue is up 15% from last quarter"],
"follow_up_questions": ["How does this compare to last year?"]
}| Variable | Description | Default |
|---|---|---|
OPENAI_API_KEY |
OpenAI API key (required) | - |
DB_HOST |
PostgreSQL host | localhost |
DB_PORT |
PostgreSQL port | 5432 |
DB_NAME |
Database name | hermes |
DB_USER |
Database user | hermes |
DB_PASSWORD |
Database password | hermes |
PORT |
Backend server port | 3001 |
NEXT_PUBLIC_API_URL |
Backend URL for frontend | http://localhost:3001 |
- The AI is instructed to only generate SELECT queries
- SQL is validated to ensure it starts with SELECT
- Consider using a read-only database user in production
- API keys should be kept secure and rotated regularly
Check that PostgreSQL is running and the seed data was loaded:
docker compose -f docker-compose.dev.yml ps
docker compose -f docker-compose.dev.yml logs postgresMake sure you've exported the environment variable:
export OPENAI_API_KEY=sk-your-key-hereCheck the browser console for errors. Ensure the data returned has numeric values for the Y-axis.
MIT