fix: 修复 web_api.py 登录限流、静态文件 404、星图 LIMIT 200 问题

- 添加登录限流逻辑(LOGIN_MAX_ATTEMPTS=5, LOGIN_WAIT_MINUTES=5)
- 修复 PyInstaller 打包后模板和静态文件路径问题
- 移除 entities 查询 LIMIT 200 限制,确保星图显示全部节点
- 修正 graph_db 死锁问题,使用 get_global_db() 回退
This commit is contained in:
root
2026-05-08 10:13:47 +08:00
parent 2de699e2aa
commit 90df082a92
2 changed files with 197 additions and 173 deletions

106
TrulyMEM.spec Normal file
View File

@ -0,0 +1,106 @@
# -*- mode: python ; coding: utf-8 -*-
import os
import sys
block_cipher = None
project_root = os.path.dirname(os.path.abspath(SPEC))
sys.path.insert(0, project_root)
datas = []
# UI 样式
ui_styles_dir = os.path.join(project_root, 'ui', 'styles')
if os.path.exists(ui_styles_dir):
for root, dirs, files in os.walk(ui_styles_dir):
for f in files:
datas.append((os.path.join(root, f), 'ui/styles'))
# Prompt 模板
prompt_tmpl_dir = os.path.join(project_root, 'core', 'prompts', 'templates')
if os.path.exists(prompt_tmpl_dir):
for root, dirs, files in os.walk(prompt_tmpl_dir):
for f in files:
datas.append((os.path.join(root, f), 'core/prompts/templates'))
# Web 静态文件
static_dir = os.path.join(project_root, 'ui', 'static')
if os.path.exists(static_dir):
for root, dirs, files in os.walk(static_dir):
for f in files:
rel_dir = os.path.relpath(root, project_root)
datas.append((os.path.join(root, f), rel_dir))
# 兼容旧的 static 目录(如果存在)
static_dir_old = os.path.join(project_root, 'static')
if os.path.exists(static_dir_old):
for root, dirs, files in os.walk(static_dir_old):
for f in files:
datas.append((os.path.join(root, f), 'static'))
# Web 模板(Flask template_folder 指向 ui/templates/)
templates_dir = os.path.join(project_root, 'ui', 'templates')
if os.path.exists(templates_dir):
for root, dirs, files in os.walk(templates_dir):
for f in files:
rel_dir = os.path.relpath(root, project_root)
datas.append((os.path.join(root, f), rel_dir))
# Web API 脚本(以便子进程模式回退使用)
web_api_src = os.path.join(project_root, 'core', 'web_api.py')
if os.path.exists(web_api_src):
datas.append((web_api_src, 'core'))
# ——— TUI 主二进制 ———
a = Analysis(
[os.path.join(project_root, 'trulymem_entry.py')],
pathex=[],
binaries=[],
datas=datas,
hiddenimports=[
'textual', 'textual.app', 'textual.widgets', 'textual.css',
'openai', 'openai._client',
'neo4j',
'sqlite3',
'core', 'core.embedded_db', 'core.graph_client',
'core.tool_executor', 'core.tool_limiter',
'core.tools', 'core.tools.memory_tools',
'core.prompts', 'core.prompts.prompt_manager',
'core.server', 'core.client', 'core.web_api',
'core.migrate',
'ui', 'ui.app', 'ui.login_screen',
'ui.models', 'ui.models.message', 'ui.models.config', 'ui.models.log_entry',
'ui.widgets', 'ui.widgets.left_panel', 'ui.widgets.right_panel',
'ui.widgets.input_box', 'ui.widgets.message_history', 'ui.widgets.status_bar',
'ui.handlers',
'ui.services', 'ui.services.config_manager', 'ui.services.config_service',
'flask', 'flask_cors', 'werkzeug',
],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
noarchive=False,
optimize=0,
)
pyz = PYZ(a.pure)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.datas,
[],
name='TrulyMEM',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=True,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
)