1 line
75 KiB
JSON
1 line
75 KiB
JSON
{"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() "}}}} |