You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

97 lines
2.4 KiB
Markdown

# Personal Gmail + Calendar Agent
This project runs a small local API service that:
- scans new Gmail inbox messages
- classifies emails with an LLM as `LINKEDIN`, `ADVERTISING`, or `OTHER`
- moves LinkedIn emails to a `LinkedIn` label/folder
- moves advertising emails to an `Advertising` label/folder
- exposes a secure availability endpoint powered by Google Calendar free/busy
## 1) Prerequisites
- Python 3.11+
- A Google account
- An OpenAI-compatible API key for the LLM classifier
- A Google Cloud project with:
- Gmail API enabled
- Google Calendar API enabled
- OAuth consent configured
- OAuth Client ID of type **Desktop app**
## 2) Google OAuth setup
1. In Google Cloud Console, create a desktop OAuth client.
2. Download the client JSON file.
3. Save it in this project as `credentials.json`.
The first run opens a browser window for consent and creates `token.json`.
## 3) Install and configure
```bash
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
cp .env.example .env
```
Edit `.env` and set:
- `AGENT_API_KEY` to a strong secret for agent-to-agent calls
- `LLM_API_KEY` and optional `LLM_MODEL` / `LLM_BASE_URL`
- optional scan frequency and Gmail query
## 4) Run
```bash
uvicorn app.main:app --reload
```
At startup, the scheduler runs every `GMAIL_SCAN_INTERVAL_MINUTES`.
## 5) API usage
### Health check
```bash
curl http://127.0.0.1:8000/health
```
### Manual Gmail scan
```bash
curl -X POST "http://127.0.0.1:8000/scan?max_results=100" \
-H "X-API-Key: your-secret"
```
### Availability for other AI agents
```bash
curl -X POST "http://127.0.0.1:8000/availability" \
-H "Content-Type: application/json" \
-H "X-API-Key: your-secret" \
-d '{
"start": "2026-03-09T09:00:00+01:00",
"end": "2026-03-09T10:00:00+01:00",
"calendar_ids": ["primary"]
}'
```
If `available` is `true`, there are no busy slots in that range.
## Classification behavior
- LLM classification is used for each email (`LINKEDIN`, `ADVERTISING`, `OTHER`).
- LinkedIn has priority over advertising inside the classifier prompt.
- Set `LLM_FALLBACK_TO_RULES=true` only if you want rules-based backup when LLM calls fail.
- Every scanned message gets an `AgentProcessed` label to avoid reprocessing loops.
## Notes
- Gmail "folders" are labels. This agent creates:
- `LinkedIn`
- `Advertising`
- `AgentProcessed`
- Messages classified as LinkedIn/Advertising are removed from `INBOX` (moved out of inbox).