Add scripts/rate_limit.py with cloud-aware key function: - In cloud mode, extracts user_id from _request_db ContextVar path (part[-3]) so each cloud user has their own rate limit bucket - In demo mode, returns unique per-request key to disable limiting entirely (_demo_guard handles write-blocking; rate limiting would block the demo UX) - Falls back to client IP for local/self-hosted installs Wire limiter to 4 endpoints with conservative per-user limits: - POST /generate/cover-letter: 20/hour - POST /research/run: 10/hour - POST /qa/suggest: 60/hour - POST /survey/analyze: 30/hour Add _demo_guard() to generate_research and suggest_qa_answer (was missing). Fix pre-existing silent except in suggest_qa_answer: was bare except pass, now logs warning with exc_info. Add _RL_WIZARD placeholder constant with TODO to wire to wizard/ai/interview after feat/77 merges (declared but intentionally not applied yet to avoid false sense of security — comment makes the gap explicit). 18 tests covering cloud user isolation, demo bypass, IP fallback, all 4 endpoints returning 429 on excess, retry_after header, and demo guard. Closes: #122
83 lines
3.8 KiB
YAML
83 lines
3.8 KiB
YAML
name: cf
|
|
# Recreate: conda env create -f environment.yml
|
|
# Update pinned snapshot: conda env export --no-builds > environment.yml
|
|
channels:
|
|
- conda-forge
|
|
- defaults
|
|
dependencies:
|
|
- python=3.12
|
|
- pip
|
|
- pip:
|
|
# ── Web UI ────────────────────────────────────────────────────────────────
|
|
- streamlit>=1.35
|
|
- watchdog # live reload
|
|
- reportlab>=4.0 # PDF cover letter export
|
|
- pandas>=2.0
|
|
- pyarrow # streamlit data tables
|
|
- streamlit-paste-button>=0.1.0
|
|
|
|
# ── Job scraping ──────────────────────────────────────────────────────────
|
|
- python-jobspy>=1.1
|
|
- playwright # browser automation (run: playwright install chromium)
|
|
- selenium
|
|
- undetected-chromedriver
|
|
- webdriver-manager
|
|
- beautifulsoup4
|
|
- requests
|
|
- curl_cffi # Chrome TLS fingerprint — bypasses Cloudflare on The Ladders
|
|
- fake-useragent # company scraper rotation
|
|
|
|
# ── LLM / AI backends ─────────────────────────────────────────────────────
|
|
- openai>=1.55.0,<2.0.0 # >=1.55 required for httpx 0.28 compat; <2.0 for langchain-openai
|
|
- anthropic>=0.80 # direct Anthropic API fallback
|
|
- ollama # Python client for Ollama management
|
|
- langchain>=0.2
|
|
- langchain-openai
|
|
- langchain-anthropic
|
|
- langchain-ollama
|
|
- langchain-community
|
|
- langchain-google-genai
|
|
- google-generativeai
|
|
- tiktoken
|
|
|
|
# ── Resume matching ───────────────────────────────────────────────────────
|
|
- scikit-learn>=1.3
|
|
- rapidfuzz
|
|
- lib-resume-builder-aihawk
|
|
|
|
# ── Notion integration ────────────────────────────────────────────────────
|
|
- notion-client>=3.0
|
|
|
|
# ── Calendar integrations ─────────────────────────────────────────────────
|
|
- caldav>=1.3
|
|
- icalendar>=5.0
|
|
- google-api-python-client>=2.0
|
|
- google-auth>=2.0
|
|
|
|
# ── Document handling ─────────────────────────────────────────────────────
|
|
- pypdf
|
|
- pdfminer-six
|
|
- pyyaml>=6.0
|
|
- python-dotenv
|
|
|
|
# ── Auth / licensing ──────────────────────────────────────────────────────
|
|
- PyJWT>=2.8
|
|
|
|
# ── Rate limiting ─────────────────────────────────────────────────────────
|
|
- slowapi>=0.1.9 # per-user rate limiting on LLM endpoints
|
|
|
|
# ── Utilities ─────────────────────────────────────────────────────────────
|
|
- sqlalchemy
|
|
- tqdm
|
|
- loguru
|
|
- rich
|
|
- tenacity
|
|
- httpx
|
|
|
|
# ── Testing ───────────────────────────────────────────────────────────────
|
|
- pytest>=9.0
|
|
- pytest-cov
|
|
- pytest-mock
|
|
# Documentation
|
|
- mkdocs>=1.5
|
|
- mkdocs-material>=9.5
|