feat: show speaker nickname instead of raw user ID in voice logs
Resolve the Discord user ID to a server nickname / global name (cached) and display that in the transcript channel + console logs.
This commit is contained in:
@@ -38,6 +38,9 @@ export interface TurnInfo {
|
||||
/** Discord user ID of the speaker, so the transcript shows whose audio
|
||||
* produced each turn (and which user a dropped/VAD turn belongs to). */
|
||||
user?: string;
|
||||
/** Resolved display name (server nickname / global name); shown instead of
|
||||
* the raw user ID when available. */
|
||||
userName?: string;
|
||||
transcript: string;
|
||||
reply: string;
|
||||
note?: string;
|
||||
@@ -72,7 +75,7 @@ function durSec(a?: number, b?: number): string | null {
|
||||
* timing breakdown (listening / LLM / TTS) with start→end wall-clock times and
|
||||
* durations, so it's obvious what took long. Pure + exported for testing. */
|
||||
export function formatTurnMessage(info: TurnInfo): string {
|
||||
const who = info.user ? `👤 ${info.user} ` : "";
|
||||
const who = info.userName || info.user ? `👤 ${info.userName || info.user} ` : "";
|
||||
const head = info.transcript
|
||||
? `${who}🎤 들음 → 🗣️ "${info.transcript}"\n🤖 답변: ${(info.reply || "").trim() || "(무응답)"}`
|
||||
: `${who}🎤 들음 → ❌ ${info.note || "무시됨"}`;
|
||||
@@ -124,7 +127,7 @@ async function joinAndListen(client: AnyClient, channelId: string): Promise<void
|
||||
// joinVoiceChannel (it exposes id, guild.id and guild.voiceAdapterCreator).
|
||||
const session = await joinChannel(channel as unknown as VoiceBasedChannel);
|
||||
session.onTurn = (info) => {
|
||||
console.log(`👤 ${info.user || "?"} 🗣️ ${info.transcript || "(" + (info.note || "empty") + ")"}\n🤖 ${info.reply}`);
|
||||
console.log(`👤 ${info.userName || info.user || "?"} 🗣️ ${info.transcript || "(" + (info.note || "empty") + ")"}\n🤖 ${info.reply}`);
|
||||
// Mirror every heard utterance (and the reply / drop reason) to a text
|
||||
// channel so you can see what the bot understood even when it doesn't answer.
|
||||
void postTranscript(client, info);
|
||||
|
||||
@@ -81,6 +81,9 @@ export class VoiceSession {
|
||||
* diagnosable. `note` says why (e.g. "음성 아님(VAD 차단)", "너무 짧음", "ok"). */
|
||||
onTurn?: (info: {
|
||||
user: string;
|
||||
/** Resolved display name (server nickname / global name) for the speaker,
|
||||
* so logs show a human name instead of the raw Discord user ID. */
|
||||
userName?: string;
|
||||
transcript: string;
|
||||
reply: string;
|
||||
note?: string;
|
||||
@@ -164,6 +167,31 @@ export class VoiceSession {
|
||||
});
|
||||
}
|
||||
|
||||
/** Resolve a speaker's Discord user ID to a human display name (server
|
||||
* nickname, else global name / username), cached so we don't refetch every
|
||||
* utterance. Falls back to the ID if lookup fails. */
|
||||
private nameCache = new Map<string, string>();
|
||||
private async displayName(userId: string): Promise<string> {
|
||||
const cached = this.nameCache.get(userId);
|
||||
if (cached) return cached;
|
||||
let name = userId;
|
||||
try {
|
||||
const guild: any = this.client?.guilds?.cache?.get(this.guildId);
|
||||
let member: any = guild?.members?.cache?.get(userId);
|
||||
if (!member && guild?.members?.fetch) member = await guild.members.fetch(userId).catch(() => null);
|
||||
if (member) {
|
||||
name = member.displayName || member.nickname || member.user?.globalName || member.user?.username || userId;
|
||||
} else {
|
||||
const u: any = this.client?.users?.cache?.get(userId) || (await this.client?.users?.fetch?.(userId).catch(() => null));
|
||||
name = u?.globalName || u?.username || userId;
|
||||
}
|
||||
} catch {
|
||||
/* fall back to id */
|
||||
}
|
||||
this.nameCache.set(userId, name);
|
||||
return name;
|
||||
}
|
||||
|
||||
private async captureUtterance(userId: string): Promise<void> {
|
||||
// Don't start a new capture once we're tearing down (user left).
|
||||
if (this.destroyed) return;
|
||||
@@ -199,6 +227,7 @@ export class VoiceSession {
|
||||
if (mono.length < DISCORD_RATE * 0.3 * 2) {
|
||||
this.onTurn?.({
|
||||
user: userId,
|
||||
userName: await this.displayName(userId),
|
||||
transcript: "",
|
||||
reply: "",
|
||||
note: "너무 짧음(<300ms)",
|
||||
@@ -247,6 +276,7 @@ export class VoiceSession {
|
||||
// explains why a turn did or didn't answer, with full stage timing.
|
||||
this.onTurn?.({
|
||||
user: userId,
|
||||
userName: await this.displayName(userId),
|
||||
transcript: metaSeen?.transcript ?? "",
|
||||
reply: metaSeen?.reply ?? "",
|
||||
note: metaSeen?.note,
|
||||
|
||||
Reference in New Issue
Block a user