Files
hack/tools/scripts/llm-key-hunter/results/_cache/content/1832094726_autogensurvey-based-on-aeg.json

1 line
75 KiB
JSON
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{"repo": "1832094726/autogensurvey-based-on-aeg", "files": {"app/config.py": {"9f9d4dc37fc2d5ebd9bd167570fdafba22f88fcc": {"t": 1785674240.8571215, "n": 13064, "h": "ce277b586fcd2a1b", "c": "import os\nimport json\n\nclass Config:\n \"\"\"基础配置类\"\"\"\n # 环境配置\n ENV = os.getenv('ENV', 'development') # 默认为开发环境\n DEBUG = ENV == 'development' # 在开发环境中启用调试\n LOG_LEVEL = os.getenv('LOG_LEVEL', 'INFO') # 日志级别\n \n # 项目路径\n BASE_DIR = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))\n \n # 数据库配置\n DATABASE_PATH = os.path.join('./data', 'db', 'algknowledge.db') # SQLite数据库路径\n \n # 上传文件配置\n UPLOAD_FOLDER = os.path.join('./data', 'uploads') # 文件上传目录\n TEMP_FOLDER = os.path.join('./data', 'temp')\n ALLOWED_EXTENSIONS = {'pdf', 'txt', 'csv', 'xlsx', 'json'} # 允许上传的文件类型\n MAX_CONTENT_LENGTH = 100 * 1024 * 1024 # 最大文件上传大小(100MB)\n \n # 缓存配置\n CACHE_DIR = os.path.join('./data', 'cache') # 缓存目录\n CACHE_MAX_SIZE = 500 * 1024 * 1024 # 缓存目录最大大小限制(500MB)\n CACHE_CHECK_INTERVAL = 86400 # 缓存检查间隔(秒),默认为1天\n CACHE_MAX_AGE = 30 * 86400 # 缓存文件最大保存时间(秒),默认为30天\n \n # API配置\n API_PREFIX = '/api/v1' # API前缀\n DISABLE_AI = os.environ.get('DISABLE_AI', 'False').lower() == 'true' # 是否禁用AI功能\n # 安全配置\n SECRET_KEY = os.getenv('SECRET_KEY', 'dev_secret_key') # 密钥\n SECURITY_PASSWORD_SALT = os.getenv('SECURITY_PASSWORD_SALT', 'dev_password_salt') # 密码盐值\n \n # 模型配置\n QWEN_API_KEY = os.getenv('QWEN_API_KEY', 'sk-') # 千问API密钥\n QWEN_BASE_URL = os.getenv('QWEN_BASE_URL', 'https://dashscope.aliyuncs.com/compatible-mode/v1')\n QWEN_MODEL = os.getenv('QWEN_MODEL', 'qwen-long') # 千问模型\n DEFAULT_MODEL = os.environ.get('DEFAULT_MODEL', 'gpt-4.1-mini') # 默认使用GPT模型进行PDF提取\n \n # 新增模型API密钥配置(统一使用shubiaobiao)\n ANTHROPIC_API_KEY = os.environ.get('ANTHROPIC_API_KEY', 'sk-') # Claude API密钥\n OPENAI_API_KEY = os.environ.get('OPENAI_API_KEY', 'sk-') # OpenAI API密钥\n GEMINI_API_KEY = os.environ.get('GEMINI_API_KEY', 'sk-') # Gemini API密钥\n DEEPSEEK_API_KEY = os.environ.get('DEEPSEEK_API_KEY', 'sk-') # DeepSeek API密钥\n\n # 模型基础URL配置(统一使用shubiaobiao)\n ANTHROPIC_BASE_URL = os.environ.get('ANTHROPIC_BASE_URL', 'https://api.shubiaobiao.cn/v1/')\n OPENAI_BASE_URL = os.environ.get('OPENAI_BASE_URL', 'https://api.shubiaobiao.cn/v1/')\n GEMINI_BASE_URL = os.environ.get('GEMINI_BASE_URL', 'https://api.shubiaobiao.cn/v1/')\n DEEPSEEK_BASE_URL = os.environ.get('DEEPSEEK_BASE_URL', 'https://api.shubiaobiao.cn/v1/')\n \n # JSON响应大小限制配置\n MAX_JSON_RESPONSE_SIZE = 8192000 # 最大JSON响应大小(字符数)\n \n # 处理并发配置\n MAX_WORKERS = 40 # 最大工作线程数\n\n # 重试配置\n MAX_RETRY_ATTEMPTS = 3 # 最大重试次数\n RETRY_DELAY = 5 # 重试延迟(秒)\n \n # 算法处理配置\n ALGORITHM_BATCH_SIZE = 10 # 每批处理的算法数量\n \n # 基础配置\n TESTING = False\n SECRET_KEY = os.environ.get('SECRET_KEY', 'dev-key')\n \n # 文件路径配置\n ROOT_DIR = os.path.dirname(BASE_DIR)\n UPLOAD_DIR = os.path.join('./data', 'pdfs') # 上传PDF文件存储目录\n OUTPUT_FOLDER = os.path.join('./data') # 输出文件夹\n GRAPH_DATA_DIR = os.path.join('./data', 'graph') # 图数据存储目录\n LOG_DIR = os.path.join('./data', 'logs') # 日志存储目录\n CITED_PAPERS_DIR = os.path.join('./data', 'cited_papers') # 引用文献存储目录\n \n # 数据库配置 - 只使用MySQL\n DB_TYPE = 'mysql' # 固定为MySQL\n \n # MySQL配置\n MYSQL_HOST = os.environ.get('MYSQL_HOST', 'localhost')\n MYSQL_PORT = int(os.environ.get('MYSQL_PORT', 3306))\n MYSQL_USER = os.environ.get('MYSQL_USER', 'root')\n MYSQL_PASSWORD = os.environ.get('MYSQL_PASSWORD', '123456')\n MYSQL_DB = os.environ.get('MYSQL_DB', 'algorithm_evolution')\n\n # 新添加的OpenAI API相关配置\n OPENAI_MODEL = os.environ.get('OPENAI_MODEL', 'gpt-3.5-turbo')\n\n @classmethod\n def init_app(cls, app):\n \"\"\"初始化应用程序配置\"\"\"\n # 确保必要的目录存在\n os.makedirs(cls.UPLOAD_FOLDER, exist_ok=True)\n os.makedirs(cls.CACHE_DIR, exist_ok=True)\n os.makedirs(os.path.dirname(cls.DATABASE_PATH), exist_ok=True)\n \n # 配置日志\n import logging\n logging.basicConfig(\n level=getattr(logging, cls.LOG_LEVEL),\n format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'\n )\n \n # 定期清理过期缓存\n if not cls.DEBUG: # 在非开发环境中启用定期清理\n cls._schedule_cache_cleanup()\n \n @classmethod\n def _schedule_cache_cleanup(cls):\n \"\"\"安排定期清理缓存任务\"\"\"\n import threading\n import time\n \n def cleanup_task():\n while True:\n try:\n cls._clean_cache()\n time.sleep(cls.CACHE_CHECK_INTERVAL)\n except Exception as e:\n import logging\n logging.error(f\"缓存清理失败: {str(e)}\")\n # 发生错误时延迟一小时后重试\n time.sleep(3600)\n \n # 启动清理线程\n cleanup_thread = threading.Thread(target=cleanup_task, daemon=True)\n cleanup_thread.start()\n \n @classmethod\n def _clean_cache(cls):\n \"\"\"清理过期和超大缓存文件\"\"\"\n import logging\n import time\n import os\n \n try:\n now = time.time()\n total_size = 0\n files_info = []\n \n # 收集所有缓存文件信息\n for file_name in os.listdir(cls.CACHE_DIR):\n file_path = os.path.join(cls.CACHE_DIR, file_name)\n if os.path.isfile(file_path):\n stats = os.stat(file_path)\n total_size += stats.st_size\n files_info.append({\n 'path': file_path,\n 'size': stats.st_size,\n 'mtime': stats.st_mtime,\n 'atime': stats.st_atime\n })\n \n # 如果缓存总大小超过限制,则按访问时间排序删除最旧的文件\n if total_size > cls.CACHE_MAX_SIZE:\n logging.info(f\"缓存总大小 ({total_size / 1024 / 1024:.2f} MB) 超过限制 ({cls.CACHE_MAX_SIZE / 1024 / 1024:.2f} MB),开始清理...\")\n # 按访问时间排序,最旧的在前面\n files_info.sort(key=lambda x: x['atime'])\n \n # 删除最旧的文件,直到缓存大小低于限制\n for file_info in files_info:\n if total_size <= cls.CACHE_MAX_SIZE * 0.9: # 保留10%的缓冲区\n break\n \n try:\n os.remove(file_info['path'])\n total_size -= file_info['size']\n logging.info(f\"删除旧缓存文件: {file_info['path']} ({file_info['size'] / 1024 / 1024:.2f} MB)\")\n except Exception as e:\n logging.error(f\"删除缓存文件失败: {file_info['path']}, 错误: {str(e)}\")\n \n # 删除超过最大保存时间的文件\n for file_info in files_info:\n if now - file_info['mtime'] > cls.CACHE_MAX_AGE:\n try:\n os.remove(file_info['path'])\n logging.info(f\"删除过期缓存文件: {file_info['path']}, 超过 {cls.CACHE_MAX_AGE / 86400:.1f} 天\")\n except Exception as e:\n if os.path.exists(file_info['path']): # 检查文件是否还存在,可能已被之前的清理步骤删除\n logging.error(f\"删除过期缓存文件失败: {file_info['path']}, 错误: {str(e)}\")\n \n # 检查和修复不完整的缓存文件\n cls._check_incomplete_cache_files()\n \n logging.info(\"缓存清理完成\")\n except Exception as e:\n logging.exception(f\"缓存清理过程中发生错误: {str(e)}\")\n \n @classmethod\n def _check_incomplete_cache_files(cls):\n \"\"\"检查并修复不完整的缓存文件\"\"\"\n import logging\n import os\n import json\n import datetime\n \n try:\n incomplete_count = 0\n fixed_count = 0\n \n for file_name in os.listdir(cls.CACHE_DIR):\n if file_name.endswith('.json'):\n file_path = os.path.join(cls.CACHE_DIR, file_name)\n \n try:\n with open(file_path, 'r', encoding='utf-8') as f:\n try:\n data = json.load(f)\n \n # 检查是否有error字段但没有completed字段\n if 'error' in data and 'completed' not in data:\n data['completed'] = False\n data['timestamp'] = datetime.datetime.now().isoformat()\n \n with open(file_path, 'w', encoding='utf-8') as fw:\n json.dump(data, fw, ensure_ascii=False, indent=2)\n \n fixed_count += 1\n logging.info(f\"修复了不完整的缓存文件: {file_path}\")\n except json.JSONDecodeError:\n # 文件内容不是有效的JSON\n logging.warning(f\"缓存文件 {file_path} 不是有效的JSON,将被标记为不完整\")\n with open(file_path, 'w', encoding='utf-8') as fw:\n json.dump({\n 'error': 'Invalid JSON content',\n 'completed': False,\n 'timestamp': datetime.datetime.now().isoformat()\n }, fw, ensure_ascii=False, indent=2)\n \n incomplete_count += 1\n except Exception as e:\n logging.error(f\"检查缓存文件 {file_path} 时出错: {str(e)}\")\n \n if incomplete_count > 0 or fixed_count > 0:\n logging.info(f\"缓存文件检查: 发现 {incomplete_count} 个无效文件,修复了 {fixed_count} 个不完整文件\")\n \n except Exception as e:\n logging.exception(f\"检查不完整缓存文件时出错: {str(e)}\")\n\n # 新添加的加载和保存配置文件的方法\n @staticmethod\n def load_config(config_file='config.json'):\n \"\"\"从JSON文件加载配置\"\"\"\n config_path = os.path.join(Config.BASE_DIR, config_file)\n if os.path.exists(config_path):\n try:\n with open(config_path, 'r', encoding='utf-8') as f:\n config_data = json.load(f)\n \n # 更新数据库配置\n if 'mysql' in config_data:\n mysql = config_data['mysql']\n Config.MYSQL_HOST = mysql.get('host', Config.MYSQL_HOST)\n Config.MYSQL_PORT = int(mysql.get('port', Config.MYSQL_PORT))\n Config.MYSQL_USER = mysql.get('user', Config.MYSQL_USER)\n Config.MYSQL_PASSWORD = mysql.get('password', Config.MYSQL_PASSWORD)\n Config.MYSQL_DB = mysql.get('database', Config.MYSQL_DB)\n \n # 更新API配置\n if 'api' in config_data:\n api = config_data['api']\n Config.OPENAI_API_KEY = api.get('openai_api_key', Config.OPENAI_API_KEY)\n Config.OPENAI_MODEL = api.get('openai_model', Config.OPENAI_MODEL)\n Config.QWEN_API_KEY = api.get('qwen_api_key', Config.QWEN_API_KEY)\n Config.QWEN_BASE_URL = api.get('qwen_base_url', Config.QWEN_BASE_URL)\n \n print(\"配置已从文件加载: \" + config_path)\n except Exception as e:\n print(\"加载配置文件时出错: \" + str(e))\n \n @staticmethod\n def save_config(config_file='config.json'):\n \"\"\"将配置保存到JSON文件\"\"\"\n config_path = os.path.join(Config.BASE_DIR, config_file)\n try:\n config_data = {\n 'mysql': {\n 'host': Config.MYSQL_HOST,\n 'port': Config.MYSQL_PORT,\n 'user': Config.MYSQL_USER,\n 'password': Config.MYSQL_PASSWORD,\n 'database': Config.MYSQL_DB\n },\n 'api': {\n 'openai_api_key': Config.OPENAI_API_KEY,\n 'openai_model': Config.OPENAI_MODEL,\n 'qwen_api_key': Config.QWEN_API_KEY,\n 'qwen_base_url': Config.QWEN_BASE_URL\n }\n }\n \n with open(config_path, 'w', encoding='utf-8') as f:\n json.dump(config_data, f, indent=4, ensure_ascii=False)\n \n print(\"配置已保存到文件: \" + config_path)\n \n except Exception as e:\n print(\"保存配置文件时出错: \" + str(e))\n\n\nclass DevelopmentConfig(Config):\n \"\"\"开发环境配置\"\"\"\n DEBUG = True\n\n\nclass TestingConfig(Config):\n \"\"\"测试环境配置\"\"\"\n DEBUG = True\n TESTING = True\n\n\nclass ProductionConfig(Config):\n \"\"\"生产环境配置\"\"\"\n DEBUG = False\n\n\n# 配置名称映射字典\nconfig_by_name = {\n 'development': DevelopmentConfig,\n 'testing': TestingConfig,\n 'production': ProductionConfig,\n 'default': DevelopmentConfig\n}\n\n# 确保必要的目录存在\nfor directory in [Config.UPLOAD_FOLDER, Config.CITED_PAPERS_DIR, Config.OUTPUT_FOLDER, Config.GRAPH_DATA_DIR, Config.LOG_DIR, Config.CACHE_DIR]:\n if not os.path.exists(directory):\n os.makedirs(directory)\n\n# 加载配置\nConfig.load_config() "}, "eaeef66df78a1ca3527187816a8aa8546d89b8e8": {"t": 1785768275.4451547, "n": 13064, "h": "ce277b586fcd2a1b", "c": "import os\nimport json\n\nclass Config:\n \"\"\"基础配置类\"\"\"\n # 环境配置\n ENV = os.getenv('ENV', 'development') # 默认为开发环境\n DEBUG = ENV == 'development' # 在开发环境中启用调试\n LOG_LEVEL = os.getenv('LOG_LEVEL', 'INFO') # 日志级别\n \n # 项目路径\n BASE_DIR = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))\n \n # 数据库配置\n DATABASE_PATH = os.path.join('./data', 'db', 'algknowledge.db') # SQLite数据库路径\n \n # 上传文件配置\n UPLOAD_FOLDER = os.path.join('./data', 'uploads') # 文件上传目录\n TEMP_FOLDER = os.path.join('./data', 'temp')\n ALLOWED_EXTENSIONS = {'pdf', 'txt', 'csv', 'xlsx', 'json'} # 允许上传的文件类型\n MAX_CONTENT_LENGTH = 100 * 1024 * 1024 # 最大文件上传大小(100MB)\n \n # 缓存配置\n CACHE_DIR = os.path.join('./data', 'cache') # 缓存目录\n CACHE_MAX_SIZE = 500 * 1024 * 1024 # 缓存目录最大大小限制(500MB)\n CACHE_CHECK_INTERVAL = 86400 # 缓存检查间隔(秒),默认为1天\n CACHE_MAX_AGE = 30 * 86400 # 缓存文件最大保存时间(秒),默认为30天\n \n # API配置\n API_PREFIX = '/api/v1' # API前缀\n DISABLE_AI = os.environ.get('DISABLE_AI', 'False').lower() == 'true' # 是否禁用AI功能\n # 安全配置\n SECRET_KEY = os.getenv('SECRET_KEY', 'dev_secret_key') # 密钥\n SECURITY_PASSWORD_SALT = os.getenv('SECURITY_PASSWORD_SALT', 'dev_password_salt') # 密码盐值\n \n # 模型配置\n QWEN_API_KEY = os.getenv('QWEN_API_KEY', 'sk-') # 千问API密钥\n QWEN_BASE_URL = os.getenv('QWEN_BASE_URL', 'https://dashscope.aliyuncs.com/compatible-mode/v1')\n QWEN_MODEL = os.getenv('QWEN_MODEL', 'qwen-long') # 千问模型\n DEFAULT_MODEL = os.environ.get('DEFAULT_MODEL', 'gpt-4.1-mini') # 默认使用GPT模型进行PDF提取\n \n # 新增模型API密钥配置(统一使用shubiaobiao)\n ANTHROPIC_API_KEY = os.environ.get('ANTHROPIC_API_KEY', 'sk-') # Claude API密钥\n OPENAI_API_KEY = os.environ.get('OPENAI_API_KEY', 'sk-') # OpenAI API密钥\n GEMINI_API_KEY = os.environ.get('GEMINI_API_KEY', 'sk-') # Gemini API密钥\n DEEPSEEK_API_KEY = os.environ.get('DEEPSEEK_API_KEY', 'sk-') # DeepSeek API密钥\n\n # 模型基础URL配置(统一使用shubiaobiao)\n ANTHROPIC_BASE_URL = os.environ.get('ANTHROPIC_BASE_URL', 'https://api.shubiaobiao.cn/v1/')\n OPENAI_BASE_URL = os.environ.get('OPENAI_BASE_URL', 'https://api.shubiaobiao.cn/v1/')\n GEMINI_BASE_URL = os.environ.get('GEMINI_BASE_URL', 'https://api.shubiaobiao.cn/v1/')\n DEEPSEEK_BASE_URL = os.environ.get('DEEPSEEK_BASE_URL', 'https://api.shubiaobiao.cn/v1/')\n \n # JSON响应大小限制配置\n MAX_JSON_RESPONSE_SIZE = 8192000 # 最大JSON响应大小(字符数)\n \n # 处理并发配置\n MAX_WORKERS = 40 # 最大工作线程数\n\n # 重试配置\n MAX_RETRY_ATTEMPTS = 3 # 最大重试次数\n RETRY_DELAY = 5 # 重试延迟(秒)\n \n # 算法处理配置\n ALGORITHM_BATCH_SIZE = 10 # 每批处理的算法数量\n \n # 基础配置\n TESTING = False\n SECRET_KEY = os.environ.get('SECRET_KEY', 'dev-key')\n \n # 文件路径配置\n ROOT_DIR = os.path.dirname(BASE_DIR)\n UPLOAD_DIR = os.path.join('./data', 'pdfs') # 上传PDF文件存储目录\n OUTPUT_FOLDER = os.path.join('./data') # 输出文件夹\n GRAPH_DATA_DIR = os.path.join('./data', 'graph') # 图数据存储目录\n LOG_DIR = os.path.join('./data', 'logs') # 日志存储目录\n CITED_PAPERS_DIR = os.path.join('./data', 'cited_papers') # 引用文献存储目录\n \n # 数据库配置 - 只使用MySQL\n DB_TYPE = 'mysql' # 固定为MySQL\n \n # MySQL配置\n MYSQL_HOST = os.environ.get('MYSQL_HOST', 'localhost')\n MYSQL_PORT = int(os.environ.get('MYSQL_PORT', 3306))\n MYSQL_USER = os.environ.get('MYSQL_USER', 'root')\n MYSQL_PASSWORD = os.environ.get('MYSQL_PASSWORD', '123456')\n MYSQL_DB = os.environ.get('MYSQL_DB', 'algorithm_evolution')\n\n # 新添加的OpenAI API相关配置\n OPENAI_MODEL = os.environ.get('OPENAI_MODEL', 'gpt-3.5-turbo')\n\n @classmethod\n def init_app(cls, app):\n \"\"\"初始化应用程序配置\"\"\"\n # 确保必要的目录存在\n os.makedirs(cls.UPLOAD_FOLDER, exist_ok=True)\n os.makedirs(cls.CACHE_DIR, exist_ok=True)\n os.makedirs(os.path.dirname(cls.DATABASE_PATH), exist_ok=True)\n \n # 配置日志\n import logging\n logging.basicConfig(\n level=getattr(logging, cls.LOG_LEVEL),\n format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'\n )\n \n # 定期清理过期缓存\n if not cls.DEBUG: # 在非开发环境中启用定期清理\n cls._schedule_cache_cleanup()\n \n @classmethod\n def _schedule_cache_cleanup(cls):\n \"\"\"安排定期清理缓存任务\"\"\"\n import threading\n import time\n \n def cleanup_task():\n while True:\n try:\n cls._clean_cache()\n time.sleep(cls.CACHE_CHECK_INTERVAL)\n except Exception as e:\n import logging\n logging.error(f\"缓存清理失败: {str(e)}\")\n # 发生错误时延迟一小时后重试\n time.sleep(3600)\n \n # 启动清理线程\n cleanup_thread = threading.Thread(target=cleanup_task, daemon=True)\n cleanup_thread.start()\n \n @classmethod\n def _clean_cache(cls):\n \"\"\"清理过期和超大缓存文件\"\"\"\n import logging\n import time\n import os\n \n try:\n now = time.time()\n total_size = 0\n files_info = []\n \n # 收集所有缓存文件信息\n for file_name in os.listdir(cls.CACHE_DIR):\n file_path = os.path.join(cls.CACHE_DIR, file_name)\n if os.path.isfile(file_path):\n stats = os.stat(file_path)\n total_size += stats.st_size\n files_info.append({\n 'path': file_path,\n 'size': stats.st_size,\n 'mtime': stats.st_mtime,\n 'atime': stats.st_atime\n })\n \n # 如果缓存总大小超过限制,则按访问时间排序删除最旧的文件\n if total_size > cls.CACHE_MAX_SIZE:\n logging.info(f\"缓存总大小 ({total_size / 1024 / 1024:.2f} MB) 超过限制 ({cls.CACHE_MAX_SIZE / 1024 / 1024:.2f} MB),开始清理...\")\n # 按访问时间排序,最旧的在前面\n files_info.sort(key=lambda x: x['atime'])\n \n # 删除最旧的文件,直到缓存大小低于限制\n for file_info in files_info:\n if total_size <= cls.CACHE_MAX_SIZE * 0.9: # 保留10%的缓冲区\n break\n \n try:\n os.remove(file_info['path'])\n total_size -= file_info['size']\n logging.info(f\"删除旧缓存文件: {file_info['path']} ({file_info['size'] / 1024 / 1024:.2f} MB)\")\n except Exception as e:\n logging.error(f\"删除缓存文件失败: {file_info['path']}, 错误: {str(e)}\")\n \n # 删除超过最大保存时间的文件\n for file_info in files_info:\n if now - file_info['mtime'] > cls.CACHE_MAX_AGE:\n try:\n os.remove(file_info['path'])\n logging.info(f\"删除过期缓存文件: {file_info['path']}, 超过 {cls.CACHE_MAX_AGE / 86400:.1f} 天\")\n except Exception as e:\n if os.path.exists(file_info['path']): # 检查文件是否还存在,可能已被之前的清理步骤删除\n logging.error(f\"删除过期缓存文件失败: {file_info['path']}, 错误: {str(e)}\")\n \n # 检查和修复不完整的缓存文件\n cls._check_incomplete_cache_files()\n \n logging.info(\"缓存清理完成\")\n except Exception as e:\n logging.exception(f\"缓存清理过程中发生错误: {str(e)}\")\n \n @classmethod\n def _check_incomplete_cache_files(cls):\n \"\"\"检查并修复不完整的缓存文件\"\"\"\n import logging\n import os\n import json\n import datetime\n \n try:\n incomplete_count = 0\n fixed_count = 0\n \n for file_name in os.listdir(cls.CACHE_DIR):\n if file_name.endswith('.json'):\n file_path = os.path.join(cls.CACHE_DIR, file_name)\n \n try:\n with open(file_path, 'r', encoding='utf-8') as f:\n try:\n data = json.load(f)\n \n # 检查是否有error字段但没有completed字段\n if 'error' in data and 'completed' not in data:\n data['completed'] = False\n data['timestamp'] = datetime.datetime.now().isoformat()\n \n with open(file_path, 'w', encoding='utf-8') as fw:\n json.dump(data, fw, ensure_ascii=False, indent=2)\n \n fixed_count += 1\n logging.info(f\"修复了不完整的缓存文件: {file_path}\")\n except json.JSONDecodeError:\n # 文件内容不是有效的JSON\n logging.warning(f\"缓存文件 {file_path} 不是有效的JSON,将被标记为不完整\")\n with open(file_path, 'w', encoding='utf-8') as fw:\n json.dump({\n 'error': 'Invalid JSON content',\n 'completed': False,\n 'timestamp': datetime.datetime.now().isoformat()\n }, fw, ensure_ascii=False, indent=2)\n \n incomplete_count += 1\n except Exception as e:\n logging.error(f\"检查缓存文件 {file_path} 时出错: {str(e)}\")\n \n if incomplete_count > 0 or fixed_count > 0:\n logging.info(f\"缓存文件检查: 发现 {incomplete_count} 个无效文件,修复了 {fixed_count} 个不完整文件\")\n \n except Exception as e:\n logging.exception(f\"检查不完整缓存文件时出错: {str(e)}\")\n\n # 新添加的加载和保存配置文件的方法\n @staticmethod\n def load_config(config_file='config.json'):\n \"\"\"从JSON文件加载配置\"\"\"\n config_path = os.path.join(Config.BASE_DIR, config_file)\n if os.path.exists(config_path):\n try:\n with open(config_path, 'r', encoding='utf-8') as f:\n config_data = json.load(f)\n \n # 更新数据库配置\n if 'mysql' in config_data:\n mysql = config_data['mysql']\n Config.MYSQL_HOST = mysql.get('host', Config.MYSQL_HOST)\n Config.MYSQL_PORT = int(mysql.get('port', Config.MYSQL_PORT))\n Config.MYSQL_USER = mysql.get('user', Config.MYSQL_USER)\n Config.MYSQL_PASSWORD = mysql.get('password', Config.MYSQL_PASSWORD)\n Config.MYSQL_DB = mysql.get('database', Config.MYSQL_DB)\n \n # 更新API配置\n if 'api' in config_data:\n api = config_data['api']\n Config.OPENAI_API_KEY = api.get('openai_api_key', Config.OPENAI_API_KEY)\n Config.OPENAI_MODEL = api.get('openai_model', Config.OPENAI_MODEL)\n Config.QWEN_API_KEY = api.get('qwen_api_key', Config.QWEN_API_KEY)\n Config.QWEN_BASE_URL = api.get('qwen_base_url', Config.QWEN_BASE_URL)\n \n print(\"配置已从文件加载: \" + config_path)\n except Exception as e:\n print(\"加载配置文件时出错: \" + str(e))\n \n @staticmethod\n def save_config(config_file='config.json'):\n \"\"\"将配置保存到JSON文件\"\"\"\n config_path = os.path.join(Config.BASE_DIR, config_file)\n try:\n config_data = {\n 'mysql': {\n 'host': Config.MYSQL_HOST,\n 'port': Config.MYSQL_PORT,\n 'user': Config.MYSQL_USER,\n 'password': Config.MYSQL_PASSWORD,\n 'database': Config.MYSQL_DB\n },\n 'api': {\n 'openai_api_key': Config.OPENAI_API_KEY,\n 'openai_model': Config.OPENAI_MODEL,\n 'qwen_api_key': Config.QWEN_API_KEY,\n 'qwen_base_url': Config.QWEN_BASE_URL\n }\n }\n \n with open(config_path, 'w', encoding='utf-8') as f:\n json.dump(config_data, f, indent=4, ensure_ascii=False)\n \n print(\"配置已保存到文件: \" + config_path)\n \n except Exception as e:\n print(\"保存配置文件时出错: \" + str(e))\n\n\nclass DevelopmentConfig(Config):\n \"\"\"开发环境配置\"\"\"\n DEBUG = True\n\n\nclass TestingConfig(Config):\n \"\"\"测试环境配置\"\"\"\n DEBUG = True\n TESTING = True\n\n\nclass ProductionConfig(Config):\n \"\"\"生产环境配置\"\"\"\n DEBUG = False\n\n\n# 配置名称映射字典\nconfig_by_name = {\n 'development': DevelopmentConfig,\n 'testing': TestingConfig,\n 'production': ProductionConfig,\n 'default': DevelopmentConfig\n}\n\n# 确保必要的目录存在\nfor directory in [Config.UPLOAD_FOLDER, Config.CITED_PAPERS_DIR, Config.OUTPUT_FOLDER, Config.GRAPH_DATA_DIR, Config.LOG_DIR, Config.CACHE_DIR]:\n if not os.path.exists(directory):\n os.makedirs(directory)\n\n# 加载配置\nConfig.load_config() "}, "6fb070d1bc306ba292adb31c48d2da18f0ff52c9": {"t": 1785768278.2739284, "n": 13288, "h": "fcf73453c30783eb", "c": "import os\nimport json\n\nclass Config:\n \"\"\"基础配置类\"\"\"\n # 环境配置\n ENV = os.getenv('ENV', 'development') # 默认为开发环境\n DEBUG = ENV == 'development' # 在开发环境中启用调试\n LOG_LEVEL = os.getenv('LOG_LEVEL', 'INFO') # 日志级别\n \n # 项目路径\n BASE_DIR = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))\n \n # 数据库配置\n DATABASE_PATH = os.path.join('./data', 'db', 'algknowledge.db') # SQLite数据库路径\n \n # 上传文件配置\n UPLOAD_FOLDER = os.path.join('./data', 'uploads') # 文件上传目录\n TEMP_FOLDER = os.path.join('./data', 'temp')\n ALLOWED_EXTENSIONS = {'pdf', 'txt', 'csv', 'xlsx', 'json'} # 允许上传的文件类型\n MAX_CONTENT_LENGTH = 100 * 1024 * 1024 # 最大文件上传大小(100MB)\n \n # 缓存配置\n CACHE_DIR = os.path.join('./data', 'cache') # 缓存目录\n CACHE_MAX_SIZE = 500 * 1024 * 1024 # 缓存目录最大大小限制(500MB)\n CACHE_CHECK_INTERVAL = 86400 # 缓存检查间隔(秒),默认为1天\n CACHE_MAX_AGE = 30 * 86400 # 缓存文件最大保存时间(秒),默认为30天\n \n # API配置\n API_PREFIX = '/api/v1' # API前缀\n DISABLE_AI = os.environ.get('DISABLE_AI', 'False').lower() == 'true' # 是否禁用AI功能\n # 安全配置\n SECRET_KEY = os.getenv('SECRET_KEY', 'dev_secret_key') # 密钥\n SECURITY_PASSWORD_SALT = os.getenv('SECURITY_PASSWORD_SALT', 'dev_password_salt') # 密码盐值\n \n # 模型配置\n QWEN_API_KEY = os.getenv('QWEN_API_KEY', 'sk-0fe80fc99c3045dfaa4c2921910245c1') # 千问API密钥\n QWEN_BASE_URL = os.getenv('QWEN_BASE_URL', 'https://dashscope.aliyuncs.com/compatible-mode/v1')\n QWEN_MODEL = os.getenv('QWEN_MODEL', 'qwen-long') # 千问模型\n DEFAULT_MODEL = os.environ.get('DEFAULT_MODEL', 'gpt-4.1-mini') # 默认使用GPT模型进行PDF提取\n \n # 新增模型API密钥配置(统一使用shubiaobiao)\n ANTHROPIC_API_KEY = os.environ.get('ANTHROPIC_API_KEY', 'sk-aYa1InFVmrtzBU2u77E9D8153a534522Ae49506058984019') # Claude API密钥\n OPENAI_API_KEY = os.environ.get('OPENAI_API_KEY', 'sk-aYa1InFVmrtzBU2u77E9D8153a534522Ae49506058984019') # OpenAI API密钥\n GEMINI_API_KEY = os.environ.get('GEMINI_API_KEY', 'sk-aYa1InFVmrtzBU2u77E9D8153a534522Ae49506058984019') # Gemini API密钥\n DEEPSEEK_API_KEY = os.environ.get('DEEPSEEK_API_KEY', 'sk-aYa1InFVmrtzBU2u77E9D8153a534522Ae49506058984019') # DeepSeek API密钥\n\n # 模型基础URL配置(统一使用shubiaobiao)\n ANTHROPIC_BASE_URL = os.environ.get('ANTHROPIC_BASE_URL', 'https://api.shubiaobiao.cn/v1/')\n OPENAI_BASE_URL = os.environ.get('OPENAI_BASE_URL', 'https://api.shubiaobiao.cn/v1/')\n GEMINI_BASE_URL = os.environ.get('GEMINI_BASE_URL', 'https://api.shubiaobiao.cn/v1/')\n DEEPSEEK_BASE_URL = os.environ.get('DEEPSEEK_BASE_URL', 'https://api.shubiaobiao.cn/v1/')\n \n # JSON响应大小限制配置\n MAX_JSON_RESPONSE_SIZE = 8192000 # 最大JSON响应大小(字符数)\n \n # 处理并发配置\n MAX_WORKERS = 40 # 最大工作线程数\n\n # 重试配置\n MAX_RETRY_ATTEMPTS = 3 # 最大重试次数\n RETRY_DELAY = 5 # 重试延迟(秒)\n \n # 算法处理配置\n ALGORITHM_BATCH_SIZE = 10 # 每批处理的算法数量\n \n # 基础配置\n TESTING = False\n SECRET_KEY = os.environ.get('SECRET_KEY', 'dev-key')\n \n # 文件路径配置\n ROOT_DIR = os.path.dirname(BASE_DIR)\n UPLOAD_DIR = os.path.join('./data', 'pdfs') # 上传PDF文件存储目录\n OUTPUT_FOLDER = os.path.join('./data') # 输出文件夹\n GRAPH_DATA_DIR = os.path.join('./data', 'graph') # 图数据存储目录\n LOG_DIR = os.path.join('./data', 'logs') # 日志存储目录\n CITED_PAPERS_DIR = os.path.join('./data', 'cited_papers') # 引用文献存储目录\n \n # 数据库配置 - 只使用MySQL\n DB_TYPE = 'mysql' # 固定为MySQL\n \n # MySQL配置\n MYSQL_HOST = os.environ.get('MYSQL_HOST', 'localhost')\n MYSQL_PORT = int(os.environ.get('MYSQL_PORT', 3306))\n MYSQL_USER = os.environ.get('MYSQL_USER', 'root')\n MYSQL_PASSWORD = os.environ.get('MYSQL_PASSWORD', '123456')\n MYSQL_DB = os.environ.get('MYSQL_DB', 'algorithm_evolution')\n\n # 新添加的OpenAI API相关配置\n OPENAI_MODEL = os.environ.get('OPENAI_MODEL', 'gpt-3.5-turbo')\n\n @classmethod\n def init_app(cls, app):\n \"\"\"初始化应用程序配置\"\"\"\n # 确保必要的目录存在\n os.makedirs(cls.UPLOAD_FOLDER, exist_ok=True)\n os.makedirs(cls.CACHE_DIR, exist_ok=True)\n os.makedirs(os.path.dirname(cls.DATABASE_PATH), exist_ok=True)\n \n # 配置日志\n import logging\n logging.basicConfig(\n level=getattr(logging, cls.LOG_LEVEL),\n format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'\n )\n \n # 定期清理过期缓存\n if not cls.DEBUG: # 在非开发环境中启用定期清理\n cls._schedule_cache_cleanup()\n \n @classmethod\n def _schedule_cache_cleanup(cls):\n \"\"\"安排定期清理缓存任务\"\"\"\n import threading\n import time\n \n def cleanup_task():\n while True:\n try:\n cls._clean_cache()\n time.sleep(cls.CACHE_CHECK_INTERVAL)\n except Exception as e:\n import logging\n logging.error(f\"缓存清理失败: {str(e)}\")\n # 发生错误时延迟一小时后重试\n time.sleep(3600)\n \n # 启动清理线程\n cleanup_thread = threading.Thread(target=cleanup_task, daemon=True)\n cleanup_thread.start()\n \n @classmethod\n def _clean_cache(cls):\n \"\"\"清理过期和超大缓存文件\"\"\"\n import logging\n import time\n import os\n \n try:\n now = time.time()\n total_size = 0\n files_info = []\n \n # 收集所有缓存文件信息\n for file_name in os.listdir(cls.CACHE_DIR):\n file_path = os.path.join(cls.CACHE_DIR, file_name)\n if os.path.isfile(file_path):\n stats = os.stat(file_path)\n total_size += stats.st_size\n files_info.append({\n 'path': file_path,\n 'size': stats.st_size,\n 'mtime': stats.st_mtime,\n 'atime': stats.st_atime\n })\n \n # 如果缓存总大小超过限制,则按访问时间排序删除最旧的文件\n if total_size > cls.CACHE_MAX_SIZE:\n logging.info(f\"缓存总大小 ({total_size / 1024 / 1024:.2f} MB) 超过限制 ({cls.CACHE_MAX_SIZE / 1024 / 1024:.2f} MB),开始清理...\")\n # 按访问时间排序,最旧的在前面\n files_info.sort(key=lambda x: x['atime'])\n \n # 删除最旧的文件,直到缓存大小低于限制\n for file_info in files_info:\n if total_size <= cls.CACHE_MAX_SIZE * 0.9: # 保留10%的缓冲区\n break\n \n try:\n os.remove(file_info['path'])\n total_size -= file_info['size']\n logging.info(f\"删除旧缓存文件: {file_info['path']} ({file_info['size'] / 1024 / 1024:.2f} MB)\")\n except Exception as e:\n logging.error(f\"删除缓存文件失败: {file_info['path']}, 错误: {str(e)}\")\n \n # 删除超过最大保存时间的文件\n for file_info in files_info:\n if now - file_info['mtime'] > cls.CACHE_MAX_AGE:\n try:\n os.remove(file_info['path'])\n logging.info(f\"删除过期缓存文件: {file_info['path']}, 超过 {cls.CACHE_MAX_AGE / 86400:.1f} 天\")\n except Exception as e:\n if os.path.exists(file_info['path']): # 检查文件是否还存在,可能已被之前的清理步骤删除\n logging.error(f\"删除过期缓存文件失败: {file_info['path']}, 错误: {str(e)}\")\n \n # 检查和修复不完整的缓存文件\n cls._check_incomplete_cache_files()\n \n logging.info(\"缓存清理完成\")\n except Exception as e:\n logging.exception(f\"缓存清理过程中发生错误: {str(e)}\")\n \n @classmethod\n def _check_incomplete_cache_files(cls):\n \"\"\"检查并修复不完整的缓存文件\"\"\"\n import logging\n import os\n import json\n import datetime\n \n try:\n incomplete_count = 0\n fixed_count = 0\n \n for file_name in os.listdir(cls.CACHE_DIR):\n if file_name.endswith('.json'):\n file_path = os.path.join(cls.CACHE_DIR, file_name)\n \n try:\n with open(file_path, 'r', encoding='utf-8') as f:\n try:\n data = json.load(f)\n \n # 检查是否有error字段但没有completed字段\n if 'error' in data and 'completed' not in data:\n data['completed'] = False\n data['timestamp'] = datetime.datetime.now().isoformat()\n \n with open(file_path, 'w', encoding='utf-8') as fw:\n json.dump(data, fw, ensure_ascii=False, indent=2)\n \n fixed_count += 1\n logging.info(f\"修复了不完整的缓存文件: {file_path}\")\n except json.JSONDecodeError:\n # 文件内容不是有效的JSON\n logging.warning(f\"缓存文件 {file_path} 不是有效的JSON,将被标记为不完整\")\n with open(file_path, 'w', encoding='utf-8') as fw:\n json.dump({\n 'error': 'Invalid JSON content',\n 'completed': False,\n 'timestamp': datetime.datetime.now().isoformat()\n }, fw, ensure_ascii=False, indent=2)\n \n incomplete_count += 1\n except Exception as e:\n logging.error(f\"检查缓存文件 {file_path} 时出错: {str(e)}\")\n \n if incomplete_count > 0 or fixed_count > 0:\n logging.info(f\"缓存文件检查: 发现 {incomplete_count} 个无效文件,修复了 {fixed_count} 个不完整文件\")\n \n except Exception as e:\n logging.exception(f\"检查不完整缓存文件时出错: {str(e)}\")\n\n # 新添加的加载和保存配置文件的方法\n @staticmethod\n def load_config(config_file='config.json'):\n \"\"\"从JSON文件加载配置\"\"\"\n config_path = os.path.join(Config.BASE_DIR, config_file)\n if os.path.exists(config_path):\n try:\n with open(config_path, 'r', encoding='utf-8') as f:\n config_data = json.load(f)\n \n # 更新数据库配置\n if 'mysql' in config_data:\n mysql = config_data['mysql']\n Config.MYSQL_HOST = mysql.get('host', Config.MYSQL_HOST)\n Config.MYSQL_PORT = int(mysql.get('port', Config.MYSQL_PORT))\n Config.MYSQL_USER = mysql.get('user', Config.MYSQL_USER)\n Config.MYSQL_PASSWORD = mysql.get('password', Config.MYSQL_PASSWORD)\n Config.MYSQL_DB = mysql.get('database', Config.MYSQL_DB)\n \n # 更新API配置\n if 'api' in config_data:\n api = config_data['api']\n Config.OPENAI_API_KEY = api.get('openai_api_key', Config.OPENAI_API_KEY)\n Config.OPENAI_MODEL = api.get('openai_model', Config.OPENAI_MODEL)\n Config.QWEN_API_KEY = api.get('qwen_api_key', Config.QWEN_API_KEY)\n Config.QWEN_BASE_URL = api.get('qwen_base_url', Config.QWEN_BASE_URL)\n \n print(\"配置已从文件加载: \" + config_path)\n except Exception as e:\n print(\"加载配置文件时出错: \" + str(e))\n \n @staticmethod\n def save_config(config_file='config.json'):\n \"\"\"将配置保存到JSON文件\"\"\"\n config_path = os.path.join(Config.BASE_DIR, config_file)\n try:\n config_data = {\n 'mysql': {\n 'host': Config.MYSQL_HOST,\n 'port': Config.MYSQL_PORT,\n 'user': Config.MYSQL_USER,\n 'password': Config.MYSQL_PASSWORD,\n 'database': Config.MYSQL_DB\n },\n 'api': {\n 'openai_api_key': Config.OPENAI_API_KEY,\n 'openai_model': Config.OPENAI_MODEL,\n 'qwen_api_key': Config.QWEN_API_KEY,\n 'qwen_base_url': Config.QWEN_BASE_URL\n }\n }\n \n with open(config_path, 'w', encoding='utf-8') as f:\n json.dump(config_data, f, indent=4, ensure_ascii=False)\n \n print(\"配置已保存到文件: \" + config_path)\n \n except Exception as e:\n print(\"保存配置文件时出错: \" + str(e))\n\n\nclass DevelopmentConfig(Config):\n \"\"\"开发环境配置\"\"\"\n DEBUG = True\n\n\nclass TestingConfig(Config):\n \"\"\"测试环境配置\"\"\"\n DEBUG = True\n TESTING = True\n\n\nclass ProductionConfig(Config):\n \"\"\"生产环境配置\"\"\"\n DEBUG = False\n\n\n# 配置名称映射字典\nconfig_by_name = {\n 'development': DevelopmentConfig,\n 'testing': TestingConfig,\n 'production': ProductionConfig,\n 'default': DevelopmentConfig\n}\n\n# 确保必要的目录存在\nfor directory in [Config.UPLOAD_FOLDER, Config.CITED_PAPERS_DIR, Config.OUTPUT_FOLDER, Config.GRAPH_DATA_DIR, Config.LOG_DIR, Config.CACHE_DIR]:\n if not os.path.exists(directory):\n os.makedirs(directory)\n\n# 加载配置\nConfig.load_config() "}, "7fc03755175e97f503ce76d79a7a032c1dadaf3f": {"t": 1785768280.6050525, "n": 13391, "h": "036818919cf52116", "c": "import os\nimport json\n\nclass Config:\n \"\"\"基础配置类\"\"\"\n # 环境配置\n ENV = os.getenv('ENV', 'development') # 默认为开发环境\n DEBUG = ENV == 'development' # 在开发环境中启用调试\n LOG_LEVEL = os.getenv('LOG_LEVEL', 'INFO') # 日志级别\n \n # 项目路径\n BASE_DIR = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))\n \n # 数据库配置\n DATABASE_PATH = os.path.join('./data', 'db', 'algknowledge.db') # SQLite数据库路径\n \n # 上传文件配置\n UPLOAD_FOLDER = os.path.join('./data', 'uploads') # 文件上传目录\n TEMP_FOLDER = os.path.join('./data', 'temp')\n ALLOWED_EXTENSIONS = {'pdf', 'txt', 'csv', 'xlsx', 'json'} # 允许上传的文件类型\n MAX_CONTENT_LENGTH = 100 * 1024 * 1024 # 最大文件上传大小(100MB)\n \n # 缓存配置\n CACHE_DIR = os.path.join('./data', 'cache') # 缓存目录\n CACHE_MAX_SIZE = 500 * 1024 * 1024 # 缓存目录最大大小限制(500MB)\n CACHE_CHECK_INTERVAL = 86400 # 缓存检查间隔(秒),默认为1天\n CACHE_MAX_AGE = 30 * 86400 # 缓存文件最大保存时间(秒),默认为30天\n \n # API配置\n API_PREFIX = '/api/v1' # API前缀\n DISABLE_AI = os.environ.get('DISABLE_AI', 'False').lower() == 'true' # 是否禁用AI功能\n # 安全配置\n SECRET_KEY = os.getenv('SECRET_KEY', 'dev_secret_key') # 密钥\n SECURITY_PASSWORD_SALT = os.getenv('SECURITY_PASSWORD_SALT', 'dev_password_salt') # 密码盐值\n \n # 模型配置\n QWEN_API_KEY = os.getenv('QWEN_API_KEY', 'sk-0fe80fc99c3045dfaa4c2921910245c1') # 千问API密钥\n QWEN_BASE_URL = os.getenv('QWEN_BASE_URL', 'https://dashscope.aliyuncs.com/compatible-mode/v1')\n QWEN_MODEL = os.getenv('QWEN_MODEL', 'qwen-long') # 千问模型\n DEFAULT_MODEL = os.environ.get('DEFAULT_MODEL', 'qwen-long') # 默认使用千问长文本模型\n \n # 新增模型API密钥配置\n ANTHROPIC_API_KEY = os.environ.get('ANTHROPIC_API_KEY', 'sk-ZHVYXikfYSPi4eq4Qi8W7XPjZx6r90bQcV2hgI454Bi5DwjN') # Claude API密钥\n OPENAI_API_KEY = os.environ.get('OPENAI_API_KEY', 'sk-ZHVYXikfYSPi4eq4Qi8W7XPjZx6r90bQcV2hgI454Bi5DwjN') # OpenAI API密钥\n GEMINI_API_KEY = os.environ.get('GEMINI_API_KEY', 'sk-ZHVYXikfYSPi4eq4Qi8W7XPjZx6r90bQcV2hgI454Bi5DwjN') # Gemini API密钥\n \n # 模型基础URL配置\n ANTHROPIC_BASE_URL = os.environ.get('ANTHROPIC_BASE_URL', 'https://api.shubiaobiao.com/v1')\n OPENAI_BASE_URL = os.environ.get('OPENAI_BASE_URL', 'https://api.shubiaobiao.com/v1')\n GEMINI_BASE_URL = os.environ.get('GEMINI_BASE_URL', 'https://api.shubiaobiao.com/v1')\n \n # JSON响应大小限制配置\n MAX_JSON_RESPONSE_SIZE = 8192000 # 最大JSON响应大小(字符数)\n \n # 处理并发配置\n MAX_WORKERS = 40 # 最大工作线程数\n\n # 重试配置\n MAX_RETRY_ATTEMPTS = 3 # 最大重试次数\n RETRY_DELAY = 5 # 重试延迟(秒)\n \n # 算法处理配置\n ALGORITHM_BATCH_SIZE = 10 # 每批处理的算法数量\n \n # 基础配置\n TESTING = False\n SECRET_KEY = os.environ.get('SECRET_KEY', 'dev-key')\n \n # 文件路径配置\n ROOT_DIR = os.path.dirname(BASE_DIR)\n UPLOAD_DIR = os.path.join('./data', 'pdfs') # 上传PDF文件存储目录\n OUTPUT_FOLDER = os.path.join('./data') # 输出文件夹\n GRAPH_DATA_DIR = os.path.join('./data', 'graph') # 图数据存储目录\n LOG_DIR = os.path.join('./data', 'logs') # 日志存储目录\n CITED_PAPERS_DIR = os.path.join('./data', 'cited_papers') # 引用文献存储目录\n \n # DeepSeek大模型API配置\n DEEPSEEK_API_KEY = os.environ.get('DEEPSEEK_API_KEY', 'your-deepseek-api-key')\n DEEPSEEK_API_BASE = os.environ.get('DEEPSEEK_API_BASE', 'https://api.deepseek.com')\n DEEPSEEK_MODEL = os.environ.get('DEEPSEEK_MODEL', 'deepseek-chat')\n DEEPSEEK_EMBEDDING_MODEL = os.environ.get('DEEPSEEK_EMBEDDING_MODEL', 'deepseek-embedding')\n \n # 数据库配置 - 只使用MySQL\n DB_TYPE = 'mysql' # 固定为MySQL\n \n # MySQL配置\n MYSQL_HOST = os.environ.get('MYSQL_HOST', 'localhost')\n MYSQL_PORT = int(os.environ.get('MYSQL_PORT', 3306))\n MYSQL_USER = os.environ.get('MYSQL_USER', 'root')\n MYSQL_PASSWORD = os.environ.get('MYSQL_PASSWORD', '123456')\n MYSQL_DB = os.environ.get('MYSQL_DB', 'algorithm_evolution')\n\n # 新添加的OpenAI API相关配置\n OPENAI_MODEL = os.environ.get('OPENAI_MODEL', 'gpt-3.5-turbo')\n\n @classmethod\n def init_app(cls, app):\n \"\"\"初始化应用程序配置\"\"\"\n # 确保必要的目录存在\n os.makedirs(cls.UPLOAD_FOLDER, exist_ok=True)\n os.makedirs(cls.CACHE_DIR, exist_ok=True)\n os.makedirs(os.path.dirname(cls.DATABASE_PATH), exist_ok=True)\n \n # 配置日志\n import logging\n logging.basicConfig(\n level=getattr(logging, cls.LOG_LEVEL),\n format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'\n )\n \n # 定期清理过期缓存\n if not cls.DEBUG: # 在非开发环境中启用定期清理\n cls._schedule_cache_cleanup()\n \n @classmethod\n def _schedule_cache_cleanup(cls):\n \"\"\"安排定期清理缓存任务\"\"\"\n import threading\n import time\n \n def cleanup_task():\n while True:\n try:\n cls._clean_cache()\n time.sleep(cls.CACHE_CHECK_INTERVAL)\n except Exception as e:\n import logging\n logging.error(f\"缓存清理失败: {str(e)}\")\n # 发生错误时延迟一小时后重试\n time.sleep(3600)\n \n # 启动清理线程\n cleanup_thread = threading.Thread(target=cleanup_task, daemon=True)\n cleanup_thread.start()\n \n @classmethod\n def _clean_cache(cls):\n \"\"\"清理过期和超大缓存文件\"\"\"\n import logging\n import time\n import os\n \n try:\n now = time.time()\n total_size = 0\n files_info = []\n \n # 收集所有缓存文件信息\n for file_name in os.listdir(cls.CACHE_DIR):\n file_path = os.path.join(cls.CACHE_DIR, file_name)\n if os.path.isfile(file_path):\n stats = os.stat(file_path)\n total_size += stats.st_size\n files_info.append({\n 'path': file_path,\n 'size': stats.st_size,\n 'mtime': stats.st_mtime,\n 'atime': stats.st_atime\n })\n \n # 如果缓存总大小超过限制,则按访问时间排序删除最旧的文件\n if total_size > cls.CACHE_MAX_SIZE:\n logging.info(f\"缓存总大小 ({total_size / 1024 / 1024:.2f} MB) 超过限制 ({cls.CACHE_MAX_SIZE / 1024 / 1024:.2f} MB),开始清理...\")\n # 按访问时间排序,最旧的在前面\n files_info.sort(key=lambda x: x['atime'])\n \n # 删除最旧的文件,直到缓存大小低于限制\n for file_info in files_info:\n if total_size <= cls.CACHE_MAX_SIZE * 0.9: # 保留10%的缓冲区\n break\n \n try:\n os.remove(file_info['path'])\n total_size -= file_info['size']\n logging.info(f\"删除旧缓存文件: {file_info['path']} ({file_info['size'] / 1024 / 1024:.2f} MB)\")\n except Exception as e:\n logging.error(f\"删除缓存文件失败: {file_info['path']}, 错误: {str(e)}\")\n \n # 删除超过最大保存时间的文件\n for file_info in files_info:\n if now - file_info['mtime'] > cls.CACHE_MAX_AGE:\n try:\n os.remove(file_info['path'])\n logging.info(f\"删除过期缓存文件: {file_info['path']}, 超过 {cls.CACHE_MAX_AGE / 86400:.1f} 天\")\n except Exception as e:\n if os.path.exists(file_info['path']): # 检查文件是否还存在,可能已被之前的清理步骤删除\n logging.error(f\"删除过期缓存文件失败: {file_info['path']}, 错误: {str(e)}\")\n \n # 检查和修复不完整的缓存文件\n cls._check_incomplete_cache_files()\n \n logging.info(\"缓存清理完成\")\n except Exception as e:\n logging.exception(f\"缓存清理过程中发生错误: {str(e)}\")\n \n @classmethod\n def _check_incomplete_cache_files(cls):\n \"\"\"检查并修复不完整的缓存文件\"\"\"\n import logging\n import os\n import json\n import datetime\n \n try:\n incomplete_count = 0\n fixed_count = 0\n \n for file_name in os.listdir(cls.CACHE_DIR):\n if file_name.endswith('.json'):\n file_path = os.path.join(cls.CACHE_DIR, file_name)\n \n try:\n with open(file_path, 'r', encoding='utf-8') as f:\n try:\n data = json.load(f)\n \n # 检查是否有error字段但没有completed字段\n if 'error' in data and 'completed' not in data:\n data['completed'] = False\n data['timestamp'] = datetime.datetime.now().isoformat()\n \n with open(file_path, 'w', encoding='utf-8') as fw:\n json.dump(data, fw, ensure_ascii=False, indent=2)\n \n fixed_count += 1\n logging.info(f\"修复了不完整的缓存文件: {file_path}\")\n except json.JSONDecodeError:\n # 文件内容不是有效的JSON\n logging.warning(f\"缓存文件 {file_path} 不是有效的JSON,将被标记为不完整\")\n with open(file_path, 'w', encoding='utf-8') as fw:\n json.dump({\n 'error': 'Invalid JSON content',\n 'completed': False,\n 'timestamp': datetime.datetime.now().isoformat()\n }, fw, ensure_ascii=False, indent=2)\n \n incomplete_count += 1\n except Exception as e:\n logging.error(f\"检查缓存文件 {file_path} 时出错: {str(e)}\")\n \n if incomplete_count > 0 or fixed_count > 0:\n logging.info(f\"缓存文件检查: 发现 {incomplete_count} 个无效文件,修复了 {fixed_count} 个不完整文件\")\n \n except Exception as e:\n logging.exception(f\"检查不完整缓存文件时出错: {str(e)}\")\n\n # 新添加的加载和保存配置文件的方法\n @staticmethod\n def load_config(config_file='config.json'):\n \"\"\"从JSON文件加载配置\"\"\"\n config_path = os.path.join(Config.BASE_DIR, config_file)\n if os.path.exists(config_path):\n try:\n with open(config_path, 'r', encoding='utf-8') as f:\n config_data = json.load(f)\n \n # 更新数据库配置\n if 'mysql' in config_data:\n mysql = config_data['mysql']\n Config.MYSQL_HOST = mysql.get('host', Config.MYSQL_HOST)\n Config.MYSQL_PORT = int(mysql.get('port', Config.MYSQL_PORT))\n Config.MYSQL_USER = mysql.get('user', Config.MYSQL_USER)\n Config.MYSQL_PASSWORD = mysql.get('password', Config.MYSQL_PASSWORD)\n Config.MYSQL_DB = mysql.get('database', Config.MYSQL_DB)\n \n # 更新API配置\n if 'api' in config_data:\n api = config_data['api']\n Config.OPENAI_API_KEY = api.get('openai_api_key', Config.OPENAI_API_KEY)\n Config.OPENAI_MODEL = api.get('openai_model', Config.OPENAI_MODEL)\n Config.QWEN_API_KEY = api.get('qwen_api_key', Config.QWEN_API_KEY)\n Config.QWEN_BASE_URL = api.get('qwen_base_url', Config.QWEN_BASE_URL)\n \n print(\"配置已从文件加载: \" + config_path)\n except Exception as e:\n print(\"加载配置文件时出错: \" + str(e))\n \n @staticmethod\n def save_config(config_file='config.json'):\n \"\"\"将配置保存到JSON文件\"\"\"\n config_path = os.path.join(Config.BASE_DIR, config_file)\n try:\n config_data = {\n 'mysql': {\n 'host': Config.MYSQL_HOST,\n 'port': Config.MYSQL_PORT,\n 'user': Config.MYSQL_USER,\n 'password': Config.MYSQL_PASSWORD,\n 'database': Config.MYSQL_DB\n },\n 'api': {\n 'openai_api_key': Config.OPENAI_API_KEY,\n 'openai_model': Config.OPENAI_MODEL,\n 'qwen_api_key': Config.QWEN_API_KEY,\n 'qwen_base_url': Config.QWEN_BASE_URL\n }\n }\n \n with open(config_path, 'w', encoding='utf-8') as f:\n json.dump(config_data, f, indent=4, ensure_ascii=False)\n \n print(\"配置已保存到文件: \" + config_path)\n \n except Exception as e:\n print(\"保存配置文件时出错: \" + str(e))\n\n\nclass DevelopmentConfig(Config):\n \"\"\"开发环境配置\"\"\"\n DEBUG = True\n\n\nclass TestingConfig(Config):\n \"\"\"测试环境配置\"\"\"\n DEBUG = True\n TESTING = True\n\n\nclass ProductionConfig(Config):\n \"\"\"生产环境配置\"\"\"\n DEBUG = False\n\n\n# 配置名称映射字典\nconfig_by_name = {\n 'development': DevelopmentConfig,\n 'testing': TestingConfig,\n 'production': ProductionConfig,\n 'default': DevelopmentConfig\n}\n\n# 确保必要的目录存在\nfor directory in [Config.UPLOAD_FOLDER, Config.CITED_PAPERS_DIR, Config.OUTPUT_FOLDER, Config.GRAPH_DATA_DIR, Config.LOG_DIR, Config.CACHE_DIR]:\n if not os.path.exists(directory):\n os.makedirs(directory)\n\n# 加载配置\nConfig.load_config() "}, "f6b291e715c91009be2d7b828c08a6e9b17e59a3": {"t": 1785768283.0411668, "n": 12749, "h": "13aaffa250a8d7c2", "c": "import os\nimport json\n\nclass Config:\n \"\"\"基础配置类\"\"\"\n # 环境配置\n ENV = os.getenv('ENV', 'development') # 默认为开发环境\n DEBUG = ENV == 'development' # 在开发环境中启用调试\n LOG_LEVEL = os.getenv('LOG_LEVEL', 'INFO') # 日志级别\n \n # 项目路径\n BASE_DIR = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))\n \n # 数据库配置\n DATABASE_PATH = os.path.join('./data', 'db', 'algknowledge.db') # SQLite数据库路径\n \n # 上传文件配置\n UPLOAD_FOLDER = os.path.join('./data', 'uploads') # 文件上传目录\n TEMP_FOLDER = os.path.join('./data', 'temp')\n ALLOWED_EXTENSIONS = {'pdf', 'txt', 'csv', 'xlsx', 'json'} # 允许上传的文件类型\n MAX_CONTENT_LENGTH = 100 * 1024 * 1024 # 最大文件上传大小(100MB)\n \n # 缓存配置\n CACHE_DIR = os.path.join('./data', 'cache') # 缓存目录\n CACHE_MAX_SIZE = 500 * 1024 * 1024 # 缓存目录最大大小限制(500MB)\n CACHE_CHECK_INTERVAL = 86400 # 缓存检查间隔(秒),默认为1天\n CACHE_MAX_AGE = 30 * 86400 # 缓存文件最大保存时间(秒),默认为30天\n \n # API配置\n API_PREFIX = '/api/v1' # API前缀\n DISABLE_AI = os.environ.get('DISABLE_AI', 'False').lower() == 'true' # 是否禁用AI功能\n # 安全配置\n SECRET_KEY = os.getenv('SECRET_KEY', 'dev_secret_key') # 密钥\n SECURITY_PASSWORD_SALT = os.getenv('SECURITY_PASSWORD_SALT', 'dev_password_salt') # 密码盐值\n \n # 模型配置\n QWEN_API_KEY = os.getenv('QWEN_API_KEY', 'sk-0fe80fc99c3045dfaa4c2921910245c1') # 千问API密钥\n QWEN_BASE_URL = os.getenv('QWEN_BASE_URL', 'https://dashscope.aliyuncs.com/compatible-mode/v1')\n QWEN_MODEL = os.getenv('QWEN_MODEL', 'qwen-long') # 千问模型\n DEFAULT_MODEL = os.environ.get('DEFAULT_MODEL', 'qwen') # 默认使用千问模型,可通过环境变量修改\n \n # JSON响应大小限制配置\n MAX_JSON_RESPONSE_SIZE = 8192000 # 最大JSON响应大小(字符数)\n \n # 处理并发配置\n MAX_WORKERS = 4 # 最大工作线程数\n\n # 重试配置\n MAX_RETRY_ATTEMPTS = 3 # 最大重试次数\n RETRY_DELAY = 5 # 重试延迟(秒)\n \n # 算法处理配置\n ALGORITHM_BATCH_SIZE = 10 # 每批处理的算法数量\n \n # 基础配置\n TESTING = False\n SECRET_KEY = os.environ.get('SECRET_KEY', 'dev-key')\n \n # 文件路径配置\n ROOT_DIR = os.path.dirname(BASE_DIR)\n UPLOAD_DIR = os.path.join('./data', 'pdfs') # 上传PDF文件存储目录\n OUTPUT_FOLDER = os.path.join('./data') # 输出文件夹\n GRAPH_DATA_DIR = os.path.join('./data', 'graph') # 图数据存储目录\n LOG_DIR = os.path.join('./data', 'logs') # 日志存储目录\n CITED_PAPERS_DIR = os.path.join('./data', 'cited_papers') # 引用文献存储目录\n \n # DeepSeek大模型API配置\n DEEPSEEK_API_KEY = os.environ.get('DEEPSEEK_API_KEY', 'your-deepseek-api-key')\n DEEPSEEK_API_BASE = os.environ.get('DEEPSEEK_API_BASE', 'https://api.deepseek.com')\n DEEPSEEK_MODEL = os.environ.get('DEEPSEEK_MODEL', 'deepseek-chat')\n DEEPSEEK_EMBEDDING_MODEL = os.environ.get('DEEPSEEK_EMBEDDING_MODEL', 'deepseek-embedding')\n \n # 数据库配置 - 只使用MySQL\n DB_TYPE = 'mysql' # 固定为MySQL\n \n # MySQL配置\n MYSQL_HOST = os.environ.get('MYSQL_HOST', 'localhost')\n MYSQL_PORT = int(os.environ.get('MYSQL_PORT', 3306))\n MYSQL_USER = os.environ.get('MYSQL_USER', 'root')\n MYSQL_PASSWORD = os.environ.get('MYSQL_PASSWORD', '123456')\n MYSQL_DB = os.environ.get('MYSQL_DB', 'algorithm_evolution')\n\n # 新添加的OpenAI API相关配置\n OPENAI_API_KEY = os.environ.get('OPENAI_API_KEY', '')\n OPENAI_MODEL = os.environ.get('OPENAI_MODEL', 'gpt-3.5-turbo')\n\n @classmethod\n def init_app(cls, app):\n \"\"\"初始化应用程序配置\"\"\"\n # 确保必要的目录存在\n os.makedirs(cls.UPLOAD_FOLDER, exist_ok=True)\n os.makedirs(cls.CACHE_DIR, exist_ok=True)\n os.makedirs(os.path.dirname(cls.DATABASE_PATH), exist_ok=True)\n \n # 配置日志\n import logging\n logging.basicConfig(\n level=getattr(logging, cls.LOG_LEVEL),\n format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'\n )\n \n # 定期清理过期缓存\n if not cls.DEBUG: # 在非开发环境中启用定期清理\n cls._schedule_cache_cleanup()\n \n @classmethod\n def _schedule_cache_cleanup(cls):\n \"\"\"安排定期清理缓存任务\"\"\"\n import threading\n import time\n \n def cleanup_task():\n while True:\n try:\n cls._clean_cache()\n time.sleep(cls.CACHE_CHECK_INTERVAL)\n except Exception as e:\n import logging\n logging.error(f\"缓存清理失败: {str(e)}\")\n # 发生错误时延迟一小时后重试\n time.sleep(3600)\n \n # 启动清理线程\n cleanup_thread = threading.Thread(target=cleanup_task, daemon=True)\n cleanup_thread.start()\n \n @classmethod\n def _clean_cache(cls):\n \"\"\"清理过期和超大缓存文件\"\"\"\n import logging\n import time\n import os\n \n try:\n now = time.time()\n total_size = 0\n files_info = []\n \n # 收集所有缓存文件信息\n for file_name in os.listdir(cls.CACHE_DIR):\n file_path = os.path.join(cls.CACHE_DIR, file_name)\n if os.path.isfile(file_path):\n stats = os.stat(file_path)\n total_size += stats.st_size\n files_info.append({\n 'path': file_path,\n 'size': stats.st_size,\n 'mtime': stats.st_mtime,\n 'atime': stats.st_atime\n })\n \n # 如果缓存总大小超过限制,则按访问时间排序删除最旧的文件\n if total_size > cls.CACHE_MAX_SIZE:\n logging.info(f\"缓存总大小 ({total_size / 1024 / 1024:.2f} MB) 超过限制 ({cls.CACHE_MAX_SIZE / 1024 / 1024:.2f} MB),开始清理...\")\n # 按访问时间排序,最旧的在前面\n files_info.sort(key=lambda x: x['atime'])\n \n # 删除最旧的文件,直到缓存大小低于限制\n for file_info in files_info:\n if total_size <= cls.CACHE_MAX_SIZE * 0.9: # 保留10%的缓冲区\n break\n \n try:\n os.remove(file_info['path'])\n total_size -= file_info['size']\n logging.info(f\"删除旧缓存文件: {file_info['path']} ({file_info['size'] / 1024 / 1024:.2f} MB)\")\n except Exception as e:\n logging.error(f\"删除缓存文件失败: {file_info['path']}, 错误: {str(e)}\")\n \n # 删除超过最大保存时间的文件\n for file_info in files_info:\n if now - file_info['mtime'] > cls.CACHE_MAX_AGE:\n try:\n os.remove(file_info['path'])\n logging.info(f\"删除过期缓存文件: {file_info['path']}, 超过 {cls.CACHE_MAX_AGE / 86400:.1f} 天\")\n except Exception as e:\n if os.path.exists(file_info['path']): # 检查文件是否还存在,可能已被之前的清理步骤删除\n logging.error(f\"删除过期缓存文件失败: {file_info['path']}, 错误: {str(e)}\")\n \n # 检查和修复不完整的缓存文件\n cls._check_incomplete_cache_files()\n \n logging.info(\"缓存清理完成\")\n except Exception as e:\n logging.exception(f\"缓存清理过程中发生错误: {str(e)}\")\n \n @classmethod\n def _check_incomplete_cache_files(cls):\n \"\"\"检查并修复不完整的缓存文件\"\"\"\n import logging\n import os\n import json\n import datetime\n \n try:\n incomplete_count = 0\n fixed_count = 0\n \n for file_name in os.listdir(cls.CACHE_DIR):\n if file_name.endswith('.json'):\n file_path = os.path.join(cls.CACHE_DIR, file_name)\n \n try:\n with open(file_path, 'r', encoding='utf-8') as f:\n try:\n data = json.load(f)\n \n # 检查是否有error字段但没有completed字段\n if 'error' in data and 'completed' not in data:\n data['completed'] = False\n data['timestamp'] = datetime.datetime.now().isoformat()\n \n with open(file_path, 'w', encoding='utf-8') as fw:\n json.dump(data, fw, ensure_ascii=False, indent=2)\n \n fixed_count += 1\n logging.info(f\"修复了不完整的缓存文件: {file_path}\")\n except json.JSONDecodeError:\n # 文件内容不是有效的JSON\n logging.warning(f\"缓存文件 {file_path} 不是有效的JSON,将被标记为不完整\")\n with open(file_path, 'w', encoding='utf-8') as fw:\n json.dump({\n 'error': 'Invalid JSON content',\n 'completed': False,\n 'timestamp': datetime.datetime.now().isoformat()\n }, fw, ensure_ascii=False, indent=2)\n \n incomplete_count += 1\n except Exception as e:\n logging.error(f\"检查缓存文件 {file_path} 时出错: {str(e)}\")\n \n if incomplete_count > 0 or fixed_count > 0:\n logging.info(f\"缓存文件检查: 发现 {incomplete_count} 个无效文件,修复了 {fixed_count} 个不完整文件\")\n \n except Exception as e:\n logging.exception(f\"检查不完整缓存文件时出错: {str(e)}\")\n\n # 新添加的加载和保存配置文件的方法\n @staticmethod\n def load_config(config_file='config.json'):\n \"\"\"从JSON文件加载配置\"\"\"\n config_path = os.path.join(Config.BASE_DIR, config_file)\n if os.path.exists(config_path):\n try:\n with open(config_path, 'r', encoding='utf-8') as f:\n config_data = json.load(f)\n \n # 更新数据库配置\n if 'mysql' in config_data:\n mysql = config_data['mysql']\n Config.MYSQL_HOST = mysql.get('host', Config.MYSQL_HOST)\n Config.MYSQL_PORT = int(mysql.get('port', Config.MYSQL_PORT))\n Config.MYSQL_USER = mysql.get('user', Config.MYSQL_USER)\n Config.MYSQL_PASSWORD = mysql.get('password', Config.MYSQL_PASSWORD)\n Config.MYSQL_DB = mysql.get('database', Config.MYSQL_DB)\n \n # 更新API配置\n if 'api' in config_data:\n api = config_data['api']\n Config.OPENAI_API_KEY = api.get('openai_api_key', Config.OPENAI_API_KEY)\n Config.OPENAI_MODEL = api.get('openai_model', Config.OPENAI_MODEL)\n Config.QWEN_API_KEY = api.get('qwen_api_key', Config.QWEN_API_KEY)\n Config.QWEN_BASE_URL = api.get('qwen_base_url', Config.QWEN_BASE_URL)\n \n print(\"配置已从文件加载: \" + config_path)\n except Exception as e:\n print(\"加载配置文件时出错: \" + str(e))\n \n @staticmethod\n def save_config(config_file='config.json'):\n \"\"\"将配置保存到JSON文件\"\"\"\n config_path = os.path.join(Config.BASE_DIR, config_file)\n try:\n config_data = {\n 'mysql': {\n 'host': Config.MYSQL_HOST,\n 'port': Config.MYSQL_PORT,\n 'user': Config.MYSQL_USER,\n 'password': Config.MYSQL_PASSWORD,\n 'database': Config.MYSQL_DB\n },\n 'api': {\n 'openai_api_key': Config.OPENAI_API_KEY,\n 'openai_model': Config.OPENAI_MODEL,\n 'qwen_api_key': Config.QWEN_API_KEY,\n 'qwen_base_url': Config.QWEN_BASE_URL\n }\n }\n \n with open(config_path, 'w', encoding='utf-8') as f:\n json.dump(config_data, f, indent=4, ensure_ascii=False)\n \n print(\"配置已保存到文件: \" + config_path)\n \n except Exception as e:\n print(\"保存配置文件时出错: \" + str(e))\n\n\nclass DevelopmentConfig(Config):\n \"\"\"开发环境配置\"\"\"\n DEBUG = True\n\n\nclass TestingConfig(Config):\n \"\"\"测试环境配置\"\"\"\n DEBUG = True\n TESTING = True\n\n\nclass ProductionConfig(Config):\n \"\"\"生产环境配置\"\"\"\n DEBUG = False\n\n\n# 配置名称映射字典\nconfig_by_name = {\n 'development': DevelopmentConfig,\n 'testing': TestingConfig,\n 'production': ProductionConfig,\n 'default': DevelopmentConfig\n}\n\n# 确保必要的目录存在\nfor directory in [Config.UPLOAD_FOLDER, Config.CITED_PAPERS_DIR, Config.OUTPUT_FOLDER, Config.GRAPH_DATA_DIR, Config.LOG_DIR, Config.CACHE_DIR]:\n if not os.path.exists(directory):\n os.makedirs(directory)\n\n# 加载配置\nConfig.load_config() "}}}}