之前 evaluate() 写死 0.8、decide() 直接透传,history 参数没人用, "自学习"只有骨架。这次补上: 置信度(MetadataNormalizer.evaluate) - 字段来源可追溯:NormalizedMetadata 新增 titleFromTag / artistFromTag / albumFromTag - 基础分 0.25;标题 +0.20、标题来自标签再 +0.10(文件名当标题则 -0.10) - 艺术家 +0.15、来自标签 +0.10;专辑 +0.10;年份 +0.03;封面 +0.02 - 历史一致性:同艺人 >=2 条 +0.05,同专辑 >=2 条 +0.03 - 结果 clamp 到 0.05~0.98,且每个加分项写入 evidence,便于日志解释 状态机(MetadataService) - 只有 confidence>=0.6 且 status=verified 的记录才直接命中 - pending 记录下次播放会重新读取并合并(自修复) - validation_count 累加;>=2 次且置信度达标才升级为 verified - 新结果置信度低于旧结果时保留旧字段,只累加验证次数 - 日志输出 status / confidence / validation_count / evidence 测试 - 新增 test/metadata_normalizer_test.dart,9 个用例覆盖来源标记、分级、 历史加权、证据、阈值;flutter test 全绿 真机验证 - 起播看门狗在真实弱网下触发:23:44:50 打开失败 → 15s 后自动重连 → 1.4s 出声(open 仅 100ms)
141 lines
4.3 KiB
Dart
141 lines
4.3 KiB
Dart
// test/metadata_normalizer_test.dart
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:qingting_player/metadata/metadata_model.dart';
|
|
import 'package:qingting_player/metadata/metadata_normalizer.dart';
|
|
|
|
void main() {
|
|
final normalizer = MetadataNormalizer();
|
|
|
|
RawMetadata raw({
|
|
String title = '',
|
|
String artist = '',
|
|
String album = '',
|
|
int year = 0,
|
|
}) =>
|
|
RawMetadata(title: title, artist: artist, album: album, year: year);
|
|
|
|
group('normalize 字段来源', () {
|
|
test('标签齐全时三个字段都标记为来自标签', () {
|
|
final n = normalizer.normalize(
|
|
raw(title: '夜曲', artist: '周杰伦', album: '十一月的萧邦'),
|
|
fileName: 'track01.mp3',
|
|
filePath: '/音乐/周杰伦/track01.mp3',
|
|
);
|
|
expect(n.title, '夜曲');
|
|
expect(n.artist, '周杰伦');
|
|
expect(n.album, '十一月的萧邦');
|
|
expect(n.titleFromTag, isTrue);
|
|
expect(n.artistFromTag, isTrue);
|
|
expect(n.albumFromTag, isTrue);
|
|
});
|
|
|
|
test('没有标签时回退到文件名与目录', () {
|
|
final n = normalizer.normalize(
|
|
raw(),
|
|
fileName: '晴天.mp3',
|
|
filePath: '/音乐/周杰伦/晴天.mp3',
|
|
);
|
|
expect(n.title, '晴天');
|
|
expect(n.artist, '周杰伦');
|
|
expect(n.titleFromTag, isFalse);
|
|
expect(n.artistFromTag, isFalse);
|
|
});
|
|
});
|
|
|
|
group('evaluate 置信度分级', () {
|
|
NormalizedMetadata norm({
|
|
required String title,
|
|
required String artist,
|
|
String album = '',
|
|
bool titleTag = true,
|
|
bool artistTag = true,
|
|
bool albumTag = false,
|
|
}) =>
|
|
NormalizedMetadata(
|
|
title: title,
|
|
artist: artist,
|
|
album: album,
|
|
titleFromTag: titleTag,
|
|
artistFromTag: artistTag,
|
|
albumFromTag: albumTag,
|
|
);
|
|
|
|
test('标题 + 艺术家 + 专辑 → 0.90', () {
|
|
final c = normalizer.evaluate(
|
|
norm(title: '夜曲', artist: '周杰伦', album: '十一月的萧邦', albumTag: true),
|
|
const [],
|
|
);
|
|
expect(c.confidence, closeTo(0.90, 0.001));
|
|
});
|
|
|
|
test('只有标题和艺术家 → 0.80', () {
|
|
final c = normalizer.evaluate(norm(title: '夜曲', artist: '周杰伦'), const []);
|
|
expect(c.confidence, closeTo(0.80, 0.001));
|
|
});
|
|
|
|
test('只有文件名(无标签)→ 0.35,低于阈值', () {
|
|
final c = normalizer.evaluate(
|
|
norm(title: 'track01', artist: '未知艺术家', titleTag: false, artistTag: false),
|
|
const [],
|
|
);
|
|
expect(c.confidence, closeTo(0.35, 0.001));
|
|
expect(c.confidence < 0.6, isTrue);
|
|
});
|
|
|
|
test('历史一致性加权:同艺人 ≥2 条 → +0.05', () {
|
|
final history = [
|
|
{'artist': '周杰伦', 'album': ''},
|
|
{'artist': '周杰伦', 'album': ''},
|
|
];
|
|
final c = normalizer.evaluate(
|
|
norm(title: '夜曲', artist: '周杰伦'),
|
|
history,
|
|
);
|
|
expect(c.confidence, closeTo(0.85, 0.001));
|
|
expect(c.evidence['artist_history'], 0.05);
|
|
});
|
|
|
|
test('证据可解释:每一项加分都有记录', () {
|
|
final c = normalizer.evaluate(
|
|
norm(title: '夜曲', artist: '周杰伦', album: '十一月的萧邦', albumTag: true),
|
|
const [],
|
|
);
|
|
expect(c.evidence.containsKey('base'), isTrue);
|
|
expect(c.evidence.containsKey('title_from_tag'), isTrue);
|
|
expect(c.evidence.containsKey('artist_from_tag'), isTrue);
|
|
expect(c.evidence.containsKey('album'), isTrue);
|
|
});
|
|
});
|
|
|
|
group('decide 阈值', () {
|
|
test('高于阈值时 source=normalized', () {
|
|
final c = normalizer.evaluate(
|
|
const NormalizedMetadata(
|
|
title: '夜曲',
|
|
artist: '周杰伦',
|
|
titleFromTag: true,
|
|
artistFromTag: true,
|
|
),
|
|
const [],
|
|
);
|
|
final f = normalizer.decide(c);
|
|
expect(f.source, 'normalized');
|
|
expect(f.title, '夜曲');
|
|
});
|
|
|
|
test('低于阈值时 source=pending', () {
|
|
final c = normalizer.evaluate(
|
|
const NormalizedMetadata(
|
|
title: 'track01',
|
|
artist: '未知艺术家',
|
|
titleFromTag: false,
|
|
artistFromTag: false,
|
|
),
|
|
const [],
|
|
);
|
|
final f = normalizer.decide(c);
|
|
expect(f.source, 'pending');
|
|
});
|
|
});
|
|
}
|