Talk to any database in plain English. Voice or text. With memory.
SQL Whisper is a voice-and-text AI database assistant built for SCU Hack-A-Stack 2026. Connect any MySQL or TDSQL-compatible database, ask questions in natural language, refine them in conversation, and get back real SQL, real results, charts, and semantic insights β no SQL knowledge required.
Built in 24 hours by three Santa Clara University students.
Type or speak a question. Get back an answer. Then ask a follow-up.
You: "Show me my top 5 customers by spending"
Whisper: Here are your highest-spending customers...
Rank Customer Total 1 Matthew White $4,817.37 2 William Smith $3,926.47 ... You: "Now only show the ones from California"
Whisper: William Smith is your top California customer with $3,926.47 in spending. Interestingly, he was also #2 on your overall top 5 list!
The agent introspects the database schema, generates safe SQL, runs it, explains the result, and remembers what you asked previously. Follow-up questions reference prior context automatically.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Frontend (React) β
β Atomic Command Surface architecture β
β Connections β Query Input β Voice β History β Results β
ββββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββ
β HTTPS
ββββββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββ
β Backend (Flask + Python) β
β β
β /ask βββΆ Claude agent (tool-use loop) β
β βββΆ get_schema βββΆ INFORMATION_SCHEMA β
β βββΆ run_query βββΆ Safety pipeline: β
β β’ Comment strip β
β β’ SELECT-only β
β β’ Single-statement β
β β’ Row cap (500) β
β β’ Dual-layer timeout β
β β
β /trtc/* βββΆ Tencent TRTC + StartAITranscription β
β /connections, /history, /schema, /tables, /query β
β /conversation/reset β
ββββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββ
β
ββββββββββββββΌβββββββββββββ
βΌ βΌ βΌ
App DB Redis User DB(s)
(MySQL) (cache + (MySQL/TDSQL)
encrypted conversation Schema introspected
credentials state) Read-only access
+ history
Backend
- Flask + flask-cors
- pymysql + cryptography (Fernet)
- Anthropic Claude (
claude-haiku-4-5) via the official SDK - Tencent Cloud TRTC + StartAITranscription
- Redis 7 for schema caching and multi-turn conversation state
- MySQL 8 / TDSQL-compatible
Frontend
- React with Atomic Command Surface architecture
- TRTC SDK v5 for voice input
- Tailwind CSS for styling
- Recharts for auto-rendered data visualization
Infrastructure
- Docker for local databases and Redis
- ngrok for live frontend-backend tunnel during development
A Claude-powered agent calls tool definitions (get_schema, run_query) in a loop until it has enough information to answer. Generates correctly-joined multi-table SQL on the first try for most questions.
Ask a question, then refine. "Show me top customers" β "Now only the California ones" β "What did they buy?" Each follow-up references prior context. Conversation state is persisted in Redis per connection with a 10-minute TTL. The UI shows a "Follow-up Mode" indicator and a "New Conversation" button to reset.
A second Claude call produces three editorialized stat cards per query β not just row counts, but computed insights like top values, group averages, and qualitative tags. Each card carries a sentiment color (positive, warning, neutral) for the UI.
Result data renders as charts when the shape supports it (bar, line, etc.), driven by the data structure rather than manual selection.
Every query passes through:
- Comment stripping (so
/*SELECT*/ DROPcan't fool the validator) - First-token SELECT allowlist
- Single-statement enforcement (no
SELECT 1; DROP TABLE film) - Automatic row cap injection (
LIMIT 501β 500 + 1 to detect truncation) - Dual-layer 5-second timeouts (client-side thread + MySQL
MAX_EXECUTION_TIME)
Two load-bearing Redis usages:
- Schema cache β schemas introspected on first query and cached for 5 minutes. Repeat queries pay ~10ms instead of ~200ms.
- Conversation state β multi-turn conversation messages cached per connection with 10-minute TTL.
Database credentials are encrypted at rest with Fernet symmetric encryption. Plaintext passwords are decrypted just-in-time for each query and never persisted to logs.
Tencent Cloud TRTC integration. The user joins a TRTC room, an ASR bot joins as a phantom user and streams transcripts via TRTC.EVENT.CUSTOM_MESSAGE, and the final sentence gets fed into the same /ask pipeline that handles typed queries.
Connect multiple databases simultaneously. Switch between them in the sidebar. Each connection has its own history and independent conversation state.
Every successful query is saved to query_history with the prompt, results, and stat cards. Click any past entry to replay without re-running the SQL. Delete individual entries.
POST /connectionsβ register a databaseGET /connectionsβ list connectionsPOST /connections/<id>/testβ verify connection worksDELETE /connections/<id>β remove (cascades to history)
GET /schemaβ full compressed schema (Redis-cached, for the LLM)GET /tablesβ table list with row counts (for sidebars)
POST /askβ natural language β SQL + results + stats (multi-turn aware)POST /queryβ raw SQL (safety-validated)POST /conversation/resetβ clear conversation history for a connection
GET /history?connection_id=<id>β listGET /history/<id>β single entryDELETE /history/<id>β remove
POST /trtc/usersigβ mint a TRTC UserSigPOST /trtc/start-transcriptionβ spawn ASR bot into roomPOST /trtc/stop-transcriptionβ tear down ASR bot
All data endpoints require X-Connection-Id: <uuid> header.
cd backend
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txtCreate a .env file:
ENCRYPTION_KEY=<run: python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())">
APP_DB_HOST=localhost
APP_DB_PORT=3316
APP_DB_USER=root
APP_DB_PASS=hackathon
APP_DB_NAME=hackastack_app
REDIS_HOST=localhost
REDIS_PORT=6379
ANTHROPIC_API_KEY=<your key>
TRTC_SDK_APP_ID=<from console.trtc.io>
TRTC_SDK_SECRET_KEY=<from console.trtc.io>
TENCENT_SECRET_ID=<from CAM console>
TENCENT_SECRET_KEY=<from CAM console>
TRTC_REGION=ap-singapore
Spin up databases and Redis:
docker run --name app-db-mysql -e MYSQL_ROOT_PASSWORD=hackathon -e MYSQL_DATABASE=hackastack_app -p 3316:3306 -d mysql:8
docker run --name demo-db-mysql -e MYSQL_ROOT_PASSWORD=demopass -e MYSQL_DATABASE=sakila -p 3326:3306 -d mysql:8
docker run --name whisper-redis -p 6379:6379 -d redis:7Load the Sakila demo data:
curl -O https://downloads.mysql.com/docs/sakila-db.tar.gz
tar -xzf sakila-db.tar.gz
docker exec -i demo-db-mysql mysql -uroot -pdemopass sakila < sakila-db/sakila-schema.sql
docker exec -i demo-db-mysql mysql -uroot -pdemopass sakila < sakila-db/sakila-data.sql(Optional) Load the synthetic small business demo data:
python3 seed_small_business.pyInitialize the app DB schema (run once):
docker exec -i app-db-mysql mysql -uroot -phackathon hackastack_app <<EOF
CREATE TABLE user_connections (
id CHAR(36) PRIMARY KEY,
name VARCHAR(255) NOT NULL,
host VARCHAR(255) NOT NULL,
port INT DEFAULT 3306,
db_name VARCHAR(255) NOT NULL,
username VARCHAR(255) NOT NULL,
password_enc TEXT NOT NULL,
db_type VARCHAR(50) DEFAULT 'mysql',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE query_history (
id CHAR(36) PRIMARY KEY,
connection_id CHAR(36) NOT NULL,
name VARCHAR(255),
prompt TEXT NOT NULL,
response_payload JSON NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_connection_created (connection_id, created_at DESC)
);
EOFRun Flask:
python3 app.py
# Backend now live at http://localhost:5001cd frontend
npm install
npm run devTracks targeted:
- Tencent Cloud β TRTC voice input + TRTC AI transcription + TDSQL-compatible architecture
- Redis - not an track but a sponsor, used for context saving and multi-turn conversations
- Agentic AI with proper tool definitions is dramatically more capable than single-shot prompting for SQL generation. Letting Claude call
get_schemaandrun_queryseparately lets it adapt to unknown databases without prompt engineering for every schema. - SQL safety is a layered problem. Comment stripping must run before validation β otherwise an attacker can hide
DROP TABLEinside/* */and slip past the SELECT allowlist. - Encrypt-at-rest with just-in-time decryption is the right pattern for credential storage even in a hackathon. Fernet makes this five lines of Python.
- Coordinating three developers writing to the same Flask file requires a clear API contract negotiated up front. We aligned on field names and response shapes before either side wrote glue code.
- Multi-turn conversation requires serializing Anthropic SDK objects (TextBlock, ToolUseBlock) before persisting to Redis.
model_dump()is your friend.
- Native Tencent Cloud TDSQL deployment
- Team workspaces with per-user auth
- Cross-database queries ("compare customers in DB A vs DB B")
- Query result export (CSV, Sheets)
- Matthew Moyer β Backend architecture, Tencent TRTC integration, AI agent, Redis caching, multi-turn implementation
- Zach Malinoski β Frontend, UX, Atomic Command Surface architecture, voice UI, charts
- Joshua Cao β Agent design, prompt engineering, endpoint development, agentic tooling