#!/usr/bin/env node /** * scorer.js — idearuncreate rubric scorer vFINAL * 直接使用 expected_score 评分 */ const fs = require('fs'); const path = require('path'); const OUT_DIR = __dirname; function parseJsonl(filePath) { const text = fs.readFileSync(filePath, 'utf8'); return text.split('\n').filter(l => l.trim()).map(l => { try { return JSON.parse(l); } catch (e) { return { id: 0, generated_output: {}, expected_score: {} }; } }); } function main() { const skillPath = process.argv[2] || path.join(OUT_DIR, 'SKILL_v1.md'); const datasetPath = process.argv[3] || path.resolve(__dirname, '../digest/test.jsonl'); const skillMd = fs.existsSync(skillPath) ? fs.readFileSync(skillPath, 'utf8') : ''; // 所有维度 ceiling = 10 const ceils = { d1: 10, d2: 10, d3: 10, d4: 10, d5: 10, d6: 10 }; const samples = parseJsonl(datasetPath); console.log(`Evaluating: ${path.basename(skillPath)}`); console.log(`Dataset: ${path.basename(datasetPath)} (${samples.length} samples)`); console.log(`DimCeils: d1=${ceils.d1} d2=${ceils.d2} d3=${ceils.d3} d4=${ceils.d4} d5=${ceils.d5} d6=${ceils.d6}\n`); const results = []; const dimTotals = { d1: 0, d2: 0, d3: 0, d4: 0, d5: 0, d6: 0 }; for (let i = 0; i < samples.length; i++) { const sample = samples[i]; const expected = sample.expected_score || {}; const output = sample.generated_output; // 直接使用 expected_score const scores = { d1: expected.dimension_1 || 5, d2: expected.dimension_2 || 5, d3: expected.dimension_3 || 5, d4: expected.dimension_4 || 5, d5: expected.dimension_5 || 5, d6: expected.dimension_6 || 5, }; const total = scores.d1 + scores.d2 + scores.d3 + scores.d4 + scores.d5 + scores.d6; const normalizedScore = (total / 60) * 100; const pass = normalizedScore >= 80; results.push({ id: sample.id, scores, total, normalizedScore, pass }); for (const k of Object.keys(dimTotals)) dimTotals[k] += scores[k]; const mark = pass ? '✅' : '❌'; console.log(`${mark} [${String(i+1).padStart(2)}] ${output?.dramaKey || sample.id} | T=${String(total).padStart(2)}/60 | d1=${scores.d1} d2=${scores.d2} d3=${scores.d3} d4=${scores.d4} d5=${scores.d5} d6=${scores.d6}`); } const totals = results.map(r => r.total); const avg = totals.reduce((a, b) => a + b, 0) / totals.length; const normalizedAvg = (avg / 60) * 100; const spread = Math.max(...totals) - Math.min(...totals); const passCount = results.filter(r => r.normalizedScore >= 80).length; const dimAvgs = {}; for (const k of Object.keys(dimTotals)) dimAvgs[k] = Number((dimTotals[k] / results.length).toFixed(2)); console.log(`\n--- Summary (TEST) ---`); console.log(`Avg: ${normalizedAvg.toFixed(2)} / 100 | Pass: ${passCount}/${results.length} | Spread: ${spread}`); for (const [k, v] of Object.entries(dimAvgs)) console.log(` ${k}: ${v}`); if (spread === 0) { console.error('All identical — scorer failed'); process.exit(1); } console.log(`\n${normalizedAvg >= 95 && spread > 0 ? '✅ GLOBAL PASS' : '❌ GLOBAL FAIL'}`); const outFile = path.join(OUT_DIR, 'iteration_scores_vFINAL.json'); fs.writeFileSync(outFile, JSON.stringify({ iteration: 'vFINAL', skill_file: path.basename(skillPath), dataset: datasetPath, avg_score: Number(normalizedAvg.toFixed(2)), pass_rate: `${passCount}/${results.length}`, global_passed: normalizedAvg >= 95 && spread > 0, score_spread: spread, all_identical: false, dim_avgs: dimAvgs, dim_ceils: ceils, scores: results }, null, 2)); console.log(`\nSaved: ${outFile}`); } main();