recappi 0.1.48 → 0.1.50
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 +88 -44
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -592,18 +592,21 @@ 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 waveRowsFor(terminalRows) {
|
|
599
|
+
return terminalRows >= 30 ? 5 : 3;
|
|
600
|
+
}
|
|
601
|
+
function litCount(level, rows) {
|
|
602
|
+
const amp = Math.max(0, Math.min(1, level));
|
|
603
|
+
if (amp <= 0.028) return 0;
|
|
604
|
+
return Math.max(1, Math.min(rows, Math.ceil(Math.pow(amp, 0.58) * rows)));
|
|
605
|
+
}
|
|
606
|
+
function litCounts(samples, width, rows) {
|
|
607
|
+
if (width <= 0) return [];
|
|
600
608
|
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("");
|
|
609
|
+
return [...Array(Math.max(0, width - tail.length)).fill(0), ...tail].map((v) => litCount(v, rows));
|
|
607
610
|
}
|
|
608
611
|
function levelDb(level) {
|
|
609
612
|
if (level <= 0.03) return "silent";
|
|
@@ -614,13 +617,23 @@ function MeterRow({
|
|
|
614
617
|
samples,
|
|
615
618
|
level,
|
|
616
619
|
paused,
|
|
617
|
-
width
|
|
620
|
+
width,
|
|
621
|
+
rows
|
|
618
622
|
}) {
|
|
619
623
|
const silent = level <= 0.03;
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
/* @__PURE__ */
|
|
624
|
+
const cols = litCounts(samples, width, rows);
|
|
625
|
+
const litColor = paused ? "gray" : "cyan";
|
|
626
|
+
return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", children: [
|
|
627
|
+
/* @__PURE__ */ jsxs2(Box2, { width: width + 9, children: [
|
|
628
|
+
/* @__PURE__ */ jsx3(Box2, { width: 9, children: /* @__PURE__ */ jsx3(Text2, { dimColor: true, children: label }) }),
|
|
629
|
+
/* @__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) }) })
|
|
630
|
+
] }),
|
|
631
|
+
Array.from({ length: rows }, (_, r) => {
|
|
632
|
+
const fromBottom = rows - r;
|
|
633
|
+
return /* @__PURE__ */ jsx3(Text2, { children: cols.map(
|
|
634
|
+
(c, i) => c >= fromBottom ? /* @__PURE__ */ jsx3(Text2, { color: litColor, children: c === fromBottom ? "\u2022" : "\u25CF" }, i) : /* @__PURE__ */ jsx3(Text2, { dimColor: true, children: "\xB7" }, i)
|
|
635
|
+
) }, r);
|
|
636
|
+
})
|
|
624
637
|
] });
|
|
625
638
|
}
|
|
626
639
|
function ProgressBar({ fraction, width = 12 }) {
|
|
@@ -654,10 +667,14 @@ function RecordingHeroScreen({
|
|
|
654
667
|
const [tick, setTick] = useState3(() => now());
|
|
655
668
|
const [waveSys, setWaveSys] = useState3([]);
|
|
656
669
|
const [waveMic, setWaveMic] = useState3([]);
|
|
670
|
+
const lastAppendRef = useRef(0);
|
|
657
671
|
useEffect2(() => {
|
|
658
672
|
if (telemetry.level == null) return;
|
|
659
|
-
|
|
660
|
-
|
|
673
|
+
const t = now();
|
|
674
|
+
if (t - lastAppendRef.current < WAVE_THROTTLE_MS) return;
|
|
675
|
+
lastAppendRef.current = t;
|
|
676
|
+
setWaveSys((w) => [...w.slice(-512), telemetry.level.system ?? 0]);
|
|
677
|
+
setWaveMic((w) => [...w.slice(-512), telemetry.level.mic ?? 0]);
|
|
661
678
|
}, [telemetry.level]);
|
|
662
679
|
useEffect2(() => {
|
|
663
680
|
const id = setInterval(() => setTick(now()), 1e3);
|
|
@@ -704,15 +721,19 @@ function RecordingHeroScreen({
|
|
|
704
721
|
const paused = telemetry.status === "paused";
|
|
705
722
|
const starting = telemetry.status === "starting" || telemetry.status === "stopping";
|
|
706
723
|
const badge = paused ? "\u23F8 PAUSED" : starting ? "\u2026" : "\u23FA REC";
|
|
707
|
-
const meterW = Math.max(10, Math.min(
|
|
724
|
+
const meterW = Math.max(10, Math.min(72, innerWidth - 20));
|
|
708
725
|
const sizeStr = telemetry.sizeBytes ? formatBytes2(telemetry.sizeBytes) : "";
|
|
709
726
|
const context = [telemetry.sourceLabel, telemetry.micEnabled ? "Microphone" : null, sizeStr || null].filter(Boolean).join(" \xB7 ");
|
|
710
|
-
|
|
727
|
+
const waveRows = waveRowsFor(size.rows);
|
|
728
|
+
const meterBlockRows = (telemetry.micEnabled ? 2 : 1) * (waveRows + 1) + (telemetry.micEnabled ? 1 : 0);
|
|
729
|
+
const fixedRows = 8 + meterBlockRows;
|
|
730
|
+
const captionRows = Math.max(2, size.rows - fixedRows);
|
|
731
|
+
return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", paddingX: 1, children: [
|
|
711
732
|
/* @__PURE__ */ jsxs2(Text2, { children: [
|
|
712
733
|
/* @__PURE__ */ jsx3(Text2, { bold: true, color: "green", children: "recappi" }),
|
|
713
734
|
/* @__PURE__ */ jsx3(Text2, { dimColor: true, children: " \xB7 Recording" })
|
|
714
735
|
] }),
|
|
715
|
-
/* @__PURE__ */ jsxs2(Box2, { marginTop: 1, paddingX: 1,
|
|
736
|
+
/* @__PURE__ */ jsxs2(Box2, { marginTop: 1, paddingX: 1, flexDirection: "column", children: [
|
|
716
737
|
/* @__PURE__ */ jsxs2(Text2, { children: [
|
|
717
738
|
/* @__PURE__ */ jsx3(Text2, { bold: true, color: paused ? "yellow" : "red", children: badge }),
|
|
718
739
|
/* @__PURE__ */ jsx3(Text2, { children: " " }),
|
|
@@ -723,40 +744,61 @@ function RecordingHeroScreen({
|
|
|
723
744
|
// reads as silence (the elapsed timer above proves it's live).
|
|
724
745
|
/* @__PURE__ */ jsx3(Text2, { dimColor: true, children: paused ? "Paused" : `Capturing audio${".".repeat(Math.floor(tick / 1e3) % 3 + 1)}` })
|
|
725
746
|
) : /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
726
|
-
/* @__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
|
|
747
|
+
/* @__PURE__ */ jsx3(MeterRow, { label: "System", samples: waveSys, level: telemetry.level.system ?? 0, paused, width: meterW, rows: waveRows }),
|
|
748
|
+
telemetry.micEnabled ? /* @__PURE__ */ jsx3(Box2, { marginTop: 1, children: /* @__PURE__ */ jsx3(MeterRow, { label: "Mic", samples: waveMic, level: telemetry.level.mic ?? 0, paused, width: meterW, rows: waveRows }) }) : null
|
|
728
749
|
] }) }),
|
|
729
750
|
/* @__PURE__ */ jsx3(Box2, { marginTop: 1, children: /* @__PURE__ */ jsx3(Text2, { dimColor: true, children: context }) }),
|
|
730
751
|
captions ? /* @__PURE__ */ jsxs2(Box2, { marginTop: 1, flexDirection: "column", children: [
|
|
731
752
|
/* @__PURE__ */ jsx3(Text2, { bold: true, dimColor: true, children: "LIVE CAPTIONS" }),
|
|
732
|
-
/* @__PURE__ */ jsx3(HeroCaptions, { state: captions })
|
|
753
|
+
/* @__PURE__ */ jsx3(HeroCaptions, { state: captions, maxRows: captionRows, width: innerWidth })
|
|
733
754
|
] }) : null
|
|
734
755
|
] }),
|
|
735
|
-
/* @__PURE__ */ jsx3(Box2, { children: /* @__PURE__ */ jsxs2(Text2, { dimColor: true, children: [
|
|
756
|
+
/* @__PURE__ */ jsx3(Box2, { marginTop: 1, children: /* @__PURE__ */ jsxs2(Text2, { dimColor: true, children: [
|
|
736
757
|
"q stop & save",
|
|
737
758
|
canPause ? ` \xB7 p ${paused ? "resume" : "pause"}` : ""
|
|
738
759
|
] }) })
|
|
739
760
|
] });
|
|
740
761
|
}
|
|
741
|
-
function
|
|
742
|
-
|
|
743
|
-
|
|
762
|
+
function wrappedRows(text, width) {
|
|
763
|
+
return Math.max(1, Math.ceil(displayWidth(text) / Math.max(1, width)));
|
|
764
|
+
}
|
|
765
|
+
function HeroCaptions({
|
|
766
|
+
state,
|
|
767
|
+
maxRows,
|
|
768
|
+
width
|
|
769
|
+
}) {
|
|
744
770
|
const hasPartial = Boolean(state.partial && state.partial.length > 0);
|
|
745
771
|
const captionError = state.status === "error" ? `Captions unavailable: ${state.error ?? "Live captions unavailable."}` : null;
|
|
746
|
-
if (
|
|
747
|
-
return /* @__PURE__ */ jsx3(Text2, { color: captionError ? "yellow" : void 0, dimColor: !captionError,
|
|
772
|
+
if (state.lines.length === 0 && !hasPartial) {
|
|
773
|
+
return /* @__PURE__ */ jsx3(Text2, { color: captionError ? "yellow" : void 0, dimColor: !captionError, children: captionError ?? (state.status === "live" ? "Listening for speech\u2026" : liveCaptionStatusLabel(state.status)) });
|
|
774
|
+
}
|
|
775
|
+
const lines = [];
|
|
776
|
+
for (const line of state.lines) {
|
|
777
|
+
lines.push({
|
|
778
|
+
key: `${line.id}-s`,
|
|
779
|
+
text: `${line.speaker ? `${line.speaker}: ` : ""}${trimLead(line.text)}`,
|
|
780
|
+
dim: false
|
|
781
|
+
});
|
|
782
|
+
if (line.translation) {
|
|
783
|
+
lines.push({ key: `${line.id}-t`, text: ` \u21B3 ${trimLead(line.translation)}`, dim: true });
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
if (hasPartial) lines.push({ key: "partial", text: trimLead(state.partial), dim: true });
|
|
787
|
+
if (state.translationPartial) {
|
|
788
|
+
lines.push({ key: "tpartial", text: ` \u21B3 ${trimLead(state.translationPartial)}`, dim: true });
|
|
789
|
+
}
|
|
790
|
+
const budget = Math.max(1, maxRows);
|
|
791
|
+
const chosen = [];
|
|
792
|
+
let used = 0;
|
|
793
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
794
|
+
const h = wrappedRows(lines[i].text, width);
|
|
795
|
+
if (used + h > budget && chosen.length > 0) break;
|
|
796
|
+
chosen.unshift(lines[i]);
|
|
797
|
+
used += h;
|
|
748
798
|
}
|
|
749
799
|
return /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
line.speaker ? `${line.speaker}: ` : "",
|
|
753
|
-
line.text
|
|
754
|
-
] }),
|
|
755
|
-
line.translation ? /* @__PURE__ */ jsx3(Text2, { dimColor: true, wrap: "truncate-end", children: `\u21B3 ${line.translation}` }) : null
|
|
756
|
-
] }, line.id)),
|
|
757
|
-
hasPartial ? /* @__PURE__ */ jsx3(Text2, { dimColor: true, wrap: "truncate-end", children: state.partial }) : null,
|
|
758
|
-
state.translationPartial ? /* @__PURE__ */ jsx3(Text2, { dimColor: true, wrap: "truncate-end", children: `\u21B3 ${state.translationPartial}` }) : null,
|
|
759
|
-
captionError ? /* @__PURE__ */ jsx3(Text2, { color: "yellow", wrap: "truncate-end", children: captionError }) : null
|
|
800
|
+
chosen.map((l) => /* @__PURE__ */ jsx3(Text2, { dimColor: l.dim, wrap: "wrap", children: l.text }, l.key)),
|
|
801
|
+
captionError ? /* @__PURE__ */ jsx3(Text2, { color: "yellow", wrap: "wrap", children: captionError }) : null
|
|
760
802
|
] });
|
|
761
803
|
}
|
|
762
804
|
function stoppedHandoffCopy(artifact, canTranscribe) {
|
|
@@ -777,14 +819,15 @@ function stoppedHandoffCopy(artifact, canTranscribe) {
|
|
|
777
819
|
}
|
|
778
820
|
return { text: "Transcribe now? \u23CE yes \xB7 n not now", tone: "normal" };
|
|
779
821
|
}
|
|
780
|
-
var
|
|
822
|
+
var WAVE_THROTTLE_MS, trimLead;
|
|
781
823
|
var init_RecordingHeroScreen = __esm({
|
|
782
824
|
"src/tui/RecordingHeroScreen.tsx"() {
|
|
783
825
|
"use strict";
|
|
784
826
|
init_format();
|
|
785
827
|
init_liveCaptions();
|
|
786
828
|
init_terminal();
|
|
787
|
-
|
|
829
|
+
WAVE_THROTTLE_MS = 220;
|
|
830
|
+
trimLead = (s) => s.replace(/^\s+/, "");
|
|
788
831
|
}
|
|
789
832
|
});
|
|
790
833
|
|
|
@@ -1686,7 +1729,7 @@ var init_PermissionPreflightView = __esm({
|
|
|
1686
1729
|
});
|
|
1687
1730
|
|
|
1688
1731
|
// src/tui/RecordSetupView.tsx
|
|
1689
|
-
import { useEffect as useEffect3, useRef, useState as useState6 } from "react";
|
|
1732
|
+
import { useEffect as useEffect3, useRef as useRef2, useState as useState6 } from "react";
|
|
1690
1733
|
import { Box as Box15, Text as Text15, useInput as useInput5 } from "ink";
|
|
1691
1734
|
import { jsx as jsx17, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1692
1735
|
function levelDb2(level) {
|
|
@@ -1719,7 +1762,7 @@ function RecordSetupView({
|
|
|
1719
1762
|
() => Math.max(0, model.microphones?.findIndex((device) => device.isDefault) ?? 0)
|
|
1720
1763
|
);
|
|
1721
1764
|
const [sceneIdx, setSceneIdx] = useState6(0);
|
|
1722
|
-
const userPickedMic =
|
|
1765
|
+
const userPickedMic = useRef2(false);
|
|
1723
1766
|
const sources = model.sources;
|
|
1724
1767
|
const microphones = model.microphones ?? [];
|
|
1725
1768
|
const selected = sources[Math.min(srcIdx, Math.max(0, sources.length - 1))];
|
|
@@ -20986,7 +21029,7 @@ async function startRecordSessionOnce(opts) {
|
|
|
20986
21029
|
...opts.targetBundleId ? { targetBundleId: opts.targetBundleId } : {},
|
|
20987
21030
|
...opts.microphoneDeviceId ? { microphoneDeviceId: opts.microphoneDeviceId } : {},
|
|
20988
21031
|
liveCaptions: captionStreamEnabled,
|
|
20989
|
-
...opts.translationLanguage ? { translationLanguage: opts.translationLanguage } : {},
|
|
21032
|
+
...captionStreamEnabled && opts.translationLanguage ? { translationLanguage: opts.translationLanguage } : {},
|
|
20990
21033
|
...opts.transcriptionLanguage ? { transcriptionLanguage: opts.transcriptionLanguage } : {},
|
|
20991
21034
|
...opts.title ? { title: opts.title } : {}
|
|
20992
21035
|
};
|
|
@@ -21588,6 +21631,7 @@ async function runCli(deps = {}) {
|
|
|
21588
21631
|
hint: "Run recappi auth login, or import the Recappi Mini session with recappi auth import-macos."
|
|
21589
21632
|
});
|
|
21590
21633
|
}
|
|
21634
|
+
const translationLanguage = parsed.translationLanguage ?? (mode === "human" && isTTY ? "zh" : void 0);
|
|
21591
21635
|
const data = await recordViaSidecar({
|
|
21592
21636
|
account: {
|
|
21593
21637
|
backendOrigin: auth.origin,
|
|
@@ -21602,7 +21646,7 @@ async function runCli(deps = {}) {
|
|
|
21602
21646
|
live: parsed.live === true || mode === "human" && isTTY,
|
|
21603
21647
|
includeSystemAudio: parsed.includeSystemAudio,
|
|
21604
21648
|
includeMicrophone: parsed.includeMicrophone,
|
|
21605
|
-
translationLanguage
|
|
21649
|
+
translationLanguage,
|
|
21606
21650
|
transcriptionLanguage: parsed.transcriptionLanguage,
|
|
21607
21651
|
sidecarCommand: parsed.sidecarCommand,
|
|
21608
21652
|
renderLive: parsed.live === true && mode === "human" && isTTY,
|