open-agents-ai 0.163.0 → 0.165.0
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 +121 -24
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -11674,6 +11674,25 @@ async function loadTranscribeCli() {
|
|
|
11674
11674
|
}
|
|
11675
11675
|
return null;
|
|
11676
11676
|
}
|
|
11677
|
+
function isYouTubeUrl(url) {
|
|
11678
|
+
return /(?:youtube\.com\/(?:watch|shorts|live|embed|v\/)|youtu\.be\/)/i.test(url);
|
|
11679
|
+
}
|
|
11680
|
+
function ensureYtDlp() {
|
|
11681
|
+
try {
|
|
11682
|
+
execSync10("yt-dlp --version", { timeout: 5e3, stdio: "pipe" });
|
|
11683
|
+
return true;
|
|
11684
|
+
} catch {
|
|
11685
|
+
try {
|
|
11686
|
+
execSync10("pip3 install --user yt-dlp 2>/dev/null || pip install --user yt-dlp 2>/dev/null", {
|
|
11687
|
+
timeout: 6e4,
|
|
11688
|
+
stdio: "pipe"
|
|
11689
|
+
});
|
|
11690
|
+
return true;
|
|
11691
|
+
} catch {
|
|
11692
|
+
return false;
|
|
11693
|
+
}
|
|
11694
|
+
}
|
|
11695
|
+
}
|
|
11677
11696
|
function formatTime(seconds) {
|
|
11678
11697
|
const m = Math.floor(seconds / 60);
|
|
11679
11698
|
const s = Math.floor(seconds % 60);
|
|
@@ -11762,23 +11781,69 @@ var init_transcribe_tool = __esm({
|
|
|
11762
11781
|
model,
|
|
11763
11782
|
format: "json",
|
|
11764
11783
|
diarize,
|
|
11765
|
-
wordTimestamps:
|
|
11784
|
+
wordTimestamps: true
|
|
11785
|
+
// Always get timestamps for structured output
|
|
11766
11786
|
});
|
|
11767
11787
|
const transcriptDir = join19(this.workingDir, ".oa", "transcripts");
|
|
11768
11788
|
mkdirSync7(transcriptDir, { recursive: true });
|
|
11769
|
-
const
|
|
11770
|
-
|
|
11789
|
+
const fileBase = basename4(filePath).replace(/\.[^.]+$/, "");
|
|
11790
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19);
|
|
11791
|
+
const txtFile = join19(transcriptDir, `${fileBase}-${timestamp}.txt`);
|
|
11792
|
+
writeFileSync7(txtFile, result.text, "utf-8");
|
|
11793
|
+
const jsonFile = join19(transcriptDir, `${fileBase}-${timestamp}.json`);
|
|
11794
|
+
const structured = {
|
|
11795
|
+
source: filePath,
|
|
11796
|
+
model,
|
|
11797
|
+
language: result.language,
|
|
11798
|
+
duration: result.duration,
|
|
11799
|
+
wordCount: result.wordCount,
|
|
11800
|
+
speakers: result.speakers,
|
|
11801
|
+
transcribedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
11802
|
+
segments: result.segments.map((seg) => ({
|
|
11803
|
+
start: seg.start,
|
|
11804
|
+
end: seg.end,
|
|
11805
|
+
text: seg.text,
|
|
11806
|
+
speaker: seg.speaker || void 0
|
|
11807
|
+
})),
|
|
11808
|
+
fullText: result.text
|
|
11809
|
+
};
|
|
11810
|
+
writeFileSync7(jsonFile, JSON.stringify(structured, null, 2), "utf-8");
|
|
11811
|
+
try {
|
|
11812
|
+
const memDir = join19(this.workingDir, ".oa", "memory");
|
|
11813
|
+
mkdirSync7(memDir, { recursive: true });
|
|
11814
|
+
const memFile = join19(memDir, "transcripts.json");
|
|
11815
|
+
let memEntries = [];
|
|
11816
|
+
try {
|
|
11817
|
+
memEntries = JSON.parse(readFileSync13(memFile, "utf-8"));
|
|
11818
|
+
} catch {
|
|
11819
|
+
}
|
|
11820
|
+
memEntries.push({
|
|
11821
|
+
source: basename4(filePath),
|
|
11822
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
11823
|
+
duration: result.duration,
|
|
11824
|
+
wordCount: result.wordCount,
|
|
11825
|
+
language: result.language,
|
|
11826
|
+
summary: result.text.slice(0, 200),
|
|
11827
|
+
jsonPath: jsonFile,
|
|
11828
|
+
txtPath: txtFile
|
|
11829
|
+
});
|
|
11830
|
+
if (memEntries.length > 50)
|
|
11831
|
+
memEntries = memEntries.slice(-50);
|
|
11832
|
+
writeFileSync7(memFile, JSON.stringify(memEntries, null, 2), "utf-8");
|
|
11833
|
+
} catch {
|
|
11834
|
+
}
|
|
11771
11835
|
const lines = [
|
|
11772
11836
|
`Transcription of: ${basename4(filePath)}`,
|
|
11773
11837
|
`Model: ${model} | Language: ${result.language} | Duration: ${result.duration ? `${result.duration.toFixed(1)}s` : "unknown"}`,
|
|
11774
|
-
`Words: ${result.wordCount} |
|
|
11838
|
+
`Words: ${result.wordCount} | Segments: ${result.segments.length}`,
|
|
11839
|
+
`Saved: ${txtFile} (text) + ${jsonFile} (structured with timestamps)`,
|
|
11775
11840
|
""
|
|
11776
11841
|
];
|
|
11777
11842
|
if (result.speakers.length > 1) {
|
|
11778
11843
|
lines.push(`Speakers: ${result.speakers.join(", ")}`);
|
|
11779
11844
|
lines.push("");
|
|
11780
11845
|
}
|
|
11781
|
-
if (
|
|
11846
|
+
if (result.segments.length > 0) {
|
|
11782
11847
|
for (const seg of result.segments) {
|
|
11783
11848
|
const ts = `[${formatTime(seg.start)} \u2192 ${formatTime(seg.end)}]`;
|
|
11784
11849
|
const speaker = seg.speaker ? `${seg.speaker}: ` : "";
|
|
@@ -11832,13 +11897,13 @@ var init_transcribe_tool = __esm({
|
|
|
11832
11897
|
};
|
|
11833
11898
|
TranscribeUrlTool = class {
|
|
11834
11899
|
name = "transcribe_url";
|
|
11835
|
-
description = "Download
|
|
11900
|
+
description = "Download and transcribe audio/video from a URL. Supports YouTube links (youtube.com/watch?v=..., youtu.be/...) and direct media URLs (MP3, WAV, MP4, etc.). YouTube audio is extracted via yt-dlp (auto-installed). Transcription is local via faster-whisper (no cloud API).";
|
|
11836
11901
|
parameters = {
|
|
11837
11902
|
type: "object",
|
|
11838
11903
|
properties: {
|
|
11839
11904
|
url: {
|
|
11840
11905
|
type: "string",
|
|
11841
|
-
description: "URL
|
|
11906
|
+
description: "URL to transcribe \u2014 YouTube links (youtube.com/watch?v=..., youtu.be/...) or direct media files (MP3, WAV, MP4)"
|
|
11842
11907
|
},
|
|
11843
11908
|
model: {
|
|
11844
11909
|
type: "string",
|
|
@@ -11866,25 +11931,57 @@ var init_transcribe_tool = __esm({
|
|
|
11866
11931
|
}
|
|
11867
11932
|
const tmpDir = join19(this.workingDir, ".oa", "tmp");
|
|
11868
11933
|
mkdirSync7(tmpDir, { recursive: true });
|
|
11869
|
-
const
|
|
11870
|
-
let
|
|
11871
|
-
if (!ext || !AUDIO_EXTS.has(ext) && !VIDEO_EXTS.has(ext)) {
|
|
11872
|
-
ext = ".mp3";
|
|
11873
|
-
}
|
|
11874
|
-
const tmpFile = join19(tmpDir, `download-${Date.now()}${ext}`);
|
|
11934
|
+
const tmpBase = join19(tmpDir, `download-${Date.now()}`);
|
|
11935
|
+
let tmpFile = "";
|
|
11875
11936
|
try {
|
|
11876
|
-
|
|
11877
|
-
|
|
11878
|
-
|
|
11879
|
-
|
|
11880
|
-
|
|
11881
|
-
|
|
11882
|
-
|
|
11883
|
-
|
|
11884
|
-
|
|
11885
|
-
}
|
|
11937
|
+
if (isYouTubeUrl(url)) {
|
|
11938
|
+
if (!ensureYtDlp()) {
|
|
11939
|
+
return {
|
|
11940
|
+
success: false,
|
|
11941
|
+
output: "",
|
|
11942
|
+
error: "yt-dlp not found and auto-install failed. Install manually: pip3 install yt-dlp",
|
|
11943
|
+
durationMs: performance.now() - start
|
|
11944
|
+
};
|
|
11945
|
+
}
|
|
11946
|
+
tmpFile = `${tmpBase}.mp3`;
|
|
11947
|
+
try {
|
|
11948
|
+
execSync10(`yt-dlp -x --audio-format mp3 --audio-quality 5 -o "${tmpBase}.%(ext)s" "${url}" 2>&1`, { timeout: 3e5, stdio: ["pipe", "pipe", "pipe"] });
|
|
11949
|
+
if (!existsSync16(tmpFile)) {
|
|
11950
|
+
const { readdirSync: rd } = __require("node:fs");
|
|
11951
|
+
const files = rd(tmpDir).filter((f) => f.startsWith(`download-`) && f !== ".gitkeep");
|
|
11952
|
+
const match = files.find((f) => f.includes(basename4(tmpBase)));
|
|
11953
|
+
if (match)
|
|
11954
|
+
tmpFile = join19(tmpDir, match);
|
|
11955
|
+
}
|
|
11956
|
+
} catch (dlErr) {
|
|
11957
|
+
const errMsg = dlErr instanceof Error ? dlErr.message : String(dlErr);
|
|
11958
|
+
return {
|
|
11959
|
+
success: false,
|
|
11960
|
+
output: "",
|
|
11961
|
+
error: `yt-dlp failed: ${errMsg.slice(0, 200)}. Is the video available and not age-restricted?`,
|
|
11962
|
+
durationMs: performance.now() - start
|
|
11963
|
+
};
|
|
11964
|
+
}
|
|
11965
|
+
} else {
|
|
11966
|
+
const urlPath = new URL(url).pathname;
|
|
11967
|
+
let ext = extname3(urlPath).toLowerCase();
|
|
11968
|
+
if (!ext || !AUDIO_EXTS.has(ext) && !VIDEO_EXTS.has(ext)) {
|
|
11969
|
+
ext = ".mp3";
|
|
11970
|
+
}
|
|
11971
|
+
tmpFile = `${tmpBase}${ext}`;
|
|
11972
|
+
try {
|
|
11973
|
+
execSync10(`curl -sL -o "${tmpFile}" "${url}"`, {
|
|
11974
|
+
timeout: 12e4,
|
|
11975
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
11976
|
+
});
|
|
11977
|
+
} catch {
|
|
11978
|
+
execSync10(`wget -q -O "${tmpFile}" "${url}"`, {
|
|
11979
|
+
timeout: 12e4,
|
|
11980
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
11981
|
+
});
|
|
11982
|
+
}
|
|
11886
11983
|
}
|
|
11887
|
-
if (!existsSync16(tmpFile)) {
|
|
11984
|
+
if (!tmpFile || !existsSync16(tmpFile)) {
|
|
11888
11985
|
return {
|
|
11889
11986
|
success: false,
|
|
11890
11987
|
output: "",
|
package/package.json
CHANGED