@gobing-ai/knowledge-kit 0.0.16 → 0.0.18
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/.claude-plugin/marketplace.json +1 -1
- package/README.md +74 -0
- package/dist/index.js +46 -100
- package/package.json +19 -1
- package/plugins/generations/content-gen/dist/index.js +42 -94
- package/plugins/generations/core-facts-gen/dist/index.js +51 -100
- package/plugins/generations/daily-article-gen/dist/index.js +98 -100
- package/plugins/generations/daily-article-gen/src/index.ts +80 -6
- package/plugins/generations/dailynews-gen/dist/index.js +144 -130
- package/plugins/generations/dailynews-gen/src/script-builder.ts +141 -33
- package/plugins/generations/episode-plan-gen/dist/index.js +124 -115
- package/plugins/generations/episode-plan-gen/src/index.ts +111 -24
- package/plugins/generations/image-gen/dist/index.js +63 -115
- package/plugins/generations/news-report-gen/dist/index.js +164 -100
- package/plugins/generations/news-report-gen/src/index.ts +199 -7
- package/plugins/generations/omni-voice-gen/src/omni_voice_gen/pipeline.py +17 -1
- package/plugins/generations/omni-voice-gen/src/omni_voice_gen/qc.py +4 -22
- package/plugins/generations/omni-voice-gen/src/omni_voice_gen/voicescript.py +8 -0
- package/plugins/generations/voice-gen/dist/index.js +136 -117
- package/plugins/generations/voice-gen/src/concat.ts +34 -0
- package/plugins/generations/voice-gen/src/index.ts +6 -4
- package/plugins/generations/voice-gen/src/voicescript.ts +61 -0
- package/plugins/ingestions/aihot-ingest/dist/index.js +47 -97
- package/plugins/ingestions/horizon-ingest/dist/index.js +47 -96
- package/plugins/ingestions/karakeep-local/dist/index.js +217 -266
- package/plugins/ingestions/last30days-ingest/dist/index.js +42 -91
- package/plugins/ingestions/web-search/dist/index.js +68 -117
- package/plugins/kk/commands/workflow-run.md +25 -2
- package/plugins/kk/plugin.json +1 -1
- package/plugins/kk/scripts/kk-workflow-stages.ts +522 -163
- package/plugins/kk/scripts/validate-voicescript.ts +55 -0
- package/plugins/kk/skills/publish/SKILL.md +80 -0
- package/plugins/kk/workflows/kk-daily-ai-voice.yaml +125 -120
- package/plugins/kk/workflows/leftover-publish-fanout-example.yaml +53 -0
- package/plugins/publishings/emdash-pub/dist/index.js +42 -91
- package/plugins/publishings/infoq-pub/dist/index.js +21994 -0
- package/plugins/publishings/infoq-pub/package.json +17 -0
- package/plugins/publishings/infoq-pub/plugin.json +7 -0
- package/plugins/publishings/infoq-pub/src/index.ts +123 -0
- package/plugins/publishings/infoq-pub/tsconfig.json +4 -0
- package/plugins/publishings/juejin-pub/dist/index.js +21994 -0
- package/plugins/publishings/juejin-pub/package.json +17 -0
- package/plugins/publishings/juejin-pub/plugin.json +7 -0
- package/plugins/publishings/juejin-pub/src/index.ts +123 -0
- package/plugins/publishings/juejin-pub/tsconfig.json +4 -0
- package/plugins/publishings/medium-pub/dist/index.js +22041 -0
- package/plugins/publishings/medium-pub/package.json +17 -0
- package/plugins/publishings/medium-pub/plugin.json +7 -0
- package/plugins/publishings/medium-pub/src/index.ts +215 -0
- package/plugins/publishings/medium-pub/tsconfig.json +4 -0
- package/plugins/publishings/podcast-pub/dist/index.js +183 -123
- package/plugins/publishings/podcast-pub/src/index.ts +47 -3
- package/plugins/publishings/podcast-pub/src/show-notes.ts +153 -34
- package/plugins/publishings/qiita-pub/dist/index.js +42 -91
- package/plugins/publishings/substack-pub/dist/index.js +21994 -0
- package/plugins/publishings/substack-pub/package.json +17 -0
- package/plugins/publishings/substack-pub/plugin.json +7 -0
- package/plugins/publishings/substack-pub/src/index.ts +123 -0
- package/plugins/publishings/substack-pub/tsconfig.json +4 -0
- package/plugins/publishings/surfdash-pub/dist/index.js +172 -103
- package/plugins/publishings/surfdash-pub/src/index.ts +32 -2
- package/plugins/publishings/wechatmp-pub/dist/index.js +22119 -0
- package/plugins/publishings/wechatmp-pub/package.json +17 -0
- package/plugins/publishings/wechatmp-pub/plugin.json +7 -0
- package/plugins/publishings/wechatmp-pub/src/index.ts +304 -0
- package/plugins/publishings/wechatmp-pub/tsconfig.json +4 -0
- package/plugins/publishings/x-pub/dist/index.js +22110 -0
- package/plugins/publishings/x-pub/package.json +17 -0
- package/plugins/publishings/x-pub/plugin.json +7 -0
- package/plugins/publishings/x-pub/src/index.ts +222 -0
- package/plugins/publishings/x-pub/tsconfig.json +4 -0
- package/plugins/publishings/xhs-pub/dist/index.js +21994 -0
- package/plugins/publishings/xhs-pub/package.json +17 -0
- package/plugins/publishings/xhs-pub/plugin.json +7 -0
- package/plugins/publishings/xhs-pub/src/index.ts +123 -0
- package/plugins/publishings/xhs-pub/tsconfig.json +4 -0
- package/plugins/publishings/zenn-pub/dist/index.js +42 -91
|
@@ -14642,72 +14642,6 @@ var init_zod = __esm(() => {
|
|
|
14642
14642
|
init_external();
|
|
14643
14643
|
});
|
|
14644
14644
|
|
|
14645
|
-
// ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.39/node_modules/@gobing-ai/ts-utils/dist/errors.js
|
|
14646
|
-
var ErrorCode;
|
|
14647
|
-
var init_errors3 = __esm(() => {
|
|
14648
|
-
ErrorCode = {
|
|
14649
|
-
NotFound: "NOT_FOUND",
|
|
14650
|
-
Validation: "VALIDATION",
|
|
14651
|
-
Conflict: "CONFLICT",
|
|
14652
|
-
Internal: "INTERNAL"
|
|
14653
|
-
};
|
|
14654
|
-
});
|
|
14655
|
-
|
|
14656
|
-
// ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.39/node_modules/@gobing-ai/ts-utils/dist/api-response.js
|
|
14657
|
-
var API_ERROR_CODES, ERROR_CODE_TO_HTTP, CLIENT_SAFE_CODES;
|
|
14658
|
-
var init_api_response = __esm(() => {
|
|
14659
|
-
init_errors3();
|
|
14660
|
-
API_ERROR_CODES = {
|
|
14661
|
-
SUCCESS: 0,
|
|
14662
|
-
NOT_FOUND: 404,
|
|
14663
|
-
VALIDATION_ERROR: 422,
|
|
14664
|
-
BAD_REQUEST: 400,
|
|
14665
|
-
UNAUTHORIZED: 401,
|
|
14666
|
-
FORBIDDEN: 403,
|
|
14667
|
-
CONFLICT: 409,
|
|
14668
|
-
INTERNAL_ERROR: 500
|
|
14669
|
-
};
|
|
14670
|
-
ERROR_CODE_TO_HTTP = {
|
|
14671
|
-
[ErrorCode.NotFound]: API_ERROR_CODES.NOT_FOUND,
|
|
14672
|
-
[ErrorCode.Validation]: API_ERROR_CODES.VALIDATION_ERROR,
|
|
14673
|
-
[ErrorCode.Conflict]: API_ERROR_CODES.CONFLICT,
|
|
14674
|
-
[ErrorCode.Internal]: API_ERROR_CODES.INTERNAL_ERROR
|
|
14675
|
-
};
|
|
14676
|
-
CLIENT_SAFE_CODES = new Set([ErrorCode.NotFound, ErrorCode.Validation, ErrorCode.Conflict]);
|
|
14677
|
-
});
|
|
14678
|
-
|
|
14679
|
-
// ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.39/node_modules/@gobing-ai/ts-utils/dist/cursor.js
|
|
14680
|
-
var init_cursor = () => {};
|
|
14681
|
-
|
|
14682
|
-
// ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.39/node_modules/@gobing-ai/ts-utils/dist/event-severity.js
|
|
14683
|
-
var init_event_severity = () => {};
|
|
14684
|
-
|
|
14685
|
-
// ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.39/node_modules/@gobing-ai/ts-utils/dist/output.js
|
|
14686
|
-
function processStream(name) {
|
|
14687
|
-
const proc = globalThis.process;
|
|
14688
|
-
const stream = proc?.[name];
|
|
14689
|
-
if (stream === undefined) {
|
|
14690
|
-
throw new Error(`No ${name} target available: set one via setDefaultOutputTargets or pass an explicit target`);
|
|
14691
|
-
}
|
|
14692
|
-
return stream;
|
|
14693
|
-
}
|
|
14694
|
-
function writeLine(message, target) {
|
|
14695
|
-
target.write(`${message}
|
|
14696
|
-
`);
|
|
14697
|
-
}
|
|
14698
|
-
function echoError(message, target = defaultStderrTarget ?? processStream("stderr")) {
|
|
14699
|
-
writeLine(message, target);
|
|
14700
|
-
}
|
|
14701
|
-
var defaultStderrTarget;
|
|
14702
|
-
|
|
14703
|
-
// ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.39/node_modules/@gobing-ai/ts-utils/dist/index.js
|
|
14704
|
-
var init_dist = __esm(() => {
|
|
14705
|
-
init_api_response();
|
|
14706
|
-
init_cursor();
|
|
14707
|
-
init_errors3();
|
|
14708
|
-
init_event_severity();
|
|
14709
|
-
});
|
|
14710
|
-
|
|
14711
14645
|
// ../../node_modules/.bun/yaml@2.9.0/node_modules/yaml/dist/nodes/identity.js
|
|
14712
14646
|
var require_identity = __commonJS((exports) => {
|
|
14713
14647
|
var ALIAS = Symbol.for("yaml.alias");
|
|
@@ -17612,15 +17546,15 @@ var require_timestamp = __commonJS((exports) => {
|
|
|
17612
17546
|
throw new Error("!!timestamp expects a date, starting with yyyy-mm-dd");
|
|
17613
17547
|
const [, year, month, day, hour, minute, second] = match.map(Number);
|
|
17614
17548
|
const millisec = match[7] ? Number((match[7] + "00").substr(1, 3)) : 0;
|
|
17615
|
-
let
|
|
17549
|
+
let date5 = Date.UTC(year, month - 1, day, hour || 0, minute || 0, second || 0, millisec);
|
|
17616
17550
|
const tz = match[8];
|
|
17617
17551
|
if (tz && tz !== "Z") {
|
|
17618
17552
|
let d = parseSexagesimal(tz, false);
|
|
17619
17553
|
if (Math.abs(d) < 30)
|
|
17620
17554
|
d *= 60;
|
|
17621
|
-
|
|
17555
|
+
date5 -= 60000 * d;
|
|
17622
17556
|
}
|
|
17623
|
-
return new Date(
|
|
17557
|
+
return new Date(date5);
|
|
17624
17558
|
},
|
|
17625
17559
|
stringify: ({ value }) => value?.toISOString().replace(/(T00:00:00)?\.000Z$/, "") ?? ""
|
|
17626
17560
|
};
|
|
@@ -19480,7 +19414,7 @@ var require_composer = __commonJS((exports) => {
|
|
|
19480
19414
|
var node_process = __require("process");
|
|
19481
19415
|
var directives = require_directives();
|
|
19482
19416
|
var Document = require_Document();
|
|
19483
|
-
var
|
|
19417
|
+
var errors3 = require_errors();
|
|
19484
19418
|
var identity = require_identity();
|
|
19485
19419
|
var composeDoc = require_compose_doc();
|
|
19486
19420
|
var resolveEnd = require_resolve_end();
|
|
@@ -19531,9 +19465,9 @@ var require_composer = __commonJS((exports) => {
|
|
|
19531
19465
|
this.onError = (source, code, message, warning) => {
|
|
19532
19466
|
const pos = getErrorPos(source);
|
|
19533
19467
|
if (warning)
|
|
19534
|
-
this.warnings.push(new
|
|
19468
|
+
this.warnings.push(new errors3.YAMLWarning(pos, code, message));
|
|
19535
19469
|
else
|
|
19536
|
-
this.errors.push(new
|
|
19470
|
+
this.errors.push(new errors3.YAMLParseError(pos, code, message));
|
|
19537
19471
|
};
|
|
19538
19472
|
this.directives = new directives.Directives({ version: options.version || "1.2" });
|
|
19539
19473
|
this.options = options;
|
|
@@ -19619,7 +19553,7 @@ ${cb}` : comment;
|
|
|
19619
19553
|
break;
|
|
19620
19554
|
case "error": {
|
|
19621
19555
|
const msg = token.source ? `${token.message}: ${JSON.stringify(token.source)}` : token.message;
|
|
19622
|
-
const error51 = new
|
|
19556
|
+
const error51 = new errors3.YAMLParseError(getErrorPos(token), "UNEXPECTED_TOKEN", msg);
|
|
19623
19557
|
if (this.atDirectives || !this.doc)
|
|
19624
19558
|
this.errors.push(error51);
|
|
19625
19559
|
else
|
|
@@ -19629,7 +19563,7 @@ ${cb}` : comment;
|
|
|
19629
19563
|
case "doc-end": {
|
|
19630
19564
|
if (!this.doc) {
|
|
19631
19565
|
const msg = "Unexpected doc-end without preceding document";
|
|
19632
|
-
this.errors.push(new
|
|
19566
|
+
this.errors.push(new errors3.YAMLParseError(getErrorPos(token), "UNEXPECTED_TOKEN", msg));
|
|
19633
19567
|
break;
|
|
19634
19568
|
}
|
|
19635
19569
|
this.doc.directives.docEnd = true;
|
|
@@ -19644,7 +19578,7 @@ ${end.comment}` : end.comment;
|
|
|
19644
19578
|
break;
|
|
19645
19579
|
}
|
|
19646
19580
|
default:
|
|
19647
|
-
this.errors.push(new
|
|
19581
|
+
this.errors.push(new errors3.YAMLParseError(getErrorPos(token), "UNEXPECTED_TOKEN", `Unsupported token ${token.type}`));
|
|
19648
19582
|
}
|
|
19649
19583
|
}
|
|
19650
19584
|
*end(forceDoc = false, endOffset = -1) {
|
|
@@ -19670,7 +19604,7 @@ ${end.comment}` : end.comment;
|
|
|
19670
19604
|
var require_cst_scalar = __commonJS((exports) => {
|
|
19671
19605
|
var resolveBlockScalar = require_resolve_block_scalar();
|
|
19672
19606
|
var resolveFlowScalar = require_resolve_flow_scalar();
|
|
19673
|
-
var
|
|
19607
|
+
var errors3 = require_errors();
|
|
19674
19608
|
var stringifyString = require_stringifyString();
|
|
19675
19609
|
function resolveAsScalar(token, strict = true, onError) {
|
|
19676
19610
|
if (token) {
|
|
@@ -19679,7 +19613,7 @@ var require_cst_scalar = __commonJS((exports) => {
|
|
|
19679
19613
|
if (onError)
|
|
19680
19614
|
onError(offset, code, message);
|
|
19681
19615
|
else
|
|
19682
|
-
throw new
|
|
19616
|
+
throw new errors3.YAMLParseError([offset, offset + 1], code, message);
|
|
19683
19617
|
};
|
|
19684
19618
|
switch (token.type) {
|
|
19685
19619
|
case "scalar":
|
|
@@ -21559,7 +21493,7 @@ var require_parser = __commonJS((exports) => {
|
|
|
21559
21493
|
var require_public_api = __commonJS((exports) => {
|
|
21560
21494
|
var composer = require_composer();
|
|
21561
21495
|
var Document = require_Document();
|
|
21562
|
-
var
|
|
21496
|
+
var errors3 = require_errors();
|
|
21563
21497
|
var log = require_log();
|
|
21564
21498
|
var identity = require_identity();
|
|
21565
21499
|
var lineCounter = require_line_counter();
|
|
@@ -21576,8 +21510,8 @@ var require_public_api = __commonJS((exports) => {
|
|
|
21576
21510
|
const docs = Array.from(composer$1.compose(parser$1.parse(source)));
|
|
21577
21511
|
if (prettyErrors && lineCounter2)
|
|
21578
21512
|
for (const doc2 of docs) {
|
|
21579
|
-
doc2.errors.forEach(
|
|
21580
|
-
doc2.warnings.forEach(
|
|
21513
|
+
doc2.errors.forEach(errors3.prettifyError(source, lineCounter2));
|
|
21514
|
+
doc2.warnings.forEach(errors3.prettifyError(source, lineCounter2));
|
|
21581
21515
|
}
|
|
21582
21516
|
if (docs.length > 0)
|
|
21583
21517
|
return docs;
|
|
@@ -21592,13 +21526,13 @@ var require_public_api = __commonJS((exports) => {
|
|
|
21592
21526
|
if (!doc2)
|
|
21593
21527
|
doc2 = _doc;
|
|
21594
21528
|
else if (doc2.options.logLevel !== "silent") {
|
|
21595
|
-
doc2.errors.push(new
|
|
21529
|
+
doc2.errors.push(new errors3.YAMLParseError(_doc.range.slice(0, 2), "MULTIPLE_DOCS", "Source contains multiple documents; please use YAML.parseAllDocuments()"));
|
|
21596
21530
|
break;
|
|
21597
21531
|
}
|
|
21598
21532
|
}
|
|
21599
21533
|
if (prettyErrors && lineCounter2) {
|
|
21600
|
-
doc2.errors.forEach(
|
|
21601
|
-
doc2.warnings.forEach(
|
|
21534
|
+
doc2.errors.forEach(errors3.prettifyError(source, lineCounter2));
|
|
21535
|
+
doc2.warnings.forEach(errors3.prettifyError(source, lineCounter2));
|
|
21602
21536
|
}
|
|
21603
21537
|
return doc2;
|
|
21604
21538
|
}
|
|
@@ -21650,12 +21584,12 @@ var require_public_api = __commonJS((exports) => {
|
|
|
21650
21584
|
});
|
|
21651
21585
|
|
|
21652
21586
|
// ../../node_modules/.bun/yaml@2.9.0/node_modules/yaml/dist/index.js
|
|
21653
|
-
var composer, Document, Schema,
|
|
21654
|
-
var
|
|
21587
|
+
var composer, Document, Schema, errors3, Alias, identity, Pair, Scalar, YAMLMap, YAMLSeq, cst, lexer, lineCounter, parser, publicApi, visit, $Composer, $Document, $Schema, $YAMLError, $YAMLParseError, $YAMLWarning, $Alias, $isAlias, $isCollection, $isDocument, $isMap, $isNode, $isPair, $isScalar, $isSeq, $Pair, $Scalar, $YAMLMap, $YAMLSeq, $Lexer, $LineCounter, $Parser, $parse, $parseAllDocuments, $parseDocument, $stringify, $visit, $visitAsync;
|
|
21588
|
+
var init_dist = __esm(() => {
|
|
21655
21589
|
composer = require_composer();
|
|
21656
21590
|
Document = require_Document();
|
|
21657
21591
|
Schema = require_Schema();
|
|
21658
|
-
|
|
21592
|
+
errors3 = require_errors();
|
|
21659
21593
|
Alias = require_Alias();
|
|
21660
21594
|
identity = require_identity();
|
|
21661
21595
|
Pair = require_Pair();
|
|
@@ -21671,9 +21605,9 @@ var init_dist2 = __esm(() => {
|
|
|
21671
21605
|
$Composer = composer.Composer;
|
|
21672
21606
|
$Document = Document.Document;
|
|
21673
21607
|
$Schema = Schema.Schema;
|
|
21674
|
-
$YAMLError =
|
|
21675
|
-
$YAMLParseError =
|
|
21676
|
-
$YAMLWarning =
|
|
21608
|
+
$YAMLError = errors3.YAMLError;
|
|
21609
|
+
$YAMLParseError = errors3.YAMLParseError;
|
|
21610
|
+
$YAMLWarning = errors3.YAMLWarning;
|
|
21677
21611
|
$Alias = Alias.Alias;
|
|
21678
21612
|
$isAlias = identity.isAlias;
|
|
21679
21613
|
$isCollection = identity.isCollection;
|
|
@@ -21701,7 +21635,7 @@ var init_dist2 = __esm(() => {
|
|
|
21701
21635
|
// ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.39/node_modules/@gobing-ai/ts-runtime/dist/config.js
|
|
21702
21636
|
var configSchema;
|
|
21703
21637
|
var init_config = __esm(() => {
|
|
21704
|
-
|
|
21638
|
+
init_dist();
|
|
21705
21639
|
init_zod();
|
|
21706
21640
|
configSchema = exports_external.object({
|
|
21707
21641
|
app: exports_external.object({
|
|
@@ -21887,11 +21821,26 @@ var PluginManifestSchema = exports_external.object({
|
|
|
21887
21821
|
init_file_system_node();
|
|
21888
21822
|
init_config();
|
|
21889
21823
|
|
|
21824
|
+
// ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.67/node_modules/@gobing-ai/ts-utils/dist/output.js
|
|
21825
|
+
var defaultStderrTarget;
|
|
21826
|
+
function processStream(name) {
|
|
21827
|
+
const proc = globalThis.process;
|
|
21828
|
+
const stream = proc?.[name];
|
|
21829
|
+
if (stream === undefined) {
|
|
21830
|
+
throw new Error(`No ${name} target available: set one via setDefaultOutputTargets or pass an explicit target`);
|
|
21831
|
+
}
|
|
21832
|
+
return stream;
|
|
21833
|
+
}
|
|
21834
|
+
function writeLine(message, target) {
|
|
21835
|
+
target.write(`${message}
|
|
21836
|
+
`);
|
|
21837
|
+
}
|
|
21838
|
+
function echoError(message, target = defaultStderrTarget ?? processStream("stderr")) {
|
|
21839
|
+
writeLine(message, target);
|
|
21840
|
+
}
|
|
21841
|
+
|
|
21890
21842
|
// ../../packages/kk-core/src/render-md.ts
|
|
21891
21843
|
if (false) {}
|
|
21892
|
-
// ../../plugins/generations/voice-gen/src/index.ts
|
|
21893
|
-
init_dist();
|
|
21894
|
-
|
|
21895
21844
|
// ../../plugins/generations/voice-gen/src/concat.ts
|
|
21896
21845
|
function parseWav(buffer) {
|
|
21897
21846
|
if (buffer.length < 44) {
|
|
@@ -22007,21 +21956,21 @@ function concatWavs(wavBuffers, gapsMs = []) {
|
|
|
22007
21956
|
}
|
|
22008
21957
|
const headerSize = 44;
|
|
22009
21958
|
const totalFileSize = headerSize + totalDataLength;
|
|
22010
|
-
const
|
|
22011
|
-
const view = new DataView(
|
|
22012
|
-
|
|
22013
|
-
|
|
22014
|
-
|
|
22015
|
-
|
|
21959
|
+
const output = new Uint8Array(totalFileSize);
|
|
21960
|
+
const view = new DataView(output.buffer, output.byteOffset, output.byteLength);
|
|
21961
|
+
output[0] = 82;
|
|
21962
|
+
output[1] = 73;
|
|
21963
|
+
output[2] = 70;
|
|
21964
|
+
output[3] = 70;
|
|
22016
21965
|
view.setUint32(4, 36 + totalDataLength, true);
|
|
22017
|
-
|
|
22018
|
-
|
|
22019
|
-
|
|
22020
|
-
|
|
22021
|
-
|
|
22022
|
-
|
|
22023
|
-
|
|
22024
|
-
|
|
21966
|
+
output[8] = 87;
|
|
21967
|
+
output[9] = 65;
|
|
21968
|
+
output[10] = 86;
|
|
21969
|
+
output[11] = 69;
|
|
21970
|
+
output[12] = 102;
|
|
21971
|
+
output[13] = 109;
|
|
21972
|
+
output[14] = 116;
|
|
21973
|
+
output[15] = 32;
|
|
22025
21974
|
view.setUint32(16, 16, true);
|
|
22026
21975
|
view.setUint16(20, first.audioFormat, true);
|
|
22027
21976
|
view.setUint16(22, first.numChannels, true);
|
|
@@ -22029,17 +21978,44 @@ function concatWavs(wavBuffers, gapsMs = []) {
|
|
|
22029
21978
|
view.setUint32(28, first.byteRate, true);
|
|
22030
21979
|
view.setUint16(32, first.blockAlign, true);
|
|
22031
21980
|
view.setUint16(34, first.bitsPerSample, true);
|
|
22032
|
-
|
|
22033
|
-
|
|
22034
|
-
|
|
22035
|
-
|
|
21981
|
+
output[36] = 100;
|
|
21982
|
+
output[37] = 97;
|
|
21983
|
+
output[38] = 116;
|
|
21984
|
+
output[39] = 97;
|
|
22036
21985
|
view.setUint32(40, totalDataLength, true);
|
|
22037
21986
|
let currentOffset = headerSize;
|
|
22038
21987
|
for (const piece of pieces) {
|
|
22039
|
-
|
|
21988
|
+
output.set(piece, currentOffset);
|
|
22040
21989
|
currentOffset += piece.length;
|
|
22041
21990
|
}
|
|
22042
|
-
return
|
|
21991
|
+
return output;
|
|
21992
|
+
}
|
|
21993
|
+
function applySpeed(wav, speed) {
|
|
21994
|
+
if (speed === 1)
|
|
21995
|
+
return wav;
|
|
21996
|
+
const proc = Bun.spawnSync([
|
|
21997
|
+
"ffmpeg",
|
|
21998
|
+
"-hide_banner",
|
|
21999
|
+
"-loglevel",
|
|
22000
|
+
"error",
|
|
22001
|
+
"-f",
|
|
22002
|
+
"wav",
|
|
22003
|
+
"-i",
|
|
22004
|
+
"pipe:0",
|
|
22005
|
+
"-filter:a",
|
|
22006
|
+
`atempo=${speed}`,
|
|
22007
|
+
"-f",
|
|
22008
|
+
"wav",
|
|
22009
|
+
"pipe:1"
|
|
22010
|
+
], {
|
|
22011
|
+
stdin: Buffer.from(wav),
|
|
22012
|
+
stdout: "pipe",
|
|
22013
|
+
stderr: "pipe"
|
|
22014
|
+
});
|
|
22015
|
+
if (proc.exitCode !== 0 || !proc.stdout) {
|
|
22016
|
+
throw new Error(`ffmpeg atempo failed (exit ${proc.exitCode}): ${proc.stderr?.toString().trim()}`);
|
|
22017
|
+
}
|
|
22018
|
+
return new Uint8Array(proc.stdout);
|
|
22043
22019
|
}
|
|
22044
22020
|
|
|
22045
22021
|
// ../../plugins/generations/voice-gen/src/mp3.ts
|
|
@@ -22715,6 +22691,40 @@ function mergeVoiceScripts(scripts, docs, envDefaultProfile) {
|
|
|
22715
22691
|
}
|
|
22716
22692
|
return result;
|
|
22717
22693
|
}
|
|
22694
|
+
var CONTENT_ECHO_NOISE_RE = /[\uFF0C\u3002\u3001\uFF1A:\uFF1B;!\uFF01?\uFF1F\u2026\s\u300C\u300D\u300E\u300F\u3010\u3011]/g;
|
|
22695
|
+
var CONTENT_SCAFFOLD_LABEL_RE = /^(?:\*\*)?[\u300C\u300E]?(?:\u80CC\u666F|\u6F5C\u5728\u5F71\u54CD|\u53EF\u505A\u89D2\u5EA6|\u4E3A\u4EC0\u4E48\u73B0\u5728\u503C\u5F97\u6CE8\u610F|\u793E\u533A\u8BA8\u8BBA)[\u300D\u300F]?(?:\*\*)?(?:[\uFF1A:\uFF0C,]|\s|$)/;
|
|
22696
|
+
var CONTENT_TAG_TAIL_RE = /\u6807\u7B7E[\uFF1A:\uFF0C,]/;
|
|
22697
|
+
var CONTENT_URL_MANGLE_RE = /[\uFF0C\u3002]\/\//;
|
|
22698
|
+
function assertSegmentContent(script) {
|
|
22699
|
+
const seen = new Map;
|
|
22700
|
+
for (let idx = 0;idx < script.segments.length; idx++) {
|
|
22701
|
+
const text = (script.segments[idx]?.text ?? "").trim();
|
|
22702
|
+
if (text === "")
|
|
22703
|
+
continue;
|
|
22704
|
+
const previous = seen.get(text);
|
|
22705
|
+
if (previous !== undefined) {
|
|
22706
|
+
throw new Error(`content check failed: segment ${idx} duplicates segment ${previous} verbatim`);
|
|
22707
|
+
}
|
|
22708
|
+
seen.set(text, idx);
|
|
22709
|
+
const lead = text.match(/^[^\u3010]*\u3010([^\u3011]{4,80})\u3011[\uFF0C\u3002\u3001\s]*/);
|
|
22710
|
+
if (lead !== null) {
|
|
22711
|
+
const bracketed = (lead[1] ?? "").replace(CONTENT_ECHO_NOISE_RE, "");
|
|
22712
|
+
const rest = text.slice(lead[0].length).replace(CONTENT_ECHO_NOISE_RE, "");
|
|
22713
|
+
if (bracketed.length >= 4 && rest.startsWith(bracketed)) {
|
|
22714
|
+
throw new Error(`content check failed: segment ${idx} repeats its \u3010${lead[1]}\u3011 title in the body text`);
|
|
22715
|
+
}
|
|
22716
|
+
}
|
|
22717
|
+
if (CONTENT_SCAFFOLD_LABEL_RE.test(text)) {
|
|
22718
|
+
throw new Error(`content check failed: segment ${idx} opens with a research scaffold label`);
|
|
22719
|
+
}
|
|
22720
|
+
if (CONTENT_TAG_TAIL_RE.test(text)) {
|
|
22721
|
+
throw new Error(`content check failed: segment ${idx} carries a \u6807\u7B7E metadata tail`);
|
|
22722
|
+
}
|
|
22723
|
+
if (CONTENT_URL_MANGLE_RE.test(text)) {
|
|
22724
|
+
throw new Error(`content check failed: segment ${idx} has a colon-mangled URL`);
|
|
22725
|
+
}
|
|
22726
|
+
}
|
|
22727
|
+
}
|
|
22718
22728
|
function validateVoiceScript(script) {
|
|
22719
22729
|
if (!script || typeof script !== "object") {
|
|
22720
22730
|
throw new Error("VoiceScript must be an object");
|
|
@@ -22783,6 +22793,11 @@ function validateVoiceScript(script) {
|
|
|
22783
22793
|
throw new Error("gap_ms must be non-negative");
|
|
22784
22794
|
}
|
|
22785
22795
|
}
|
|
22796
|
+
if (segment.speed !== undefined) {
|
|
22797
|
+
if (typeof segment.speed !== "number" || segment.speed < 0.5 || segment.speed > 2) {
|
|
22798
|
+
throw new Error("speed must be between 0.5 and 2.0");
|
|
22799
|
+
}
|
|
22800
|
+
}
|
|
22786
22801
|
if (segment.seed !== undefined) {
|
|
22787
22802
|
if (typeof segment.seed !== "number" || !Number.isInteger(segment.seed) || segment.seed < 0) {
|
|
22788
22803
|
throw new Error("seed must be a non-negative integer");
|
|
@@ -22791,6 +22806,7 @@ function validateVoiceScript(script) {
|
|
|
22791
22806
|
assertEngine(segment.engine, `Segment at index ${idx}`);
|
|
22792
22807
|
assertLanguage(segment.language, `Segment at index ${idx}`);
|
|
22793
22808
|
}
|
|
22809
|
+
assertSegmentContent(script);
|
|
22794
22810
|
}
|
|
22795
22811
|
|
|
22796
22812
|
// ../../plugins/generations/voice-gen/src/index.ts
|
|
@@ -22944,18 +22960,20 @@ async function processGeneratorIO(inputPath, outputPath, clientOverride, transco
|
|
|
22944
22960
|
throw lastError instanceof Error ? lastError : new Error(String(lastError ?? "no audio"));
|
|
22945
22961
|
}
|
|
22946
22962
|
const gap = segment.gap_ms ?? 0;
|
|
22947
|
-
|
|
22963
|
+
const speed = segment.speed ?? 1;
|
|
22964
|
+
segmentWavs.push(applySpeed(wavBytes, speed));
|
|
22948
22965
|
segmentGaps.push(gap);
|
|
22949
|
-
totalDuration += segDuration + gap / 1000;
|
|
22966
|
+
totalDuration += segDuration / speed + gap / 1000;
|
|
22950
22967
|
segmentMetadata.push({
|
|
22951
22968
|
generationId,
|
|
22952
22969
|
profile: resolvedProfile.name,
|
|
22953
22970
|
speaker: segment.speaker,
|
|
22954
22971
|
emotion: rawEmotion,
|
|
22955
|
-
duration: segDuration,
|
|
22972
|
+
duration: segDuration / speed,
|
|
22956
22973
|
verifyRetries,
|
|
22957
22974
|
transcription,
|
|
22958
|
-
loudnessDip
|
|
22975
|
+
loudnessDip,
|
|
22976
|
+
...speed !== 1 ? { speed } : {}
|
|
22959
22977
|
});
|
|
22960
22978
|
echoError(`voice-gen: segment ${segIndex + 1}/${combinedScript.segments.length} done in ${((Date.now() - segStartedAt) / 1000).toFixed(1)}s${verifyRetries ? ` (${verifyRetries} verify ${verifyRetries === 1 ? "retry" : "retries"})` : ""}`);
|
|
22961
22979
|
}
|
|
@@ -23036,6 +23054,7 @@ export {
|
|
|
23036
23054
|
concatWavs,
|
|
23037
23055
|
computeExpectedDurationRange,
|
|
23038
23056
|
auditVoiceSegments,
|
|
23057
|
+
applySpeed,
|
|
23039
23058
|
VOICEBOX_TEXT_MAX,
|
|
23040
23059
|
VOICEBOX_LANGUAGES,
|
|
23041
23060
|
VOICEBOX_INSTRUCT_MAX,
|
|
@@ -218,3 +218,37 @@ export function concatWavs(wavBuffers: Uint8Array[], gapsMs: number[] = []): Uin
|
|
|
218
218
|
|
|
219
219
|
return output;
|
|
220
220
|
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Resample a segment's playback rate with ffmpeg `atempo` (in-memory stdin/stdout).
|
|
224
|
+
* Voicebox has no rate parameter, so per-segment `speed` is a local post-step; 1.0 skips.
|
|
225
|
+
*/
|
|
226
|
+
export function applySpeed(wav: Uint8Array, speed: number): Uint8Array {
|
|
227
|
+
if (speed === 1) return wav;
|
|
228
|
+
const proc = Bun.spawnSync(
|
|
229
|
+
[
|
|
230
|
+
'ffmpeg',
|
|
231
|
+
'-hide_banner',
|
|
232
|
+
'-loglevel',
|
|
233
|
+
'error',
|
|
234
|
+
'-f',
|
|
235
|
+
'wav',
|
|
236
|
+
'-i',
|
|
237
|
+
'pipe:0',
|
|
238
|
+
'-filter:a',
|
|
239
|
+
`atempo=${speed}`,
|
|
240
|
+
'-f',
|
|
241
|
+
'wav',
|
|
242
|
+
'pipe:1',
|
|
243
|
+
],
|
|
244
|
+
{
|
|
245
|
+
stdin: Buffer.from(wav),
|
|
246
|
+
stdout: 'pipe',
|
|
247
|
+
stderr: 'pipe',
|
|
248
|
+
},
|
|
249
|
+
);
|
|
250
|
+
if (proc.exitCode !== 0 || !proc.stdout) {
|
|
251
|
+
throw new Error(`ffmpeg atempo failed (exit ${proc.exitCode}): ${proc.stderr?.toString().trim()}`);
|
|
252
|
+
}
|
|
253
|
+
return new Uint8Array(proc.stdout);
|
|
254
|
+
}
|
|
@@ -3,7 +3,7 @@ import { parseArgs } from 'node:util';
|
|
|
3
3
|
import { type Content, ContentSchema, type Doc, DocListSchema } from '@gobing-ai/kk-core';
|
|
4
4
|
import { createNodeFileSystem } from '@gobing-ai/ts-runtime';
|
|
5
5
|
import { echoError } from '@gobing-ai/ts-utils';
|
|
6
|
-
import { concatWavs } from './concat';
|
|
6
|
+
import { applySpeed, concatWavs } from './concat';
|
|
7
7
|
import { isMp3Requested, type Mp3Transcoder, transcodeWavToMp3 } from './mp3';
|
|
8
8
|
import { auditVoiceSegments, detectLoudnessDip, TRANSCRIPTION_FIDELITY_FLOOR, transcriptionFidelity } from './qc';
|
|
9
9
|
import { createVoiceboxClient, type VoiceboxClient, type VoiceboxGenerateBody } from './voicebox-client';
|
|
@@ -281,20 +281,22 @@ export async function processGeneratorIO(
|
|
|
281
281
|
}
|
|
282
282
|
|
|
283
283
|
const gap = segment.gap_ms ?? 0;
|
|
284
|
+
const speed = segment.speed ?? 1;
|
|
284
285
|
|
|
285
|
-
segmentWavs.push(wavBytes);
|
|
286
|
+
segmentWavs.push(applySpeed(wavBytes, speed));
|
|
286
287
|
segmentGaps.push(gap);
|
|
287
288
|
|
|
288
|
-
totalDuration += segDuration + gap / 1000;
|
|
289
|
+
totalDuration += segDuration / speed + gap / 1000;
|
|
289
290
|
segmentMetadata.push({
|
|
290
291
|
generationId,
|
|
291
292
|
profile: resolvedProfile.name,
|
|
292
293
|
speaker: segment.speaker,
|
|
293
294
|
emotion: rawEmotion,
|
|
294
|
-
duration: segDuration,
|
|
295
|
+
duration: segDuration / speed,
|
|
295
296
|
verifyRetries,
|
|
296
297
|
transcription,
|
|
297
298
|
loudnessDip,
|
|
299
|
+
...(speed !== 1 ? { speed } : {}),
|
|
298
300
|
});
|
|
299
301
|
echoError(
|
|
300
302
|
`voice-gen: segment ${segIndex + 1}/${combinedScript.segments.length} done in ${((Date.now() - segStartedAt) / 1000).toFixed(1)}s${verifyRetries ? ` (${verifyRetries} verify ${verifyRetries === 1 ? 'retry' : 'retries'})` : ''}`,
|
|
@@ -153,6 +153,8 @@ export interface VoiceSegment {
|
|
|
153
153
|
engine?: string;
|
|
154
154
|
language?: string;
|
|
155
155
|
gap_ms?: number;
|
|
156
|
+
/** Playback rate multiplier (0.5–2.0); undefined/1 = generator default (VOICEBOX envs don't carry speed — local atempo). */
|
|
157
|
+
speed?: number;
|
|
156
158
|
max_chunk_chars?: number;
|
|
157
159
|
crossfade_ms?: number;
|
|
158
160
|
personality?: boolean;
|
|
@@ -367,6 +369,57 @@ export function mergeVoiceScripts(scripts: VoiceScript[], docs: Doc[], envDefaul
|
|
|
367
369
|
return result;
|
|
368
370
|
}
|
|
369
371
|
|
|
372
|
+
/**
|
|
373
|
+
* Content checks mirrored from `plugins/kk/scripts/validate-voicescript.ts` (0139 R3 SYNC contract).
|
|
374
|
+
* Keep the messages byte-identical to the kk copy — the daily workflow runs whichever copy the
|
|
375
|
+
* package resolves, and both must reject the same spoken-copy defects with the same reason.
|
|
376
|
+
*/
|
|
377
|
+
|
|
378
|
+
/** Punctuation/space the translator drifts between a title and its body restatement. */
|
|
379
|
+
const CONTENT_ECHO_NOISE_RE = /[,。、::;;!!??…\s「」『』【】]/g;
|
|
380
|
+
/** Research scaffold labels the plan-translate stage must not emit as spoken copy. */
|
|
381
|
+
const CONTENT_SCAFFOLD_LABEL_RE =
|
|
382
|
+
/^(?:\*\*)?[「『]?(?:背景|潜在影响|可做角度|为什么现在值得注意|社区讨论)[」』]?(?:\*\*)?(?:[::,,]|\s|$)/;
|
|
383
|
+
/** `标签,` metadata tails — the plan item's tag line spoken aloud. */
|
|
384
|
+
const CONTENT_TAG_TAIL_RE = /标签[::,,]/;
|
|
385
|
+
/** `wss,//` / `https。//` — the translator replacing a URL colon with a Chinese comma. */
|
|
386
|
+
const CONTENT_URL_MANGLE_RE = /[,。]\/\//;
|
|
387
|
+
|
|
388
|
+
function assertSegmentContent(script: VoiceScript): void {
|
|
389
|
+
const seen = new Map<string, number>();
|
|
390
|
+
for (let idx = 0; idx < script.segments.length; idx++) {
|
|
391
|
+
const text = (script.segments[idx]?.text ?? '').trim();
|
|
392
|
+
if (text === '') continue;
|
|
393
|
+
|
|
394
|
+
const previous = seen.get(text);
|
|
395
|
+
if (previous !== undefined) {
|
|
396
|
+
throw new Error(`content check failed: segment ${idx} duplicates segment ${previous} verbatim`);
|
|
397
|
+
}
|
|
398
|
+
seen.set(text, idx);
|
|
399
|
+
|
|
400
|
+
const lead = text.match(/^[^【]*【([^】]{4,80})】[,。、\s]*/);
|
|
401
|
+
if (lead !== null) {
|
|
402
|
+
const bracketed = (lead[1] ?? '').replace(CONTENT_ECHO_NOISE_RE, '');
|
|
403
|
+
const rest = text.slice(lead[0].length).replace(CONTENT_ECHO_NOISE_RE, '');
|
|
404
|
+
if (bracketed.length >= 4 && rest.startsWith(bracketed)) {
|
|
405
|
+
throw new Error(
|
|
406
|
+
`content check failed: segment ${idx} repeats its 【${lead[1]}】 title in the body text`,
|
|
407
|
+
);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
if (CONTENT_SCAFFOLD_LABEL_RE.test(text)) {
|
|
412
|
+
throw new Error(`content check failed: segment ${idx} opens with a research scaffold label`);
|
|
413
|
+
}
|
|
414
|
+
if (CONTENT_TAG_TAIL_RE.test(text)) {
|
|
415
|
+
throw new Error(`content check failed: segment ${idx} carries a 标签 metadata tail`);
|
|
416
|
+
}
|
|
417
|
+
if (CONTENT_URL_MANGLE_RE.test(text)) {
|
|
418
|
+
throw new Error(`content check failed: segment ${idx} has a colon-mangled URL`);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
|
|
370
423
|
/**
|
|
371
424
|
* Validate that a VoiceScript satisfies all Voicebox and plugin constraints.
|
|
372
425
|
*/
|
|
@@ -490,6 +543,12 @@ export function validateVoiceScript(script: VoiceScript): void {
|
|
|
490
543
|
}
|
|
491
544
|
}
|
|
492
545
|
|
|
546
|
+
if (segment.speed !== undefined) {
|
|
547
|
+
if (typeof segment.speed !== 'number' || segment.speed < 0.5 || segment.speed > 2.0) {
|
|
548
|
+
throw new Error('speed must be between 0.5 and 2.0');
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
|
|
493
552
|
if (segment.seed !== undefined) {
|
|
494
553
|
if (typeof segment.seed !== 'number' || !Number.isInteger(segment.seed) || segment.seed < 0) {
|
|
495
554
|
throw new Error('seed must be a non-negative integer');
|
|
@@ -499,4 +558,6 @@ export function validateVoiceScript(script: VoiceScript): void {
|
|
|
499
558
|
assertEngine(segment.engine, `Segment at index ${idx}`);
|
|
500
559
|
assertLanguage(segment.language, `Segment at index ${idx}`);
|
|
501
560
|
}
|
|
561
|
+
|
|
562
|
+
assertSegmentContent(script);
|
|
502
563
|
}
|