@bingran/sbti-cli 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/NOTICE +6 -12
- package/README.md +9 -308
- package/bin/sbti-cli.cjs +4 -30
- package/dist/sbti-cli.mjs +762 -0
- package/package.json +3 -35
- package/README.zh-CN.md +0 -319
- package/lib/platform-package.cjs +0 -117
|
@@ -0,0 +1,762 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import vm from 'node:vm';
|
|
4
|
+
import { createInterface } from 'node:readline/promises';
|
|
5
|
+
import process from 'node:process';
|
|
6
|
+
import { gunzipSync } from 'node:zlib';
|
|
7
|
+
|
|
8
|
+
const BUNDLED_SBTI_SNAPSHOT = JSON.parse(
|
|
9
|
+
gunzipSync(Buffer.from('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', 'base64')).toString('utf8')
|
|
10
|
+
);
|
|
11
|
+
|
|
12
|
+
const BUNDLED_SBTI_SOURCE_URL = 'bundled:offline-survey';
|
|
13
|
+
const NORMAL_TYPE_SIMILARITY_FALLBACK_THRESHOLD = 60;
|
|
14
|
+
const SIMILARITY_DISTANCE_DENOMINATOR = 30;
|
|
15
|
+
const DIMENSION_GROUP_SIZE = 3;
|
|
16
|
+
|
|
17
|
+
const OPTION_CODES = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('');
|
|
18
|
+
const LEVEL_TO_NUMBER = { L: 1, M: 2, H: 3 };
|
|
19
|
+
|
|
20
|
+
function createClassListStub() {
|
|
21
|
+
return {
|
|
22
|
+
add() {},
|
|
23
|
+
remove() {},
|
|
24
|
+
toggle() {}
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function createElementStub(tagName = 'div') {
|
|
29
|
+
return {
|
|
30
|
+
tagName: String(tagName).toUpperCase(),
|
|
31
|
+
className: '',
|
|
32
|
+
classList: createClassListStub(),
|
|
33
|
+
style: {},
|
|
34
|
+
children: [],
|
|
35
|
+
dataset: {},
|
|
36
|
+
disabled: false,
|
|
37
|
+
innerHTML: '',
|
|
38
|
+
textContent: '',
|
|
39
|
+
alt: '',
|
|
40
|
+
src: '',
|
|
41
|
+
appendChild(child) {
|
|
42
|
+
this.children.push(child);
|
|
43
|
+
return child;
|
|
44
|
+
},
|
|
45
|
+
querySelectorAll() {
|
|
46
|
+
return [];
|
|
47
|
+
},
|
|
48
|
+
addEventListener() {},
|
|
49
|
+
removeEventListener() {},
|
|
50
|
+
setAttribute(name, value) {
|
|
51
|
+
this[name] = value;
|
|
52
|
+
},
|
|
53
|
+
removeAttribute(name) {
|
|
54
|
+
delete this[name];
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function createDocumentStub() {
|
|
60
|
+
const elements = new Map();
|
|
61
|
+
const document = {
|
|
62
|
+
getElementById(id) {
|
|
63
|
+
if (!elements.has(id)) {
|
|
64
|
+
elements.set(id, createElementStub('div'));
|
|
65
|
+
}
|
|
66
|
+
return elements.get(id);
|
|
67
|
+
},
|
|
68
|
+
createElement(tagName) {
|
|
69
|
+
return createElementStub(tagName);
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
return { document, elements };
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function toPlainValue(value) {
|
|
77
|
+
return JSON.parse(JSON.stringify(value));
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function serializeBundledValue(value) {
|
|
81
|
+
return JSON.stringify(value, null, 2);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function buildBundledSbtiSource(snapshot = BUNDLED_SBTI_SNAPSHOT) {
|
|
85
|
+
return `// Built-in offline snapshot
|
|
86
|
+
const dimensionMeta = ${serializeBundledValue(snapshot.dimensionMeta)};
|
|
87
|
+
const questions = ${serializeBundledValue(snapshot.questions)};
|
|
88
|
+
const specialQuestions = ${serializeBundledValue(snapshot.specialQuestions)};
|
|
89
|
+
const TYPE_LIBRARY = ${serializeBundledValue(snapshot.TYPE_LIBRARY)};
|
|
90
|
+
const NORMAL_TYPES = ${serializeBundledValue(snapshot.NORMAL_TYPES)};
|
|
91
|
+
const DIM_EXPLANATIONS = ${serializeBundledValue(snapshot.DIM_EXPLANATIONS)};
|
|
92
|
+
const dimensionOrder = ${serializeBundledValue(snapshot.dimensionOrder)};
|
|
93
|
+
const DRUNK_TRIGGER_QUESTION_ID = ${serializeBundledValue(snapshot.DRUNK_TRIGGER_QUESTION_ID)};
|
|
94
|
+
|
|
95
|
+
const app = {
|
|
96
|
+
shuffledQuestions: [],
|
|
97
|
+
answers: {}
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
function shuffle(array) {
|
|
101
|
+
const arr = [...array];
|
|
102
|
+
for (let i = arr.length - 1; i > 0; i--) {
|
|
103
|
+
const j = Math.floor(Math.random() * (i + 1));
|
|
104
|
+
[arr[i], arr[j]] = [arr[j], arr[i]];
|
|
105
|
+
}
|
|
106
|
+
return arr;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function getVisibleQuestions() {
|
|
110
|
+
const visible = [...app.shuffledQuestions];
|
|
111
|
+
const gateIndex = visible.findIndex(q => q.id === 'drink_gate_q1');
|
|
112
|
+
if (gateIndex !== -1 && app.answers['drink_gate_q1'] === 3) {
|
|
113
|
+
visible.splice(gateIndex + 1, 0, specialQuestions[1]);
|
|
114
|
+
}
|
|
115
|
+
return visible;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function sumToLevel(score) {
|
|
119
|
+
if (score <= 3) return 'L';
|
|
120
|
+
if (score === 4) return 'M';
|
|
121
|
+
return 'H';
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function levelNum(level) {
|
|
125
|
+
return { L: 1, M: 2, H: 3 }[level];
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function parsePattern(pattern) {
|
|
129
|
+
return pattern.replace(/-/g, '').split('');
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function getDrunkTriggered() {
|
|
133
|
+
return app.answers[DRUNK_TRIGGER_QUESTION_ID] === 2;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function computeResult() {
|
|
137
|
+
const rawScores = {};
|
|
138
|
+
const levels = {};
|
|
139
|
+
Object.keys(dimensionMeta).forEach(dim => { rawScores[dim] = 0; });
|
|
140
|
+
|
|
141
|
+
questions.forEach(q => {
|
|
142
|
+
rawScores[q.dim] += Number(app.answers[q.id] || 0);
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
Object.entries(rawScores).forEach(([dim, score]) => {
|
|
146
|
+
levels[dim] = sumToLevel(score);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
const userVector = dimensionOrder.map(dim => levelNum(levels[dim]));
|
|
150
|
+
const ranked = NORMAL_TYPES.map(type => {
|
|
151
|
+
const vector = parsePattern(type.pattern).map(levelNum);
|
|
152
|
+
let distance = 0;
|
|
153
|
+
let exact = 0;
|
|
154
|
+
for (let i = 0; i < vector.length; i++) {
|
|
155
|
+
const diff = Math.abs(userVector[i] - vector[i]);
|
|
156
|
+
distance += diff;
|
|
157
|
+
if (diff === 0) exact += 1;
|
|
158
|
+
}
|
|
159
|
+
const similarity = Math.max(0, Math.round((1 - distance / 30) * 100));
|
|
160
|
+
return { ...type, ...TYPE_LIBRARY[type.code], distance, exact, similarity };
|
|
161
|
+
}).sort((a, b) => {
|
|
162
|
+
if (a.distance !== b.distance) return a.distance - b.distance;
|
|
163
|
+
if (b.exact !== a.exact) return b.exact - a.exact;
|
|
164
|
+
return b.similarity - a.similarity;
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
const bestNormal = ranked[0];
|
|
168
|
+
const drunkTriggered = getDrunkTriggered();
|
|
169
|
+
|
|
170
|
+
let finalType;
|
|
171
|
+
let modeKicker = '你的主类型';
|
|
172
|
+
let badge = \`匹配度 \${bestNormal.similarity}% · 精准命中 \${bestNormal.exact}/15 维\`;
|
|
173
|
+
let sub = '维度命中度较高,当前结果可视为你的第一人格画像。';
|
|
174
|
+
let special = false;
|
|
175
|
+
let secondaryType = null;
|
|
176
|
+
|
|
177
|
+
if (drunkTriggered) {
|
|
178
|
+
finalType = TYPE_LIBRARY.DRUNK;
|
|
179
|
+
secondaryType = bestNormal;
|
|
180
|
+
modeKicker = '隐藏人格已激活';
|
|
181
|
+
badge = '匹配度 100% · 酒精异常因子已接管';
|
|
182
|
+
sub = '乙醇亲和性过强,系统已直接跳过常规人格审判。';
|
|
183
|
+
special = true;
|
|
184
|
+
} else if (bestNormal.similarity < 60) {
|
|
185
|
+
finalType = TYPE_LIBRARY.HHHH;
|
|
186
|
+
modeKicker = '系统强制兜底';
|
|
187
|
+
badge = \`标准人格库最高匹配仅 \${bestNormal.similarity}%\`;
|
|
188
|
+
sub = '标准人格库对你的脑回路集体罢工了,于是系统把你强制分配给了 HHHH。';
|
|
189
|
+
special = true;
|
|
190
|
+
} else {
|
|
191
|
+
finalType = bestNormal;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return {
|
|
195
|
+
rawScores,
|
|
196
|
+
levels,
|
|
197
|
+
ranked,
|
|
198
|
+
bestNormal,
|
|
199
|
+
finalType,
|
|
200
|
+
modeKicker,
|
|
201
|
+
badge,
|
|
202
|
+
sub,
|
|
203
|
+
special,
|
|
204
|
+
secondaryType
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function startTest() {
|
|
209
|
+
app.answers = {};
|
|
210
|
+
const shuffledRegular = shuffle(questions);
|
|
211
|
+
const insertIndex = Math.floor(Math.random() * shuffledRegular.length) + 1;
|
|
212
|
+
app.shuffledQuestions = [
|
|
213
|
+
...shuffledRegular.slice(0, insertIndex),
|
|
214
|
+
specialQuestions[0],
|
|
215
|
+
...shuffledRegular.slice(insertIndex)
|
|
216
|
+
];
|
|
217
|
+
}
|
|
218
|
+
`;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
const BUNDLED_SBTI_SOURCE_TEXT = buildBundledSbtiSource();
|
|
222
|
+
const BUNDLED_SBTI_SOURCE_DESCRIPTION = '内置离线题库';
|
|
223
|
+
|
|
224
|
+
function createSeededRandom(seed) {
|
|
225
|
+
const normalized = Number(seed);
|
|
226
|
+
let state = Number.isFinite(normalized) ? normalized >>> 0 : 0;
|
|
227
|
+
|
|
228
|
+
if (state === 0) {
|
|
229
|
+
state = 0x6d2b79f5;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
return function seededRandom() {
|
|
233
|
+
state += 0x6d2b79f5;
|
|
234
|
+
let t = state;
|
|
235
|
+
t = Math.imul(t ^ (t >>> 15), t | 1);
|
|
236
|
+
t ^= t + Math.imul(t ^ (t >>> 7), t | 61);
|
|
237
|
+
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
function createRuntimeEvaluationContext(random = Math.random) {
|
|
242
|
+
const { document, elements } = createDocumentStub();
|
|
243
|
+
const math = Object.create(Math);
|
|
244
|
+
math.random = typeof random === 'function' ? random : Math.random;
|
|
245
|
+
|
|
246
|
+
const window = {
|
|
247
|
+
document,
|
|
248
|
+
scrollTo() {},
|
|
249
|
+
addEventListener() {},
|
|
250
|
+
removeEventListener() {}
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
const context = vm.createContext({
|
|
254
|
+
console,
|
|
255
|
+
document,
|
|
256
|
+
Math: math,
|
|
257
|
+
window,
|
|
258
|
+
setTimeout,
|
|
259
|
+
clearTimeout,
|
|
260
|
+
setInterval,
|
|
261
|
+
clearInterval
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
return {
|
|
265
|
+
context,
|
|
266
|
+
elements
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
function evaluateSbtiRuntimeSource(source, sourceUrl, random = Math.random) {
|
|
271
|
+
const { context, elements } = createRuntimeEvaluationContext(random);
|
|
272
|
+
|
|
273
|
+
const instrumentedSource = `${source}
|
|
274
|
+
globalThis.__sbtiExports = {
|
|
275
|
+
dimensionMeta,
|
|
276
|
+
questions,
|
|
277
|
+
specialQuestions,
|
|
278
|
+
TYPE_LIBRARY,
|
|
279
|
+
NORMAL_TYPES,
|
|
280
|
+
DIM_EXPLANATIONS,
|
|
281
|
+
dimensionOrder,
|
|
282
|
+
DRUNK_TRIGGER_QUESTION_ID,
|
|
283
|
+
app,
|
|
284
|
+
getVisibleQuestions,
|
|
285
|
+
startTest,
|
|
286
|
+
computeResult
|
|
287
|
+
};
|
|
288
|
+
`;
|
|
289
|
+
|
|
290
|
+
try {
|
|
291
|
+
vm.runInContext(instrumentedSource, context, {
|
|
292
|
+
filename: sourceUrl,
|
|
293
|
+
timeout: 5000
|
|
294
|
+
});
|
|
295
|
+
} catch (error) {
|
|
296
|
+
throw new Error(error.message);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
return {
|
|
300
|
+
context,
|
|
301
|
+
elements,
|
|
302
|
+
exports: context.__sbtiExports
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
function buildBundledRuntimeMetadata() {
|
|
307
|
+
return {
|
|
308
|
+
source: BUNDLED_SBTI_SOURCE_TEXT,
|
|
309
|
+
sourceUrl: BUNDLED_SBTI_SOURCE_URL,
|
|
310
|
+
sourceKind: 'bundled',
|
|
311
|
+
sourceDescription: BUNDLED_SBTI_SOURCE_DESCRIPTION,
|
|
312
|
+
fallbackReason: null
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
async function loadSbtiRuntime({
|
|
317
|
+
sourceText,
|
|
318
|
+
sourceUrl = BUNDLED_SBTI_SOURCE_URL,
|
|
319
|
+
random = Math.random
|
|
320
|
+
} = {}) {
|
|
321
|
+
if (sourceText !== null && sourceText !== undefined) {
|
|
322
|
+
const evaluated = evaluateSbtiRuntimeSource(sourceText, sourceUrl, random);
|
|
323
|
+
return {
|
|
324
|
+
source: sourceText,
|
|
325
|
+
sourceUrl,
|
|
326
|
+
sourceKind: 'provided',
|
|
327
|
+
sourceDescription: sourceUrl,
|
|
328
|
+
fallbackReason: null,
|
|
329
|
+
...evaluated
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
const bundled = buildBundledRuntimeMetadata();
|
|
334
|
+
const evaluated = evaluateSbtiRuntimeSource(bundled.source, bundled.sourceUrl, random);
|
|
335
|
+
return {
|
|
336
|
+
...bundled,
|
|
337
|
+
...evaluated
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
function createSurveySession(runtime) {
|
|
342
|
+
if (!runtime?.exports) {
|
|
343
|
+
throw new Error('A loaded SBTI runtime is required.');
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
runtime.exports.startTest(false);
|
|
347
|
+
|
|
348
|
+
let finalized = false;
|
|
349
|
+
|
|
350
|
+
const getSessionState = () => {
|
|
351
|
+
const visibleQuestions = runtime.exports.getVisibleQuestions();
|
|
352
|
+
const total = visibleQuestions.length;
|
|
353
|
+
const done = visibleQuestions.filter((question) => runtime.exports.app.answers[question.id] !== undefined).length;
|
|
354
|
+
const nextQuestion =
|
|
355
|
+
visibleQuestions.find((question) => runtime.exports.app.answers[question.id] === undefined) ?? null;
|
|
356
|
+
|
|
357
|
+
return {
|
|
358
|
+
visibleQuestions,
|
|
359
|
+
total,
|
|
360
|
+
done,
|
|
361
|
+
complete: total > 0 && done === total,
|
|
362
|
+
nextQuestion
|
|
363
|
+
};
|
|
364
|
+
};
|
|
365
|
+
|
|
366
|
+
return {
|
|
367
|
+
getAnswers() {
|
|
368
|
+
return toPlainValue(runtime.exports.app.answers);
|
|
369
|
+
},
|
|
370
|
+
getCurrentQuestion() {
|
|
371
|
+
return toPlainValue(getSessionState().nextQuestion);
|
|
372
|
+
},
|
|
373
|
+
getVisibleQuestions() {
|
|
374
|
+
return toPlainValue(getSessionState().visibleQuestions);
|
|
375
|
+
},
|
|
376
|
+
getProgress() {
|
|
377
|
+
const { done, total, complete } = getSessionState();
|
|
378
|
+
return { done, total, complete };
|
|
379
|
+
},
|
|
380
|
+
answerQuestion(questionId, value) {
|
|
381
|
+
if (finalized) {
|
|
382
|
+
throw new Error('This survey session has already been finalized.');
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
const { nextQuestion, complete } = getSessionState();
|
|
386
|
+
if (complete || !nextQuestion) {
|
|
387
|
+
throw new Error('All questions have already been answered.');
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
if (questionId !== nextQuestion.id) {
|
|
391
|
+
throw new Error(`Expected answer for ${nextQuestion.id}, received ${questionId}.`);
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
const numericValue = Number(value);
|
|
395
|
+
runtime.exports.app.answers[questionId] = numericValue;
|
|
396
|
+
|
|
397
|
+
if (questionId === 'drink_gate_q1' && numericValue !== 3) {
|
|
398
|
+
delete runtime.exports.app.answers.drink_gate_q2;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
return this.getProgress();
|
|
402
|
+
},
|
|
403
|
+
computeResult() {
|
|
404
|
+
const progress = this.getProgress();
|
|
405
|
+
if (!progress.complete) {
|
|
406
|
+
throw new Error('All visible questions must be answered before computing a result.');
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
finalized = true;
|
|
410
|
+
return buildResultSummary(runtime, runtime.exports.app.answers);
|
|
411
|
+
}
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
function formatOptionCode(index) {
|
|
416
|
+
return OPTION_CODES[index] ?? String(index + 1);
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
function scoreToLevel(score) {
|
|
420
|
+
if (score <= 3) {
|
|
421
|
+
return 'L';
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
if (score === 4) {
|
|
425
|
+
return 'M';
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
return 'H';
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
function levelToNumber(level) {
|
|
432
|
+
const numericLevel = LEVEL_TO_NUMBER[level];
|
|
433
|
+
if (!numericLevel) {
|
|
434
|
+
throw new Error(`Unknown level: ${level}`);
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
return numericLevel;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
function patternToLetters(pattern) {
|
|
441
|
+
return String(pattern).replace(/-/g, '').split('');
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
function patternToVector(pattern) {
|
|
445
|
+
return patternToLetters(pattern).map(levelToNumber);
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
function lettersToPattern(letters, groupSize = DIMENSION_GROUP_SIZE) {
|
|
449
|
+
const groups = [];
|
|
450
|
+
|
|
451
|
+
for (let index = 0; index < letters.length; index += groupSize) {
|
|
452
|
+
groups.push(letters.slice(index, index + groupSize).join(''));
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
return groups.join('-');
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
function buildResultPattern(levels, dimensionOrder) {
|
|
459
|
+
return lettersToPattern(dimensionOrder.map((dimensionId) => levels[dimensionId]));
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
function computeDimensionStats(runtime, answersInput = runtime.exports.app.answers) {
|
|
463
|
+
const rawAnswers = answersInput ?? {};
|
|
464
|
+
const answers = toPlainValue(rawAnswers);
|
|
465
|
+
const rawScores = {};
|
|
466
|
+
const levels = {};
|
|
467
|
+
|
|
468
|
+
runtime.exports.dimensionOrder.forEach((dimensionId) => {
|
|
469
|
+
rawScores[dimensionId] = 0;
|
|
470
|
+
});
|
|
471
|
+
|
|
472
|
+
runtime.exports.questions.forEach((question) => {
|
|
473
|
+
rawScores[question.dim] += Number(answers[question.id] || 0);
|
|
474
|
+
});
|
|
475
|
+
|
|
476
|
+
runtime.exports.dimensionOrder.forEach((dimensionId) => {
|
|
477
|
+
levels[dimensionId] = scoreToLevel(rawScores[dimensionId]);
|
|
478
|
+
});
|
|
479
|
+
|
|
480
|
+
const resultPattern = buildResultPattern(levels, runtime.exports.dimensionOrder);
|
|
481
|
+
const resultVector = patternToVector(resultPattern);
|
|
482
|
+
|
|
483
|
+
return {
|
|
484
|
+
answers,
|
|
485
|
+
rawScores,
|
|
486
|
+
levels,
|
|
487
|
+
resultPattern,
|
|
488
|
+
resultVector
|
|
489
|
+
};
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
function rankNormalTypes(runtime, resultPattern) {
|
|
493
|
+
const userVector = Array.isArray(resultPattern) ? resultPattern : patternToVector(resultPattern);
|
|
494
|
+
|
|
495
|
+
return runtime.exports.NORMAL_TYPES.map((type) => {
|
|
496
|
+
const vector = patternToVector(type.pattern);
|
|
497
|
+
let distance = 0;
|
|
498
|
+
let exact = 0;
|
|
499
|
+
|
|
500
|
+
for (let index = 0; index < vector.length; index += 1) {
|
|
501
|
+
const diff = Math.abs(userVector[index] - vector[index]);
|
|
502
|
+
distance += diff;
|
|
503
|
+
|
|
504
|
+
if (diff === 0) {
|
|
505
|
+
exact += 1;
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
const similarity = Math.max(
|
|
510
|
+
0,
|
|
511
|
+
Math.round((1 - distance / SIMILARITY_DISTANCE_DENOMINATOR) * 100)
|
|
512
|
+
);
|
|
513
|
+
|
|
514
|
+
return {
|
|
515
|
+
...type,
|
|
516
|
+
...runtime.exports.TYPE_LIBRARY[type.code],
|
|
517
|
+
distance,
|
|
518
|
+
exact,
|
|
519
|
+
similarity
|
|
520
|
+
};
|
|
521
|
+
}).sort((left, right) => {
|
|
522
|
+
if (left.distance !== right.distance) {
|
|
523
|
+
return left.distance - right.distance;
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
if (right.exact !== left.exact) {
|
|
527
|
+
return right.exact - left.exact;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
return right.similarity - left.similarity;
|
|
531
|
+
});
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
function buildResultSummary(runtime, answersInput = runtime.exports.app.answers) {
|
|
535
|
+
const dimensionStats = computeDimensionStats(runtime, answersInput);
|
|
536
|
+
const previousAnswers = runtime.exports.app.answers;
|
|
537
|
+
runtime.exports.app.answers = { ...dimensionStats.answers };
|
|
538
|
+
|
|
539
|
+
let computedResult;
|
|
540
|
+
try {
|
|
541
|
+
computedResult = toPlainValue(runtime.exports.computeResult());
|
|
542
|
+
} finally {
|
|
543
|
+
runtime.exports.app.answers = previousAnswers;
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
const ranked = rankNormalTypes(runtime, dimensionStats.resultVector);
|
|
547
|
+
const bestNormal = ranked[0];
|
|
548
|
+
const drinkTriggered =
|
|
549
|
+
Number(dimensionStats.answers[runtime.exports.DRUNK_TRIGGER_QUESTION_ID] || 0) === 2;
|
|
550
|
+
const fallbackTriggered =
|
|
551
|
+
!drinkTriggered && bestNormal.similarity < NORMAL_TYPE_SIMILARITY_FALLBACK_THRESHOLD;
|
|
552
|
+
|
|
553
|
+
return {
|
|
554
|
+
...computedResult,
|
|
555
|
+
...dimensionStats,
|
|
556
|
+
ranked,
|
|
557
|
+
bestNormal,
|
|
558
|
+
normalTypeCount: runtime.exports.NORMAL_TYPES.length,
|
|
559
|
+
specialTypeCount: 2,
|
|
560
|
+
flags: {
|
|
561
|
+
drinkTriggered,
|
|
562
|
+
fallbackTriggered
|
|
563
|
+
}
|
|
564
|
+
};
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
function getQuestionMetaLabel(question) {
|
|
568
|
+
if (question.special) {
|
|
569
|
+
return '补充题';
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
return '维度已隐藏';
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
function findOptionValue(question, rawInput) {
|
|
576
|
+
const normalized = String(rawInput ?? '').trim().toUpperCase();
|
|
577
|
+
if (!normalized) {
|
|
578
|
+
return null;
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
const codeIndex = OPTION_CODES.indexOf(normalized);
|
|
582
|
+
if (codeIndex !== -1 && question.options[codeIndex]) {
|
|
583
|
+
return question.options[codeIndex].value;
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
const numericValue = Number(normalized);
|
|
587
|
+
if (Number.isInteger(numericValue) && question.options.some((option) => option.value === numericValue)) {
|
|
588
|
+
return numericValue;
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
return null;
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
function parseArgs(argv) {
|
|
595
|
+
const options = {
|
|
596
|
+
help: false,
|
|
597
|
+
json: false,
|
|
598
|
+
seed: null
|
|
599
|
+
};
|
|
600
|
+
|
|
601
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
602
|
+
const arg = argv[index];
|
|
603
|
+
|
|
604
|
+
if (arg === '--help' || arg === '-h') {
|
|
605
|
+
options.help = true;
|
|
606
|
+
continue;
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
if (arg === '--json') {
|
|
610
|
+
options.json = true;
|
|
611
|
+
continue;
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
if (arg === '--seed') {
|
|
615
|
+
options.seed = argv[index + 1] ?? null;
|
|
616
|
+
index += 1;
|
|
617
|
+
continue;
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
throw new Error(`Unknown argument: ${arg}`);
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
return options;
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
function printHelp() {
|
|
627
|
+
console.log(`SBTI survey CLI
|
|
628
|
+
|
|
629
|
+
Usage:
|
|
630
|
+
sbti-cli
|
|
631
|
+
sbti-cli --seed 42
|
|
632
|
+
|
|
633
|
+
Options:
|
|
634
|
+
--seed <number> Use deterministic question ordering for testing.
|
|
635
|
+
--json Print the final result as JSON.
|
|
636
|
+
--help, -h Show this help message.
|
|
637
|
+
`);
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
function printQuestion(question, index, total) {
|
|
641
|
+
const metaLabel = getQuestionMetaLabel(question);
|
|
642
|
+
|
|
643
|
+
console.log(`\n第 ${index + 1} 题 / ${total} · ${metaLabel}`);
|
|
644
|
+
console.log(question.text);
|
|
645
|
+
console.log('');
|
|
646
|
+
|
|
647
|
+
question.options.forEach((option, optionIndex) => {
|
|
648
|
+
console.log(` ${formatOptionCode(optionIndex)}. ${option.label}`);
|
|
649
|
+
});
|
|
650
|
+
|
|
651
|
+
console.log('\n输入 A/B/C/D 选择,或输入 q 退出。');
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
function printResult(result, runtime) {
|
|
655
|
+
const type = result.finalType;
|
|
656
|
+
|
|
657
|
+
console.log('\n=== 测试结果 ===');
|
|
658
|
+
console.log(result.modeKicker);
|
|
659
|
+
console.log(`${type.code}(${type.cn})`);
|
|
660
|
+
console.log(result.badge);
|
|
661
|
+
console.log(result.sub);
|
|
662
|
+
console.log(`结果字符串: ${result.resultPattern}`);
|
|
663
|
+
console.log('');
|
|
664
|
+
console.log(type.intro);
|
|
665
|
+
console.log(type.desc);
|
|
666
|
+
|
|
667
|
+
if (result.secondaryType) {
|
|
668
|
+
console.log('');
|
|
669
|
+
console.log(`常规主类型: ${result.secondaryType.code}(${result.secondaryType.cn})`);
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
console.log('');
|
|
673
|
+
console.log(
|
|
674
|
+
`普通人格第一名: ${result.bestNormal.code}(${result.bestNormal.cn}) · 相似度 ${result.bestNormal.similarity}% · 精准命中 ${result.bestNormal.exact}/15 · 总差值 ${result.bestNormal.distance}`
|
|
675
|
+
);
|
|
676
|
+
|
|
677
|
+
console.log('\n常规人格 Top 5');
|
|
678
|
+
result.ranked.slice(0, 5).forEach((match, index) => {
|
|
679
|
+
console.log(
|
|
680
|
+
`${index + 1}. ${match.code}(${match.cn}) · 相似度 ${match.similarity}% · 精准命中 ${match.exact}/15 · 总差值 ${match.distance}`
|
|
681
|
+
);
|
|
682
|
+
});
|
|
683
|
+
|
|
684
|
+
console.log('\n十五维度评分');
|
|
685
|
+
runtime.exports.dimensionOrder.forEach((dimensionId) => {
|
|
686
|
+
const meta = runtime.exports.dimensionMeta[dimensionId];
|
|
687
|
+
const level = result.levels[dimensionId];
|
|
688
|
+
const rawScore = result.rawScores[dimensionId];
|
|
689
|
+
const explanation = runtime.exports.DIM_EXPLANATIONS[dimensionId][level];
|
|
690
|
+
console.log(`- ${meta.name}: ${level} / ${rawScore}分`);
|
|
691
|
+
console.log(` ${explanation}`);
|
|
692
|
+
});
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
async function run() {
|
|
696
|
+
const options = parseArgs(process.argv.slice(2));
|
|
697
|
+
|
|
698
|
+
if (options.help) {
|
|
699
|
+
printHelp();
|
|
700
|
+
return;
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
const random = options.seed === null ? Math.random : createSeededRandom(options.seed);
|
|
704
|
+
const runtime = await loadSbtiRuntime({
|
|
705
|
+
random
|
|
706
|
+
});
|
|
707
|
+
const session = createSurveySession(runtime);
|
|
708
|
+
|
|
709
|
+
const rl = createInterface({
|
|
710
|
+
input: process.stdin,
|
|
711
|
+
output: process.stdout
|
|
712
|
+
});
|
|
713
|
+
|
|
714
|
+
console.log('SBTI 人格测试 CLI');
|
|
715
|
+
if (options.seed !== null) {
|
|
716
|
+
console.log(`随机种子: ${options.seed}`);
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
try {
|
|
720
|
+
while (!session.getProgress().complete) {
|
|
721
|
+
const progress = session.getProgress();
|
|
722
|
+
const question = session.getCurrentQuestion();
|
|
723
|
+
printQuestion(question, progress.done, progress.total);
|
|
724
|
+
const response = await rl.question('> ');
|
|
725
|
+
const normalized = response.trim();
|
|
726
|
+
|
|
727
|
+
if (!normalized) {
|
|
728
|
+
console.log('请输入一个选项。');
|
|
729
|
+
continue;
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
if (/^(q|quit|exit)$/i.test(normalized)) {
|
|
733
|
+
console.log('已退出,未提交结果。');
|
|
734
|
+
return;
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
const value = findOptionValue(question, normalized);
|
|
738
|
+
if (value === null) {
|
|
739
|
+
console.log('请输入有效选项,比如 A、B、C、D 或对应数字。');
|
|
740
|
+
continue;
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
session.answerQuestion(question.id, value);
|
|
744
|
+
}
|
|
745
|
+
} finally {
|
|
746
|
+
rl.close();
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
const result = session.computeResult();
|
|
750
|
+
|
|
751
|
+
if (options.json) {
|
|
752
|
+
console.log(JSON.stringify(result, null, 2));
|
|
753
|
+
return;
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
printResult(result, runtime);
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
run().catch((error) => {
|
|
760
|
+
console.error(error.message);
|
|
761
|
+
process.exitCode = 1;
|
|
762
|
+
});
|