问题优化
This commit is contained in:
parent
5d4c52fba4
commit
265dd6bfa3
99
README.md
99
README.md
@ -27,6 +27,11 @@
|
|||||||
- 交互式命令行界面,便于直接使用
|
- 交互式命令行界面,便于直接使用
|
||||||
- 支持自定义评分参数
|
- 支持自定义评分参数
|
||||||
|
|
||||||
|
5. **Web界面模块**
|
||||||
|
- 基于Flask的Web界面,提供图形化操作体验
|
||||||
|
- 可视化显示阵容推荐结果
|
||||||
|
- 支持在线调整权重参数与配置
|
||||||
|
|
||||||
## 环境与依赖
|
## 环境与依赖
|
||||||
|
|
||||||
- **Python版本:** Python 3.8+
|
- **Python版本:** Python 3.8+
|
||||||
@ -34,7 +39,12 @@
|
|||||||
- requests: 用于获取在线数据
|
- requests: 用于获取在线数据
|
||||||
- pandas: 用于数据处理
|
- pandas: 用于数据处理
|
||||||
- pyyaml: 用于配置文件解析
|
- pyyaml: 用于配置文件解析
|
||||||
|
- numpy: 用于数值计算
|
||||||
|
- flask: 用于Web界面
|
||||||
|
- flask-cors: 处理跨域请求
|
||||||
|
- waitress: 生产环境Web服务器
|
||||||
- pytest: 用于单元测试
|
- pytest: 用于单元测试
|
||||||
|
- tqdm: 用于进度显示
|
||||||
|
|
||||||
## 项目安装
|
## 项目安装
|
||||||
|
|
||||||
@ -61,7 +71,7 @@ python main.py --help
|
|||||||
|
|
||||||
输出结果会显示所有可用的子命令和选项。
|
输出结果会显示所有可用的子命令和选项。
|
||||||
|
|
||||||
### Web界面(新增)
|
### Web界面
|
||||||
|
|
||||||
运行以下命令启动Web界面:
|
运行以下命令启动Web界面:
|
||||||
|
|
||||||
@ -74,6 +84,7 @@ python main.py web
|
|||||||
- `--host`: 指定服务器主机地址,默认为"0.0.0.0"(允许所有网络接口访问)
|
- `--host`: 指定服务器主机地址,默认为"0.0.0.0"(允许所有网络接口访问)
|
||||||
- `--port`: 指定服务器端口,默认为5000
|
- `--port`: 指定服务器端口,默认为5000
|
||||||
- `--dev`: 启用开发模式(开启调试功能,自动重载代码)
|
- `--dev`: 启用开发模式(开启调试功能,自动重载代码)
|
||||||
|
- `--config`: 指定自定义配置文件路径
|
||||||
|
|
||||||
例如:
|
例如:
|
||||||
```bash
|
```bash
|
||||||
@ -135,6 +146,32 @@ python main.py scoring
|
|||||||
python main.py scoring --config path/to/custom_config.yaml
|
python main.py scoring --config path/to/custom_config.yaml
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### 配置管理
|
||||||
|
|
||||||
|
运行以下命令管理权重配置:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python main.py config --show
|
||||||
|
```
|
||||||
|
|
||||||
|
配置管理提供以下功能:
|
||||||
|
- 显示当前所有权重配置
|
||||||
|
- 设置特定羁绊的权重
|
||||||
|
- 设置特定棋子的权重
|
||||||
|
- 设置基础权重参数
|
||||||
|
|
||||||
|
例如:
|
||||||
|
```bash
|
||||||
|
# 设置羁绊权重
|
||||||
|
python main.py config --set-synergy "超频战士" 1.5
|
||||||
|
|
||||||
|
# 设置棋子权重
|
||||||
|
python main.py config --set-chess "厄加特" 1.8
|
||||||
|
|
||||||
|
# 设置基础权重参数
|
||||||
|
python main.py config --set-base "synergy_level_weight" 1.2
|
||||||
|
```
|
||||||
|
|
||||||
### 命令行界面
|
### 命令行界面
|
||||||
|
|
||||||
运行以下命令启动交互式命令行界面:
|
运行以下命令启动交互式命令行界面:
|
||||||
@ -160,6 +197,7 @@ python main.py cli --population 8 --results 5 --level-weight 1.2 --count-weight
|
|||||||
- `--level-weight`:羁绊等级权重,默认为1.0
|
- `--level-weight`:羁绊等级权重,默认为1.0
|
||||||
- `--count-weight`:羁绊数量权重,默认为0.5
|
- `--count-weight`:羁绊数量权重,默认为0.5
|
||||||
- `--cost-weight`:棋子费用权重,默认为0.1
|
- `--cost-weight`:棋子费用权重,默认为0.1
|
||||||
|
- `--config`:指定自定义配置文件路径
|
||||||
|
|
||||||
## 项目结构
|
## 项目结构
|
||||||
|
|
||||||
@ -186,7 +224,10 @@ TFT-Strategist/
|
|||||||
│ │ ├── __init__.py
|
│ │ ├── __init__.py
|
||||||
│ │ ├── api.py # 编程接口
|
│ │ ├── api.py # 编程接口
|
||||||
│ │ └── cli.py # 命令行界面
|
│ │ └── cli.py # 命令行界面
|
||||||
│ ├── web/ # Web界面模块 (新增)
|
│ ├── config/ # 配置管理模块
|
||||||
|
│ │ ├── __init__.py
|
||||||
|
│ │ └── weights_config.py # 权重配置管理
|
||||||
|
│ ├── web/ # Web界面模块
|
||||||
│ │ ├── __init__.py
|
│ │ ├── __init__.py
|
||||||
│ │ ├── app.py # Flask应用
|
│ │ ├── app.py # Flask应用
|
||||||
│ │ ├── static/ # 静态资源
|
│ │ ├── static/ # 静态资源
|
||||||
@ -207,6 +248,10 @@ TFT-Strategist/
|
|||||||
│ └── test_interface.py # 接口模块测试
|
│ └── test_interface.py # 接口模块测试
|
||||||
├── main.py # 主程序入口
|
├── main.py # 主程序入口
|
||||||
├── requirements.txt # 项目依赖
|
├── requirements.txt # 项目依赖
|
||||||
|
├── test_direct.py # 直接测试脚本
|
||||||
|
├── test_recommendation.py # 阵容推荐测试脚本
|
||||||
|
├── generate_weights_config.py # 权重配置生成工具
|
||||||
|
├── get_data.py # 数据获取工具
|
||||||
└── README.md # 项目文档
|
└── README.md # 项目文档
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -478,20 +523,68 @@ python main.py cli [参数]
|
|||||||
2. 添加必选棋子
|
2. 添加必选棋子
|
||||||
3. 获取详细的阵容推荐结果
|
3. 获取详细的阵容推荐结果
|
||||||
|
|
||||||
|
## Web界面模块详解
|
||||||
|
|
||||||
|
Web界面模块提供了图形化的用户交互方式,基于Flask框架实现。
|
||||||
|
|
||||||
|
### 主要功能
|
||||||
|
|
||||||
|
1. **阵容推荐设置**
|
||||||
|
- 可视化选择阵容人口
|
||||||
|
- 添加/删除必选羁绊和棋子
|
||||||
|
- 自定义权重调整
|
||||||
|
|
||||||
|
2. **阵容展示**
|
||||||
|
- 直观显示推荐阵容棋子和羁绊
|
||||||
|
- 支持多种排序和筛选方式
|
||||||
|
- 详细的阵容分析数据
|
||||||
|
|
||||||
|
3. **配置管理**
|
||||||
|
- 在线编辑权重配置
|
||||||
|
- 保存和加载配置文件
|
||||||
|
- 配置模板管理
|
||||||
|
|
||||||
|
### 启动方式
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python main.py web [--host HOST] [--port PORT] [--dev] [--config CONFIG_PATH]
|
||||||
|
```
|
||||||
|
|
||||||
|
## 工具脚本
|
||||||
|
|
||||||
|
### generate_weights_config.py
|
||||||
|
|
||||||
|
用于生成初始权重配置文件,可根据游戏最新数据自动更新配置。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python generate_weights_config.py [--output OUTPUT_PATH]
|
||||||
|
```
|
||||||
|
|
||||||
|
### get_data.py
|
||||||
|
|
||||||
|
用于从官方接口获取最新游戏数据,支持手动更新。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python get_data.py [--force]
|
||||||
|
```
|
||||||
|
|
||||||
## 开发计划
|
## 开发计划
|
||||||
|
|
||||||
- [x] 数据提供模块
|
- [x] 数据提供模块
|
||||||
- [x] 阵容推荐模块
|
- [x] 阵容推荐模块
|
||||||
- [x] 阵容评分模块
|
- [x] 阵容评分模块
|
||||||
- [x] 接口模块
|
- [x] 接口模块
|
||||||
|
- [x] Web界面模块
|
||||||
|
- [x] 配置管理功能
|
||||||
|
|
||||||
## 未来展望
|
## 未来展望
|
||||||
|
|
||||||
- [ ] 图形用户界面(GUI)开发
|
- [ ] 优化算法效率,支持更复杂的推荐策略
|
||||||
- [ ] 基于历史数据的胜率分析
|
- [ ] 基于历史数据的胜率分析
|
||||||
- [ ] 支持装备推荐
|
- [ ] 支持装备推荐
|
||||||
- [ ] 多语言支持
|
- [ ] 多语言支持
|
||||||
- [ ] 基于机器学习的个性化推荐
|
- [ ] 基于机器学习的个性化推荐
|
||||||
|
- [ ] 移动端应用开发
|
||||||
|
|
||||||
## 贡献指南
|
## 贡献指南
|
||||||
|
|
||||||
|
BIN
analysis_summary.txt
Normal file
BIN
analysis_summary.txt
Normal file
Binary file not shown.
@ -56,11 +56,26 @@ def create_app(config_path: Optional[str] = None):
|
|||||||
all_synergies = all_jobs + all_races
|
all_synergies = all_jobs + all_races
|
||||||
all_chess = data_api.get_all_chess()
|
all_chess = data_api.get_all_chess()
|
||||||
|
|
||||||
|
# 打印羁绊和棋子数据结构,用于调试
|
||||||
|
logger.info(f"羁绊数量: {len(all_synergies)}")
|
||||||
|
if all_synergies:
|
||||||
|
sample_synergy = all_synergies[0]
|
||||||
|
logger.info(f"羁绊示例: {sample_synergy}")
|
||||||
|
|
||||||
|
logger.info(f"棋子数量: {len(all_chess)}")
|
||||||
|
if all_chess:
|
||||||
|
sample_chess = all_chess[0]
|
||||||
|
logger.info(f"棋子示例: {sample_chess}")
|
||||||
|
|
||||||
# 获取全局配置中的权重信息
|
# 获取全局配置中的权重信息
|
||||||
base_weights = weights_config.get_base_weights()
|
base_weights = weights_config.get_base_weights()
|
||||||
synergy_weights = weights_config.get_synergy_weights()
|
synergy_weights = weights_config.get_synergy_weights()
|
||||||
chess_weights = weights_config.get_chess_weights()
|
chess_weights = weights_config.get_chess_weights()
|
||||||
|
|
||||||
|
# 打印权重配置,用于调试
|
||||||
|
logger.info(f"羁绊权重示例: {list(synergy_weights.items())[:3]}")
|
||||||
|
logger.info(f"棋子权重示例: {list(chess_weights.items())[:3]}")
|
||||||
|
|
||||||
return render_template('index.html',
|
return render_template('index.html',
|
||||||
synergies=all_synergies,
|
synergies=all_synergies,
|
||||||
chess=all_chess,
|
chess=all_chess,
|
||||||
@ -144,9 +159,10 @@ def create_app(config_path: Optional[str] = None):
|
|||||||
for synergy_id, level in active_synergies.items():
|
for synergy_id, level in active_synergies.items():
|
||||||
synergy_info = data_api.get_synergy_by_id(synergy_id)
|
synergy_info = data_api.get_synergy_by_id(synergy_id)
|
||||||
if synergy_info:
|
if synergy_info:
|
||||||
|
name = synergy_info.get('name', '')
|
||||||
active_synergies_list.append({
|
active_synergies_list.append({
|
||||||
'id': synergy_id,
|
'id': synergy_id,
|
||||||
'name': synergy_info.get('name', ''),
|
'name': name,
|
||||||
'level': level,
|
'level': level,
|
||||||
'description': synergy_info.get('description', ''),
|
'description': synergy_info.get('description', ''),
|
||||||
'image': f"synergy_{synergy_id}.png" # 假设有对应图片
|
'image': f"synergy_{synergy_id}.png" # 假设有对应图片
|
||||||
|
@ -556,30 +556,123 @@ function updateActiveStatus(results) {
|
|||||||
|
|
||||||
// 收集所有被激活的羁绊和棋子
|
// 收集所有被激活的羁绊和棋子
|
||||||
const activeSynergies = new Set();
|
const activeSynergies = new Set();
|
||||||
|
const activeSynergyNames = new Set(); // 添加名称集合
|
||||||
const activeChess = new Set();
|
const activeChess = new Set();
|
||||||
|
const activeChessNames = new Set(); // 添加名称集合
|
||||||
|
|
||||||
|
console.log('更新激活状态:', results);
|
||||||
|
|
||||||
results.forEach(result => {
|
results.forEach(result => {
|
||||||
// 添加激活的羁绊
|
// 添加激活的羁绊
|
||||||
result.active_synergies.forEach(synergy => {
|
result.active_synergies.forEach(synergy => {
|
||||||
activeSynergies.add(synergy.id);
|
console.log('激活羁绊:', synergy);
|
||||||
|
if (synergy.id) activeSynergies.add(synergy.id);
|
||||||
|
if (synergy.name) activeSynergyNames.add(synergy.name); // 添加名称
|
||||||
});
|
});
|
||||||
|
|
||||||
// 添加激活的棋子
|
// 添加激活的棋子
|
||||||
result.chess_list.forEach(chess => {
|
result.chess_list.forEach(chess => {
|
||||||
activeChess.add(chess.id);
|
console.log('激活棋子:', chess);
|
||||||
|
if (chess.id) activeChess.add(chess.id);
|
||||||
|
if (chess.name) activeChessNames.add(chess.name); // 添加名称
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// 设置羁绊激活状态
|
console.log('所有激活的羁绊ID:', Array.from(activeSynergies));
|
||||||
|
console.log('所有激活的羁绊名称:', Array.from(activeSynergyNames));
|
||||||
|
console.log('所有激活的棋子ID:', Array.from(activeChess));
|
||||||
|
console.log('所有激活的棋子名称:', Array.from(activeChessNames));
|
||||||
|
|
||||||
|
// 记录是否有成功匹配
|
||||||
|
let synergyMatched = false;
|
||||||
|
let chessMatched = false;
|
||||||
|
|
||||||
|
// 使用多种方式尝试匹配
|
||||||
|
|
||||||
|
// 1. 通过ID直接匹配
|
||||||
activeSynergies.forEach(synergyId => {
|
activeSynergies.forEach(synergyId => {
|
||||||
$(`.synergy-weight-item[data-synergy-id="${synergyId}"]`).addClass('active');
|
const selector = `.synergy-weight-item[data-synergy-id="${synergyId}"]`;
|
||||||
|
const $elements = $(selector);
|
||||||
|
console.log('查找羁绊元素(通过ID):', selector, $elements.length);
|
||||||
|
if ($elements.length > 0) {
|
||||||
|
$elements.addClass('active');
|
||||||
|
synergyMatched = true;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 设置棋子激活状态
|
|
||||||
activeChess.forEach(chessId => {
|
activeChess.forEach(chessId => {
|
||||||
$(`.chess-weight-item[data-chess-id="${chessId}"]`).addClass('active');
|
const selector = `.chess-weight-item[data-chess-id="${chessId}"]`;
|
||||||
|
const $elements = $(selector);
|
||||||
|
console.log('查找棋子元素(通过ID):', selector, $elements.length);
|
||||||
|
if ($elements.length > 0) {
|
||||||
|
$elements.addClass('active');
|
||||||
|
chessMatched = true;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 2. 通过名称匹配
|
||||||
|
if (!synergyMatched) {
|
||||||
|
console.log('ID匹配失败,尝试使用名称匹配羁绊');
|
||||||
|
$('.synergy-weight-item').each(function() {
|
||||||
|
const $item = $(this);
|
||||||
|
const synergyName = $item.find('label').text().trim();
|
||||||
|
const dataName = $item.data('synergy-name');
|
||||||
|
|
||||||
|
if (activeSynergyNames.has(synergyName) ||
|
||||||
|
(dataName && activeSynergyNames.has(dataName))) {
|
||||||
|
$item.addClass('active');
|
||||||
|
console.log('通过名称匹配到羁绊:', synergyName);
|
||||||
|
synergyMatched = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!chessMatched) {
|
||||||
|
console.log('ID匹配失败,尝试使用名称匹配棋子');
|
||||||
|
$('.chess-weight-item').each(function() {
|
||||||
|
const $item = $(this);
|
||||||
|
const chessName = $item.find('label').text().trim();
|
||||||
|
const dataName = $item.data('chess-name');
|
||||||
|
|
||||||
|
if (activeChessNames.has(chessName) ||
|
||||||
|
(dataName && activeChessNames.has(dataName))) {
|
||||||
|
$item.addClass('active');
|
||||||
|
console.log('通过名称匹配到棋子:', chessName);
|
||||||
|
chessMatched = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 最后的尝试:直接遍历匹配名称(不区分大小写)
|
||||||
|
if (!synergyMatched) {
|
||||||
|
console.log('所有正常匹配方式失败,尝试不区分大小写的名称匹配');
|
||||||
|
const lowerSynergyNames = Array.from(activeSynergyNames).map(name => name.toLowerCase());
|
||||||
|
|
||||||
|
$('.synergy-weight-item').each(function() {
|
||||||
|
const $item = $(this);
|
||||||
|
const synergyName = $item.find('label').text().trim().toLowerCase();
|
||||||
|
|
||||||
|
if (lowerSynergyNames.includes(synergyName)) {
|
||||||
|
$item.addClass('active');
|
||||||
|
console.log('通过不区分大小写名称匹配到羁绊:', synergyName);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!chessMatched) {
|
||||||
|
const lowerChessNames = Array.from(activeChessNames).map(name => name.toLowerCase());
|
||||||
|
|
||||||
|
$('.chess-weight-item').each(function() {
|
||||||
|
const $item = $(this);
|
||||||
|
const chessName = $item.find('label').text().trim().toLowerCase();
|
||||||
|
|
||||||
|
if (lowerChessNames.includes(chessName)) {
|
||||||
|
$item.addClass('active');
|
||||||
|
console.log('通过不区分大小写名称匹配到棋子:', chessName);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// 如果勾选了"仅显示已激活",则更新显示状态
|
// 如果勾选了"仅显示已激活",则更新显示状态
|
||||||
if ($('#show-only-active').is(':checked')) {
|
if ($('#show-only-active').is(':checked')) {
|
||||||
$('.synergy-weight-item').hide();
|
$('.synergy-weight-item').hide();
|
||||||
@ -590,4 +683,12 @@ function updateActiveStatus(results) {
|
|||||||
$('.chess-weight-item').hide();
|
$('.chess-weight-item').hide();
|
||||||
$('.chess-weight-item.active').show();
|
$('.chess-weight-item.active').show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 添加高亮样式,以便更好地区分激活项
|
||||||
|
$('.synergy-weight-item.active').css('background-color', '#e0e7ff');
|
||||||
|
$('.chess-weight-item.active').css('background-color', '#e0e7ff');
|
||||||
|
|
||||||
|
// 输出激活项目数量统计
|
||||||
|
console.log('成功激活的羁绊数量:', $('.synergy-weight-item.active').length);
|
||||||
|
console.log('成功激活的棋子数量:', $('.chess-weight-item.active').length);
|
||||||
}
|
}
|
@ -44,6 +44,15 @@
|
|||||||
.drawer-backdrop.open {
|
.drawer-backdrop.open {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 添加激活状态样式 */
|
||||||
|
.synergy-weight-item.active,
|
||||||
|
.chess-weight-item.active {
|
||||||
|
background-color: #e0e7ff;
|
||||||
|
border-left: 3px solid #4f46e5;
|
||||||
|
padding-left: 5px;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body class="bg-gray-100 min-h-screen">
|
<body class="bg-gray-100 min-h-screen">
|
||||||
@ -109,7 +118,7 @@
|
|||||||
|
|
||||||
<div id="synergy-weights-container" class="space-y-4 mb-6">
|
<div id="synergy-weights-container" class="space-y-4 mb-6">
|
||||||
{% for synergy_id, weight in synergy_weights.items() %}
|
{% for synergy_id, weight in synergy_weights.items() %}
|
||||||
<div class="synergy-weight-item" data-synergy-id="{{ synergy_id }}">
|
<div class="synergy-weight-item" data-synergy-id="{{ synergy_id }}" data-synergy-name="{{ synergy_id }}">
|
||||||
<div class="flex items-center justify-between mb-1">
|
<div class="flex items-center justify-between mb-1">
|
||||||
<label class="text-gray-700">{{ synergy_id }}</label>
|
<label class="text-gray-700">{{ synergy_id }}</label>
|
||||||
<span class="synergy-weight-value text-xs text-gray-700">{{ weight }}</span>
|
<span class="synergy-weight-value text-xs text-gray-700">{{ weight }}</span>
|
||||||
@ -129,7 +138,7 @@
|
|||||||
|
|
||||||
<div id="chess-weights-container" class="space-y-4">
|
<div id="chess-weights-container" class="space-y-4">
|
||||||
{% for chess_id, weight in chess_weights.items() %}
|
{% for chess_id, weight in chess_weights.items() %}
|
||||||
<div class="chess-weight-item" data-chess-id="{{ chess_id }}">
|
<div class="chess-weight-item" data-chess-id="{{ chess_id }}" data-chess-name="{{ chess_id }}">
|
||||||
<div class="flex items-center justify-between mb-1">
|
<div class="flex items-center justify-between mb-1">
|
||||||
<label class="text-gray-700">{{ chess_id }}</label>
|
<label class="text-gray-700">{{ chess_id }}</label>
|
||||||
<span class="chess-weight-value text-xs text-gray-700">{{ weight }}</span>
|
<span class="chess-weight-value text-xs text-gray-700">{{ weight }}</span>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user