A phone-based investment assistant that can check prices, research companies, and trade on your behalf.
TrevorAI is a hackathon project named after Trevor Lefkowitz from Ghosts (US). You call a number, talk to Trevor, and he looks up your profile, researches stocks, gives a Buy / Hold / Sell opinion, and executes trades you authorize. A web dashboard shows the resulting portfolio and transaction history.
- Voice agent. A Retell phone call streams transcripts over a WebSocket to a FastAPI server. Gemini 2.5 Flash (through the OpenAI-compatible endpoint) drafts the replies and decides when to call a tool. While a slow tool runs, Trevor sends a short filler line so the call does not go silent.
- Tools the agent can call.
quick_stock_check,web_search, andmarket_research(OpenAIgpt-4owith the web search tool),get_user_profile,buy_stock,sell_stock, andend_call. Trades require the caller to state a user ID first. - Trades that update the books. A buy or sell looks up the current price by web search, adjusts the user's cash balance and holdings, and appends a transaction tagged
"initiator": "agent"to the shared JSON file. - Dashboard. A Next.js app with a portfolio page (cash balance, holdings treemap, and a per-stock price history chart) and a transactions page. A user picker in the header switches between the seeded accounts. Live quotes come from Finnhub and history from Alpha Vantage.
flowchart LR
Caller["Phone caller"]
Retell["Retell"]
Agent["Voice agent<br/>FastAPI, src/agent"]
LLM["Gemini 2.5 Flash<br/>function calling"]
Search["OpenAI gpt-4o<br/>web search"]
Data["JSON files<br/>trevorai-backend/data"]
API["Flask API<br/>trevorai-backend, :8081"]
UI["Next.js dashboard<br/>trevorai-frontend, :3000"]
Market["Finnhub, Alpha Vantage"]
Caller <--> Retell
Retell <-- "WS /llm-websocket/{call_id}" --> Agent
Agent <--> LLM
Agent -- "research, price lookup" --> Search
Agent -- "read profile, write trades" --> Data
Data --> API
API -- "REST" --> UI
Market --> UI
The two Python services never talk to each other. They share the same two files, user_data.json (per-user cash and holdings) and user_transaction.json (trade log). The agent writes to them, the Flask API reads them, and the dashboard polls the API.
You need Python 3.10+, Node 18+, a Retell account, and API keys for Gemini, OpenAI, Finnhub, and Alpha Vantage.
1. Portfolio API
python3 -m venv .venv && .venv/bin/pip install -r requirements.txt
.venv/bin/python trevorai-backend/app.py # http://127.0.0.1:80812. Voice agent
cd src/agent
cat > .env <<EOF
RETELL_API_KEY=...
GEMINI_API_KEY=...
OPENAI_API_KEY=...
EOF
../../.venv/bin/uvicorn server:app --port 8080Expose the server to the internet (ngrok or similar) and point your Retell agent's custom LLM URL at wss://<host>/llm-websocket and its webhook at https://<host>/webhook.
Before running, edit the file paths in src/agent/tools/db_handler.py. They are hard-coded to a Windows path and must point at trevorai-backend/data/.
3. Dashboard
cd trevorai-frontend
cat > .env.local <<EOF
NEXT_PUBLIC_FINNHUB_API_KEY=...
NEXT_PUBLIC_ALPHA_VANTAGE_API_KEY=...
EOF
npm install && npm run dev # http://localhost:3000Open the dashboard, pick a user in the header, and call your Retell number. Give Trevor the same user ID (for example FYJ57) when he asks.
| Variable | Used by | Purpose |
|---|---|---|
RETELL_API_KEY |
voice agent | Verifies webhook signatures and authenticates with Retell. Required at startup. |
GEMINI_API_KEY |
voice agent | Gemini key, used through the OpenAI-compatible endpoint for conversation and function calling. |
OPENAI_API_KEY |
voice agent | OpenAI key for gpt-4o web search, company research, and the price lookups behind trades. |
NEXT_PUBLIC_FINNHUB_API_KEY |
dashboard | Live quotes for the holdings treemap. |
NEXT_PUBLIC_ALPHA_VANTAGE_API_KEY |
dashboard | Price history for the stock detail chart. |
The voice agent loads .env from its working directory. The dashboard reads .env.local. Both keys with the NEXT_PUBLIC_ prefix are shipped to the browser.
src/agent/ Voice agent: Retell WebSocket + webhook server
├── server.py FastAPI app, /webhook and /llm-websocket/{call_id}
├── llm_with_func.py System prompt, tool schemas, Gemini call loop
├── custom_types.py Retell request and response shapes
└── tools/
├── web_search.py gpt-4o with web search
├── company_research.py gpt-4o deep company research
└── db_handler.py profile lookup, buy and sell, transaction log
trevorai-backend/ Flask read-only API over the JSON data
├── app.py /api/portfolios, /api/portfolio/{id}, /api/transactions/{id}
└── data/ user_data.json, user_transaction.json
trevorai-frontend/ Next.js 15 dashboard (Tailwind, Recharts, Nivo)
└── src/
├── app/portfolio/ Balance, treemap, and stock detail chart
├── app/transactions/ Trade history for the selected user
├── app/api/alphavantage/ Server route that proxies Alpha Vantage
└── lib/ Finnhub and Alpha Vantage clients, user picker context
requirements.txt Python dependencies for both services
- Storage is two JSON files with no locking. Concurrent calls can overwrite each other.
- Trade prices come from a web search parsed with a regex, not a market data feed. A bad parse fails the trade.
- The agent's data paths are hard-coded to a Windows machine and must be edited by hand.
- The dashboard's API base is hard-coded to
http://127.0.0.1:8081. The user list in the header is also hard-coded to the four seeded accounts. - Finnhub and Alpha Vantage keys are exposed to the browser. Free-tier quotas are small.
- There are no tests and no auth on any endpoint.
MIT License.
