13 KiB
天璇 v5 — 18 Issues Full Fix Plan
TL;DR (For humans)
修复上传管理、列检测、大规模数据处理、Globe可视化、聚类可视化等18个问题。
Workstream A: 上传管理修复 (Issues 1, 2, 3, 10, 11)
A1 重启后端后旧数据可分析
Files: analysis/views.py, analysis/session_store.py
Root Cause: 旧分析的 AnalysisRun 记录在 DB 中,但 csv_glob 指向的目录是 %APPDATA%/TianXuan/data/uploads/{timestamp}/。重启后 session_store 内存清空,但上传文件仍在磁盘。globe_view 和 run_detail 尝试加载旧运行时会调用 load_csv_directory(run.csv_glob) 重新读取 CSV。
Fix: 确保 load_csv_directory 能处理已删除的上传目录 → 优雅降级。在 globe_view 和 _background_process 中添加 os.path.isdir() 检查,目录不存在时将 run 标记为 failed 并设置友好的错误消息。
A2 Web图标在所有页面显示
Files: templates/base.html, static/tianxuan/
Root Cause: base.html 没有 <link rel="icon">。浏览器自动请求 /favicon.ico 但项目无此文件。
Fix:
- 创建
static/tianxuan/favicon.svg或使用基于主题的 HTML favicon base.html的<head>中添加<link rel="icon" href="{% static 'tianxuan/favicon.ico' %}">
A3 上传按钮在页面顶部
File: templates/tianxuan/upload.html
Root Cause: 上传 <form> 在 "已上传数据集" 表格之前,但上传按钮 (#submitBtn) 初始 display:none,只有在选择文件后才显示。
Fix: 将上传按钮移到 dropZone 下方、紧跟在选择文件后显示。或者将上传区域移到页面顶部的固定/粘性位置。
A10 Django文件上传无限制
Files: tianxuan/settings.py, analysis/views.py
Root Cause: 当前限制:DATA_UPLOAD_MAX_NUMBER_FIELDS=10000、DATA_UPLOAD_MAX_MEMORY_SIZE=50MB、views.py 中硬编码 2000 文件/10GB 总大小限制。用户说"只能上传100文件"可能是由于 FILE_UPLOAD_MAX_MEMORY_SIZE=10MB 导致大文件被写入临时文件时出现问题。
Fix:
- 移除
DATA_UPLOAD_MAX_NUMBER_FIELDS限制(设为 0 或大幅增加) - 增大
DATA_UPLOAD_MAX_MEMORY_SIZE到 256MB - 移除
views.py中的 2000 文件限制(改为仅警告)
A11 上传页删除功能完善
Files: templates/tianxuan/upload.html, analysis/views.py
Root Cause: 删除按钮只显示在 status 为 ready/completed/failed 的运行上。loading/profiling/aggregating 状态的运行没有删除按钮(可能是为了安全)。
Fix:
- 修改模板,在所有状态下显示删除按钮(
loading状态时弹出确认:"后台处理中,删除将中断分析") - 确保
delete_upload视图能安全处理正在处理的运行(shutil.rmtree+ ORM delete)
Workstream B: 列检测与类型分类修复 (Issues 7, 15, 18)
B7 TLS 0ver hex格式识别
Files: analysis/type_classifier.py, analysis/views.py, templates/tianxuan/globe.html
Root Cause: 0ver 列名不在名称启发式规则中(需要 ^ver_ 前缀)。TLS版本检测在 views.py 中硬编码为 '1.3' in tls / '1.2' in tls,不知道 hex 格式如 03 03 (TLS 1.2) / 03 04 (TLS 1.3)。
Fix:
type_classifier.py的_NAME_TYPE_MAP添加0ver→ ENUM 映射views.py的globe_view中添加 hex→TLS版本映射:TLS_HEX_MAP = {'0303': 'TLSv1.2', '0304': 'TLSv1.3', '0302': 'TLSv1.1', '0301': 'TLSv1.0'} hex_val = tls.replace(' ', '') # "03 03" → "0303" tls_label = TLS_HEX_MAP.get(hex_val, 'other')- Globe legend 添加对 hex 版本的说明
B15 "+"字符串被识别为数字
Files: analysis/type_classifier.py, analysis/data_loader.py
Root Cause: 独立 + 在 _coerce_to_float 中被列为 artifact(正常),但值如 +5、+0.5 等前导加号的值会通过 float("+5") 解析。在 _values_to_type 中,LAT_LON 检测会过滤独立 +,但列中混有 + 和数字的列可能被分类为 FLOAT。
Fix:
- 在
_values_to_type的 FLOAT 检测步骤中,检查采样中是否有+或-开头的字符串值 - 如果存在前导
+/-且并非所有值都是有效数字,降级为 STRING - 在
_coerce_to_float中添加对+前缀值的更严格检查
B18 根据真实列名配置实体检测
Files: analysis/entity_detector.py, analysis/entity_aggregator.py, config/config.yaml
Changes:
entity_detector.py的ENTITY_KEYWORDS添加用户全部列名entity_aggregator.py的关键词集合添加用户列名config.yaml更新entity.ip_columns和 column 覆盖type_classifier.py的_NAME_TYPE_MAP添加全部列名映射
用户列名映射表:
| 列名 | 类型 | 聚合用途 | 检测关键词 |
|---|---|---|---|
:ips |
IPv4 (已存在) | src IP | :ips |
:ipd |
IPv4 (已存在) | dst IP | :ipd |
:prs |
ENUM/端口 | src port | :prs |
:prd |
ENUM/端口 | dst port | :prd |
scnt |
STRING/ENUM | source country | scnt |
dcnt |
STRING/ENUM | dest country | dcnt |
server-ip |
IPv4 | server IP | server_ip |
client-ip |
IPv4 | client IP | client_ip |
0ver |
ENUM | TLS version | 0ver |
cnam |
STRING | cert common name | cnam |
snam |
STRING | server name | snam |
4dur |
FLOAT | duration | 4dur |
8ses |
FLOAT | session offset | 8ses |
2tmo |
FLOAT | timeout offset | 2tmo |
4ksz |
INT | key size | 4ksz |
cnrs |
BOOL_ENUM | recoverable | cnrs |
isrs |
BOOL_ENUM | is recovered | isrs |
8ack |
INT | backward bytes | 8ack |
8ppk |
INT | payload packets | 8ppk |
8dbd |
TIMESTAMP | db timestamp | 8dbd |
1ipp |
ENUM | IP protocol | 1ipp |
4dbn |
ENUM | database number | 4dbn |
tabl |
STRING | table name | tabl |
name |
STRING | link name | name |
source-node |
STRING | source node | source_node |
cipher-suite |
HEX | TLS cipher | cipher_suite |
ecdhe-named-curve |
STRING | ECDHE curve | ecdhe_named_curve |
0cph |
HEX | TLS cipher hex | 0cph |
0crv |
HEX | TLS curve hex | 0crv |
0rnd |
STRING | TLS random | 0rnd |
0rnt |
FLOAT/TIMESTAMP | TLS random time | 0rnt |
4dbn |
STRING | db number | 4dbn |
time |
TIMESTAMP | time | time |
timestamp |
TIMESTAMP | timestamp | timestamp |
row |
INT | row number | row |
+.latd |
LAT_LON | latitude (entity_aggregator 子串匹配) | latd |
+.lond |
LAT_LON | longitude | lond |
+.ispn |
STRING | ISP name | ispn |
+.orgn |
STRING | org name | orgn |
+.city |
STRING | city | city |
关键的 _find_column 改进:
entity_aggregator.py 中的 _find_column 使用严格匹配。对于 :prs 需要匹配 dst_port keywords → 不匹配。需要在 _find_column 中添加 + 和 : 前缀剥离:
normalised = name.lower().lstrip(':+').replace('-', '_').replace(' ', '_')
Lat/Lon 列检测修复:
+.latd / +.lond 列:
type_classifier._values_to_type中如果值 max_abs ≤ 10 则 LAT_LON 检测失败- 需要在
_NAME_TYPE_MAP中添加latd|lond模式 → LAT_LON - 或在
_name_to_type中添加对+.前缀的感知
Workstream C: Traceback截断修复 (Issue 4)
C4 清理所有 traceback 截断
File: analysis/tool_registry.py line 1138
Current: traceback.format_exc()[:200] 截断 PCA 错误到 200 字符
Fix: 改为完整 traceback。同时审计整个项目:
tianxuan/llm_orchestrator.pyline 71:json.dumps(...)[:1200]— 这是工具结果截断,合理,保留analysis/tool_registry.pyline 43:_truncate_response()— 工具响应截断,合理,保留- 只修复 line 1138 的
[:200]
Workstream D: 大规模数据处理 (Issues 5, 6, 14, 16)
D5 大数据量卡顿优化 (1M-20M行)
Root Cause: 当前 MAX_ROWS_PER_RUN = 300 但分析流水线是一次性 collect 所有数据到内存。
Fix:
data_loader.py的load_csv_directory添加head=N参数用于预览场景- 聚类分析使用 Polars streaming (
engine='streaming') - 在
tool_registry.py的_cluster_sync中添加数据降采样:>50K 行时随机采样 views.py中 globe_view 的MAX_ROWS_PER_RUN从 300 改为 500(对于 20M 数据来说 300 行太稀疏了)
D6 进度条 + 静默处理
Root Cause: 当前状态机只有 loading→profiling→aggregating→ready→clustering→extracting→completed/failed,无百分比。
Fix:
- 在
AnalysisRunmodel 添加progress_pct(IntegerField, default=0) 和progress_msg(CharField) - 后台线程在每一步更新
progress_pct(loading=10, profiling=30, aggregating=50, clustering=70, extracting=90, completed=100) run_status_api返回progress_pct和progress_msgupload.html中的进度条显示实际百分比- 无前端静默处理:添加
?background=true参数,后端仍全速分析但前端不轮询
D14 低内存设备聚类崩溃
Root Cause: 8GB 设备上,20M 行 × 30 列的数据在聚类时会产生巨大 float64 ndarray。 Fix:
_cluster_sync中添加内存检查:psutil.virtual_memory().available < 2GB时自动启用流式模式- 自动降采样:>100K 行时使用
sklearn.utils.resample采样到 50K 行 - 使用
MiniBatchKMeans替代KMeans(内存效率更高) - 在聚类前使用
sklearn.decomposition.PCA(n_components=min(50, n_features))降维
D16 空闲时高磁盘IO
Root Cause: session_store.py 是纯内存的,不应有磁盘 IO。但 Django 日志 RotatingFileHandler 可能在后台写入。另外 SQLite 使用 DELETE 模式(非 WAL)可能导致写入阻塞。
Fix:
- 审计后台线程是否有不必要的 ORM 轮询
- 如果
settings.py中的LOGGING配置了低级别(如 DEBUG),改为 INFO+ - 检查是否有任何定时任务或 watchdog
Workstream E: Globe可视化修复 (Issues 8, 9)
E8 Globe响应式缩放
File: templates/tianxuan/globe.html
Root Cause: 当前高度固定为 700px(H = 700),resize 只更新宽度和 aspect。缩放(wheel)只移动 camera.position.z(zoom),不按比例调整数据点大小。
Fix:
- resize handler 中根据容器尺寸动态计算高度:
H = container.clientHeight || window.innerHeight * 0.8 - 添加设备像素比处理:
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)) - 弧线粗细使用相对比例(根据 zoom level 调整
TubeGeometry.radius或LineBasicMaterial.linewidth)
E9 ?data= 访问拒绝支持
File: analysis/views.py (globe_view), templates/tianxuan/globe.html
Root Cause: globe_view 只识别 ?runs=1&runs=2 格式,没有 ?data= 参数的处理逻辑。
Fix:
globe_view添加?data=dataset_id参数支持- 当提供
data=时,直接从SessionStore按 dataset_id 读取数据 - Globe 模板更新 JavaScript 以支持 dataset 模式
Workstream F: LLM日志 (Issue 12)
F12 LLM运行过程打印到前端
Files: tianxuan/llm_orchestrator.py, analysis/views.py, templates/tianxuan/auto.html
Root Cause: LLM 在 thread 中运行,logger.info 写入日志文件,但前端 auto.html 通过轮询 /logs/?pos=N 显示日志。问题是日志缓冲可能延迟写入。
Fix:
- 添加
llm_status_api视图返回当前 LLM 运行状态 llm_orchestrator使用回调函数报告进度(步骤/工具调用/中间结果)_run_llm_analysisworker 写入AnalysisRun.run_log字段
Workstream G: 聚类可视化修复 (Issue 13)
G13 聚类图表完善
Files: templates/analysis/cluster_overview.html, analysis/views.py
Root Cause: 当前只有 PCA 散点图 + 地理散点图(两个 Canvas)。用户要求更丰富的图表。
Fix:
- 添加簇大小饼图/柱状图(Canvas)
- 添加 Silhouette 得分的簇间对比图
- 添加特征重要性水平条形图(top 10 features per cluster)
- 确保 PCA 坐标在 web 分析流程中正确保存(当前
_handle_extract_features在 tool_registry.py 中保存,但异常被[:200]截断 → 先修 C4)
Workstream H: 聚类质量改进 (Issue 17)
H17 预处理降维+特征工程后聚类
Files: analysis/tool_registry.py, analysis/entity_aggregator.py
Root Cause: 当前聚类直接对原始聚合特征(flow_count, total_bytes, unique_dst_ips 等)做 StandardScaler + HDBSCAN。没有特征选择、PCA/UMAP 预处理。
Fix:
- 在
_cluster_sync中添加可选的 PCA 预处理步骤 - 添加方差过滤:去除方差为 0 或接近 0 的特征
- 添加相关性过滤:去除相关性 >0.95 的特征对中的冗余特征
- HDBSCAN 超参数根据数据规模自动调整
Dependencies
- C4 (traceback fix) is prerequisite for G13 (PCA fix won't be debuggable without full traceback)
- B18 (column mapping) is prerequisite for B7 (0ver hex detection needs 0ver in column map) and G17 (proper features need proper column detection)
- D5 (optimization) is partially prerequisite for D14 (memory handling both affect clustering path)
Must-Not-Have
- 不修改
runtime/目录下的任何文件 - 不删除或重命名现有数据库表
- 不添加新的 Python 包依赖(除非绝对必要且用户批准)
- 不修改 Polars 版本锁定