Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
dbe93cd
fix: convert unsupported audio formats (ogg) to wav for LLM formatter
claude Mar 14, 2026
d1bff1a
feat: add audio transcription with auto-detect for voice messages
claude Mar 14, 2026
8944164
feat: add voice transcription settings UI, API, and CLI config
claude Mar 14, 2026
cb32811
style: run prettier on console directory
claude Mar 14, 2026
4cfba0b
style: apply black formatting to message_processing.py
claude Mar 14, 2026
e54df48
fix: address PR review comments on voice transcription
claude Mar 14, 2026
669fc90
fix: run ffmpeg in thread pool and validate audio_mode config
claude Mar 14, 2026
6cb7a6a
Merge branch 'agentscope-ai:main' into claude/fix-discord-voice-messa…
ekzhu Mar 15, 2026
e19b9b1
chore: revert unrelated prettier spacing changes
claude Mar 15, 2026
6486e85
Fix voice message handling: bypass debounce and fix transcription lookup
ekzhu Mar 15, 2026
4d3640a
Update Voice Transcription settings UI with Whisper API explanation
ekzhu Mar 15, 2026
b800420
Add transcription provider selector to Voice Transcription settings
ekzhu Mar 15, 2026
4d0ff97
Add Local Whisper transcription provider support
ekzhu Mar 15, 2026
b5e85d2
Merge branch 'agentscope-ai:main' into claude/fix-discord-voice-messa…
ekzhu Mar 15, 2026
085bc0b
refactor(voice): merge auto/transcribe modes and suppress file metada…
ekzhu Mar 15, 2026
647a8cf
handle audio conversion for dingtalk
ekzhu Mar 16, 2026
ba6cd12
fix(voice): address PR review feedback and add disabled transcription…
ekzhu Mar 16, 2026
025a414
fix(voice): allow downloads dir in audio path validation
ekzhu Mar 16, 2026
eb81043
fix(voice): allow downloads dir in audio path validation
ekzhu Mar 16, 2026
345b5ed
Merge branch 'main' into claude/fix-discord-voice-messages-NVPD1
ekzhu Mar 17, 2026
9ccd8d9
feat(voice): add ffmpeg status check for native audio mode
ekzhu Mar 17, 2026
c789c13
format
ekzhu Mar 17, 2026
4149eff
fix(voice): normalize base URL to include /v1 for transcription
ekzhu Mar 17, 2026
ac546ba
Merge branch 'main' into claude/fix-discord-voice-messages-NVPD1
ekzhu Mar 17, 2026
5d8cff3
Fix typo
ekzhu Mar 17, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions console/src/api/modules/agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,12 @@ export const agentApi = {
method: "PUT",
body: JSON.stringify({ language }),
}),

getAudioMode: () => request<{ audio_mode: string }>("/agent/audio-mode"),

