Sub / app /config.py
Himankpro's picture
Upload 93 files
3a6c182 verified
Raw History Blame Contribute Delete
5.86 kB
"""
配置管理
统一从项目根目录的 .env 文件加载配置
"""
import os
from dotenv import load_dotenv
# 加载项目根目录的 .env 文件
# 路径: MiroFish/.env (相对于 backend/app/config.py)
project_root_env = os.path.join(os.path.dirname(__file__), '../../.env')
if os.path.exists(project_root_env):
load_dotenv(project_root_env, override=True)
else:
# 如果根目录没有 .env,尝试加载环境变量(用于生产环境)
load_dotenv(override=True)
class Config:
"""Flask配置类"""
# Flask配置
SECRET_KEY = os.environ.get('SECRET_KEY', 'mirofish-secret-key')
DEBUG = os.environ.get('FLASK_DEBUG', 'True').lower() == 'true'
# JSON配置 - 禁用ASCII转义,让中文直接显示(而不是 \uXXXX 格式)
JSON_AS_ASCII = False
# LLM(OpenAI 兼容)。优先使用 LLM_1 / LLM_2,避免逗号拼接误配
LLM_1 = os.environ.get("LLM_1", "").strip()
LLM_2 = os.environ.get("LLM_2", "").strip()
LLM_API_KEY = os.environ.get('LLM_API_KEY')
LLM_BASE_URL = os.environ.get('LLM_BASE_URL', 'https://api.openai.com/v1')
LLM_MODEL_NAME = os.environ.get('LLM_MODEL_NAME', 'gpt-4o-mini')
# Zep:优先 ZEP_1 / ZEP_2
ZEP_1 = os.environ.get("ZEP_1", "").strip()
ZEP_2 = os.environ.get("ZEP_2", "").strip()
ZEP_API_KEY = os.environ.get('ZEP_API_KEY')
@classmethod
def get_zep_api_keys(cls):
keys = [k for k in (cls.ZEP_1, cls.ZEP_2) if k]
if keys:
return keys
raw = (cls.ZEP_API_KEY or "").strip()
if not raw:
return []
if "," in raw:
return [k.strip() for k in raw.split(",") if k.strip()]
return [raw]
@classmethod
def get_llm_api_keys(cls):
keys = [k for k in (cls.LLM_1, cls.LLM_2) if k]
if keys:
return keys
raw = (cls.LLM_API_KEY or "").strip()
if not raw:
return []
if "," in raw:
return [k.strip() for k in raw.split(",") if k.strip()]
return [raw]
# Razorpay + simulation unlock (website)
RAZORPAY_KEY_ID = os.environ.get("RAZORPAY_KEY_ID", "").strip()
RAZORPAY_KEY_SECRET = os.environ.get("RAZORPAY_KEY_SECRET", "").strip()
RAZORPAY_AMOUNT_PAISE = int(os.environ.get("RAZORPAY_AMOUNT_PAISE", "49900"))
RAZORPAY_CURRENCY = os.environ.get("RAZORPAY_CURRENCY", "INR").strip() or "INR"
PAYMENT_COUPON_CODES = os.environ.get("PAYMENT_COUPON_CODES", "").strip()
PAYMENT_JWT_SECRET = os.environ.get("PAYMENT_JWT_SECRET", "").strip()
@classmethod
def payment_coupon_set(cls):
if not cls.PAYMENT_COUPON_CODES:
return set()
return {c.strip().lower() for c in cls.PAYMENT_COUPON_CODES.split(",") if c.strip()}
@classmethod
def billing_enabled(cls) -> bool:
razorpay_ok = bool(cls.RAZORPAY_KEY_ID and cls.RAZORPAY_KEY_SECRET)
return razorpay_ok or bool(cls.payment_coupon_set())
@classmethod
def payment_signing_secret(cls) -> str:
return (cls.PAYMENT_JWT_SECRET or cls.PIPELINE_CLIENT_SECRET or cls.SECRET_KEY or "mirofish-pay").strip()
# 文件上传配置
MAX_CONTENT_LENGTH = 50 * 1024 * 1024 # 50MB
UPLOAD_FOLDER = os.path.join(os.path.dirname(__file__), '../uploads')
ALLOWED_EXTENSIONS = {'pdf', 'md', 'txt', 'markdown'}
# 文本处理配置
DEFAULT_CHUNK_SIZE = 500 # 默认切块大小
DEFAULT_CHUNK_OVERLAP = 50 # 默认重叠大小
# OASIS模拟配置
OASIS_DEFAULT_MAX_ROUNDS = int(os.environ.get('OASIS_DEFAULT_MAX_ROUNDS', '10'))
OASIS_SIMULATION_DATA_DIR = os.path.join(os.path.dirname(__file__), '../uploads/simulations')
# OASIS平台可用动作配置
OASIS_TWITTER_ACTIONS = [
'CREATE_POST', 'LIKE_POST', 'REPOST', 'FOLLOW', 'DO_NOTHING', 'QUOTE_POST'
]
OASIS_REDDIT_ACTIONS = [
'LIKE_POST', 'DISLIKE_POST', 'CREATE_POST', 'CREATE_COMMENT',
'LIKE_COMMENT', 'DISLIKE_COMMENT', 'SEARCH_POSTS', 'SEARCH_USER',
'TREND', 'REFRESH', 'DO_NOTHING', 'FOLLOW', 'MUTE'
]
# 全自动流水线(website → /api/pipeline/start)
PIPELINE_MAX_ROUNDS = os.environ.get('PIPELINE_MAX_ROUNDS') # optional cap on OASIS rounds
PIPELINE_PARALLEL_PROFILES = int(os.environ.get('PIPELINE_PARALLEL_PROFILES', '5'))
# Supabase: report storage + simulation_runs table (free tier friendly)
SUPABASE_URL = os.environ.get('SUPABASE_URL', '').rstrip('/')
SUPABASE_SERVICE_ROLE_KEY = os.environ.get('SUPABASE_SERVICE_ROLE_KEY', '')
# Project Settings → API → JWT Secret (verify user access tokens from the website)
SUPABASE_JWT_SECRET = os.environ.get('SUPABASE_JWT_SECRET', '')
SUPABASE_REPORTS_BUCKET = os.environ.get('SUPABASE_REPORTS_BUCKET', 'reports')
# Optional: signing secret for legacy MiroFish Bearer JWTs. Defaults to SECRET_KEY.
MIROFISH_SESSION_JWT_SECRET = os.environ.get('MIROFISH_SESSION_JWT_SECRET', '').strip()
# Same value as website VITE_PIPELINE_CLIENT_SECRET (browser sends X-Mirofish-User-Id + X-Pipeline-Client-Secret).
PIPELINE_CLIENT_SECRET = os.environ.get('PIPELINE_CLIENT_SECRET', '').strip()
# Report Agent配置
REPORT_AGENT_MAX_TOOL_CALLS = int(os.environ.get('REPORT_AGENT_MAX_TOOL_CALLS', '5'))
REPORT_AGENT_MAX_REFLECTION_ROUNDS = int(os.environ.get('REPORT_AGENT_MAX_REFLECTION_ROUNDS', '2'))
REPORT_AGENT_TEMPERATURE = float(os.environ.get('REPORT_AGENT_TEMPERATURE', '0.5'))
@classmethod
def validate(cls):
"""验证必要配置"""
errors = []
if not cls.get_llm_api_keys():
errors.append("LLM_1 / LLM_2 or LLM_API_KEY 未配置")
if not cls.get_zep_api_keys():
errors.append("ZEP_1 / ZEP_2 or ZEP_API_KEY 未配置")
return errors