music on atproto
plyr.fm
1//! Configuration loading from environment variables.
2
3use anyhow::anyhow;
4use std::env;
5
6/// Service configuration loaded from environment.
7pub struct Config {
8 pub host: String,
9 pub port: u16,
10 pub auth_token: Option<String>,
11 pub audd_api_token: String,
12 pub audd_api_url: String,
13 pub database_url: Option<String>,
14 pub labeler_did: Option<String>,
15 pub labeler_signing_key: Option<String>,
16 /// Anthropic API key for Claude image moderation
17 pub claude_api_key: Option<String>,
18 /// Claude model to use (default: claude-sonnet-4-5-20250929)
19 pub claude_model: String,
20 /// Minimum AuDD score to flag as potential copyright violation (default: 85)
21 pub copyright_score_threshold: i32,
22}
23
24impl Config {
25 /// Load configuration from environment variables.
26 pub fn from_env() -> anyhow::Result<Self> {
27 Ok(Self {
28 host: env::var("MODERATION_HOST").unwrap_or_else(|_| "0.0.0.0".to_string()),
29 port: env::var("MODERATION_PORT")
30 .ok()
31 .and_then(|v| v.parse().ok())
32 .unwrap_or(8083),
33 auth_token: env::var("MODERATION_AUTH_TOKEN").ok(),
34 audd_api_token: env::var("MODERATION_AUDD_API_TOKEN")
35 .map_err(|_| anyhow!("MODERATION_AUDD_API_TOKEN is required"))?,
36 audd_api_url: env::var("MODERATION_AUDD_API_URL")
37 .unwrap_or_else(|_| "https://enterprise.audd.io/".to_string()),
38 database_url: env::var("MODERATION_DATABASE_URL").ok(),
39 labeler_did: env::var("MODERATION_LABELER_DID").ok(),
40 labeler_signing_key: env::var("MODERATION_LABELER_SIGNING_KEY").ok(),
41 claude_api_key: env::var("ANTHROPIC_API_KEY").ok(),
42 claude_model: env::var("MODERATION_CLAUDE_MODEL")
43 .unwrap_or_else(|_| "claude-sonnet-4-5-20250929".to_string()),
44 copyright_score_threshold: env::var("MODERATION_COPYRIGHT_SCORE_THRESHOLD")
45 .ok()
46 .and_then(|v| v.parse().ok())
47 .unwrap_or(85),
48 })
49 }
50
51 /// Check if Claude image moderation is enabled.
52 pub fn claude_enabled(&self) -> bool {
53 self.claude_api_key.is_some() && self.database_url.is_some()
54 }
55
56 /// Check if labeler is fully configured.
57 pub fn labeler_enabled(&self) -> bool {
58 self.database_url.is_some()
59 && self.labeler_did.is_some()
60 && self.labeler_signing_key.is_some()
61 }
62}