updateAudioMode: (audio_mode: string) =>
request<{ audio_mode: string }>("/agent/audio-mode", {
method: "PUT",
body: JSON.stringify({ audio_mode }),
}),
};
4 changes: 2 additions & 2 deletions console/src/components/MarkdownCopy/MarkdownCopy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,8 @@ export function MarkdownCopy({
localShowMarkdown && !(editable && !textareaProps.disabled)
? content
: editable
? editContent
: content;
? editContent
: content;

if (!contentToCopy) return;

Expand Down
6 changes: 6 additions & 0 deletions console/src/layouts/MainLayout/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import ModelsPage from "../../pages/Settings/Models";
import EnvironmentsPage from "../../pages/Settings/Environments";
import SecurityPage from "../../pages/Settings/Security";
import TokenUsagePage from "../../pages/Settings/TokenUsage";
import VoiceTranscriptionPage from "../../pages/Settings/VoiceTranscription";

const { Content } = Layout;

Expand All @@ -38,6 +39,7 @@ const pathToKey: Record<string, string> = {
"/agent-config": "agent-config",
"/security": "security",
"/token-usage": "token-usage",
"/voice-transcription": "voice-transcription",
};

export default function MainLayout() {
Expand Down Expand Up @@ -84,6 +86,10 @@ export default function MainLayout() {
<Route path="/agent-config" element={<AgentConfigPage />} />
<Route path="/security" element={<SecurityPage />} />
<Route path="/token-usage" element={<TokenUsagePage />} />
<Route
path="/voice-transcription"
element={<VoiceTranscriptionPage />}
/>
</Routes>
)}
</div>
Expand Down
13 changes: 10 additions & 3 deletions console/src/layouts/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import {
Copy,
Check,
BarChart3,
Mic,
} from "lucide-react";
import api from "../api";
import styles from "./index.module.less";
Expand Down Expand Up @@ -66,6 +67,7 @@ const KEY_TO_PATH: Record<string, string> = {
"agent-config": "/agent-config",
security: "/security",
"token-usage": "/token-usage",
"voice-transcription": "/voice-transcription",
};

const UPDATE_MD: Record<string, string> = {
Expand Down Expand Up @@ -255,8 +257,8 @@ export default function Sidebar({ selectedKey }: SidebarProps) {
const lang = i18n.language?.startsWith("zh")
? "zh"
: i18n.language?.startsWith("ru")
? "ru"
: "en";
? "ru"
: "en";
const faqLang = lang === "zh" ? "zh" : "en";
const url = `https://copaw.agentscope.io/docs/faq.${faqLang}.md`;
fetch(url, { cache: "no-cache" })
Expand All @@ -268,7 +270,7 @@ export default function Sidebar({ selectedKey }: SidebarProps) {
setUpdateMarkdown(
match && lang !== "ru"
? match[0].trim()
: UPDATE_MD[lang] ?? UPDATE_MD.en,
: (UPDATE_MD[lang] ?? UPDATE_MD.en),
);
})
.catch(() => {
Expand Down Expand Up @@ -353,6 +355,11 @@ export default function Sidebar({ selectedKey }: SidebarProps) {
label: t("nav.tokenUsage"),
icon: <BarChart3 size={16} />,
},
{
key: "voice-transcription",
label: t("nav.voiceTranscription"),
Comment thread
ekzhu marked this conversation as resolved.
icon: <Mic size={16} />,
},
],
},
];
Expand Down
18 changes: 17 additions & 1 deletion console/src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,23 @@
"models": "Models",
"environments": "Environments",
"security": "Security",
"tokenUsage": "Token Usage"
"tokenUsage": "Token Usage",
"voiceTranscription": "Voice Transcription"
},
"voiceTranscription": {
"title": "Voice Transcription",
"description": "Configure how incoming audio and voice messages are handled.",
"loadFailed": "Failed to load audio mode settings",
"saveSuccess": "Audio mode saved",
"saveFailed": "Failed to save audio mode",
"audioModeLabel": "Audio Mode",
"audioModeDescription": "Choose how voice messages from channels (Discord, Telegram, etc.) are processed before being sent to the model.",
"modeAuto": "Auto",
"modeAutoDesc": "Try transcription first, fall back to native audio",
"modeTranscribe": "Transcribe",
"modeTranscribeDesc": "Always convert audio to text (works with all models)",
"modeNative": "Native",
"modeNativeDesc": "Send audio directly to the model (requires ffmpeg, only for audio-capable models)"
},
"workspace": {
"title": "WorkSpace",
Expand Down
18 changes: 17 additions & 1 deletion console/src/locales/zh.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@
"models": "模型",
"environments": "环境变量",
"security": "安全",
"tokenUsage": "Token 消耗"
"tokenUsage": "Token 消耗",
"voiceTranscription": "语音转写"
},
"workspace": {
"title": "工作区",
Expand Down Expand Up @@ -644,5 +645,20 @@
"TOOL_CMD_DANGEROUS_MV": "检测可能意外移动或覆盖文件的 mv 命令"
}
}
},
"voiceTranscription": {
"title": "语音转写",
"description": "配置如何处理收到的音频和语音消息。",
"loadFailed": "加载音频模式设置失败",
"saveSuccess": "音频模式已保存",
"saveFailed": "保存音频模式失败",
"audioModeLabel": "音频模式",
"audioModeDescription": "选择来自频道(Discord、Telegram 等)的语音消息在发送给模型之前如何处理。",
"modeAuto": "自动",
"modeAutoDesc": "优先转写,失败时回退到原生音频",
"modeTranscribe": "转写",
"modeTranscribeDesc": "始终将音频转为文字(适用于所有模型)",
"modeNative": "原生",
"modeNativeDesc": "直接发送音频给模型(需要 ffmpeg,仅支持音频的模型可用)"
}
}
5 changes: 2 additions & 3 deletions console/src/pages/Control/Sessions/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,8 @@ function SessionsPage() {
let filtered: Session[] = sessions;

if (filterUserId) {
filtered = filtered.filter(
(session: Session) =>
session.user_id?.toLowerCase().includes(filterUserId.toLowerCase()),
filtered = filtered.filter((session: Session) =>
session.user_id?.toLowerCase().includes(filterUserId.toLowerCase()),
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,23 +87,23 @@ export function RemoteProviderCard({
const statusLabel = isAvailable
? t("models.providerAvailable")
: isConfigured
? t("models.providerNoModels")
: t("models.providerNotConfigured");
? t("models.providerNoModels")
: t("models.providerNotConfigured");
const statusType = isAvailable
? "enabled"
: isConfigured
? "partial"
: "disabled";
? "partial"
: "disabled";
const statusDotColor = isAvailable
? "#52c41a"
: isConfigured
? "#faad14"
: "#d9d9d9";
? "#faad14"
: "#d9d9d9";
const statusDotShadow = isAvailable
? "0 0 0 2px rgba(82, 196, 26, 0.2)"
: isConfigured
? "0 0 0 2px rgba(250, 173, 20, 0.2)"
: "none";
? "0 0 0 2px rgba(250, 173, 20, 0.2)"
: "none";

return (
<Card
Expand Down Expand Up @@ -135,8 +135,8 @@ export function RemoteProviderCard({
statusType === "enabled"
? styles.enabled
: statusType === "partial"
? styles.partial
: styles.disabled
? styles.partial
: styles.disabled
}`}
>
{statusLabel}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@ import api from "../../../../../api";
import { useTranslation } from "react-i18next";
import styles from "../../index.module.less";

interface ProviderConfigFormValues
extends Omit<ProviderConfigRequest, "generate_kwargs"> {
interface ProviderConfigFormValues extends Omit<
ProviderConfigRequest,
"generate_kwargs"
> {
generate_kwargs_text?: string;
}

Expand Down
73 changes: 73 additions & 0 deletions console/src/pages/Settings/VoiceTranscription/index.module.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
.page {
padding: 24px;
height: 100%;
overflow-y: auto;
width: 100%;
}

.header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 24px;
}

.title {
font-size: 24px;
font-weight: 600;
margin: 0 0 8px 0;
color: #000;
}

.description {
font-size: 14px;
color: #666;
margin: 0;
}

.card {
width: 100%;
margin-bottom: 16px;

&:hover {
border: 1px solid #615ced;
box-shadow: 0 12px 32px rgba(0, 0, 0, 0.08);
}
}

.cardTitle {
font-size: 16px;
font-weight: 600;
margin: 0 0 4px 0;
}

.cardDescription {
font-size: 13px;
color: #888;
margin: 0 0 16px 0;
}

.optionLabel {
font-weight: 500;
margin-right: 8px;
}

.optionDescription {
font-size: 13px;
color: #888;
}

.centerState {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 400px;
}

.footerActions {
display: flex;
justify-content: flex-end;
align-items: center;
padding: 16px 24px;
}
Loading
Loading