You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
117 lines
3.9 KiB
117 lines
3.9 KiB
import 'package:eaimar/modules/translation/models/translation_export.dart';
|
|
import 'package:eaimar/modules/translation/models/translation_models.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
|
|
TranslationItem _item(
|
|
DateTime at, {
|
|
String src = '你好',
|
|
String dst = 'Hello',
|
|
String srcLang = 'zh-CN',
|
|
String serviceId = '',
|
|
bool intermediate = false,
|
|
}) =>
|
|
TranslationItem(
|
|
sourceText: src,
|
|
translatedText: dst,
|
|
sourceLanguageCode: srcLang,
|
|
targetLanguageCode: srcLang == 'zh-CN' ? 'en-US' : 'zh-CN',
|
|
timestamp: at,
|
|
sessionId: 's',
|
|
serviceId: serviceId,
|
|
isIntermediate: intermediate,
|
|
);
|
|
|
|
void main() {
|
|
final t0 = DateTime(2026, 9, 18, 10, 0, 0);
|
|
|
|
test('只取录音开始之后的整句,时间是相对录音起点的毫秒', () {
|
|
final out = buildMeetingTranscript(
|
|
items: [
|
|
_item(t0.subtract(const Duration(seconds: 5)), src: '上一轮的'),
|
|
_item(t0.add(const Duration(seconds: 2))),
|
|
_item(t0.add(const Duration(seconds: 6)), src: '半句', intermediate: true),
|
|
_item(t0.add(const Duration(seconds: 9)), src: '第二句', dst: 'Second'),
|
|
],
|
|
recordingStartedAt: t0,
|
|
mode: 'simultaneous',
|
|
ownLanguageCode: 'zh-CN',
|
|
);
|
|
expect(out.length, 2);
|
|
expect(out[0]['starttime'], 2000);
|
|
expect(out[0]['endtime'], 9000); // 下一句开头
|
|
expect(out[0]['content'], '你好\nHello');
|
|
expect(out[0]['speaker'], ''); // 同传单向,不标说话人
|
|
expect(out[1]['starttime'], 9000);
|
|
expect(out[1]['endtime'], greaterThan(9000)); // 最后一句按字数估
|
|
});
|
|
|
|
test('通话翻译按 AST 的 serviceId 分说话人:A=0 本端 B=1 对端', () {
|
|
final out = buildMeetingTranscript(
|
|
items: [
|
|
_item(t0.add(const Duration(seconds: 1)), serviceId: 'A'),
|
|
_item(t0.add(const Duration(seconds: 3)),
|
|
src: 'Hi', dst: '嗨', srcLang: 'en-US', serviceId: 'B'),
|
|
],
|
|
recordingStartedAt: t0,
|
|
mode: 'call',
|
|
ownLanguageCode: 'zh-CN',
|
|
);
|
|
expect(out.map((e) => e['speaker']), ['Speaker_0', 'Speaker_1']);
|
|
});
|
|
|
|
test('面对面没有 serviceId,按这句话的语言分:说源语言的是本端', () {
|
|
final out = buildMeetingTranscript(
|
|
items: [
|
|
_item(t0.add(const Duration(seconds: 1))),
|
|
_item(t0.add(const Duration(seconds: 3)),
|
|
src: 'Hi', dst: '嗨', srcLang: 'en-US'),
|
|
],
|
|
recordingStartedAt: t0,
|
|
mode: 'faceToFace',
|
|
ownLanguageCode: 'zh-CN',
|
|
);
|
|
expect(out.map((e) => e['speaker']), ['Speaker_0', 'Speaker_1']);
|
|
});
|
|
|
|
test('暂停区间要从偏移里扣掉(面对面逐句松手即暂停)', () {
|
|
final out = buildMeetingTranscript(
|
|
items: [
|
|
_item(t0.add(const Duration(seconds: 2))),
|
|
// 3s~13s 暂停了 10 秒,这句在 15s 说的,音频里其实是第 5 秒
|
|
_item(t0.add(const Duration(seconds: 15)), src: '第二句', dst: ''),
|
|
],
|
|
recordingStartedAt: t0,
|
|
mode: 'faceToFace',
|
|
ownLanguageCode: 'zh-CN',
|
|
pauses: [
|
|
(t0.add(const Duration(seconds: 3)), t0.add(const Duration(seconds: 13)))
|
|
],
|
|
);
|
|
expect(out[0]['starttime'], 2000);
|
|
expect(out[0]['endtime'], 5000);
|
|
expect(out[1]['starttime'], 5000);
|
|
expect(out[1]['content'], '第二句'); // 没译文就只有原文一行
|
|
});
|
|
|
|
test('译文与原文相同时不重复', () {
|
|
final out = buildMeetingTranscript(
|
|
items: [_item(t0.add(const Duration(seconds: 1)), src: 'OK', dst: 'OK')],
|
|
recordingStartedAt: t0,
|
|
mode: 'simultaneous',
|
|
ownLanguageCode: 'zh-CN',
|
|
);
|
|
expect(out.single['content'], 'OK');
|
|
});
|
|
|
|
test('没有整句就返回空,调用方据此退回普通录音归档', () {
|
|
expect(
|
|
buildMeetingTranscript(
|
|
items: [_item(t0.add(const Duration(seconds: 1)), src: ' ')],
|
|
recordingStartedAt: t0,
|
|
mode: 'call',
|
|
ownLanguageCode: 'zh-CN',
|
|
),
|
|
isEmpty,
|
|
);
|
|
});
|
|
}
|
|
|