Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,8 @@ docs/public/d2
docs/dist
docs/.astro
docs/**/*.bin

claude/
.claude/
CONTEXT.MD
eim_config.toml
45 changes: 45 additions & 0 deletions application/edge_agent/components/app_config/app_config.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,37 @@ typedef struct {
#define APP_DEFAULT_LLM_SUPPORTS_TOOLS "false"
#define APP_DEFAULT_LLM_SUPPORTS_VISION "false"
#define APP_DEFAULT_LLM_IMAGE_REMOTE_URL_ONLY "false"
#ifdef CONFIG_APP_STT_ENABLED
#define APP_DEFAULT_STT_ENABLED "true"
#else
#define APP_DEFAULT_STT_ENABLED "false"
#endif
#ifdef CONFIG_APP_STT_BACKEND_TYPE
#define APP_DEFAULT_STT_BACKEND_TYPE CONFIG_APP_STT_BACKEND_TYPE
#else
#define APP_DEFAULT_STT_BACKEND_TYPE "openai"
#endif
#ifdef CONFIG_APP_STT_API_KEY
#define APP_DEFAULT_STT_API_KEY CONFIG_APP_STT_API_KEY
#else
#define APP_DEFAULT_STT_API_KEY ""
#endif
#ifdef CONFIG_APP_STT_BASE_URL
#define APP_DEFAULT_STT_BASE_URL CONFIG_APP_STT_BASE_URL
#else
#define APP_DEFAULT_STT_BASE_URL "https://api.openai.com/v1"
#endif
#ifdef CONFIG_APP_STT_MODEL
#define APP_DEFAULT_STT_MODEL CONFIG_APP_STT_MODEL
#else
#define APP_DEFAULT_STT_MODEL "whisper-1"
#endif
#ifdef CONFIG_APP_STT_LANGUAGE
#define APP_DEFAULT_STT_LANGUAGE CONFIG_APP_STT_LANGUAGE
#else
#define APP_DEFAULT_STT_LANGUAGE ""
#endif
#define APP_DEFAULT_STT_KEEP_AUDIO "false"
#define APP_DEFAULT_QQ_APP_ID ""
#define APP_DEFAULT_QQ_APP_SECRET ""
#define APP_DEFAULT_FEISHU_APP_ID ""
Expand Down Expand Up @@ -79,6 +110,13 @@ static const app_config_field_t s_fields[] = {
APP_CONFIG_FIELD(llm_supports_tools, "llm_sup_tools", APP_DEFAULT_LLM_SUPPORTS_TOOLS),
APP_CONFIG_FIELD(llm_supports_vision, "llm_sup_vis", APP_DEFAULT_LLM_SUPPORTS_VISION),
APP_CONFIG_FIELD(llm_image_remote_url_only, "llm_img_url_o", APP_DEFAULT_LLM_IMAGE_REMOTE_URL_ONLY),
APP_CONFIG_FIELD(stt_enabled, "stt_enabled", APP_DEFAULT_STT_ENABLED),
APP_CONFIG_FIELD(stt_backend_type, "stt_backend", APP_DEFAULT_STT_BACKEND_TYPE),
APP_CONFIG_FIELD(stt_api_key, "stt_api_key", APP_DEFAULT_STT_API_KEY),
APP_CONFIG_FIELD(stt_base_url, "stt_base_url", APP_DEFAULT_STT_BASE_URL),
APP_CONFIG_FIELD(stt_model, "stt_model", APP_DEFAULT_STT_MODEL),
APP_CONFIG_FIELD(stt_language, "stt_lang", APP_DEFAULT_STT_LANGUAGE),
APP_CONFIG_FIELD(stt_keep_audio, "stt_keep_aud", APP_DEFAULT_STT_KEEP_AUDIO),
APP_CONFIG_FIELD(qq_app_id, "qq_app_id", APP_DEFAULT_QQ_APP_ID),
APP_CONFIG_FIELD(qq_app_secret, "qq_app_secret", APP_DEFAULT_QQ_APP_SECRET),
APP_CONFIG_FIELD(feishu_app_id, "feishu_app_id", APP_DEFAULT_FEISHU_APP_ID),
Expand Down Expand Up @@ -552,6 +590,13 @@ void app_config_to_claw(const app_config_t *config, app_claw_config_t *out)
strlcpy(out->llm_image_remote_url_only,
config->llm_image_remote_url_only,
sizeof(out->llm_image_remote_url_only));
strlcpy(out->stt_enabled, config->stt_enabled, sizeof(out->stt_enabled));
strlcpy(out->stt_backend_type, config->stt_backend_type, sizeof(out->stt_backend_type));
strlcpy(out->stt_api_key, config->stt_api_key, sizeof(out->stt_api_key));
strlcpy(out->stt_base_url, config->stt_base_url, sizeof(out->stt_base_url));
strlcpy(out->stt_model, config->stt_model, sizeof(out->stt_model));
strlcpy(out->stt_language, config->stt_language, sizeof(out->stt_language));
strlcpy(out->stt_keep_audio, config->stt_keep_audio, sizeof(out->stt_keep_audio));
strlcpy(out->qq_app_id, config->qq_app_id, sizeof(out->qq_app_id));
strlcpy(out->qq_app_secret, config->qq_app_secret, sizeof(out->qq_app_secret));
strlcpy(out->feishu_app_id, config->feishu_app_id, sizeof(out->feishu_app_id));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,13 @@ typedef struct {
char llm_supports_tools[8];
char llm_supports_vision[8];
char llm_image_remote_url_only[8];
char stt_enabled[8];
char stt_backend_type[32];
char stt_api_key[APP_CONFIG_STR_LEN];
char stt_base_url[APP_CONFIG_STR_LEN];
char stt_model[64];
char stt_language[32];
char stt_keep_audio[8];
char qq_app_id[32];
char qq_app_secret[APP_CONFIG_STR_LEN];
char feishu_app_id[64];
Expand Down
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const BasicPage = lazy(() => import('./pages/BasicPage').then((mod) => ({ defaul
const SearchPage = lazy(() => import('./pages/SearchPage').then((mod) => ({ default: mod.SearchPage })));
const MemoryPage = lazy(() => import('./pages/MemoryPage').then((mod) => ({ default: mod.MemoryPage })));
const LlmPage = lazy(() => import('./pages/LlmPage').then((mod) => ({ default: mod.LlmPage })));
const SttPage = lazy(() => import('./pages/SttPage').then((mod) => ({ default: mod.SttPage })));
const ImPage = lazy(() => import('./pages/ImPage').then((mod) => ({ default: mod.ImPage })));
const CapabilitiesPage = lazy(() =>
import('./pages/CapabilitiesPage').then((mod) => ({ default: mod.CapabilitiesPage })),
Expand Down Expand Up @@ -232,6 +233,9 @@ const App: Component = () => {
<Show when={currentTab() === 'llm'}>
<LlmPage />
</Show>
<Show when={currentTab() === 'stt'}>
<SttPage onRestartRequest={() => void handleRestartRequest({ reloadOnSuccess: true })} />
</Show>
<Show when={currentTab() === 'im'}>
<ImPage />
</Show>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@ export type AppConfig = {
llm_supports_tools: string;
llm_supports_vision: string;
llm_image_remote_url_only: string;
stt_enabled: string;
stt_backend_type: string;
stt_api_key: string;
stt_base_url: string;
stt_model: string;
stt_language: string;
stt_keep_audio: string;
qq_app_id: string;
qq_app_secret: string;
feishu_app_id: string;
Expand All @@ -39,6 +46,7 @@ export type AppConfig = {
export type ConfigGroup =
| 'wifi'
| 'llm'
| 'stt'
| 'im'
| 'search'
| 'capabilities'
Expand All @@ -61,6 +69,15 @@ export const GROUP_FIELDS: Record<ConfigGroup, (keyof AppConfig)[]> = {
'llm_supports_vision',
'llm_image_remote_url_only',
],
stt: [
'stt_enabled',
'stt_backend_type',
'stt_api_key',
'stt_base_url',
'stt_model',
'stt_language',
'stt_keep_audio',
],
im: [
'qq_app_id',
'qq_app_secret',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {
Activity,
AudioLines,
Blocks,
Bot,
DatabaseZap,
Expand All @@ -22,6 +23,7 @@ const IconStatus: Component = () => <Activity class={iconClass} />;
const IconGear: Component = () => <Settings class={iconClass} />;
const IconWifi: Component = () => <WifiPen class={iconClass} />;
const IconLlm: Component = () => <Bot class={iconClass} />;
const IconStt: Component = () => <AudioLines class={iconClass} />;
const IconIm: Component = () => <MessageSquareCode class={iconClass} />;
const IconSearch: Component = () => <Search class={iconClass} />;
const IconMemory: Component = () => <DatabaseZap class={iconClass} />;
Expand All @@ -37,6 +39,7 @@ export type LeafNode = {
| 'navStatus'
| 'navBasic'
| 'navLlm'
| 'navStt'
| 'navIm'
| 'navSearch'
| 'navMemory'
Expand Down Expand Up @@ -65,6 +68,7 @@ export const NAV_TREE: NavNode[] = [
children: [
{ kind: 'leaf', id: 'basic', labelKey: 'navBasic', icon: IconWifi },
{ kind: 'leaf', id: 'llm', labelKey: 'navLlm', icon: IconLlm },
{ kind: 'leaf', id: 'stt', labelKey: 'navStt', icon: IconStt },
{ kind: 'leaf', id: 'im', labelKey: 'navIm', icon: IconIm },
{ kind: 'leaf', id: 'search', labelKey: 'navSearch', icon: IconSearch },
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export const en = {
navSystemSettings: 'System Settings',
navBasic: 'Basic Settings',
navLlm: 'LLM',
navStt: 'Speech-to-Text',
navIm: 'IM',
navSearch: 'Web Search',
navMemory: 'Memory',
Expand Down Expand Up @@ -132,6 +133,25 @@ export const en = {
llmValidationMaxTokens: 'Max Tokens must be a positive integer.',
llmValidationImageMaxBytes: 'Default Image Max Bytes must be a positive integer.',

sectionStt: 'Speech-to-Text',
sttNote:
'When enabled, voice and audio messages received from chat platforms (e.g. Telegram voice notes) are transcribed and fed to the agent as text.',
sttEnabled: 'Enable inbound transcription',
sttBackendType: 'Backend',
sttBackendOpenai: 'OpenAI / Whisper-compatible',
sttBackendDeepgram: 'Deepgram',
sttApiKey: 'API Key',
sttBaseUrl: 'Base URL',
sttBaseUrlPlaceholder: 'https://api.openai.com/v1',
sttModel: 'Model',
sttModelPlaceholderOpenai: 'whisper-1',
sttModelPlaceholderDeepgram: 'nova-2',
sttLanguage: 'Language (leave blank for multi-language auto-detect)',
sttLanguagePlaceholder: 'e.g. es, en, pt — blank = auto-detect',
sttKeepAudio: 'Keep raw audio in FATFS (debug / retry)',
sttKeepAudioHint:
'Off by default — voice notes stream straight from Telegram into the STT API (faster, no flash wear). Enable to also save the original .oga to /fatfs/inbox/ for retry or inspection.',

sectionIm: 'Instant Messaging (IM)',
imAdd: 'Add',
imClearConf: 'Clear Config',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export const zhCn: Dict = {
navSystemSettings: '系统设置',
navBasic: '基本设置',
navLlm: 'LLM 设置',
navStt: '语音转文字',
navIm: 'IM 设置',
navSearch: '网络搜索设置',
navMemory: '记忆管理',
Expand Down Expand Up @@ -128,6 +129,25 @@ export const zhCn: Dict = {
llmValidationMaxTokens: '最大 Token 数必须是正整数。',
llmValidationImageMaxBytes: '默认图片大小上限必须是正整数。',

sectionStt: '语音转文字',
sttNote:
'启用后,聊天平台收到的语音和音频消息(如 Telegram 语音条)会被转写为文本并送入 Agent。',
sttEnabled: '启用入站语音转写',
sttBackendType: '后端',
sttBackendOpenai: 'OpenAI / Whisper 兼容',
sttBackendDeepgram: 'Deepgram',
sttApiKey: 'API Key',
sttBaseUrl: 'Base URL',
sttBaseUrlPlaceholder: 'https://api.openai.com/v1',
sttModel: '模型',
sttModelPlaceholderOpenai: 'whisper-1',
sttModelPlaceholderDeepgram: 'nova-2',
sttLanguage: '语言(留空则自动检测多语言)',
sttLanguagePlaceholder: '例如 es、en、pt — 留空表示自动检测',
sttKeepAudio: '保留原始音频到 FATFS(调试 / 重试)',
sttKeepAudioHint:
'默认关闭——语音消息直接从 Telegram 流到 STT API(更快、不写闪存)。启用后会将原始 .oga 保存到 /fatfs/inbox/ 以便重试或检查。',

sectionIm: '即时通讯 (IM)',
imAdd: '添加',
imClearConf: '清空配置',
Expand Down
Loading