{{ locale === 'zh' ? '请登录以继续' : 'Please sign in to continue' }}
{{ locale === 'zh' ? '你的账号正在等待管理员审批,审批通过后即可使用。' : 'Your account is pending admin approval.' }}
{{ locale === 'zh' ? '你的账号已被管理员拒绝,请联系管理员。' : 'Your account has been rejected. Please contact the admin.' }}
{{ locale === 'zh' ? '你还没有注册任何设备。点击下方按钮添加一台 Mac Studio,开始使用 AI 推理服务。' : 'No devices registered yet. Add a Mac Studio to start using AI inference services.' }}
| {{ locale === 'zh' ? '时间' : 'Time' }} | tenant | {{ locale === 'zh' ? '阶段' : 'Stage' }} | {{ locale === 'zh' ? '退出码' : 'Exit' }} | {{ locale === 'zh' ? '错误' : 'Error' }} | |
|---|---|---|---|---|---|
| {{ formatDate((r._ts || 0) * 1000) }} | {{ r.tenant_id }} |
{{ r.stage }} | {{ r.exit_code }} | ||
| {{ installReportsLoading ? '...' : (locale === 'zh' ? '暂无诊断报告' : 'No reports yet') }} | |||||
{{ diagnoseResult.stdout }}
{{ diagnoseResult.stderr }}
| {{ locale === 'zh' ? '时间' : 'Time' }} | tenant | command | status | rc | elapsed | args |
|---|---|---|---|---|---|---|
| {{ r.ts }} | {{ r.tenant_id }} |
{{ r.command }} |
{{ r.status }} | {{ r.rc ?? '-' }} | {{ r.elapsed_ms }}ms | {{ JSON.stringify(r.args) }} |
| {{ t('col.time') }} | {{ t('col.model') }} | Tokens | {{ t('col.latency') }} | {{ t('col.status') }} |
|---|---|---|---|---|
| {{ t('noRequests') }} | ||||
| {{ formatTime(r.time_str || r.timestamp) }} | {{ r.model }} | {{ r.tokens_in + r.tokens_out }} | {{ fmtMs(r.latency_ms) }} | {{ r.status_code }} |
| {{ t('col.modelName') }} | {{ t('col.source') }} | {{ t('col.backendModel') }} | {{ t('col.apiBase') }} | {{ t('col.actions') }} |
|---|---|---|---|---|
| {{ t('noRoutes') }} | ||||
| {{ r.model_name }} {{ t('autoSync') || 'Auto' }} | {{ getRouteSource(r).label }} | {{ r.litellm_params?.model || '-' }} | {{ r.litellm_params?.api_base || '-' }} | |
| {{ t('col.route') }} | {{ t('col.behavior') }} | {{ t('col.backendModel') }} | {{ t('col.apiBase') }} | {{ t('col.actions') }} |
|---|---|---|---|---|
| {{ t('audioNoRoutes') }} | ||||
|
{{ route.route_name }}
{{ route.display_name }}
{{ locale === 'zh' ? '默认路由' : 'Default route' }}
{{ locale === 'zh' ? '当前激活' : 'Active model' }}
|
{{ route.endpoint }}
model=
{{ route.model_param }}
{{ locale === 'zh' ? '可省略 model,命中当前 active ASR' : 'model is optional and uses the current active ASR' }}
|
{{ route.backend_model }} |
{{ route.api_base }}
{{ route.files_endpoint || '/v1/files' }} / {{ route.endpoint }}
|
|
| {{ t('col.name') }} | {{ t('col.size') }} | {{ t('col.modified') }} | {{ t('col.actions') }} |
|---|---|---|---|
| {{ t('noModels') }} | |||
| {{ m.name }} | {{ formatSize(m.size) }} | {{ formatDate(m.modified_at) }} | |
| {{ t('col.name') }} | {{ t('quantType') }} | {{ t('col.size') }} | {{ t('col.status') }} | {{ t('col.actions') }} |
|---|---|---|---|---|
| {{ t('noGGUF') }} | ||||
| {{ m.name }}({{ m.shard_count }} shards) | {{ m.quant_type }} | {{ formatSize(m.total_size) }} | Loaded {{ t('llamaStatusBadgeStale') }} {{ llamaLoadingProgress >= 0 ? 'Loading ' + Math.round(llamaLoadingProgress * 100) + '%' : 'Loading...' }} Incomplete ({{ m.shard_count }}/{{ m.expected_shards }}) Error Available | |
| {{ t('col.name') }} | {{ t('audioCol.type') }} | {{ t('col.size') }} | {{ t('audioCol.languages') }} | {{ t('audioCol.status') }} | {{ t('col.actions') }} | {{ t('audioCol.note') }} |
|---|---|---|---|---|---|---|
| {{ t('noModels') }} | ||||||
|
{{ m.display_name }}
{{ m.model_id }}
|
ASR TTS | {{ formatSize(m.total_size_bytes) }} | {{ (m.supported_languages || []).join(', ') || '—' }} | {{ t('audioStatus.tts_placeholder') }} {{ t('audioStatus.not_downloaded') }} {{ t('audioStatus.downloading') }} {{ (m.download_progress || 0).toFixed(0) }}% {{ t('audioStatus.downloaded') }} {{ t('audioStatus.loaded') }} {{ t('audioStatus.active') }} {{ t('audioStatus.failed') }} |
⚠️ {{ m.unavailable_reason }}
|
|
| {{ t('col.name') }} | {{ t('col.size') }} | {{ locale === 'zh' ? '状态' : 'Status' }} | {{ locale === 'zh' ? '进度' : 'Progress' }} | {{ t('col.actions') }} | {{ locale === 'zh' ? '错误' : 'Error' }} |
|---|---|---|---|---|---|
| {{ t('noModels') }} | |||||
|
{{ m.display_name || m.model_id }}
{{ t('mano.modelState.active') }}
{{ m.model_id }}
|
{{ m.size_bytes ? formatSize(m.size_bytes) : '—' }} | {{ t('mano.modelState.not_downloaded') }} {{ t('mano.modelState.downloading') }} {{ ((m.progress || 0) * 100).toFixed(0) }}% {{ t('mano.modelState.downloaded') }} {{ t('mano.modelState.loading') }} {{ t('mano.modelState.loaded') }} {{ t('mano.modelState.unloaded') }} {{ t('mano.modelState.failed') }} | ⚠️ {{ locale === 'zh' ? '请联系管理员配置 HF token' : 'Please ask admin to configure HF token' }} {{ m.error }} | ||
| {{ t('col.name') }} | {{ locale === 'zh' ? '引擎' : 'Engine' }} | {{ t('col.size') }} | {{ locale === 'zh' ? '状态' : 'Status' }} | {{ t('col.actions') }} |
|---|---|---|---|---|
| {{ t('noModels') }} | ||||
|
{{ row.name }}
{{ row.id }}
|
{{ storageEngineLabel(row.engine) }} | {{ formatSize(row.size_bytes) }} | {{ locale === 'zh' ? '加载中' : 'Loaded' }} {{ locale === 'zh' ? '未加载' : 'Idle' }} | |
{{ currentTenantId || '-' }}| {{ locale === 'zh' ? '检查项' : 'Check' }} | {{ locale === 'zh' ? '接口' : 'Endpoint' }} | {{ locale === 'zh' ? '期望' : 'Expected' }} | {{ locale === 'zh' ? '结果' : 'Result' }} | {{ locale === 'zh' ? '耗时' : 'Latency' }} | {{ locale === 'zh' ? '详情' : 'Detail' }} |
|---|---|---|---|---|---|
| {{ item.name }} |
{{ item.method }}
{{ endpointPath(item.url) }}
|
{{ item.expected }} | {{ item.status }} · {{ item.status_code || 0 }} | {{ fmtMs(item.elapsed_ms || 0) }} | {{ item.detail }} |
| {{ t('col.model') }} | {{ t('col.requests') }} | Tokens In | Tokens Out | {{ t('avgLatency') }} |
|---|---|---|---|---|
| {{ t('noData') }} | ||||
| {{ m.model }} | {{ m.requests }} | {{ formatNumber(m.tokens_in) }} | {{ formatNumber(m.tokens_out) }} | {{ fmtMs(m.avg_latency_ms) }} |
{{ locale === 'zh' ? '注册一台设备并在你的 Mac Studio 上运行安装命令,即可开始远程管理。' : 'Register a device and run the install command on your Mac Studio to get started.' }}
| {{ locale === 'zh' ? '名称' : 'Name' }} | {{ locale === 'zh' ? '状态' : 'Status' }} | {{ locale === 'zh' ? '版本' : 'Version' }} | {{ locale === 'zh' ? '租户 ID' : 'Tenant ID' }} | Token | {{ locale === 'zh' ? '最后连接' : 'Last Connected' }} | {{ locale === 'zh' ? '操作' : 'Actions' }} |
|---|---|---|---|---|---|---|
| {{ t.name }} | {{ t.effective_status === 'connected' ? (locale === 'zh' ? '在线' : 'Online') : t.effective_status === 'never_connected' ? (locale === 'zh' ? '从未连接' : 'Never Connected') : (locale === 'zh' ? '离线' : 'Offline') }} | {{ locale === 'zh' ? '需手动升级' : 'manual upgrade' }} {{ t.agent_version.slice(0,16) }} {{ locale === 'zh' ? '可更新' : 'update' }} {{ t.upgrade_status }} {{ locale === 'zh' ? '升级失败' : 'failed' }} — | {{ t.tenant_id }} |
{{ t.agent_token_prefix }}... |
{{ t.last_connected ? formatDate(t.last_connected) : '-' }} |
| {{ t('col.engine') }} | URL | {{ t('col.port') }} | {{ t('col.status') }} |
|---|---|---|---|
| Ollama | http://127.0.0.1:11435 | 11435 | {{ statusText(engineStatus('ollama')) }} |
| llama-server | http://127.0.0.1:8000 | 8000 | {{ statusText(engineStatus('llama-server')) }} |
| LiteLLM | http://127.0.0.1:4000 | 4000 | {{ statusText(engineStatus('litellm')) }} |
| Audio Server | http://127.0.0.1:8200 | 8200 | {{ statusText(engineStatus('audio-server')) }} |
| Mano-P Server | http://127.0.0.1:8300 | 8300 | {{ statusText(engineStatus('mano-server')) }} |
| Manager | http://127.0.0.1:8080 | 8080 | {{ statusText(managerLiveStatus) }} |
| {{ t('col.service') }} | URL |
|---|---|
| LiteLLM API | {{ publicBases.inference }} |
| Audio API | {{ publicBases.audio }} |
| {{ t('managerPanel') }} | {{ publicBases.manager }} |
| {{ locale === 'zh' ? '名称' : 'Name' }} | Key | {{ locale === 'zh' ? '创建时间' : 'Created' }} | {{ locale === 'zh' ? '最后使用' : 'Last Used' }} | {{ t('col.actions') }} |
|---|---|---|---|---|
| {{ k.name }} | {{ k.prefix }}... |
{{ formatDate(k.created) }} | {{ k.last_used ? formatDate(k.last_used) : '-' }} |
{{ locale === 'zh' ? 'Mac Studio AI Manager 是一个远程管理面板,通过 WSS (WebSocket Secure) 中继技术,让你在任何地方通过浏览器管理局域网内的 Mac Studio AI 推理服务。无需公网 IP,无需端口转发。' : 'Mac Studio AI Manager is a remote management panel that uses WSS (WebSocket Secure) relay technology to manage your LAN-based Mac Studio AI inference services from anywhere via a browser. No public IP or port forwarding required.' }}
| {{ locale === 'zh' ? '项目' : 'Item' }} | {{ locale === 'zh' ? '要求' : 'Requirement' }} |
|---|---|
| {{ locale === 'zh' ? '操作系统' : 'OS' }} | macOS 13+ |
| Python | 3.10+ |
| {{ locale === 'zh' ? '网络' : 'Network' }} | {{ locale === 'zh' ? '可访问外网(WSS 外连)' : 'Internet access (WSS outbound)' }} |
| {{ locale === 'zh' ? '推理引擎' : 'Inference Engine' }} | Ollama / llama-server / LiteLLM ({{ locale === 'zh' ? '至少一个' : 'at least one' }}) |
{{ locale === 'zh' ? '在「设备」页面点击「添加设备」,输入设备名称后系统会生成专属安装命令(包含 token 和 tenant-id)。' : 'Go to the "Devices" tab, click "Add Device", enter a name. The system generates an install command with your token and tenant-id.' }}
~/.mac-studio-agent/(含 Agent + Manager)~/.mac-studio-agent/ (Agent + Manager)| {{ locale === 'zh' ? '服务' : 'Service' }} | launchd Label | {{ locale === 'zh' ? '端口' : 'Port' }} | {{ locale === 'zh' ? '说明' : 'Description' }} |
|---|---|---|---|
| Manager | com.reai.mac-studio-manager | 8080 | {{ locale === 'zh' ? '管理 API 服务' : 'Management API service' }} |
| Agent | com.reai.mac-studio-agent | - | {{ locale === 'zh' ? 'WSS 隧道客户端' : 'WSS tunnel client' }} |
{{ locale === 'zh' ? '重复执行安装命令会自动升级:停止旧服务 → 更新代码 → 保留配置和数据 → 重启。无需先卸载。' : 'Re-running the install command auto-upgrades: stop old services → update code → keep config and data → restart. No need to uninstall first.' }}
{{ locale === 'zh' ? '停止 Manager + Agent 服务,删除程序文件,保留统计数据和日志。' : 'Stops Manager + Agent services, removes program files, keeps stats data and logs.' }}
{{ locale === 'zh' ? '在标准卸载基础上,额外删除统计数据库、状态文件和日志。' : 'In addition to standard uninstall, also removes stats database, state files, and logs.' }}
传统方案需要公网 IP 或 FRP 端口转发。WSS 中继采用了不同的方式:
Traditional setups require a public IP or FRP port forwarding. WSS relay takes a different approach:
| {{ locale === 'zh' ? '层级' : 'Layer' }} | {{ locale === 'zh' ? '机制' : 'Mechanism' }} |
|---|---|
| {{ locale === 'zh' ? '传输层' : 'Transport' }} | TLS/HTTPS + WSS ({{ locale === 'zh' ? '全链路加密' : 'end-to-end encrypted' }}) |
| {{ locale === 'zh' ? '用户认证' : 'User Auth' }} | OAuth 2.0 PKCE ({{ locale === 'zh' ? '外脑登录' : 'external provider' }}) |
| {{ locale === 'zh' ? '设备认证' : 'Device Auth' }} | Per-tenant Agent Token ({{ locale === 'zh' ? '哈希存储' : 'hashed storage' }}) |
| API {{ locale === 'zh' ? '认证' : 'Auth' }} | API Key ({{ locale === 'zh' ? '绑定租户' : 'tenant-bound' }}) |
| {{ locale === 'zh' ? '本地引擎' : 'Local Engines' }} | {{ locale === 'zh' ? '仅监听 127.0.0.1,不暴露外网' : 'Listen on 127.0.0.1 only, not exposed' }} |
{{ locale === 'zh' ? '需要 Python 3.10+,当前版本 3.9' : 'Requires Python 3.10+, current version 3.9' }}brew install python@3.12curl: (22) The requested URL returned error: 404tail -f ~/Library/Logs/mac-studio-agent.err.log{{ locale === 'zh' ? '推理 API 和 Audio API 共用同一套 Key,支持两种认证方式:' : 'Inference API and Audio API share the same key and support two auth methods:' }}
| {{ locale === 'zh' ? '端点' : 'Endpoint' }} | {{ locale === 'zh' ? '说明' : 'Description' }} |
|---|---|
GET /v1/models | {{ locale === 'zh' ? '列出可用模型' : 'List available models' }} |
POST /v1/chat/completions | {{ locale === 'zh' ? '对话补全(支持流式)' : 'Chat completion (supports streaming)' }} |
POST /v1/messages | {{ locale === 'zh' ? 'Anthropic Messages / Claude Messaging 兼容对话(支持流式)' : 'Anthropic Messages / Claude Messaging-compatible chat (supports streaming)' }} |
{{ locale === 'zh' ? 'Audio API 公网入口暴露 /v1/files 和 /v1/audio/transcriptions;ASR 模型列表在管理面板的 Audio API 路由中查看。POST /v1/audio/transcriptions 中 model 可选,省略时使用当前 active ASR。' : 'The public Audio API exposes /v1/files and /v1/audio/transcriptions. ASR model routes are listed in the Manager Audio API routes. In POST /v1/audio/transcriptions, model is optional and falls back to the active ASR.' }}
| {{ locale === 'zh' ? '端点' : 'Endpoint' }} | {{ locale === 'zh' ? '说明' : 'Description' }} |
|---|---|
GET /v1/files | {{ locale === 'zh' ? '列出已上传文件' : 'List uploaded files' }} |
POST /v1/files | {{ locale === 'zh' ? '上传音频文件,返回 file_id' : 'Upload an audio file and return file_id' }} |
POST /v1/audio/transcriptions | {{ locale === 'zh' ? '音频转文字;model 可省略,命中当前 active ASR' : 'Audio transcription; model is optional and uses the current active ASR' }} |