@lightcone-ai/daemon 0.15.32 → 0.15.33
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.
|
@@ -1120,10 +1120,9 @@ function buildPhaseSentence({ phase, strategy, phaseIndex }) {
|
|
|
1120
1120
|
const slotText = resolveSummaryValue(strategy, slotKey);
|
|
1121
1121
|
const slotTextOrFallback = slotText || describeHighlightFocus(phase);
|
|
1122
1122
|
const company = resolveSummaryValue(strategy, 'company') || '该公司';
|
|
1123
|
-
const publishedAt = resolveSummaryValue(strategy, 'published_at')
|
|
1124
|
-
const recruitmentType = resolveSummaryValue(strategy, 'recruitment_type') || '
|
|
1123
|
+
const publishedAt = resolveSummaryValue(strategy, 'published_at');
|
|
1124
|
+
const recruitmentType = resolveSummaryValue(strategy, 'recruitment_type') || '招聘';
|
|
1125
1125
|
const cohort = resolveSummaryValue(strategy, 'cohort');
|
|
1126
|
-
const entry = resolveSummaryValue(strategy, 'entry_or_cta') || '官方岗位入口';
|
|
1127
1126
|
const locations = resolveSummaryValue(strategy, 'locations');
|
|
1128
1127
|
const jobDirections = resolveSummaryValue(strategy, 'job_directions');
|
|
1129
1128
|
const process = resolveSummaryValue(strategy, 'process');
|
|
@@ -1131,74 +1130,92 @@ function buildPhaseSentence({ phase, strategy, phaseIndex }) {
|
|
|
1131
1130
|
|
|
1132
1131
|
if (role === 'hook') {
|
|
1133
1132
|
if (mode === 'job_intel_broadcast') {
|
|
1134
|
-
const cohortPart = cohort ?
|
|
1133
|
+
const cohortPart = cohort ? cohort : recruitmentType;
|
|
1135
1134
|
return ensureSentenceLength(
|
|
1136
|
-
|
|
1135
|
+
`${company}${cohortPart}信息来了!岗位方向、城市和流程帮你快速过一遍。`
|
|
1137
1136
|
);
|
|
1138
1137
|
}
|
|
1139
1138
|
|
|
1140
1139
|
if (mode === 'job_alert') {
|
|
1140
|
+
const cohortPart = cohort ? cohort : recruitmentType;
|
|
1141
|
+
const timePart = publishedAt ? `,${publishedAt}发布` : '';
|
|
1141
1142
|
return ensureSentenceLength(
|
|
1142
|
-
|
|
1143
|
+
`注意!${company}${cohortPart}${timePart},感兴趣的先来看看能确认的信息。`
|
|
1143
1144
|
);
|
|
1144
1145
|
}
|
|
1145
1146
|
|
|
1146
1147
|
if (mode === 'refuse_auto_broadcast') {
|
|
1147
1148
|
return ensureSentenceLength(
|
|
1148
|
-
'
|
|
1149
|
+
'这个页面的招聘信息不太完整,我只说能确认的部分,详情去原文核实。'
|
|
1149
1150
|
);
|
|
1150
1151
|
}
|
|
1151
1152
|
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
);
|
|
1153
|
+
// info_summary
|
|
1154
|
+
const cohortPart = cohort ? cohort : recruitmentType;
|
|
1155
|
+
return ensureSentenceLength(`${company}${cohortPart}出来了,感兴趣的来看看!`);
|
|
1155
1156
|
}
|
|
1156
1157
|
|
|
1157
1158
|
if (role === 'cta') {
|
|
1159
|
+
if (mode === 'job_intel_broadcast') {
|
|
1160
|
+
return ensureSentenceLength('信息过了一遍,觉得合适直接去原文投,时间别拖。');
|
|
1161
|
+
}
|
|
1162
|
+
if (mode === 'refuse_auto_broadcast') {
|
|
1163
|
+
return ensureSentenceLength('建议去官方渠道确认一下信息,再决定要不要投。');
|
|
1164
|
+
}
|
|
1165
|
+
return ensureSentenceLength('感兴趣就进原文看看,核实岗位和要求再投。');
|
|
1166
|
+
}
|
|
1167
|
+
|
|
1168
|
+
// published_at 是元数据,不适合单独作为一个旁白段落,跳过
|
|
1169
|
+
if (slotKey === 'published_at') {
|
|
1158
1170
|
return null;
|
|
1159
1171
|
}
|
|
1160
1172
|
|
|
1161
1173
|
if (mode === 'job_intel_broadcast') {
|
|
1162
1174
|
if (slotKey === 'job_directions') {
|
|
1163
1175
|
return ensureSentenceLength(
|
|
1164
|
-
|
|
1176
|
+
`开放方向有${slotTextOrFallback},先对照自己的专业和技能筛一遍。`
|
|
1165
1177
|
);
|
|
1166
1178
|
}
|
|
1167
1179
|
if (slotKey === 'locations') {
|
|
1168
1180
|
return ensureSentenceLength(
|
|
1169
|
-
|
|
1181
|
+
`工作城市${slotTextOrFallback},城市不合适可以直接跳过。`
|
|
1170
1182
|
);
|
|
1171
1183
|
}
|
|
1172
1184
|
if (slotKey === 'process') {
|
|
1173
1185
|
return ensureSentenceLength(
|
|
1174
|
-
|
|
1186
|
+
`招聘流程:${slotTextOrFallback},提前把简历和面试节点安排好。`
|
|
1175
1187
|
);
|
|
1176
1188
|
}
|
|
1177
1189
|
if (slotKey === 'target_or_requirements') {
|
|
1178
1190
|
return ensureSentenceLength(
|
|
1179
|
-
|
|
1191
|
+
`对象和要求是${slotTextOrFallback},先核对门槛,合适再继续准备材料。`
|
|
1180
1192
|
);
|
|
1181
1193
|
}
|
|
1182
1194
|
return ensureSentenceLength(
|
|
1183
|
-
|
|
1195
|
+
`${slotTextOrFallback},这条信息帮你判断岗位是否值得继续看。`
|
|
1184
1196
|
);
|
|
1185
1197
|
}
|
|
1186
1198
|
|
|
1187
1199
|
if (mode === 'job_alert') {
|
|
1188
1200
|
return ensureSentenceLength(
|
|
1189
|
-
|
|
1201
|
+
`目前能确认的是${slotTextOrFallback},其余细节去原文逐条核对。`
|
|
1190
1202
|
);
|
|
1191
1203
|
}
|
|
1192
1204
|
|
|
1193
1205
|
if (mode === 'refuse_auto_broadcast') {
|
|
1194
1206
|
return ensureSentenceLength(
|
|
1195
|
-
|
|
1207
|
+
`${slotTextOrFallback},置信度偏低,建议补充权威来源后再做判断。`
|
|
1196
1208
|
);
|
|
1197
1209
|
}
|
|
1198
1210
|
|
|
1199
|
-
|
|
1211
|
+
// info_summary
|
|
1212
|
+
if (slotKey === 'target_or_requirements') {
|
|
1213
|
+
return ensureSentenceLength(
|
|
1214
|
+
`对象和要求看原文,${targetOrRequirements || '具体条件以原文为准'}。`
|
|
1215
|
+
);
|
|
1216
|
+
}
|
|
1200
1217
|
return ensureSentenceLength(
|
|
1201
|
-
|
|
1218
|
+
`${slotTextOrFallback},感兴趣进原文看完整信息。`
|
|
1202
1219
|
);
|
|
1203
1220
|
}
|
|
1204
1221
|
|
package/package.json
CHANGED
|
@@ -301,13 +301,30 @@ function msToAssTimestamp(ms) {
|
|
|
301
301
|
return `${hr}:${String(min).padStart(2, '0')}:${String(sec).padStart(2, '0')}.${String(cs).padStart(2, '0')}`;
|
|
302
302
|
}
|
|
303
303
|
|
|
304
|
+
// Hard-wrap CJK subtitle text so it never overflows the video frame.
|
|
305
|
+
// libass WrapStyle:0 doesn't handle Chinese text reliably (no word boundaries),
|
|
306
|
+
// so we insert explicit \N breaks every maxChars characters.
|
|
307
|
+
function wrapSubtitleText(text, maxChars = 14) {
|
|
308
|
+
const chars = Array.from(String(text ?? ''));
|
|
309
|
+
if (chars.length <= maxChars) return chars.join('');
|
|
310
|
+
const lines = [];
|
|
311
|
+
for (let i = 0; i < chars.length; i += maxChars) {
|
|
312
|
+
lines.push(chars.slice(i, i + maxChars).join(''));
|
|
313
|
+
}
|
|
314
|
+
return lines.join('\\N');
|
|
315
|
+
}
|
|
316
|
+
|
|
304
317
|
export function buildAssContent(subtitles = [], { playResX = 1080, playResY = 1920 } = {}) {
|
|
318
|
+
// Max chars per line: (playResX - marginL - marginR) / fontSizePx
|
|
319
|
+
// 1080 - 30 - 30 = 1020px, fontsize 72 ≈ 72px/char → 14 chars
|
|
320
|
+
const maxCharsPerLine = Math.floor((playResX - 60) / SUBTITLE_FONT_SIZE);
|
|
321
|
+
|
|
305
322
|
const header = [
|
|
306
323
|
'[Script Info]',
|
|
307
324
|
'ScriptType: v4.00+',
|
|
308
325
|
`PlayResX: ${playResX}`,
|
|
309
326
|
`PlayResY: ${playResY}`,
|
|
310
|
-
'WrapStyle:
|
|
327
|
+
'WrapStyle: 2',
|
|
311
328
|
'',
|
|
312
329
|
'[V4+ Styles]',
|
|
313
330
|
'Format: Name, Fontname, Fontsize, PrimaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding',
|
|
@@ -318,7 +335,8 @@ export function buildAssContent(subtitles = [], { playResX = 1080, playResY = 19
|
|
|
318
335
|
].join('\n');
|
|
319
336
|
|
|
320
337
|
const events = subtitles.map(({ text, start_ms, end_ms }) => {
|
|
321
|
-
const
|
|
338
|
+
const wrapped = wrapSubtitleText(text, maxCharsPerLine);
|
|
339
|
+
const safeText = wrapped.replace(/\r?\n/g, '\\N').replace(/,/g, '{\\,}');
|
|
322
340
|
return `Dialogue: 0,${msToAssTimestamp(start_ms)},${msToAssTimestamp(end_ms)},Default,,0,0,0,,${safeText}`;
|
|
323
341
|
});
|
|
324
342
|
|