opencrush 0.3.8 → 0.3.10
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 +70 -37
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -234588,6 +234588,21 @@ function debugLog3(msg) {
|
|
|
234588
234588
|
} catch {
|
|
234589
234589
|
}
|
|
234590
234590
|
}
|
|
234591
|
+
async function loadVoice() {
|
|
234592
|
+
if (voice) return voice;
|
|
234593
|
+
if (voiceLoadError) return null;
|
|
234594
|
+
try {
|
|
234595
|
+
voice = await import("@discordjs/voice");
|
|
234596
|
+
return voice;
|
|
234597
|
+
} catch (err) {
|
|
234598
|
+
voiceLoadError = err instanceof Error ? err.message : String(err);
|
|
234599
|
+
console.warn(`[Discord] @discordjs/voice not available \u2014 voice features disabled (${voiceLoadError})`);
|
|
234600
|
+
return null;
|
|
234601
|
+
}
|
|
234602
|
+
}
|
|
234603
|
+
function getVoiceSync() {
|
|
234604
|
+
return voice;
|
|
234605
|
+
}
|
|
234591
234606
|
async function loadPrism() {
|
|
234592
234607
|
if (!prism) {
|
|
234593
234608
|
prism = await import("prism-media");
|
|
@@ -234610,15 +234625,16 @@ function splitMessage(text, maxLength = 1900) {
|
|
|
234610
234625
|
if (current) chunks.push(current.trim());
|
|
234611
234626
|
return chunks;
|
|
234612
234627
|
}
|
|
234613
|
-
var import_discord, import_fs15,
|
|
234628
|
+
var import_discord, import_fs15, import_stream4, DEBUG_LOG, voice, voiceLoadError, prism, DiscordBridge;
|
|
234614
234629
|
var init_dist5 = __esm({
|
|
234615
234630
|
"../bridges/discord/dist/index.mjs"() {
|
|
234616
234631
|
"use strict";
|
|
234617
234632
|
import_discord = __toESM(require_src3(), 1);
|
|
234618
234633
|
import_fs15 = require("fs");
|
|
234619
|
-
import_voice = require("@discordjs/voice");
|
|
234620
234634
|
import_stream4 = require("stream");
|
|
234621
234635
|
DEBUG_LOG = "/tmp/opencrush-debug.log";
|
|
234636
|
+
voice = null;
|
|
234637
|
+
voiceLoadError = null;
|
|
234622
234638
|
prism = null;
|
|
234623
234639
|
DiscordBridge = class {
|
|
234624
234640
|
client;
|
|
@@ -234839,6 +234855,8 @@ var init_dist5 = __esm({
|
|
|
234839
234855
|
}
|
|
234840
234856
|
async handleVoiceState(oldState, newState) {
|
|
234841
234857
|
var _a3;
|
|
234858
|
+
const v2 = await loadVoice();
|
|
234859
|
+
if (!v2) return;
|
|
234842
234860
|
if (((_a3 = newState.member) == null ? void 0 : _a3.id) !== this.config.ownerId) return;
|
|
234843
234861
|
const userJoinedVoice = !oldState.channelId && newState.channelId;
|
|
234844
234862
|
const userLeftVoice = oldState.channelId && !newState.channelId;
|
|
@@ -234868,7 +234886,9 @@ var init_dist5 = __esm({
|
|
|
234868
234886
|
* Creates a loop: listen → transcribe → LLM → TTS → speak → repeat.
|
|
234869
234887
|
*/
|
|
234870
234888
|
startVoiceConversation(guildId) {
|
|
234871
|
-
const
|
|
234889
|
+
const v2 = getVoiceSync();
|
|
234890
|
+
if (!v2) return;
|
|
234891
|
+
const connection = v2.getVoiceConnection(guildId);
|
|
234872
234892
|
if (!connection) return;
|
|
234873
234893
|
this.voiceConversationActive.set(guildId, true);
|
|
234874
234894
|
console.log(`[Discord/Voice] Starting voice conversation in guild ${guildId}`);
|
|
@@ -234881,7 +234901,9 @@ var init_dist5 = __esm({
|
|
|
234881
234901
|
}
|
|
234882
234902
|
async listenForNextUtterance(guildId) {
|
|
234883
234903
|
if (!this.voiceConversationActive.get(guildId)) return;
|
|
234884
|
-
const
|
|
234904
|
+
const v2 = getVoiceSync();
|
|
234905
|
+
if (!v2) return;
|
|
234906
|
+
const connection = v2.getVoiceConnection(guildId);
|
|
234885
234907
|
if (!connection) return;
|
|
234886
234908
|
if (this.isSpeaking.get(guildId)) {
|
|
234887
234909
|
setTimeout(() => this.listenForNextUtterance(guildId), 500);
|
|
@@ -234891,7 +234913,7 @@ var init_dist5 = __esm({
|
|
|
234891
234913
|
const receiver = connection.receiver;
|
|
234892
234914
|
const opusStream = receiver.subscribe(this.config.ownerId, {
|
|
234893
234915
|
end: {
|
|
234894
|
-
behavior:
|
|
234916
|
+
behavior: v2.EndBehaviorType.AfterSilence,
|
|
234895
234917
|
duration: 1500
|
|
234896
234918
|
}
|
|
234897
234919
|
});
|
|
@@ -234990,36 +235012,42 @@ var init_dist5 = __esm({
|
|
|
234990
235012
|
}
|
|
234991
235013
|
// ── Voice Channel Management ───────────────────────────────
|
|
234992
235014
|
async joinVoiceChannel(channelId, guildId, adapterCreator) {
|
|
235015
|
+
const v2 = getVoiceSync();
|
|
235016
|
+
if (!v2) return;
|
|
234993
235017
|
try {
|
|
234994
|
-
const connection =
|
|
235018
|
+
const connection = v2.joinVoiceChannel({
|
|
234995
235019
|
channelId,
|
|
234996
235020
|
guildId,
|
|
234997
235021
|
adapterCreator,
|
|
234998
235022
|
selfDeaf: false,
|
|
234999
235023
|
selfMute: false
|
|
235000
235024
|
});
|
|
235001
|
-
await
|
|
235025
|
+
await v2.entersState(connection, v2.VoiceConnectionStatus.Ready, 3e4);
|
|
235002
235026
|
console.log(`[Discord] Joined voice channel ${channelId}`);
|
|
235003
235027
|
} catch (err) {
|
|
235004
235028
|
console.error("[Discord] Failed to join voice channel:", err);
|
|
235005
235029
|
}
|
|
235006
235030
|
}
|
|
235007
235031
|
leaveVoiceChannel(guildId) {
|
|
235008
|
-
const
|
|
235032
|
+
const v2 = getVoiceSync();
|
|
235033
|
+
if (!v2) return;
|
|
235034
|
+
const connection = v2.getVoiceConnection(guildId);
|
|
235009
235035
|
if (connection) {
|
|
235010
235036
|
connection.destroy();
|
|
235011
235037
|
console.log(`[Discord] Left voice channel in guild ${guildId}`);
|
|
235012
235038
|
}
|
|
235013
235039
|
}
|
|
235014
235040
|
async playAudio(guildId, audioBuffer) {
|
|
235015
|
-
const
|
|
235041
|
+
const v2 = getVoiceSync();
|
|
235042
|
+
if (!v2) return;
|
|
235043
|
+
const connection = v2.getVoiceConnection(guildId);
|
|
235016
235044
|
if (!connection) return;
|
|
235017
|
-
const player =
|
|
235045
|
+
const player = v2.createAudioPlayer();
|
|
235018
235046
|
const readable = import_stream4.Readable.from(audioBuffer);
|
|
235019
|
-
const resource =
|
|
235047
|
+
const resource = v2.createAudioResource(readable);
|
|
235020
235048
|
player.play(resource);
|
|
235021
235049
|
connection.subscribe(player);
|
|
235022
|
-
await
|
|
235050
|
+
await v2.entersState(player, v2.AudioPlayerStatus.Idle, 6e4);
|
|
235023
235051
|
}
|
|
235024
235052
|
// ── Message Handling ───────────────────────────────────────
|
|
235025
235053
|
/**
|
|
@@ -235215,6 +235243,7 @@ var init_dist5 = __esm({
|
|
|
235215
235243
|
}
|
|
235216
235244
|
}
|
|
235217
235245
|
async start() {
|
|
235246
|
+
await loadVoice();
|
|
235218
235247
|
await this.client.login(this.config.token);
|
|
235219
235248
|
}
|
|
235220
235249
|
async stop() {
|
|
@@ -236377,10 +236406,10 @@ var require_context = __commonJS({
|
|
|
236377
236406
|
*
|
|
236378
236407
|
* **Official reference:** https://core.telegram.org/bots/api#sendvoice
|
|
236379
236408
|
*/
|
|
236380
|
-
replyWithVoice(
|
|
236409
|
+
replyWithVoice(voice2, other, signal) {
|
|
236381
236410
|
var _a3;
|
|
236382
236411
|
const msg = this.msg;
|
|
236383
|
-
return this.api.sendVoice(orThrow(this.chatId, "sendVoice"),
|
|
236412
|
+
return this.api.sendVoice(orThrow(this.chatId, "sendVoice"), voice2, {
|
|
236384
236413
|
business_connection_id: this.businessConnectionId,
|
|
236385
236414
|
...(msg === null || msg === void 0 ? void 0 : msg.is_topic_message) ? { message_thread_id: msg.message_thread_id } : {},
|
|
236386
236415
|
direct_messages_topic_id: (_a3 = msg === null || msg === void 0 ? void 0 : msg.direct_messages_topic) === null || _a3 === void 0 ? void 0 : _a3.topic_id,
|
|
@@ -239463,8 +239492,8 @@ var require_api3 = __commonJS({
|
|
|
239463
239492
|
*
|
|
239464
239493
|
* **Official reference:** https://core.telegram.org/bots/api#sendvoice
|
|
239465
239494
|
*/
|
|
239466
|
-
sendVoice(chat_id,
|
|
239467
|
-
return this.raw.sendVoice({ chat_id, voice, ...other }, signal);
|
|
239495
|
+
sendVoice(chat_id, voice2, other, signal) {
|
|
239496
|
+
return this.raw.sendVoice({ chat_id, voice: voice2, ...other }, signal);
|
|
239468
239497
|
}
|
|
239469
239498
|
/**
|
|
239470
239499
|
* Use this method to send video messages. On success, the sent Message is returned.
|
|
@@ -245004,7 +245033,7 @@ function getExistingCharacters() {
|
|
|
245004
245033
|
const dir = getCharactersDir();
|
|
245005
245034
|
if (!(0, import_fs17.existsSync)(dir)) return [];
|
|
245006
245035
|
try {
|
|
245007
|
-
return (0, import_fs17.readdirSync)(dir, { withFileTypes: true }).filter((d2) => d2.isDirectory() && d2.name !== "example").map((d2) => d2.name);
|
|
245036
|
+
return (0, import_fs17.readdirSync)(dir, { withFileTypes: true }).filter((d2) => d2.isDirectory() && d2.name !== "example").filter((d2) => (0, import_fs17.existsSync)((0, import_path11.join)(dir, d2.name, "IDENTITY.md"))).map((d2) => d2.name);
|
|
245008
245037
|
} catch {
|
|
245009
245038
|
return [];
|
|
245010
245039
|
}
|
|
@@ -245090,16 +245119,17 @@ async function runSetupWizard() {
|
|
|
245090
245119
|
console.log(source_default.gray(" These companions are ready to go:\n"));
|
|
245091
245120
|
const choices = characters.map((c2) => {
|
|
245092
245121
|
const info = getCharacterInfo(c2);
|
|
245093
|
-
const
|
|
245122
|
+
const parts = [info.age, info.location].filter(Boolean);
|
|
245094
245123
|
const desc = info.tagline || info.hobbies.join(", ");
|
|
245095
|
-
|
|
245124
|
+
if (desc) parts.push(desc);
|
|
245125
|
+
const preview = parts.length > 0 ? source_default.gray(" \xB7 " + parts.join(" \xB7 ")) : "";
|
|
245096
245126
|
return {
|
|
245097
|
-
name: `\u2728 ${c2}${
|
|
245127
|
+
name: `\u2728 ${c2}${preview}`,
|
|
245098
245128
|
value: c2,
|
|
245099
245129
|
short: c2
|
|
245100
245130
|
};
|
|
245101
245131
|
});
|
|
245102
|
-
choices.push({ name:
|
|
245132
|
+
choices.push({ name: "\u2795 Create someone new", value: "__new__", short: "New" });
|
|
245103
245133
|
const { pick } = await esm_default12.prompt([{
|
|
245104
245134
|
type: "list",
|
|
245105
245135
|
name: "pick",
|
|
@@ -245489,7 +245519,8 @@ function parseIdentity(identityPath) {
|
|
|
245489
245519
|
const ageMatch = content.match(/\*\*Age:\*\*\s*(\d+)/i);
|
|
245490
245520
|
const age = (ageMatch == null ? void 0 : ageMatch[1]) ?? "??";
|
|
245491
245521
|
const fromMatch = content.match(/\*\*From:\*\*\s*(.+)/i);
|
|
245492
|
-
const
|
|
245522
|
+
const locationRaw = ((_b2 = fromMatch == null ? void 0 : fromMatch[1]) == null ? void 0 : _b2.trim()) ?? "Unknown";
|
|
245523
|
+
const location = locationRaw.replace(/\s*\(.*\)\s*$/, "").trim();
|
|
245493
245524
|
const hobbiesMatch = content.match(/\*\*Hobbies:\*\*\s*(.+)/i);
|
|
245494
245525
|
const hobbiesRaw = (hobbiesMatch == null ? void 0 : hobbiesMatch[1]) ?? "";
|
|
245495
245526
|
const tags = hobbiesRaw.split(",").map((t2) => t2.trim()).filter(Boolean).slice(0, 5);
|
|
@@ -245520,27 +245551,29 @@ function pickGradient(name) {
|
|
|
245520
245551
|
function createSvgOverlay(data, gradient) {
|
|
245521
245552
|
const textX = PORTRAIT_X + PORTRAIT_SIZE + 60;
|
|
245522
245553
|
const tagY = 280;
|
|
245523
|
-
const
|
|
245524
|
-
const x2 = textX + i2 * 0;
|
|
245525
|
-
const inlineX = textX;
|
|
245526
|
-
const inlineY = tagY + i2 * 36;
|
|
245527
|
-
return `
|
|
245528
|
-
<rect x="${inlineX - 4}" y="${inlineY - 18}" width="${tag.length * 10 + 24}" height="28" rx="14" fill="rgba(255,255,255,0.12)" />
|
|
245529
|
-
<text x="${inlineX + 8}" y="${inlineY}" font-family="system-ui, -apple-system, sans-serif" font-size="14" fill="#e0e0e0">${escapeXml(tag)}</text>
|
|
245530
|
-
`;
|
|
245531
|
-
}).join("\n");
|
|
245554
|
+
const maxTagX = WIDTH - 40;
|
|
245532
245555
|
let inlineTags = "";
|
|
245533
245556
|
let offsetX = textX;
|
|
245534
|
-
|
|
245557
|
+
let rowY = tagY;
|
|
245558
|
+
const rowHeight = 34;
|
|
245559
|
+
const maxRows = 2;
|
|
245560
|
+
let currentRow = 1;
|
|
245535
245561
|
for (const tag of data.tags) {
|
|
245536
|
-
const
|
|
245562
|
+
const label = tag.length > 22 ? tag.slice(0, 21) + "\u2026" : tag;
|
|
245563
|
+
const w2 = label.length * 8.5 + 24;
|
|
245564
|
+
if (offsetX + w2 > maxTagX) {
|
|
245565
|
+
if (currentRow >= maxRows) break;
|
|
245566
|
+
currentRow++;
|
|
245567
|
+
offsetX = textX;
|
|
245568
|
+
rowY += rowHeight;
|
|
245569
|
+
}
|
|
245537
245570
|
inlineTags += `
|
|
245538
|
-
<rect x="${offsetX - 2}" y="${
|
|
245539
|
-
<text x="${offsetX + 10}" y="${
|
|
245571
|
+
<rect x="${offsetX - 2}" y="${rowY - 16}" width="${w2}" height="26" rx="13" fill="rgba(255,255,255,0.10)" />
|
|
245572
|
+
<text x="${offsetX + 10}" y="${rowY}" font-family="system-ui, -apple-system, sans-serif" font-size="13" fill="#c0c0c0">${escapeXml(label)}</text>
|
|
245540
245573
|
`;
|
|
245541
245574
|
offsetX += w2 + 8;
|
|
245542
|
-
if (offsetX > WIDTH - 40) break;
|
|
245543
245575
|
}
|
|
245576
|
+
const descriptionY = tagY + currentRow * rowHeight + 16;
|
|
245544
245577
|
return `<svg width="${WIDTH}" height="${HEIGHT}" xmlns="http://www.w3.org/2000/svg">
|
|
245545
245578
|
<defs>
|
|
245546
245579
|
<linearGradient id="bg" x1="0" y1="0" x2="1" y2="1">
|
|
@@ -245568,7 +245601,7 @@ function createSvgOverlay(data, gradient) {
|
|
|
245568
245601
|
${inlineTags}
|
|
245569
245602
|
|
|
245570
245603
|
<!-- One-line description -->
|
|
245571
|
-
<text x="${textX}" y="${
|
|
245604
|
+
<text x="${textX}" y="${descriptionY}" font-family="system-ui, -apple-system, sans-serif" font-size="15" fill="#b0b0b0" font-style="italic">${escapeXml(truncate(data.description, 70))}</text>
|
|
245572
245605
|
|
|
245573
245606
|
<!-- Bottom bar -->
|
|
245574
245607
|
<rect x="0" y="${HEIGHT - 50}" width="${WIDTH}" height="50" fill="rgba(0,0,0,0.3)" />
|