Face Intel β Configuration Guide
This document is the complete reference for every configuration knob
in Face Intel. All settings are environment-driven via
pydantic-settings
with the FI_ prefix.
Source of truth:
config/settings.py. This doc is generated from that file β if you add a setting there, add a row here too.
Table of Contents
- How Settings Work
- Quick Reference: All Settings
- Core
- Provider Enable Flags
- Detection Tuning
- Recognition Tuning
- Scraping
- Reverse Image Search
- Orchestrator
- Cache
- Health & Circuit Breaker
- Storage
- API
- New-Capability Enable Flags
- Logging
- How to Enable/Disable Providers
- How to Configure API Keys
- Production vs Development
- Verifying Your Configuration
1. How Settings Work
The FI_ prefix
Every field on the Settings class is automatically mapped to an
environment variable by uppercasing the field name and prepending
FI_. Examples:
| Field | Env var |
|---|---|
enable_haar |
FI_ENABLE_HAAR |
dnn_confidence_threshold |
FI_DNN_CONFIDENCE_THRESHOLD |
serpapi_key |
FI_SERPAPI_KEY |
cache_ttl_seconds |
FI_CACHE_TTL_SECONDS |
Env var names are case-insensitive (case_sensitive=False).
Loading order
pydantic-settings loads values in this order (later wins):
- Field defaults declared in
config/settings.py. - Values from the
.envfile at the project root (if present). - Actual environment variables.
The .env file
Copy .env.example to .env and edit:
cp .env.example .env
The .env file is not committed (it's in .gitignore). Each
line is KEY=value. Comments start with #.
Programmatic overrides
For tests or scripted runs, use the make_settings() factory:
from config.settings import make_settings
settings = make_settings(
environment="test",
cache_enabled=False,
enable_dnn=False,
db_path=":memory:",
)
This is exactly what tests/conftest.py does.
The settings singleton
config/settings.py exports a module-level settings = Settings()
instance. Read-only consumers (like provider tuning knobs) may
import it directly. Stateful services (Database, Cache,
Orchestrator, services) MUST receive their dependencies via
constructor injection β they never import this module. The DI
container at api/container.py is the
composition root.
2. Quick Reference: All Settings
| Setting | Env var | Type | Default | Section |
|---|---|---|---|---|
app_name |
FI_APP_NAME |
str | "Face Intel" |
Core |
app_version |
FI_APP_VERSION |
str | "1.0.0" |
Core |
environment |
FI_ENVIRONMENT |
str | "development" |
Core |
host |
FI_HOST |
str | "0.0.0.0" |
Core |
port |
FI_PORT |
int | 8000 |
Core |
debug |
FI_DEBUG |
bool | False |
Core |
enable_haar |
FI_ENABLE_HAAR |
bool | True |
Providers |
enable_dnn |
FI_ENABLE_DNN |
bool | True |
Providers |
enable_mtcnn |
FI_ENABLE_MTCNN |
bool | True |
Providers |
enable_retinaface |
FI_ENABLE_RETINAFACE |
bool | False |
Providers |
enable_face_recognition |
FI_ENABLE_FACE_RECOGNITION |
bool | True |
Providers |
enable_deepface |
FI_ENABLE_DEEPFACE |
bool | False |
Providers |
enable_insightface |
FI_ENABLE_INSIGHTFACE |
bool | False |
Providers |
enable_beautifulsoup_scraper |
FI_ENABLE_BEAUTIFULSOUP_SCRAPER |
bool | True |
Providers |
enable_selenium_scraper |
FI_ENABLE_SELENIUM_SCRAPER |
bool | True |
Providers |
enable_bing_scraper |
FI_ENABLE_BING_SCRAPER |
bool | False |
Providers |
enable_duckduckgo_scraper |
FI_ENABLE_DUCKDUCKGO_SCRAPER |
bool | True |
Providers |
enable_google_lens |
FI_ENABLE_GOOGLE_LENS |
bool | True |
Providers |
enable_serpapi |
FI_ENABLE_SERPAPI |
bool | False |
Providers |
enable_yandex |
FI_ENABLE_YANDEX |
bool | False |
Providers |
enable_tineye |
FI_ENABLE_TINEYE |
bool | False |
Providers |
dnn_confidence_threshold |
FI_DNN_CONFIDENCE_THRESHOLD |
float | 0.7 |
Detection |
mtcnn_min_face_size |
FI_MTCNN_MIN_FACE_SIZE |
int | 20 |
Detection |
haar_scale_factor |
FI_HAAR_SCALE_FACTOR |
float | 1.1 |
Detection |
haar_min_neighbors |
FI_HAAR_MIN_NEIGHBORS |
int | 5 |
Detection |
face_recognition_tolerance |
FI_FACE_RECOGNITION_TOLERANCE |
float | 0.6 |
Recognition |
face_recognition_model |
FI_FACE_RECOGNITION_MODEL |
str | "hog" |
Recognition |
deepface_backend |
FI_DEEPFACE_BACKEND |
str | "arcface" |
Recognition |
insightface_model_pack |
FI_INSIGHTFACE_MODEL_PACK |
str | "buffalo_l" |
Recognition |
recognition_match_threshold |
FI_RECOGNITION_MATCH_THRESHOLD |
float | 0.5 |
Recognition |
scrape_timeout |
FI_SCRAPE_TIMEOUT |
int | 30 |
Scraping |
scrape_max_images |
FI_SCRAPE_MAX_IMAGES |
int | 50 |
Scraping |
selenium_headless |
FI_SELENIUM_HEADLESS |
bool | True |
Scraping |
selenium_implicit_wait |
FI_SELENIUM_IMPLICIT_WAIT |
int | 10 |
Scraping |
selenium_scroll_iterations |
FI_SELENIUM_SCROLL_ITERATIONS |
int | 5 |
Scraping |
user_agent |
FI_USER_AGENT |
str | (Chrome 121 string) | Scraping |
reverse_search_max_results |
FI_REVERSE_SEARCH_MAX_RESULTS |
int | 20 |
Reverse |
serpapi_key |
FI_SERPAPI_KEY |
str | "" |
Reverse |
bing_api_key |
FI_BING_API_KEY |
str | "" |
Reverse |
tineye_public_key |
FI_TINEYE_PUBLIC_KEY |
str | "" |
Reverse |
tineye_private_key |
FI_TINEYE_PRIVATE_KEY |
str | "" |
Reverse |
orchestrator_timeout_seconds |
FI_ORCHESTRATOR_TIMEOUT_SECONDS |
float | 90.0 |
Orchestrator |
orchestrator_max_concurrency |
FI_ORCHESTRATOR_MAX_CONCURRENCY |
int | 8 |
Orchestrator |
retry_max_attempts |
FI_RETRY_MAX_ATTEMPTS |
int | 3 |
Orchestrator |
retry_initial_backoff_seconds |
FI_RETRY_INITIAL_BACKOFF_SECONDS |
float | 0.5 |
Orchestrator |
retry_max_backoff_seconds |
FI_RETRY_MAX_BACKOFF_SECONDS |
float | 8.0 |
Orchestrator |
cache_enabled |
FI_CACHE_ENABLED |
bool | True |
Cache |
cache_ttl_seconds |
FI_CACHE_TTL_SECONDS |
int | 3600 |
Cache |
cache_max_entries |
FI_CACHE_MAX_ENTRIES |
int | 1000 |
Cache |
health_check_interval_seconds |
FI_HEALTH_CHECK_INTERVAL_SECONDS |
int | 60 |
Health |
circuit_breaker_failure_threshold |
FI_CIRCUIT_BREAKER_FAILURE_THRESHOLD |
int | 5 |
Health |
circuit_breaker_recovery_seconds |
FI_CIRCUIT_BREAKER_RECOVERY_SECONDS |
int | 120 |
Health |
db_path |
FI_DB_PATH |
str | data/face_intel.db |
Storage |
audit_log_path |
FI_AUDIT_LOG_PATH |
str | data/audit.log |
Storage |
job_retention_days |
FI_JOB_RETENTION_DAYS |
int | 7 |
Storage |
rate_limit_per_minute |
FI_RATE_LIMIT_PER_MINUTE |
int | 30 |
API |
cors_origins |
FI_CORS_ORIGINS |
list[str] | ["*"] |
API |
require_consent_header |
FI_REQUIRE_CONSENT_HEADER |
bool | True |
API |
consent_header_name |
FI_CONSENT_HEADER_NAME |
str | "X-Consent-Statement" |
API |
max_image_bytes |
FI_MAX_IMAGE_BYTES |
int | 20971520 (20 MB) |
API |
job_timeout_seconds |
FI_JOB_TIMEOUT_SECONDS |
float | 300.0 |
API |
max_request_body_bytes |
FI_MAX_REQUEST_BODY_BYTES |
int | 26214400 (25 MB) |
API |
enable_image_quality |
FI_ENABLE_IMAGE_QUALITY |
bool | True |
New caps |
enable_image_properties |
FI_ENABLE_IMAGE_PROPERTIES |
bool | True |
New caps |
enable_visual_features |
FI_ENABLE_VISUAL_FEATURES |
bool | False |
New caps |
enable_exif |
FI_ENABLE_EXIF |
bool | True |
New caps |
enable_xmp |
FI_ENABLE_XMP |
bool | False |
New caps |
enable_image_integrity |
FI_ENABLE_IMAGE_INTEGRITY |
bool | True |
New caps |
enable_duplicate_detector |
FI_ENABLE_DUPLICATE_DETECTOR |
bool | True |
New caps |
enable_manipulation_analyzer |
FI_ENABLE_MANIPULATION_ANALYZER |
bool | False |
New caps |
log_level |
FI_LOG_LEVEL |
str | "INFO" |
Logging |
log_json |
FI_LOG_JSON |
bool | False |
Logging |
3. Core
| Setting | Env var | Type | Default | Description |
|---|---|---|---|---|
app_name |
FI_APP_NAME |
str | "Face Intel" |
Display name shown in OpenAPI title and / root. |
app_version |
FI_APP_VERSION |
str | "1.0.0" |
Version string exposed in /health/providers and OpenAPI. |
environment |
FI_ENVIRONMENT |
str | "development" |
Free-form label (development, staging, production, test). Currently informational only. |
host |
FI_HOST |
str | "0.0.0.0" |
Bind address for uvicorn.run() in app.py. |
port |
FI_PORT |
int | 8000 |
Bind port. |
debug |
FI_DEBUG |
bool | False |
If True, uvicorn runs with --reload (auto-restart on code changes). Never enable in production. |
Example
FI_ENVIRONMENT=production
FI_HOST=0.0.0.0
FI_PORT=8000
FI_DEBUG=false
4. Provider Enable Flags
Each provider has a enable_<name> flag. Default values follow this
rule:
- Default
Truefor providers that ship with the platform and have no external dependencies:haar,dnn,mtcnn,face_recognition,beautifulsoup_scraper,selenium_scraper,duckduckgo_scraper,google_lens. - Default
Falsefor providers that require paid API keys or heavy optional dependencies:retinaface,deepface,insightface,bing_scraper,serpapi,yandex,tineye.
| Setting | Env var | Default | Capability |
|---|---|---|---|
enable_haar |
FI_ENABLE_HAAR |
True |
detection |
enable_dnn |
FI_ENABLE_DNN |
True |
detection |
enable_mtcnn |
FI_ENABLE_MTCNN |
True |
detection |
enable_retinaface |
FI_ENABLE_RETINAFACE |
False |
detection |
enable_face_recognition |
FI_ENABLE_FACE_RECOGNITION |
True |
recognition |
enable_deepface |
FI_ENABLE_DEEPFACE |
False |
recognition |
enable_insightface |
FI_ENABLE_INSIGHTFACE |
False |
recognition |
enable_beautifulsoup_scraper |
FI_ENABLE_BEAUTIFULSOUP_SCRAPER |
True |
scraping |
enable_selenium_scraper |
FI_ENABLE_SELENIUM_SCRAPER |
True |
scraping |
enable_bing_scraper |
FI_ENABLE_BING_SCRAPER |
False |
scraping |
enable_duckduckgo_scraper |
FI_ENABLE_DUCKDUCKGO_SCRAPER |
True |
scraping |
enable_google_lens |
FI_ENABLE_GOOGLE_LENS |
True |
reverse_search |
enable_serpapi |
FI_ENABLE_SERPAPI |
False |
reverse_search |
enable_yandex |
FI_ENABLE_YANDEX |
False |
reverse_search |
enable_tineye |
FI_ENABLE_TINEYE |
False |
reverse_search |
Notes
- A flag set to
Truedoes not guarantee the provider ishealthyβ the provider'sis_available()may still returnFalseif an optional dependency is missing or an API key is not set. In that case it shows up asnot_configuredin/providers. - See Β§16 for the workflow.
5. Detection Tuning
| Setting | Env var | Type | Default | Description |
|---|---|---|---|---|
dnn_confidence_threshold |
FI_DNN_CONFIDENCE_THRESHOLD |
float | 0.7 |
Minimum confidence (0β1) for the DNN Caffe SSD detector to accept a detection. Lower = more faces (more false positives). |
mtcnn_min_face_size |
FI_MTCNN_MIN_FACE_SIZE |
int | 20 |
Minimum face size in pixels for MTCNN. Increase for speed on high-resolution images. |
haar_scale_factor |
FI_HAAR_SCALE_FACTOR |
float | 1.1 |
Scale factor for Haar Cascade multiscale detection. Lower = more thorough, slower. |
haar_min_neighbors |
FI_HAAR_MIN_NEIGHBORS |
int | 5 |
Min neighbors for Haar group rect merging. Higher = fewer detections, more confident. |
Example: tuning for accuracy
FI_DNN_CONFIDENCE_THRESHOLD=0.5
FI_MTCNN_MIN_FACE_SIZE=40
FI_HAAR_SCALE_FACTOR=1.05
FI_HAAR_MIN_NEIGHBORS=8
Example: tuning for speed
FI_DNN_CONFIDENCE_THRESHOLD=0.9
FI_MTCNN_MIN_FACE_SIZE=80
FI_HAAR_SCALE_FACTOR=1.3
FI_HAAR_MIN_NEIGHBORS=3
6. Recognition Tuning
| Setting | Env var | Type | Default | Description |
|---|---|---|---|---|
face_recognition_tolerance |
FI_FACE_RECOGNITION_TOLERANCE |
float | 0.6 |
dlib distance tolerance for face_recognition provider. Lower = stricter (fewer false positives). |
face_recognition_model |
FI_FACE_RECOGNITION_MODEL |
str | "hog" |
dlib model: "hog" (CPU, fast) or "cnn" (CUDA, accurate). |
deepface_backend |
FI_DEEPFACE_BACKEND |
str | "arcface" |
DeepFace backend: arcface, facenet, vggface, openface, etc. |
insightface_model_pack |
FI_INSIGHTFACE_MODEL_PACK |
str | "buffalo_l" |
InsightFace model pack name. |
recognition_match_threshold |
FI_RECOGNITION_MATCH_THRESHOLD |
float | 0.5 |
Generic similarity threshold for considering a face "matched". |
Example: stricter recognition
FI_FACE_RECOGNITION_TOLERANCE=0.4
FI_RECOGNITION_MATCH_THRESHOLD=0.65
7. Scraping
| Setting | Env var | Type | Default | Description |
|---|---|---|---|---|
scrape_timeout |
FI_SCRAPE_TIMEOUT |
int | 30 |
HTTP timeout in seconds for scraper requests. |
scrape_max_images |
FI_SCRAPE_MAX_IMAGES |
int | 50 |
Maximum images to extract from a single page. |
selenium_headless |
FI_SELENIUM_HEADLESS |
bool | True |
Run Chrome/Chromium headless. Set False for debugging. |
selenium_implicit_wait |
FI_SELENIUM_IMPLICIT_WAIT |
int | 10 |
Selenium implicit wait seconds. |
selenium_scroll_iterations |
FI_SELENIUM_SCROLL_ITERATIONS |
int | 5 |
Number of times to scroll the page (loads lazy images). |
user_agent |
FI_USER_AGENT |
str | (Chrome 121 string) | User-Agent header for HTTP requests and Selenium. |
Example: scraping authenticated intranet pages
FI_USER_AGENT="MyCorp Internal Bot/1.0 (contact: ops@mycorp.example)"
FI_SELENIUM_HEADLESS=true
FI_SELENIUM_IMPLICIT_WAIT=20
FI_SELENIUM_SCROLL_ITERATIONS=10
FI_SCRAPE_MAX_IMAGES=200
8. Reverse Image Search
| Setting | Env var | Type | Default | Description |
|---|---|---|---|---|
reverse_search_max_results |
FI_REVERSE_SEARCH_MAX_RESULTS |
int | 20 |
Max results to return per reverse-search provider. |
serpapi_key |
FI_SERPAPI_KEY |
str | "" |
SerpAPI API key. Required for serpapi provider to be available. |
bing_api_key |
FI_BING_API_KEY |
str | "" |
Bing Image Search API key. Required for bing scraper. |
tineye_public_key |
FI_TINEYE_PUBLIC_KEY |
str | "" |
TinEye OAuth public key. |
tineye_private_key |
FI_TINEYE_PRIVATE_KEY |
str | "" |
TinEye OAuth private key. |
Example: enabling SerpAPI
FI_ENABLE_SERPAPI=true
FI_SERPAPI_KEY=your_serpapi_key_here
FI_REVERSE_SEARCH_MAX_RESULTS=50
See Β§17 for the full key setup workflow.
9. Orchestrator
| Setting | Env var | Type | Default | Description |
|---|---|---|---|---|
orchestrator_timeout_seconds |
FI_ORCHESTRATOR_TIMEOUT_SECONDS |
float | 90.0 |
Per-provider hard timeout. If a single provider takes longer, the orchestrator cancels it and records a TimeoutError result. |
orchestrator_max_concurrency |
FI_ORCHESTRATOR_MAX_CONCURRENCY |
int | 8 |
Max number of providers to invoke concurrently. Lower this on memory-constrained hosts. |
retry_max_attempts |
FI_RETRY_MAX_ATTEMPTS |
int | 3 |
Max retry attempts per provider invocation (including the first). |
retry_initial_backoff_seconds |
FI_RETRY_INITIAL_BACKOFF_SECONDS |
float | 0.5 |
Initial backoff. Doubles each attempt up to retry_max_backoff_seconds, with full jitter. |
retry_max_backoff_seconds |
FI_RETRY_MAX_BACKOFF_SECONDS |
float | 8.0 |
Upper bound on backoff delay. |
Retriable exceptions
Only TimeoutError, ConnectionError, and OSError are retried.
Other exceptions (e.g. RuntimeError from a bad API response) are
not retried β see docs/PROVIDERS.md Β§10
for how to convert transient errors into retriable ones.
Example: aggressive retry for flaky networks
FI_RETRY_MAX_ATTEMPTS=5
FI_RETRY_INITIAL_BACKOFF_SECONDS=1.0
FI_RETRY_MAX_BACKOFF_SECONDS=30.0
FI_ORCHESTRATOR_TIMEOUT_SECONDS=180
FI_ORCHESTRATOR_MAX_CONCURRENCY=4
Example: fast-fail for low-latency APIs
FI_RETRY_MAX_ATTEMPTS=1
FI_ORCHESTRATOR_TIMEOUT_SECONDS=15
FI_ORCHESTRATOR_MAX_CONCURRENCY=16
10. Cache
The cache stores successful ProviderResult objects keyed by
f"{provider_name}:{image_hash}". On a cache hit, the provider is
not invoked β the cached result is returned (with metadata.cache_hit=True).
| Setting | Env var | Type | Default | Description |
|---|---|---|---|---|
cache_enabled |
FI_CACHE_ENABLED |
bool | True |
Master switch. Set False to disable cache entirely (every request invokes providers). |
cache_ttl_seconds |
FI_CACHE_TTL_SECONDS |
int | 3600 |
Time-to-live for cache entries (seconds). Entries expire even if not evicted by LRU. |
cache_max_entries |
FI_CACHE_MAX_ENTRIES |
int | 1000 |
Maximum entries. When exceeded, the oldest entry is evicted (LRU). |
Cache eviction
Two policies compose:
- TTL:
cache_ttl_secondsafterset(), the entry expires. - LRU: when adding a new entry would exceed
cache_max_entries, the least-recently-accessed entry is evicted. Eviction counter is exposed inGET /cacheasevictions.
Example: development (always-fresh)
FI_CACHE_ENABLED=false
Example: high-throughput production
FI_CACHE_ENABLED=true
FI_CACHE_TTL_SECONDS=86400
FI_CACHE_MAX_ENTRIES=10000
Inspecting the cache
curl http://localhost:8000/cache
curl -X DELETE http://localhost:8000/cache
See docs/API_REFERENCE.md Β§9.
11. Health & Circuit Breaker
| Setting | Env var | Type | Default | Description |
|---|---|---|---|---|
health_check_interval_seconds |
FI_HEALTH_CHECK_INTERVAL_SECONDS |
int | 60 |
Reserved for future background health polling (currently informational). |
circuit_breaker_failure_threshold |
FI_CIRCUIT_BREAKER_FAILURE_THRESHOLD |
int | 5 |
Consecutive failures before the circuit opens for a provider. |
circuit_breaker_recovery_seconds |
FI_CIRCUIT_BREAKER_RECOVERY_SECONDS |
int | 120 |
Seconds before an open circuit transitions to half-open (allows one trial call). |
Circuit breaker lifecycle
- Provider fails β
consecutive_failures += 1. - When
consecutive_failures >= circuit_breaker_failure_threshold, the circuit opens and the orchestrator skips this provider. - After
circuit_breaker_recovery_secondselapses, the circuit transitions to half-open: the next request is allowed through. - If the trial call succeeds, the circuit closes and
consecutive_failuresresets to 0. - If the trial call fails, the circuit re-opens for another recovery window.
Example: aggressive failover
FI_CIRCUIT_BREAKER_FAILURE_THRESHOLD=3
FI_CIRCUIT_BREAKER_RECOVERY_SECONDS=30
Example: tolerant of transient blips
FI_CIRCUIT_BREAKER_FAILURE_THRESHOLD=10
FI_CIRCUIT_BREAKER_RECOVERY_SECONDS=300
Inspecting circuit state
curl http://localhost:8000/health/providers | jq '.providers[] | {name, circuit_open, consecutive_failures}'
12. Storage
| Setting | Env var | Type | Default | Description |
|---|---|---|---|---|
db_path |
FI_DB_PATH |
str | data/face_intel.db |
SQLite database path. Use :memory: for in-memory (tests). |
audit_log_path |
FI_AUDIT_LOG_PATH |
str | data/audit.log |
JSONL audit log path. Appended to on sensitive operations. |
job_retention_days |
FI_JOB_RETENTION_DAYS |
int | 7 |
Days to keep completed jobs. Older jobs are deleted by Database.cleanup_old_jobs() (call from a cron/scheduler). |
Storage directory layout
The settings module auto-creates these directories on import:
data/
βββ face_intel.db # SQLite database (jobs, results)
βββ audit.log # JSONL audit trail
βββ models/ # Auto-downloaded model files (DNN Caffe, etc.)
βββ gallery/ # Known-faces reference store
β βββ manifest.json
β βββ alice_0.npy # Per-person embeddings
βββ uploads/ # Source images saved by ArtifactStore
βββ generated/ # Annotated images, montages
Example: production paths
FI_DB_PATH=/var/lib/face-intel/face_intel.db
FI_AUDIT_LOG_PATH=/var/log/face-intel/audit.log
FI_JOB_RETENTION_DAYS=30
Example: tests (in-memory)
make_settings(db_path=":memory:")
13. API
| Setting | Env var | Type | Default | Description |
|---|---|---|---|---|
rate_limit_per_minute |
FI_RATE_LIMIT_PER_MINUTE |
int | 30 |
Max requests per client IP per 60s sliding window. /health/* is excluded. |
cors_origins |
FI_CORS_ORIGINS |
list[str] | ["*"] |
Allowed CORS origins. Comma-separated in env: FI_CORS_ORIGINS=["https://app.example.com","https://admin.example.com"]. |
require_consent_header |
FI_REQUIRE_CONSENT_HEADER |
bool | True |
Whether consent is required (currently informational β enforce at your gateway). |
consent_header_name |
FI_CONSENT_HEADER_NAME |
str | "X-Consent-Statement" |
Header name to look for. |
max_image_bytes |
FI_MAX_IMAGE_BYTES |
int | 20971520 (20 MB) |
Max decoded image size, enforced by InputValidator. |
job_timeout_seconds |
FI_JOB_TIMEOUT_SECONDS |
float | 300.0 |
Overall job timeout. A job exceeding this is marked timeout. |
max_request_body_bytes |
FI_MAX_REQUEST_BODY_BYTES |
int | 26214400 (25 MB) |
Hard HTTP body cap. Returns 413 if exceeded. |
Example: locked-down production
FI_RATE_LIMIT_PER_MINUTE=120
FI_CORS_ORIGINS=["https://app.example.com"]
FI_REQUIRE_CONSENT_HEADER=true
FI_MAX_IMAGE_BYTES=10485760
FI_JOB_TIMEOUT_SECONDS=60
FI_MAX_REQUEST_BODY_BYTES=12582912
Example: permissive development
FI_RATE_LIMIT_PER_MINUTE=10000
FI_CORS_ORIGINS=["*"]
FI_REQUIRE_CONSENT_HEADER=false
FI_DEBUG=true
14. New-Capability Enable Flags
These enable flags cover the non-detection/recognition capabilities added in Phase 4+.
| Setting | Env var | Type | Default | Capability |
|---|---|---|---|---|
enable_image_quality |
FI_ENABLE_IMAGE_QUALITY |
bool | True |
image_analysis |
enable_image_properties |
FI_ENABLE_IMAGE_PROPERTIES |
bool | True |
image_analysis |
enable_visual_features |
FI_ENABLE_VISUAL_FEATURES |
bool | False |
image_analysis |
enable_exif |
FI_ENABLE_EXIF |
bool | True |
metadata |
enable_xmp |
FI_ENABLE_XMP |
bool | False |
metadata |
enable_image_integrity |
FI_ENABLE_IMAGE_INTEGRITY |
bool | True |
forensics |
enable_duplicate_detector |
FI_ENABLE_DUPLICATE_DETECTOR |
bool | True |
forensics |
enable_manipulation_analyzer |
FI_ENABLE_MANIPULATION_ANALYZER |
bool | False |
forensics |
15. Logging
| Setting | Env var | Type | Default | Description |
|---|---|---|---|---|
log_level |
FI_LOG_LEVEL |
str | "INFO" |
Loguru level: TRACE, DEBUG, INFO, WARNING, ERROR, CRITICAL. |
log_json |
FI_LOG_JSON |
bool | False |
Emit newline-delimited JSON for log aggregators (Loki, Datadog, CloudWatch). |
Log format
Default (human-readable):
2026-07-10 14:30:00.123 | INFO | eid=abc123def456 | pid=haar | retry=0 | status=started | invoking haar
JSON mode (FI_LOG_JSON=true):
{"timestamp":"2026-07-10T14:30:00.123Z","level":"INFO","execution_id":"abc123def456","provider_id":"haar","retry_count":0,"status":"started","message":"invoking haar"}
Every log line inside an execution carries eid (execution id),
pid (provider id), retry, and status fields. See
docs/ARCHITECTURE.md Β§7 for details.
Example: production JSON logging
FI_LOG_LEVEL=INFO
FI_LOG_JSON=true
Example: debug verbosity
FI_LOG_LEVEL=DEBUG
FI_LOG_JSON=false
16. How to Enable/Disable Providers
Workflow
- Edit
.env(or set the env var directly). - Set
FI_ENABLE_<NAME>=true(orfalse). - Restart the server.
- Verify via
GET /providers.
Example: enable dnn + mtcnn, disable haar
FI_ENABLE_HAAR=false
FI_ENABLE_DNN=true
FI_ENABLE_MTCNN=true
Restart and check:
curl -s http://localhost:8000/providers | jq '.providers[] | {name, status}'
What "disabled" vs "not_configured" means
| Status | Cause |
|---|---|
disabled |
enable_<name> = False in settings. The provider class is never even imported. |
not_configured |
enable_<name> = True but the optional dependency is missing OR is_available() returned False (e.g. API key not set). |
healthy |
Enabled, instantiated, is_available() == True. |
Disabling vs uninstalling
Disabling a provider via enable_<name>=False is enough β the
provider class won't be imported, so even broken optional
dependencies won't break startup. You don't need to uninstall the
package.
17. How to Configure API Keys
SerpAPI (Google Reverse Image Search)
- Sign up at https://serpapi.com/.
- Get your API key from the dashboard.
- Set in
.env:
FI_ENABLE_SERPAPI=true
FI_SERPAPI_KEY=your_key_here
- Restart and verify:
curl -s http://localhost:8000/providers/serpapi | jq '.available'
# β true
Bing Image Search API
- Provision a Bing Search v7 resource in Azure.
- Get the API key from "Keys and Endpoint".
- Set in
.env:
FI_ENABLE_BING_SCRAPER=true
FI_BING_API_KEY=your_key_here
TinEye (OAuth)
TinEye uses public/private keypair authentication.
- Sign up at https://tineye.com/developers.
- Generate a keypair.
- Set in
.env:
FI_ENABLE_TINEYE=true
FI_TINEYE_PUBLIC_KEY=your_public_key
FI_TINEYE_PRIVATE_KEY=your_private_key
Secret management
For production, do not store API keys in .env. Use your
orchestrator's secret store:
- Kubernetes:
Secretmounted as env vars. - AWS: Secrets Manager + entrypoint script that fetches and exports.
- HashiCorp Vault:
vault kv getin the entrypoint.
The platform reads keys from env vars only β it doesn't care how they got there.
18. Production vs Development
Development profile
.env.dev:
FI_ENVIRONMENT=development
FI_DEBUG=true
FI_LOG_LEVEL=DEBUG
FI_LOG_JSON=false
FI_RATE_LIMIT_PER_MINUTE=10000
FI_CORS_ORIGINS=["*"]
FI_REQUIRE_CONSENT_HEADER=false
FI_CACHE_ENABLED=false
FI_DB_PATH=data/face_intel.dev.db
# Enable most providers for testing
FI_ENABLE_HAAR=true
FI_ENABLE_DNN=true
FI_ENABLE_MTCNN=true
FI_ENABLE_FACE_RECOGNITION=true
FI_ENABLE_BEAUTIFULSOUP_SCRAPER=true
FI_ENABLE_SELENIUM_SCRAPER=true
FI_ENABLE_DUCKDUCKGO_SCRAPER=true
FI_ENABLE_GOOGLE_LENS=true
FI_ENABLE_IMAGE_QUALITY=true
FI_ENABLE_IMAGE_PROPERTIES=true
FI_ENABLE_EXIF=true
FI_ENABLE_IMAGE_INTEGRITY=true
FI_ENABLE_DUPLICATE_DETECTOR=true
# Disable paid/heavy providers
FI_ENABLE_RETINAFACE=false
FI_ENABLE_DEEPFACE=false
FI_ENABLE_INSIGHTFACE=false
FI_ENABLE_BING_SCRAPER=false
FI_ENABLE_SERPAPI=false
FI_ENABLE_YANDEX=false
FI_ENABLE_TINEYE=false
FI_ENABLE_VISUAL_FEATURES=false
FI_ENABLE_XMP=false
FI_ENABLE_MANIPULATION_ANALYZER=false
Run with:
cp .env.dev .env
python app.py
Production profile
.env.prod:
FI_ENVIRONMENT=production
FI_DEBUG=false
FI_LOG_LEVEL=INFO
FI_LOG_JSON=true
FI_RATE_LIMIT_PER_MINUTE=120
FI_CORS_ORIGINS=["https://app.example.com"]
FI_REQUIRE_CONSENT_HEADER=true
FI_CACHE_ENABLED=true
FI_CACHE_TTL_SECONDS=86400
FI_CACHE_MAX_ENTRIES=10000
FI_DB_PATH=/var/lib/face-intel/face_intel.db
FI_AUDIT_LOG_PATH=/var/log/face-intel/audit.log
FI_JOB_RETENTION_DAYS=30
FI_JOB_TIMEOUT_SECONDS=120
FI_MAX_IMAGE_BYTES=10485760
FI_MAX_REQUEST_BODY_BYTES=12582912
# Circuit breaker β aggressive failover
FI_CIRCUIT_BREAKER_FAILURE_THRESHOLD=3
FI_CIRCUIT_BREAKER_RECOVERY_SECONDS=60
# Orchestrator
FI_ORCHESTRATOR_TIMEOUT_SECONDS=60
FI_ORCHESTRATOR_MAX_CONCURRENCY=16
FI_RETRY_MAX_ATTEMPTS=3
FI_RETRY_INITIAL_BACKOFF_SECONDS=1.0
FI_RETRY_MAX_BACKOFF_SECONDS=15.0
# Providers β only the ones you've validated
FI_ENABLE_HAAR=true
FI_ENABLE_DNN=true
FI_ENABLE_FACE_RECOGNITION=true
FI_ENABLE_IMAGE_QUALITY=true
FI_ENABLE_IMAGE_PROPERTIES=true
FI_ENABLE_EXIF=true
FI_ENABLE_IMAGE_INTEGRITY=true
FI_ENABLE_DUPLICATE_DETECTOR=true
# Disable everything else
FI_ENABLE_MTCNN=false
FI_ENABLE_RETINAFACE=false
FI_ENABLE_DEEPFACE=false
FI_ENABLE_INSIGHTFACE=false
FI_ENABLE_BEAUTIFULSOUP_SCRAPER=false
FI_ENABLE_SELENIUM_SCRAPER=false
FI_ENABLE_BING_SCRAPER=false
FI_ENABLE_DUCKDUCKGO_SCRAPER=false
FI_ENABLE_GOOGLE_LENS=false
FI_ENABLE_SERPAPI=false
FI_ENABLE_YANDEX=false
FI_ENABLE_TINEYE=false
FI_ENABLE_VISUAL_FEATURES=false
FI_ENABLE_XMP=false
FI_ENABLE_MANIPULATION_ANALYZER=false
Test profile (used by tests/conftest.py)
Settings(
environment="test",
enable_dnn=False,
enable_mtcnn=False,
# ... all optional providers disabled ...
enable_visual_features=False,
enable_xmp=False,
enable_manipulation_analyzer=False,
db_path=":memory:",
cache_enabled=False,
rate_limit_per_minute=10000,
)
This keeps tests fast and deterministic β only pure-OpenCV providers
(haar, image_quality, image_properties, exif,
image_integrity, duplicate_detector) are enabled.
19. Verifying Your Configuration
1. Check the loaded settings
python -c "from config.settings import settings; print(settings.model_dump_json(indent=2))"
2. Check provider status
curl -s http://localhost:8000/providers | jq '.providers[] | {name, status, available}'
Expected output:
{"name": "haar", "status": "healthy", "available": true}
{"name": "dnn", "status": "healthy", "available": true}
{"name": "retinaface", "status": "disabled", "available": false}
{"name": "insightface", "status": "not_configured", "available": false}
3. Check manifest errors
curl -s http://localhost:8000/providers | jq '.errors'
If errors is non-empty, those providers failed to instantiate (e.g.
missing optional dependency):
{
"insightface": "missing dependency: No module named 'insightface'"
}
4. Check health
curl -s http://localhost:8000/health/providers | jq '.status'
# β "healthy" or "degraded"
5. Check stats
curl -s http://localhost:8000/stats | jq '.counters'
See Also
docs/API_REFERENCE.mdβ what each setting affects at the API level.docs/PROVIDERS.mdβ how to add new enable flags.docs/DEPLOYMENT.mdβ running in Docker / Kubernetes, env-var injection.docs/TROUBLESHOOTING.mdβ diagnosing misconfigured providers.