Integración con OpenCode

This commit is contained in:
Rompetechos cuenta de desarrollo 2026-07-09 16:49:00 +02:00
parent a7f8ddad08
commit 7228cf1b65
8 changed files with 910 additions and 808 deletions

18
.claude/settings.json Normal file
View File

@ -0,0 +1,18 @@
{
"permissions": {
"allow": [
"Bash(python backfill_games_mayo.py)",
"Bash(findstr /i \"GAMes Actualiz MetricasDiarias actualizado\" \"C:\\\\Users\\\\jmgom\\\\AppData\\\\Local\\\\Temp\\\\claude\\\\c--Users-jmgom-projects-leads-optimizer\\\\2e73bc62-0b35-4293-96e9-676bded17b5f\\\\tasks\\\\bf9cfc1r9.output\")",
"Bash(findstr /i /c:\"actualiz\" \"C:\\\\Users\\\\jmgom\\\\AppData\\\\Local\\\\Temp\\\\claude\\\\c--Users-jmgom-projects-leads-optimizer\\\\2e73bc62-0b35-4293-96e9-676bded17b5f\\\\tasks\\\\bf9cfc1r9.output\")",
"Bash(python -c ' *)",
"Bash(git commit -m ' *)",
"Bash(git push *)",
"Bash(pkill -f \"streamlit run dashboard.py\")",
"Skill(run)",
"Skill(run:*)"
],
"additionalDirectories": [
"C:\\Users\\jmgom\\projects\\meta-optimizer"
]
}
}

84
AGENTS.md Normal file
View File

@ -0,0 +1,84 @@
# Leads Optimizer — AGENTS.md
## Quick start
```bash
pip install -r requirements.txt
python run.py # main optimizer run
python weekly_report.py # weekly strategic report
streamlit run dashboard.py # Streamlit dashboard (port 15002)
```
Python 3.12+. No build step, no linter, no test suite.
## Execution entry points
| File | Trigger | What it does |
|------|---------|-------------|
| `run.py` | daily.yml (00:00 UTC) or manual | Syncs Google Ads → Airtable, analyses campaigns, applies budget decisions, reports to Slack |
| `weekly_report.py` | weekly.yml (Mon 07:00 UTC) or manual | Deeper week-over-week analysis via Anthropic, sends Slack |
| `dashboard.py` | `streamlit run dashboard.py` | UI on port 15002, reads from Airtable directly |
## DRY_RUN mode
`config.py` has `DRY_RUN = True` by default. When `True`, decisions are printed but **no changes are applied to Google Ads**. Must be set to `False` to apply budget/pause changes. This is a module-level constant, not an env var.
## Required env vars (loaded via `python-dotenv` from `.env`)
All are mandatory except `SLACK_WEBHOOK_URL` (optional, has empty default):
- `AIRTABLE_TOKEN`, `AIRTABLE_BASE_ID`
- `Google Ads`: `GOOGLE_ADS_DEVELOPER_TOKEN`, `GOOGLE_ADS_CLIENT_ID`, `GOOGLE_ADS_CLIENT_SECRET`, `GOOGLE_ADS_REFRESH_TOKEN`, `GOOGLE_ADS_LOGIN_CUSTOMER_ID` (digits only, no dashes)
- `ANTHROPIC_API_KEY`
- `SLACK_WEBHOOK_URL`
The `.github/workflows/` files pull these from GitHub Secrets. `run.sh` has **hardcoded secrets** — never commit changes to it.
## Architecture
Flat structure, no packages. Flow:
1. **Sync**: `airtable_client.py` + `google_ads_client.py` pull campaign catalog and monthly metrics from Google Ads, write to Airtable tables `Google Ads Campaigns`, `GACampaignMes`, `Leads Lake`, `MetricasDiarias`, `GAMes`.
2. **Analyze**: `analyzer.py` computes per-campaign urgency (PAUSAR / SPRINT / ACELERAR / FRENAR / EN_RITMO).
3. **Decide**: `agent.py` calls **Anthropic Claude (claude-sonnet-4-6)** per campaign to get JSON decision with action, budget multiplier, justification, and advice. Also produces portfolio-level analysis.
4. **Apply**: `optimizer.py` mutates Google Ads campaigns (budget changes, pause/unpause) — only if `DRY_RUN = False`.
5. **Report**: `slack_reporter.py` sends formatted summary to Slack via webhook.
## Campaign naming conventions
Campaigns follow naming patterns that drive logic:
- `fco_search_<N>` — Search campaigns for formation courses
- `fco_pmx_<N>` — PMX (Performance Max) campaigns
- `fco_leadform_<N>` — Lead form campaigns (leads captured inside Google, never reach Airtable)
When a course has both Search and PMX campaigns (`_search_` + `_pmx_` with same `<N>`), Search conversions reflow to PMX. When PMX has a `_leadform` companion, leadform conversions are summed into the PMX campaign's `leads_grupo`. If a course has multiple PMX campaigns (excluding leadform), paths 4/5 are disabled to avoid double counting.
## Month-boundary metric handling
`run.py` has special logic (lines ~400-432) for when yesterday belongs to a different calendar month. It merges into the **previous month's** `GACampaignMes` record instead of overwriting the new month's (avoids a known bug that erased June history). Any edits to the metrics-writing section must preserve this redirect.
## Airtable tables
- `Google Ads Campaigns` — master campaign catalog (Curso, GoogleCampaignID, PPL, CapTotalMes, CPAMaximo, Activa)
- `Leads Lake` — individual lead records (GoogleCampaignID, FechaEntrada)
- `GACampaignMes` — per-campaign monthly snapshot; updated each run with leads, advice, criticidad, metricas_diarias
- `MetricasDiarias` — JSON field with per-day {coste, ingreso, margen, leads, leads_lake}
- `GAMes` — aggregated daily totals for all fco_ campaigns + monthly totals
## Backfill and migration scripts
Scripts prefixed `backfill_*` and `migrate_*` are one-off data scripts. Do not call them from normal flow; they are only for historical data repairs.
## CI/CD
- `daily.yml` — runs `python run.py` at 00:00 UTC (2 AM CEST / 1 AM CET)
- `weekly.yml` — runs `python weekly_report.py` Monday at 07:00 UTC (9 AM CEST)
- Both use `ubuntu-latest` + Python 3.12 + secrets from GitHub
- Logs uploaded as artifacts (30-day retention)
## Gotchas
- `run.py` wraps `sys.stdout` with a custom `Tee` class that writes to both console and `logs/<timestamp>.log`. Do not remove this.
- The Anthropic model is hardcoded to `claude-sonnet-4-6` in `agent.py`. If the model changes, update all three calls (`decide`, `portfolio_daily_analysis`, `weekly_strategic_analysis`).
- `run.sh` contains real API secrets — it should NOT be committed. Use `.env` + `python run.py` instead.