File size: 5,016 Bytes
e5d8d3a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
import type { FrontendToken } from '../api/GLTR_API';

/**
 * 验证值是否为合法的 real_topk 元组
 */
export const isValidRealTopkTuple = (value: unknown): value is [number, number] => {
    return Array.isArray(value)
        && value.length === 2
        && value.every((item) => typeof item === 'number' && Number.isFinite(item));
};

/**
 * 验证 token 的概率数据
 */
export const validateTokenProbabilities = (
    tokens: Array<{ real_topk?: [number, number] }>
): string | null => {
    if (!Array.isArray(tokens) || tokens.length === 0) {
        return null;
    }
    for (let i = 0; i < tokens.length; i++) {
        const tuple = tokens[i]?.real_topk;
        if (!isValidRealTopkTuple(tuple)) {
            return `Token #${i} 缺少合法 real_topk 数据,已取消本次处理。`;
        }
    }
    return null;
};

/**
 * 验证值是否为合法的 pred_topk 条目
 */
export const isValidPredTopkEntry = (value: unknown): value is [string, number] => {
    return Array.isArray(value)
        && value.length === 2
        && typeof value[0] === 'string'
        && typeof value[1] === 'number'
        && Number.isFinite(value[1]);
};

/**
 * 验证 token 的预测数据
 * 注意:pred_topk 可以为空数组(例如内存优化策略跳过 TopK 计算时),这是正常情况
 */
export const validateTokenPredictions = (
    tokens: Array<{ pred_topk?: [string, number][] }>
): string | null => {
    if (!Array.isArray(tokens) || tokens.length === 0) {
        return '返回数据缺少 token 序列,已取消本次处理。';
    }
    for (let i = 0; i < tokens.length; i++) {
        const list = tokens[i]?.pred_topk;
        // pred_topk 必须存在且为数组类型(允许为空数组)
        if (!Array.isArray(list)) {
            return `Token #${i} 缺少合法 pred_topk 数组,已取消本次处理。`;
        }
        // 只有当 pred_topk 不为空时,才验证其内容格式
        if (list.length > 0) {
            for (let j = 0; j < list.length; j++) {
                if (!isValidPredTopkEntry(list[j])) {
                    return `Token #${i} 的 pred_topk 项 #${j} 格式非法,已取消本次处理。`;
                }
            }
        }
    }
    return null;
};

/**
 * 格式化 token 预览文本(用于错误消息)
 */
export const formatTokenPreview = (text: string): string => {
    if (!text) {
        return '[空]';
    }

    const chars = Array.from(text);
    if (chars.length <= 12) {
        return text;
    }

    const head = chars.slice(0, 6).join('');
    const tail = chars.slice(-3).join('');
    return `${head}${tail}`;
};

/**
 * 验证 token 数据的一致性(offset 和 raw 是否匹配)
 */
export const validateTokenConsistency = (
    bpeStrings: Array<{ offset?: [number, number]; raw?: string }>,
    originalText: string,
    options: { allowOverlap?: boolean } = {}
): string | null => {
    const { allowOverlap = false } = options;
    if (!Array.isArray(bpeStrings) || bpeStrings.length === 0) {
        return null;
    }

    if (typeof originalText !== 'string') {
        return '响应缺少原始文本,无法校验 token 数据,已取消本次 demo。';
    }

    const charArray = Array.from(originalText);
    const totalChars = charArray.length;

    for (let i = 0; i < bpeStrings.length; i++) {
        const token = bpeStrings[i];
        if (!token) {
            return `Token #${i} 数据缺失,已取消本次 demo。`;
        }

        const offset = token.offset;
        if (!Array.isArray(offset) || offset.length !== 2) {
            return `Token #${i} 缺少合法 offset,已取消本次 demo。`;
        }

        const [start, end] = offset;
        if (!Number.isInteger(start) || !Number.isInteger(end)) {
            return `Token #${i} 的 offset (${start}, ${end}) 不是整数,已取消本次 demo。`;
        }

        if (start < 0 || end < start || end > totalChars) {
            return `Token #${i} 的 offset (${start}, ${end}) 超出原文范围,已取消本次 demo。`;
        }

        if (!allowOverlap && i > 0) {
            const prevOffset = bpeStrings[i - 1]?.offset;
            if (Array.isArray(prevOffset) && prevOffset.length === 2) {
                const prevEnd = prevOffset[1];
                if (Number.isInteger(prevEnd) && start < prevEnd) {
                    return `Token #${i} 的 offset (${start}, ${end}) 与 Token #${i - 1} 重叠,已取消本次 demo。`;
                }
            }
        }

        const expected = charArray.slice(start, end).join('');
        const raw = token.raw ?? '';
        if (expected !== raw) {
            const previewExpected = formatTokenPreview(expected);
            const previewRaw = formatTokenPreview(raw);
            return `Token #${i} 数据异常:offset(${start}, ${end}) 对应原文 "${previewExpected}",但 raw 为 "${previewRaw}"。请重新分析或修复数据。`;
        }
    }

    return null;
};