@lamplitisles/codex-for-love 0.3.0 → 0.4.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.
@@ -22663,6 +22663,21 @@ function parse(toml, { maxDepth = 1e3, integersAsBigInt } = {}) {
22663
22663
  /** The app-server protocol contract tested by this application. */
22664
22664
  const SUPPORTED_CODEX_VERSION = "0.154.0";
22665
22665
  const DEFAULT_CODEX_MODEL = "gpt-5.6-luna";
22666
+ const ttsSchema = object({
22667
+ provider: _enum([
22668
+ "minimax",
22669
+ "alibaba",
22670
+ "bytedance"
22671
+ ]),
22672
+ voice: string().min(1),
22673
+ speed: number().finite().min(.5).max(2).optional()
22674
+ }).strict().superRefine((tts, context) => {
22675
+ if (tts.provider === "alibaba" && tts.speed !== void 0) context.addIssue({
22676
+ code: "custom",
22677
+ path: ["speed"],
22678
+ message: "Alibaba TTS speed is unavailable on the configured non-realtime API"
22679
+ });
22680
+ });
22666
22681
  const schema = object({
22667
22682
  name: string().min(1),
22668
22683
  persona: string().min(1),
@@ -22688,15 +22703,13 @@ const schema = object({
22688
22703
  }),
22689
22704
  speech: object({
22690
22705
  endpoint: url().default("https://dashscope.aliyuncs.com/api/v1/services/aigc/multimodal-generation/generation"),
22691
- tts: object({
22692
- provider: _enum([
22693
- "minimax",
22694
- "alibaba",
22695
- "bytedance"
22696
- ]),
22697
- voice: string().min(1)
22698
- }).strict().optional()
22699
- }).strict().optional()
22706
+ tts: ttsSchema.optional()
22707
+ }).strict().optional(),
22708
+ keet: object({
22709
+ endpoint: string().min(1).optional(),
22710
+ media_root: string().min(1).optional()
22711
+ }).strict().optional(),
22712
+ pet: object({ enabled: boolean().default(false) }).strict().default({ enabled: false })
22700
22713
  }).strict();
22701
22714
  async function loadConfig(path) {
22702
22715
  const config = schema.parse(parse(await readFile(path, "utf8")));
@@ -22715,13 +22728,32 @@ async function loadConfig(path) {
22715
22728
  ...config.codex,
22716
22729
  home: config.codex.home ? resolve(base, config.codex.home) : void 0,
22717
22730
  provenance: config.codex.provenance ? resolve(base, config.codex.provenance) : void 0
22718
- }
22731
+ },
22732
+ keet: config.keet ? {
22733
+ ...config.keet.endpoint ? { endpoint: keetEndpoint(config.keet.endpoint) } : {},
22734
+ ...config.keet.media_root ? { media_root: keetMediaRoot(config.keet.media_root) } : {}
22735
+ } : void 0
22719
22736
  };
22720
22737
  }
22738
+ function keetEndpoint(value) {
22739
+ let url;
22740
+ try {
22741
+ url = new URL(value);
22742
+ } catch {
22743
+ throw new Error("Keet endpoint must be a loopback http URL");
22744
+ }
22745
+ if (url.protocol !== "http:" || url.hostname !== "127.0.0.1" || !url.port || url.username || url.password || url.pathname !== "/" || url.search || url.hash) throw new Error("Keet endpoint must be a bare http://127.0.0.1:PORT URL");
22746
+ return url.origin;
22747
+ }
22748
+ function keetMediaRoot(value) {
22749
+ if (!value.startsWith("/")) throw new Error("Keet media_root must be an absolute path");
22750
+ return resolve(value);
22751
+ }
22721
22752
  /** Alibaba STT/TTS reuses speech; ByteDance TTS keeps its separate secret. */
22722
22753
  const credentialSchema = object({
22723
22754
  speech: string().min(1).optional(),
22724
- tts: string().min(1).optional()
22755
+ tts: string().min(1).optional(),
22756
+ keet: string().min(1).optional()
22725
22757
  }).strict();
22726
22758
  async function loadCredentials(state) {
22727
22759
  try {
@@ -22792,7 +22824,8 @@ async function provider(options) {
22792
22824
  speaker: options.voice,
22793
22825
  audio_params: {
22794
22826
  format: "mp3",
22795
- sample_rate: 24e3
22827
+ sample_rate: 24e3,
22828
+ ...options.speed === void 0 ? {} : { speech_rate: Math.round((options.speed - 1) * 100) }
22796
22829
  }
22797
22830
  }
22798
22831
  })
@@ -22838,6 +22871,8 @@ async function minimax(options) {
22838
22871
  options.text,
22839
22872
  "--voice",
22840
22873
  options.voice,
22874
+ "--speed",
22875
+ String(options.speed),
22841
22876
  "--format",
22842
22877
  "mp3",
22843
22878
  "--out",
@@ -22852,7 +22887,8 @@ async function minimax(options) {
22852
22887
  }
22853
22888
  async function synthesizeSpeech(options) {
22854
22889
  const text = options.text.replace(/[\s\u00a0]+/gu, " ").trim();
22855
- if (!text || Array.from(text).length > 240) throw new Error("Invalid speech passage");
22890
+ const speed = options.speed ?? 1;
22891
+ if (!text || Array.from(text).length > 240 || !Number.isFinite(speed) || speed < .5 || speed > 2) throw new Error("Invalid speech passage");
22856
22892
  const profile = options.provider === "minimax" ? "speech-2.8-hd" : options.model;
22857
22893
  if (options.provider !== "minimax" && (!options.endpoint || !options.model || !options.credential)) throw new Error("Speech synthesis is unavailable");
22858
22894
  const key = createHash("sha256").update(JSON.stringify([
@@ -22860,6 +22896,7 @@ async function synthesizeSpeech(options) {
22860
22896
  options.provider,
22861
22897
  profile,
22862
22898
  options.voice,
22899
+ speed,
22863
22900
  text
22864
22901
  ])).digest("hex");
22865
22902
  const path = join(options.audioDir, `${key}.mp3`);
@@ -22875,6 +22912,7 @@ async function synthesizeSpeech(options) {
22875
22912
  if (options.provider === "minimax") await minimax({
22876
22913
  text,
22877
22914
  voice: options.voice,
22915
+ speed,
22878
22916
  output: temp,
22879
22917
  signal,
22880
22918
  execFileImpl: options.execFileImpl ?? execFileAsync
@@ -22886,6 +22924,7 @@ async function synthesizeSpeech(options) {
22886
22924
  model: options.model,
22887
22925
  credential: options.credential,
22888
22926
  voice: options.voice,
22927
+ speed: options.speed,
22889
22928
  text,
22890
22929
  signal,
22891
22930
  fetchImpl: options.fetchImpl ?? fetch