recappi 0.1.48 → 0.1.49
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/dist/index.js +73 -39
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -592,18 +592,18 @@ var init_LiveCaptionsScreen = __esm({
|
|
|
592
592
|
});
|
|
593
593
|
|
|
594
594
|
// src/tui/RecordingHeroScreen.tsx
|
|
595
|
-
import { useEffect as useEffect2, useState as useState3 } from "react";
|
|
595
|
+
import { useEffect as useEffect2, useRef, useState as useState3 } from "react";
|
|
596
596
|
import { Box as Box2, Text as Text2 } from "ink";
|
|
597
597
|
import { Fragment, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
598
|
-
function
|
|
599
|
-
|
|
598
|
+
function litCount(level) {
|
|
599
|
+
const amp = Math.max(0, Math.min(1, level));
|
|
600
|
+
if (amp <= 0.028) return 0;
|
|
601
|
+
return Math.max(1, Math.min(WAVE_ROWS, Math.ceil(Math.pow(amp, 0.58) * WAVE_ROWS)));
|
|
602
|
+
}
|
|
603
|
+
function litCounts(samples, width) {
|
|
604
|
+
if (width <= 0) return [];
|
|
600
605
|
const tail = samples.slice(-width);
|
|
601
|
-
|
|
602
|
-
const cells = tail.map((v) => {
|
|
603
|
-
const i = Math.max(0, Math.min(BLOCKS.length - 1, Math.round(Math.max(0, Math.min(1, v)) * (BLOCKS.length - 1))));
|
|
604
|
-
return BLOCKS[i];
|
|
605
|
-
});
|
|
606
|
-
return "\u2581".repeat(Math.max(0, pad)) + cells.join("");
|
|
606
|
+
return [...Array(Math.max(0, width - tail.length)).fill(0), ...tail].map(litCount);
|
|
607
607
|
}
|
|
608
608
|
function levelDb(level) {
|
|
609
609
|
if (level <= 0.03) return "silent";
|
|
@@ -617,10 +617,19 @@ function MeterRow({
|
|
|
617
617
|
width
|
|
618
618
|
}) {
|
|
619
619
|
const silent = level <= 0.03;
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
/* @__PURE__ */
|
|
620
|
+
const cols = litCounts(samples, width);
|
|
621
|
+
const litColor = paused ? "gray" : "cyan";
|
|
622
|
+
return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", children: [
|
|
623
|
+
/* @__PURE__ */ jsxs2(Box2, { width: width + 9, children: [
|
|
624
|
+
/* @__PURE__ */ jsx3(Box2, { width: 9, children: /* @__PURE__ */ jsx3(Text2, { dimColor: true, children: label }) }),
|
|
625
|
+
/* @__PURE__ */ jsx3(Box2, { flexGrow: 1, justifyContent: "flex-end", children: !paused && silent ? /* @__PURE__ */ jsx3(Text2, { color: "yellow", children: "silent" }) : /* @__PURE__ */ jsx3(Text2, { dimColor: true, children: paused ? "paused" : levelDb(level) }) })
|
|
626
|
+
] }),
|
|
627
|
+
Array.from({ length: WAVE_ROWS }, (_, r) => {
|
|
628
|
+
const fromBottom = WAVE_ROWS - r;
|
|
629
|
+
return /* @__PURE__ */ jsx3(Text2, { children: cols.map(
|
|
630
|
+
(c, i) => c >= fromBottom ? /* @__PURE__ */ jsx3(Text2, { color: litColor, children: c === fromBottom ? "\u2022" : "\u25CF" }, i) : /* @__PURE__ */ jsx3(Text2, { dimColor: true, children: "\xB7" }, i)
|
|
631
|
+
) }, r);
|
|
632
|
+
})
|
|
624
633
|
] });
|
|
625
634
|
}
|
|
626
635
|
function ProgressBar({ fraction, width = 12 }) {
|
|
@@ -654,10 +663,14 @@ function RecordingHeroScreen({
|
|
|
654
663
|
const [tick, setTick] = useState3(() => now());
|
|
655
664
|
const [waveSys, setWaveSys] = useState3([]);
|
|
656
665
|
const [waveMic, setWaveMic] = useState3([]);
|
|
666
|
+
const lastAppendRef = useRef(0);
|
|
657
667
|
useEffect2(() => {
|
|
658
668
|
if (telemetry.level == null) return;
|
|
659
|
-
|
|
660
|
-
|
|
669
|
+
const t = now();
|
|
670
|
+
if (t - lastAppendRef.current < WAVE_THROTTLE_MS) return;
|
|
671
|
+
lastAppendRef.current = t;
|
|
672
|
+
setWaveSys((w) => [...w.slice(-512), telemetry.level.system ?? 0]);
|
|
673
|
+
setWaveMic((w) => [...w.slice(-512), telemetry.level.mic ?? 0]);
|
|
661
674
|
}, [telemetry.level]);
|
|
662
675
|
useEffect2(() => {
|
|
663
676
|
const id = setInterval(() => setTick(now()), 1e3);
|
|
@@ -704,15 +717,18 @@ function RecordingHeroScreen({
|
|
|
704
717
|
const paused = telemetry.status === "paused";
|
|
705
718
|
const starting = telemetry.status === "starting" || telemetry.status === "stopping";
|
|
706
719
|
const badge = paused ? "\u23F8 PAUSED" : starting ? "\u2026" : "\u23FA REC";
|
|
707
|
-
const meterW = Math.max(10, Math.min(
|
|
720
|
+
const meterW = Math.max(10, Math.min(72, innerWidth - 20));
|
|
708
721
|
const sizeStr = telemetry.sizeBytes ? formatBytes2(telemetry.sizeBytes) : "";
|
|
709
722
|
const context = [telemetry.sourceLabel, telemetry.micEnabled ? "Microphone" : null, sizeStr || null].filter(Boolean).join(" \xB7 ");
|
|
710
|
-
|
|
723
|
+
const meterBlockRows = (telemetry.micEnabled ? 2 : 1) * (WAVE_ROWS + 1) + (telemetry.micEnabled ? 1 : 0);
|
|
724
|
+
const fixedRows = 8 + meterBlockRows;
|
|
725
|
+
const captionRows = Math.max(2, size.rows - fixedRows);
|
|
726
|
+
return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", paddingX: 1, children: [
|
|
711
727
|
/* @__PURE__ */ jsxs2(Text2, { children: [
|
|
712
728
|
/* @__PURE__ */ jsx3(Text2, { bold: true, color: "green", children: "recappi" }),
|
|
713
729
|
/* @__PURE__ */ jsx3(Text2, { dimColor: true, children: " \xB7 Recording" })
|
|
714
730
|
] }),
|
|
715
|
-
/* @__PURE__ */ jsxs2(Box2, { marginTop: 1, paddingX: 1,
|
|
731
|
+
/* @__PURE__ */ jsxs2(Box2, { marginTop: 1, paddingX: 1, flexDirection: "column", children: [
|
|
716
732
|
/* @__PURE__ */ jsxs2(Text2, { children: [
|
|
717
733
|
/* @__PURE__ */ jsx3(Text2, { bold: true, color: paused ? "yellow" : "red", children: badge }),
|
|
718
734
|
/* @__PURE__ */ jsx3(Text2, { children: " " }),
|
|
@@ -724,38 +740,53 @@ function RecordingHeroScreen({
|
|
|
724
740
|
/* @__PURE__ */ jsx3(Text2, { dimColor: true, children: paused ? "Paused" : `Capturing audio${".".repeat(Math.floor(tick / 1e3) % 3 + 1)}` })
|
|
725
741
|
) : /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
726
742
|
/* @__PURE__ */ jsx3(MeterRow, { label: "System", samples: waveSys, level: telemetry.level.system ?? 0, paused, width: meterW }),
|
|
727
|
-
telemetry.micEnabled ? /* @__PURE__ */ jsx3(MeterRow, { label: "Mic", samples: waveMic, level: telemetry.level.mic ?? 0, paused, width: meterW }) : null
|
|
743
|
+
telemetry.micEnabled ? /* @__PURE__ */ jsx3(Box2, { marginTop: 1, children: /* @__PURE__ */ jsx3(MeterRow, { label: "Mic", samples: waveMic, level: telemetry.level.mic ?? 0, paused, width: meterW }) }) : null
|
|
728
744
|
] }) }),
|
|
729
745
|
/* @__PURE__ */ jsx3(Box2, { marginTop: 1, children: /* @__PURE__ */ jsx3(Text2, { dimColor: true, children: context }) }),
|
|
730
746
|
captions ? /* @__PURE__ */ jsxs2(Box2, { marginTop: 1, flexDirection: "column", children: [
|
|
731
747
|
/* @__PURE__ */ jsx3(Text2, { bold: true, dimColor: true, children: "LIVE CAPTIONS" }),
|
|
732
|
-
/* @__PURE__ */ jsx3(HeroCaptions, { state: captions })
|
|
748
|
+
/* @__PURE__ */ jsx3(HeroCaptions, { state: captions, maxRows: captionRows })
|
|
733
749
|
] }) : null
|
|
734
750
|
] }),
|
|
735
|
-
/* @__PURE__ */ jsx3(Box2, { children: /* @__PURE__ */ jsxs2(Text2, { dimColor: true, children: [
|
|
751
|
+
/* @__PURE__ */ jsx3(Box2, { marginTop: 1, children: /* @__PURE__ */ jsxs2(Text2, { dimColor: true, children: [
|
|
736
752
|
"q stop & save",
|
|
737
753
|
canPause ? ` \xB7 p ${paused ? "resume" : "pause"}` : ""
|
|
738
754
|
] }) })
|
|
739
755
|
] });
|
|
740
756
|
}
|
|
741
|
-
function HeroCaptions({ state }) {
|
|
742
|
-
const MAX_LINES = 3;
|
|
743
|
-
const recent = state.lines.slice(-MAX_LINES);
|
|
757
|
+
function HeroCaptions({ state, maxRows }) {
|
|
744
758
|
const hasPartial = Boolean(state.partial && state.partial.length > 0);
|
|
745
759
|
const captionError = state.status === "error" ? `Captions unavailable: ${state.error ?? "Live captions unavailable."}` : null;
|
|
746
|
-
if (
|
|
760
|
+
if (state.lines.length === 0 && !hasPartial) {
|
|
747
761
|
return /* @__PURE__ */ jsx3(Text2, { color: captionError ? "yellow" : void 0, dimColor: !captionError, wrap: "truncate-end", children: captionError ?? (state.status === "live" ? "Listening for speech\u2026" : liveCaptionStatusLabel(state.status)) });
|
|
748
762
|
}
|
|
749
|
-
|
|
750
|
-
|
|
763
|
+
const rows = [];
|
|
764
|
+
for (const line of state.lines) {
|
|
765
|
+
rows.push(
|
|
751
766
|
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate-end", children: [
|
|
752
767
|
line.speaker ? `${line.speaker}: ` : "",
|
|
753
|
-
line.text
|
|
754
|
-
] })
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
768
|
+
trimLead(line.text)
|
|
769
|
+
] }, `${line.id}-s`)
|
|
770
|
+
);
|
|
771
|
+
if (line.translation) {
|
|
772
|
+
rows.push(
|
|
773
|
+
/* @__PURE__ */ jsx3(Text2, { dimColor: true, wrap: "truncate-end", children: ` \u21B3 ${trimLead(line.translation)}` }, `${line.id}-t`)
|
|
774
|
+
);
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
if (hasPartial) {
|
|
778
|
+
rows.push(
|
|
779
|
+
/* @__PURE__ */ jsx3(Text2, { dimColor: true, wrap: "truncate-end", children: trimLead(state.partial) }, "partial")
|
|
780
|
+
);
|
|
781
|
+
}
|
|
782
|
+
if (state.translationPartial) {
|
|
783
|
+
rows.push(
|
|
784
|
+
/* @__PURE__ */ jsx3(Text2, { dimColor: true, wrap: "truncate-end", children: ` \u21B3 ${trimLead(state.translationPartial)}` }, "tpartial")
|
|
785
|
+
);
|
|
786
|
+
}
|
|
787
|
+
const visible = rows.slice(-Math.max(1, maxRows));
|
|
788
|
+
return /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
789
|
+
visible,
|
|
759
790
|
captionError ? /* @__PURE__ */ jsx3(Text2, { color: "yellow", wrap: "truncate-end", children: captionError }) : null
|
|
760
791
|
] });
|
|
761
792
|
}
|
|
@@ -777,14 +808,16 @@ function stoppedHandoffCopy(artifact, canTranscribe) {
|
|
|
777
808
|
}
|
|
778
809
|
return { text: "Transcribe now? \u23CE yes \xB7 n not now", tone: "normal" };
|
|
779
810
|
}
|
|
780
|
-
var
|
|
811
|
+
var WAVE_ROWS, WAVE_THROTTLE_MS, trimLead;
|
|
781
812
|
var init_RecordingHeroScreen = __esm({
|
|
782
813
|
"src/tui/RecordingHeroScreen.tsx"() {
|
|
783
814
|
"use strict";
|
|
784
815
|
init_format();
|
|
785
816
|
init_liveCaptions();
|
|
786
817
|
init_terminal();
|
|
787
|
-
|
|
818
|
+
WAVE_ROWS = 5;
|
|
819
|
+
WAVE_THROTTLE_MS = 220;
|
|
820
|
+
trimLead = (s) => s.replace(/^\s+/, "");
|
|
788
821
|
}
|
|
789
822
|
});
|
|
790
823
|
|
|
@@ -1686,7 +1719,7 @@ var init_PermissionPreflightView = __esm({
|
|
|
1686
1719
|
});
|
|
1687
1720
|
|
|
1688
1721
|
// src/tui/RecordSetupView.tsx
|
|
1689
|
-
import { useEffect as useEffect3, useRef, useState as useState6 } from "react";
|
|
1722
|
+
import { useEffect as useEffect3, useRef as useRef2, useState as useState6 } from "react";
|
|
1690
1723
|
import { Box as Box15, Text as Text15, useInput as useInput5 } from "ink";
|
|
1691
1724
|
import { jsx as jsx17, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1692
1725
|
function levelDb2(level) {
|
|
@@ -1719,7 +1752,7 @@ function RecordSetupView({
|
|
|
1719
1752
|
() => Math.max(0, model.microphones?.findIndex((device) => device.isDefault) ?? 0)
|
|
1720
1753
|
);
|
|
1721
1754
|
const [sceneIdx, setSceneIdx] = useState6(0);
|
|
1722
|
-
const userPickedMic =
|
|
1755
|
+
const userPickedMic = useRef2(false);
|
|
1723
1756
|
const sources = model.sources;
|
|
1724
1757
|
const microphones = model.microphones ?? [];
|
|
1725
1758
|
const selected = sources[Math.min(srcIdx, Math.max(0, sources.length - 1))];
|
|
@@ -20986,7 +21019,7 @@ async function startRecordSessionOnce(opts) {
|
|
|
20986
21019
|
...opts.targetBundleId ? { targetBundleId: opts.targetBundleId } : {},
|
|
20987
21020
|
...opts.microphoneDeviceId ? { microphoneDeviceId: opts.microphoneDeviceId } : {},
|
|
20988
21021
|
liveCaptions: captionStreamEnabled,
|
|
20989
|
-
...opts.translationLanguage ? { translationLanguage: opts.translationLanguage } : {},
|
|
21022
|
+
...captionStreamEnabled && opts.translationLanguage ? { translationLanguage: opts.translationLanguage } : {},
|
|
20990
21023
|
...opts.transcriptionLanguage ? { transcriptionLanguage: opts.transcriptionLanguage } : {},
|
|
20991
21024
|
...opts.title ? { title: opts.title } : {}
|
|
20992
21025
|
};
|
|
@@ -21588,6 +21621,7 @@ async function runCli(deps = {}) {
|
|
|
21588
21621
|
hint: "Run recappi auth login, or import the Recappi Mini session with recappi auth import-macos."
|
|
21589
21622
|
});
|
|
21590
21623
|
}
|
|
21624
|
+
const translationLanguage = parsed.translationLanguage ?? (mode === "human" && isTTY ? "zh" : void 0);
|
|
21591
21625
|
const data = await recordViaSidecar({
|
|
21592
21626
|
account: {
|
|
21593
21627
|
backendOrigin: auth.origin,
|
|
@@ -21602,7 +21636,7 @@ async function runCli(deps = {}) {
|
|
|
21602
21636
|
live: parsed.live === true || mode === "human" && isTTY,
|
|
21603
21637
|
includeSystemAudio: parsed.includeSystemAudio,
|
|
21604
21638
|
includeMicrophone: parsed.includeMicrophone,
|
|
21605
|
-
translationLanguage
|
|
21639
|
+
translationLanguage,
|
|
21606
21640
|
transcriptionLanguage: parsed.transcriptionLanguage,
|
|
21607
21641
|
sidecarCommand: parsed.sidecarCommand,
|
|
21608
21642
|
renderLive: parsed.live === true && mode === "human" && isTTY,
|