mirror of
https://wget.la/https://github.com/leookun/cursor-byok
synced 2026-08-17 03:27:02 +08:00
Enhance README and UI components with improved user guidance and account identifier masking
- Updated README.md to provide clearer project information, features, and quick start instructions. - Added a function to mask the user's account identifier in CursorAccountCard.vue for enhanced privacy. - Adjusted localization files to remove outdated entries and improve clarity across multiple languages. - Refactored MainLayout.vue to streamline author information handling and improve user experience.
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
<div align="center">
|
||||
|
||||
# cursor-byok
|
||||
|
||||
[使用教程](https://docs.leokun.cn) · [下载最新版](https://github.com/leookun/cursor-byok/releases/latest) · [问题反馈](https://github.com/leookun/cursor-byok/issues) · [English](./README.md)
|
||||
|
||||
[](https://github.com/leookun/cursor-byok/releases/latest)
|
||||
[](https://github.com/leookun/cursor-byok/releases)
|
||||
[](./LICENSE)
|
||||
[](https://github.com/leookun/cursor-byok/releases/latest)
|
||||
|
||||
</div>
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
## 项目介绍
|
||||
|
||||
cursor-byok 是一个开源的 Cursor 本地模型接入工具。它通过运行在本机的服务连接 Cursor 与你配置的模型 API,让模型请求使用自己的渠道处理,同时保留 Cursor Agent 的工具调用、Skills 和 MCP 等能力。
|
||||
|
||||
你可以接入 OpenAI、Anthropic 及其兼容服务,自由配置接口地址、模型、密钥和请求参数,不再局限于平台预设的模型渠道。
|
||||
|
||||
> [!IMPORTANT]
|
||||
> cursor-byok 本身免费开源,但你接入的模型 API 可能由对应服务商收费。本项目不是 Cursor 官方产品,与 Cursor 或其开发公司无隶属关系。
|
||||
|
||||
## 核心能力
|
||||
|
||||
- **自定义模型渠道**:配置自己的 API 地址、访问密钥和模型标识。
|
||||
- **多种接口协议**:支持 OpenAI、Anthropic 兼容接口及自定义端点。
|
||||
- **模型管理**:添加、复制、编辑、排序和批量测试多个模型配置。
|
||||
- **连接性能测试**:查看首字延迟、生成速度与模型服务的原始响应。
|
||||
- **Agent 工作流**:支持工具调用、Skills、MCP 和多轮会话。
|
||||
- **会话统计**:查看 Token 消耗、缓存命中率、对话轮次和价值估算。
|
||||
- **跨平台运行**:支持 macOS、Windows 和 Linux。
|
||||
|
||||
## 快速开始
|
||||
|
||||
1. 从 [GitHub Releases](https://github.com/leookun/cursor-byok/releases/latest) 下载对应平台的最新版本。
|
||||
2. 启动 cursor-byok,打开“模型配置”,填写接口地址、API Key 和模型标识。
|
||||
3. 测试模型配置;测试通过后返回主界面启动服务。
|
||||
4. 打开 Cursor,选择已配置的模型并开始使用 Agent。
|
||||
|
||||
更完整的安装、系统配置和常见问题说明,请查看 [详细使用教程](https://docs.leokun.cn)。
|
||||
|
||||
## 模型管理
|
||||
|
||||
模型配置支持 OpenAI 与 Anthropic 两类接口协议。每个模型渠道可以独立设置上下文窗口、最大输出 Token、推理强度、自定义请求头和额外请求参数。
|
||||
|
||||

|
||||
|
||||
## 工作原理
|
||||
|
||||
```text
|
||||
Cursor 客户端
|
||||
│
|
||||
│ Agent 请求与工具结果
|
||||
▼
|
||||
cursor-byok 本地服务
|
||||
│
|
||||
│ OpenAI / Anthropic 兼容请求
|
||||
▼
|
||||
你配置的模型 API
|
||||
```
|
||||
|
||||
cursor-byok 在本机负责协议适配、模型请求转发、工具调用衔接与会话状态管理。模型 API Key 和应用配置保存在本机;实际请求仍会发送到你所配置的模型服务商。
|
||||
|
||||
## 为什么做这个项目
|
||||
|
||||
很多 Agent 产品会将工具能力、模型选择、订阅方案和计费方式绑定在一起,用户只能使用平台提供的模型渠道。
|
||||
|
||||
我希望将模型选择权交还给用户:开发者可以充分利用已有的模型 API 和额度,自由选择适合自己的模型与服务商,也可以在需要时自托管相关服务。
|
||||
|
||||
## 路线图
|
||||
|
||||
项目将继续改进模型兼容性、Agent 工具链、本地运行稳定性和自托管体验,并探索更多 IDE、Chat 与 Agent 场景。
|
||||
|
||||
详细计划与进展请查看 [正式版路线图](https://github.com/leookun/cursor-byok/discussions/32)。
|
||||
|
||||
## 社区与支持
|
||||
|
||||
- [使用教程](https://docs.leokun.cn)
|
||||
- [GitHub Issues](https://github.com/leookun/cursor-byok/issues)
|
||||
- [Telegram 交流群](https://t.me/cursor_byok)
|
||||
- QQ 交流群:`1095916242`、`1094411438`、`1095918002`、`1094419321`
|
||||
|
||||
<a href="https://trendshift.io/repositories/39260?utm_source=repository-badge&utm_medium=badge&utm_campaign=badge-repository-39260" target="_blank" rel="noopener noreferrer"><img src="https://trendshift.io/api/badge/repositories/39260" alt="leookun/cursor-byok | Trendshift" width="250" height="55" /></a>
|
||||
|
||||
## 开发与贡献
|
||||
|
||||
欢迎提交 Issue 和 Pull Request。开发环境、构建命令、项目结构及提交规范请阅读 [贡献指南](./CONTRIBUTING.md)。
|
||||
|
||||
## 许可证
|
||||
|
||||
本项目基于 [MIT License](./LICENSE) 开源。
|
||||
@@ -1,39 +1,95 @@
|
||||
<img width="820" alt="image" src="https://github.com/user-attachments/assets/2e1710b0-cdbd-4576-bd24-1614df016219" />
|
||||
<div align="center">
|
||||
|
||||
<img width="820" alt="image" src="https://github.com/user-attachments/assets/00885453-6a91-4052-aadf-f686daeec881" />
|
||||
# cursor-byok
|
||||
|
||||
<img width="820" alt="image" src="https://github.com/user-attachments/assets/a607be84-a738-4e33-9750-13352e74001c" />
|
||||
[User Guide](https://docs.leokun.cn) · [Latest Release](https://github.com/leookun/cursor-byok/releases/latest) · [Report an Issue](https://github.com/leookun/cursor-byok/issues) · [简体中文](./README-CN.md)
|
||||
|
||||
[](https://github.com/leookun/cursor-byok/releases/latest)
|
||||
[](https://github.com/leookun/cursor-byok/releases)
|
||||
[](./LICENSE)
|
||||
[](https://github.com/leookun/cursor-byok/releases/latest)
|
||||
|
||||
## 交流群组
|
||||
https://t.me/cursor_byok
|
||||
</div>
|
||||
|
||||

|
||||
|
||||
## 为什么做这个项目
|
||||

|
||||
|
||||
公司喜欢把 Agent 服务与模型绑定在一起,让用户只能在指定模型、指定订阅和指定计费方式下使用工具。
|
||||
## About
|
||||
|
||||
我希望打破这种绑定关系:模型应该可以自由选择。开发者应该能够把自己的模型 API 接入到任何 IDE、Chat、Agent 或开发工具中,也可以自托管整套服务,避免被单一平台锁定。
|
||||
cursor-byok is an open-source local model gateway for Cursor. It runs a service on your machine that connects Cursor to the model APIs you configure, routes model requests through your own providers, and preserves Cursor Agent capabilities such as tool calling, Skills, and MCP.
|
||||
|
||||
这个项目的目标,是让模型选择权重新回到用户手里。
|
||||
You can connect OpenAI- and Anthropic-compatible services, customize endpoints, model IDs, API keys, and request parameters, and use model channels beyond the options built into the platform.
|
||||
|
||||
## 路线图
|
||||
> [!IMPORTANT]
|
||||
> cursor-byok is free and open source, but the model APIs you connect may charge for usage. This is an independent project and is not affiliated with or endorsed by Cursor or its developers.
|
||||
|
||||
[正式版路线图](https://github.com/leookun/cursor-byok/discussions/32)
|
||||
[详细使用教程](https://docs.leokun.cn)
|
||||
## Features
|
||||
|
||||
## 后续
|
||||
- **Bring your own model channels:** Configure your own API endpoint, credentials, and model IDs.
|
||||
- **Multiple API protocols:** Use OpenAI- and Anthropic-compatible APIs or a custom endpoint.
|
||||
- **Model management:** Add, duplicate, edit, reorder, and batch-test multiple model configurations.
|
||||
- **Connection benchmarks:** Measure time to first token, generation speed, and inspect raw provider responses.
|
||||
- **Agent workflows:** Keep tool calling, Skills, MCP, and multi-turn conversations available.
|
||||
- **Session metrics:** Track token usage, cache hit rate, conversation turns, and estimated value.
|
||||
- **Cross-platform:** Run on macOS, Windows, and Linux.
|
||||
|
||||
后续会继续扩展更多工具和使用场景,包括但不限于:
|
||||
## Quick Start
|
||||
|
||||
- 支持更多 IDE 接入
|
||||
- 支持更多 Chat 类应用
|
||||
- 支持更多 Agent 工具和工作流
|
||||
- 提供更完善的自托管部署方式
|
||||
- 持续优化不同模型 API 的兼容性
|
||||
- 降低接入成本,让已有模型额度可以被更充分地利用
|
||||
1. Download the latest build for your platform from [GitHub Releases](https://github.com/leookun/cursor-byok/releases/latest).
|
||||
2. Launch cursor-byok, open **Model Settings**, and enter the endpoint, API key, and model ID.
|
||||
3. Test the model configuration. Once it passes, return to the dashboard and start the service.
|
||||
4. Open Cursor, select the configured model, and start using Agent.
|
||||
|
||||
最终希望做到:让你的模型 API 可以自由接入到你想使用的任何工具中。
|
||||
For complete installation steps, system configuration, and troubleshooting, see the [User Guide](https://docs.leokun.cn).
|
||||
|
||||
## Model Management
|
||||
|
||||
Model configurations support both OpenAI and Anthropic API protocols. Each model channel can independently define its context window, maximum output tokens, reasoning effort, custom headers, and additional request parameters.
|
||||
|
||||

|
||||
|
||||
## How It Works
|
||||
|
||||
```text
|
||||
Cursor client
|
||||
│
|
||||
│ Agent requests and tool results
|
||||
▼
|
||||
cursor-byok local service
|
||||
│
|
||||
│ OpenAI- / Anthropic-compatible requests
|
||||
▼
|
||||
Your model API
|
||||
```
|
||||
|
||||
cursor-byok handles protocol adaptation, model request forwarding, tool-call coordination, and conversation state on your machine. API keys and application settings are stored locally; requests are still sent to the model provider you configure.
|
||||
|
||||
## Why This Project
|
||||
|
||||
Many Agent products bundle their tool capabilities with a fixed set of models, subscriptions, and billing options, leaving users limited to the channels offered by the platform.
|
||||
|
||||
cursor-byok is built to return model choice to the user. Developers can make full use of the APIs and credits they already have, choose the models and providers that fit their needs, and self-host related services when required.
|
||||
|
||||
## Roadmap
|
||||
|
||||
The project will continue to improve model compatibility, Agent tooling, local runtime stability, and the self-hosting experience while exploring support for more IDE, chat, and Agent workflows.
|
||||
|
||||
See the [release roadmap](https://github.com/leookun/cursor-byok/discussions/32) for plans and progress.
|
||||
|
||||
## Community and Support
|
||||
|
||||
- [User Guide](https://docs.leokun.cn)
|
||||
- [GitHub Issues](https://github.com/leookun/cursor-byok/issues)
|
||||
- [Telegram community](https://t.me/cursor_byok)
|
||||
- QQ groups: `1095916242`, `1094411438`, `1095918002`, `1094419321`
|
||||
|
||||
<a href="https://trendshift.io/repositories/39260?utm_source=repository-badge&utm_medium=badge&utm_campaign=badge-repository-39260" target="_blank" rel="noopener noreferrer"><img src="https://trendshift.io/api/badge/repositories/39260" alt="leookun/cursor-byok | Trendshift" width="250" height="55" /></a>
|
||||
|
||||
## Development and Contributing
|
||||
|
||||
Issues and pull requests are welcome. See the [Contributing Guide](./CONTRIBUTING_EN.md) for prerequisites, build commands, project structure, and contribution guidelines.
|
||||
|
||||
## License
|
||||
|
||||
This project is open source under the [MIT License](./LICENSE).
|
||||
|
||||
@@ -25,12 +25,36 @@ const cursorAccountStatus = ref({
|
||||
const cursorAccountBusy = ref(false);
|
||||
let cursorAccountTimer = null;
|
||||
|
||||
function maskCursorAccountIdentifier(value) {
|
||||
const identifier = String(value || "").trim();
|
||||
if (!identifier) return "";
|
||||
|
||||
const atIndex = identifier.indexOf("@");
|
||||
if (atIndex > 0 && atIndex < identifier.length - 1) {
|
||||
const localPart = identifier.slice(0, atIndex);
|
||||
const domain = identifier.slice(atIndex + 1);
|
||||
const maskedLocalPart = localPart.length <= 2
|
||||
? `${localPart[0]}***`
|
||||
: `${localPart[0]}***${localPart.at(-1)}`;
|
||||
return `${maskedLocalPart}@${domain}`;
|
||||
}
|
||||
|
||||
if (identifier.length <= 8) return "****";
|
||||
return `${identifier.slice(0, 4)}****${identifier.slice(-4)}`;
|
||||
}
|
||||
|
||||
const cursorAccountSignedIn = computed(
|
||||
() => cursorAccountStatus.value.state === "signed_in",
|
||||
);
|
||||
const cursorAccountWaiting = computed(
|
||||
() => cursorAccountStatus.value.state === "waiting",
|
||||
);
|
||||
const cursorAccountDisplayIdentifier = computed(() => {
|
||||
if (!cursorAccountSignedIn.value) return "";
|
||||
return maskCursorAccountIdentifier(
|
||||
cursorAccountStatus.value.email || cursorAccountStatus.value.authId,
|
||||
);
|
||||
});
|
||||
const cursorAccountStateText = computed(() => {
|
||||
if (cursorAccountSignedIn.value) return "已经登录";
|
||||
if (cursorAccountWaiting.value) return "等待浏览器登录";
|
||||
@@ -137,10 +161,10 @@ onUnmounted(() => {
|
||||
<div class="flex items-end justify-between gap-4">
|
||||
<div class="min-w-0">
|
||||
<div
|
||||
v-if="cursorAccountSignedIn && (cursorAccountStatus.email || cursorAccountStatus.authId)"
|
||||
v-if="cursorAccountDisplayIdentifier"
|
||||
class="truncate text-sm text-[#d0d0d0]"
|
||||
>
|
||||
{{ cursorAccountStatus.email || cursorAccountStatus.authId }}
|
||||
{{ cursorAccountDisplayIdentifier }}
|
||||
</div>
|
||||
<div class="mt-1 text-sm text-[#a3a3a3]">
|
||||
独立用于插件、Skills 和 MCP;不会改变 Cursor 客户端当前账号
|
||||
|
||||
@@ -108,12 +108,12 @@
|
||||
"refs": [
|
||||
{
|
||||
"file": "src/layouts/MainLayout.vue",
|
||||
"line": 111,
|
||||
"line": 88,
|
||||
"column": 34
|
||||
},
|
||||
{
|
||||
"file": "src/layouts/MainLayout.vue",
|
||||
"line": 111,
|
||||
"line": 88,
|
||||
"column": 52
|
||||
}
|
||||
]
|
||||
@@ -130,18 +130,6 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"0dde813d719dbd01": {
|
||||
"source": "打开主页失败",
|
||||
"kind": "text",
|
||||
"placeholders": 0,
|
||||
"refs": [
|
||||
{
|
||||
"file": "src/layouts/MainLayout.vue",
|
||||
"line": 132,
|
||||
"column": 21
|
||||
}
|
||||
]
|
||||
},
|
||||
"1117a2f86030d03b": {
|
||||
"source": "缓存读写已计入 Prompt 侧统计。",
|
||||
"kind": "text",
|
||||
@@ -245,7 +233,7 @@
|
||||
"refs": [
|
||||
{
|
||||
"file": "src/layouts/MainLayout.vue",
|
||||
"line": 55,
|
||||
"line": 40,
|
||||
"column": 9
|
||||
}
|
||||
]
|
||||
@@ -269,7 +257,7 @@
|
||||
"refs": [
|
||||
{
|
||||
"file": "src/components/CursorAccountCard.vue",
|
||||
"line": 173,
|
||||
"line": 197,
|
||||
"column": 14
|
||||
}
|
||||
]
|
||||
@@ -383,18 +371,6 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"2a24519398684ed5": {
|
||||
"source": "访问主页",
|
||||
"kind": "text",
|
||||
"placeholders": 0,
|
||||
"refs": [
|
||||
{
|
||||
"file": "src/layouts/MainLayout.vue",
|
||||
"line": 35,
|
||||
"column": 24
|
||||
}
|
||||
]
|
||||
},
|
||||
"2cd0f3be8738a86c": {
|
||||
"source": "取消",
|
||||
"kind": "text",
|
||||
@@ -402,7 +378,7 @@
|
||||
"refs": [
|
||||
{
|
||||
"file": "src/components/CursorAccountCard.vue",
|
||||
"line": 74,
|
||||
"line": 98,
|
||||
"column": 17
|
||||
},
|
||||
{
|
||||
@@ -519,7 +495,7 @@
|
||||
"refs": [
|
||||
{
|
||||
"file": "src/layouts/MainLayout.vue",
|
||||
"line": 140,
|
||||
"line": 104,
|
||||
"column": 21
|
||||
}
|
||||
]
|
||||
@@ -560,18 +536,6 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"358f07b2c1445ab1": {
|
||||
"source": "作者寄语",
|
||||
"kind": "text",
|
||||
"placeholders": 0,
|
||||
"refs": [
|
||||
{
|
||||
"file": "src/layouts/MainLayout.vue",
|
||||
"line": 33,
|
||||
"column": 18
|
||||
}
|
||||
]
|
||||
},
|
||||
"37d23612f78a2e63": {
|
||||
"source": "立即重启更新",
|
||||
"kind": "text",
|
||||
@@ -630,17 +594,17 @@
|
||||
"refs": [
|
||||
{
|
||||
"file": "src/components/CursorAccountCard.vue",
|
||||
"line": 71,
|
||||
"line": 95,
|
||||
"column": 12
|
||||
},
|
||||
{
|
||||
"file": "src/components/CursorAccountCard.vue",
|
||||
"line": 73,
|
||||
"line": 97,
|
||||
"column": 18
|
||||
},
|
||||
{
|
||||
"file": "src/components/CursorAccountCard.vue",
|
||||
"line": 164,
|
||||
"line": 188,
|
||||
"column": 1
|
||||
}
|
||||
]
|
||||
@@ -681,7 +645,7 @@
|
||||
},
|
||||
{
|
||||
"file": "src/layouts/MainLayout.vue",
|
||||
"line": 261,
|
||||
"line": 223,
|
||||
"column": 11
|
||||
},
|
||||
{
|
||||
@@ -698,7 +662,7 @@
|
||||
"refs": [
|
||||
{
|
||||
"file": "src/components/CursorAccountCard.vue",
|
||||
"line": 37,
|
||||
"line": 61,
|
||||
"column": 10
|
||||
}
|
||||
]
|
||||
@@ -736,11 +700,6 @@
|
||||
"file": "src/components/ui/ContentModal.vue",
|
||||
"line": 125,
|
||||
"column": 15
|
||||
},
|
||||
{
|
||||
"file": "src/layouts/MainLayout.vue",
|
||||
"line": 36,
|
||||
"column": 23
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -883,7 +842,7 @@
|
||||
"refs": [
|
||||
{
|
||||
"file": "src/layouts/MainLayout.vue",
|
||||
"line": 60,
|
||||
"line": 45,
|
||||
"column": 9
|
||||
}
|
||||
]
|
||||
@@ -941,7 +900,7 @@
|
||||
"refs": [
|
||||
{
|
||||
"file": "src/components/CursorAccountCard.vue",
|
||||
"line": 49,
|
||||
"line": 73,
|
||||
"column": 21
|
||||
}
|
||||
]
|
||||
@@ -953,7 +912,7 @@
|
||||
"refs": [
|
||||
{
|
||||
"file": "src/layouts/MainLayout.vue",
|
||||
"line": 24,
|
||||
"line": 19,
|
||||
"column": 50
|
||||
},
|
||||
{
|
||||
@@ -1030,7 +989,7 @@
|
||||
"refs": [
|
||||
{
|
||||
"file": "src/layouts/MainLayout.vue",
|
||||
"line": 59,
|
||||
"line": 44,
|
||||
"column": 9
|
||||
}
|
||||
]
|
||||
@@ -1194,7 +1153,7 @@
|
||||
"refs": [
|
||||
{
|
||||
"file": "src/components/CursorAccountCard.vue",
|
||||
"line": 173,
|
||||
"line": 197,
|
||||
"column": 14
|
||||
}
|
||||
]
|
||||
@@ -1235,12 +1194,12 @@
|
||||
"refs": [
|
||||
{
|
||||
"file": "src/components/CursorAccountCard.vue",
|
||||
"line": 41,
|
||||
"line": 65,
|
||||
"column": 34
|
||||
},
|
||||
{
|
||||
"file": "src/components/CursorAccountCard.vue",
|
||||
"line": 41,
|
||||
"line": 65,
|
||||
"column": 52
|
||||
},
|
||||
{
|
||||
@@ -1480,7 +1439,7 @@
|
||||
"refs": [
|
||||
{
|
||||
"file": "src/layouts/MainLayout.vue",
|
||||
"line": 220,
|
||||
"line": 183,
|
||||
"column": 15
|
||||
},
|
||||
{
|
||||
@@ -1557,7 +1516,7 @@
|
||||
"refs": [
|
||||
{
|
||||
"file": "src/components/CursorAccountCard.vue",
|
||||
"line": 111,
|
||||
"line": 135,
|
||||
"column": 56
|
||||
}
|
||||
]
|
||||
@@ -1779,18 +1738,6 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"93faf55cd25c8319": {
|
||||
"source": "本软件是纯免费软件,如果你被收费,那大概率就是被骗了。\n欢迎点击访问作者主页 https://space.bilibili.com/311706663/upload/video\n查看更多更新动态、使用分享和后续内容。",
|
||||
"kind": "text",
|
||||
"placeholders": 0,
|
||||
"refs": [
|
||||
{
|
||||
"file": "src/layouts/MainLayout.vue",
|
||||
"line": 34,
|
||||
"column": 20
|
||||
}
|
||||
]
|
||||
},
|
||||
"942ff2d88baca0c6": {
|
||||
"source": "检查更新中...",
|
||||
"kind": "text",
|
||||
@@ -1798,7 +1745,7 @@
|
||||
"refs": [
|
||||
{
|
||||
"file": "src/layouts/MainLayout.vue",
|
||||
"line": 92,
|
||||
"line": 77,
|
||||
"column": 36
|
||||
}
|
||||
]
|
||||
@@ -2122,18 +2069,6 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"ab607d54d86dc789": {
|
||||
"source": "作者 leookun",
|
||||
"kind": "text",
|
||||
"placeholders": 0,
|
||||
"refs": [
|
||||
{
|
||||
"file": "src/layouts/MainLayout.vue",
|
||||
"line": 32,
|
||||
"column": 17
|
||||
}
|
||||
]
|
||||
},
|
||||
"ac217e4d1ca410f1": {
|
||||
"source": "发现新版本",
|
||||
"kind": "text",
|
||||
@@ -2324,7 +2259,7 @@
|
||||
"refs": [
|
||||
{
|
||||
"file": "src/layouts/MainLayout.vue",
|
||||
"line": 47,
|
||||
"line": 32,
|
||||
"column": 12
|
||||
}
|
||||
]
|
||||
@@ -2384,7 +2319,7 @@
|
||||
"refs": [
|
||||
{
|
||||
"file": "src/layouts/MainLayout.vue",
|
||||
"line": 63,
|
||||
"line": 48,
|
||||
"column": 12
|
||||
}
|
||||
]
|
||||
@@ -2425,7 +2360,7 @@
|
||||
"refs": [
|
||||
{
|
||||
"file": "src/components/CursorAccountCard.vue",
|
||||
"line": 72,
|
||||
"line": 96,
|
||||
"column": 14
|
||||
}
|
||||
]
|
||||
@@ -2473,7 +2408,7 @@
|
||||
"refs": [
|
||||
{
|
||||
"file": "src/components/CursorAccountCard.vue",
|
||||
"line": 83,
|
||||
"line": 107,
|
||||
"column": 21
|
||||
}
|
||||
]
|
||||
@@ -2579,7 +2514,7 @@
|
||||
"refs": [
|
||||
{
|
||||
"file": "src/components/CursorAccountCard.vue",
|
||||
"line": 36,
|
||||
"line": 60,
|
||||
"column": 42
|
||||
}
|
||||
]
|
||||
@@ -2596,18 +2531,6 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"d1bde4a4e057b2c7": {
|
||||
"source": "[MainLayout] 加载作者信息失败",
|
||||
"kind": "text",
|
||||
"placeholders": 0,
|
||||
"refs": [
|
||||
{
|
||||
"file": "src/layouts/MainLayout.vue",
|
||||
"line": 106,
|
||||
"column": 19
|
||||
}
|
||||
]
|
||||
},
|
||||
"d20ab96566d33f25": {
|
||||
"source": "{0} 的显示名称不能为空",
|
||||
"kind": "template",
|
||||
@@ -2702,7 +2625,7 @@
|
||||
"refs": [
|
||||
{
|
||||
"file": "src/components/CursorAccountCard.vue",
|
||||
"line": 146,
|
||||
"line": 170,
|
||||
"column": 1
|
||||
}
|
||||
]
|
||||
@@ -2878,7 +2801,7 @@
|
||||
"refs": [
|
||||
{
|
||||
"file": "src/components/CursorAccountCard.vue",
|
||||
"line": 62,
|
||||
"line": 86,
|
||||
"column": 21
|
||||
}
|
||||
]
|
||||
@@ -2890,7 +2813,7 @@
|
||||
"refs": [
|
||||
{
|
||||
"file": "src/components/CursorAccountCard.vue",
|
||||
"line": 122,
|
||||
"line": 146,
|
||||
"column": 20
|
||||
}
|
||||
]
|
||||
@@ -2902,7 +2825,7 @@
|
||||
"refs": [
|
||||
{
|
||||
"file": "src/components/CursorAccountCard.vue",
|
||||
"line": 149,
|
||||
"line": 173,
|
||||
"column": 1
|
||||
}
|
||||
]
|
||||
@@ -2938,7 +2861,7 @@
|
||||
"refs": [
|
||||
{
|
||||
"file": "src/components/CursorAccountCard.vue",
|
||||
"line": 35,
|
||||
"line": 59,
|
||||
"column": 43
|
||||
}
|
||||
]
|
||||
@@ -2998,7 +2921,7 @@
|
||||
"refs": [
|
||||
{
|
||||
"file": "src/layouts/MainLayout.vue",
|
||||
"line": 54,
|
||||
"line": 39,
|
||||
"column": 9
|
||||
}
|
||||
]
|
||||
@@ -3119,6 +3042,18 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"f526ab6eff33039a": {
|
||||
"source": "打开作者地址失败",
|
||||
"kind": "text",
|
||||
"placeholders": 0,
|
||||
"refs": [
|
||||
{
|
||||
"file": "src/layouts/MainLayout.vue",
|
||||
"line": 96,
|
||||
"column": 21
|
||||
}
|
||||
]
|
||||
},
|
||||
"f56c6c82203b33f6": {
|
||||
"source": "提示",
|
||||
"kind": "text",
|
||||
@@ -3180,7 +3115,7 @@
|
||||
"refs": [
|
||||
{
|
||||
"file": "src/layouts/MainLayout.vue",
|
||||
"line": 65,
|
||||
"line": 50,
|
||||
"column": 10
|
||||
}
|
||||
]
|
||||
@@ -3236,7 +3171,7 @@
|
||||
"refs": [
|
||||
{
|
||||
"file": "src/layouts/MainLayout.vue",
|
||||
"line": 228,
|
||||
"line": 191,
|
||||
"column": 15
|
||||
}
|
||||
]
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
"0b0e7478e41fe677": "{0} tooltip text cannot be empty",
|
||||
"0c3b4cf7aa259edb": "Operation failed",
|
||||
"0d6b7efd5ccefd8a": "You can configure model channels. Runtime logs are stored in",
|
||||
"0dde813d719dbd01": "Failed to open homepage",
|
||||
"1117a2f86030d03b": "Cache reads and writes are included in Prompt-side statistics.",
|
||||
"11afd2a534395b18": "Valid",
|
||||
"124be3f86f197802": "Token Usage",
|
||||
@@ -28,7 +27,6 @@
|
||||
"26a3855aed1d8d17": "Service not running",
|
||||
"281eb6d08c9960d0": "{0} thinking budget token must be a positive integer",
|
||||
"28aeffc70ceb4267": "Change the display language for this interface. The setting takes effect immediately and is saved on this device.",
|
||||
"2a24519398684ed5": "Visit Homepage",
|
||||
"2cd0f3be8738a86c": "Cancel",
|
||||
"2d706f7981b45a7b": "Local settings saved",
|
||||
"2f9daa828907b93f": "Delete",
|
||||
@@ -39,7 +37,6 @@
|
||||
"3463c5585c246df9": "Total: {0}",
|
||||
"3468b57e3edbc599": "Aggregated from turn summaries scanned from the history.",
|
||||
"35076178fe79a210": "Configuration changed. Please test again.",
|
||||
"358f07b2c1445ab1": "Author's Message",
|
||||
"37d23612f78a2e63": "Restart Now to Update",
|
||||
"392d0dceb45998d3": "Extreme",
|
||||
"393df9bb13ea4900": "Hit",
|
||||
@@ -126,7 +123,6 @@
|
||||
"9196835e388d2550": "Test All",
|
||||
"91cba5c107a51892": "/ Invalid",
|
||||
"93e08803675e378b": "Model ID",
|
||||
"93faf55cd25c8319": "This software is completely free. If you were charged, you were likely scammed.\nWelcome to visit the author's homepage at https://space.bilibili.com/311706663/upload/video\nto see more updates, sharing guides, and future content.",
|
||||
"942ff2d88baca0c6": "Checking for updates...",
|
||||
"970388573a3c88c9": "Cache Read: {0} × ${1}/1M = {2}",
|
||||
"9730c15f3c1963a1": "Max",
|
||||
@@ -150,7 +146,6 @@
|
||||
"a693d69af48bfe48": "Save and Test",
|
||||
"a98585871c5313ff": "Display Name",
|
||||
"aa9e366f68d3d097": "Low",
|
||||
"ab607d54d86dc789": "Author leookun",
|
||||
"ac217e4d1ca410f1": "New version available",
|
||||
"ad79540418be700a": "Open the settings folder, or manage model settings separately",
|
||||
"ae5a738238463a92": "Hide API Key",
|
||||
@@ -187,7 +182,6 @@
|
||||
"cd7ca5fb221e1c53": "{0} cannot be empty",
|
||||
"cfa6c803eb3fc713": "Waiting for browser login",
|
||||
"d0325067fed88e5a": "Cache hit rate {0}",
|
||||
"d1bde4a4e057b2c7": "[MainLayout] Failed to load author info",
|
||||
"d20ab96566d33f25": "{0} display name cannot be empty",
|
||||
"d2243e1d44b2a94e": "Edit Model Settings",
|
||||
"d3209b935ae86797": "Model settings not found; cannot delete",
|
||||
@@ -226,6 +220,7 @@
|
||||
"f3fae6cccb9004b1": "Custom header name cannot be empty",
|
||||
"f474a4108aba4c4c": "Stop Service",
|
||||
"f4f0ead1116b5b62": "Enable",
|
||||
"f526ab6eff33039a": "Failed to open author page",
|
||||
"f56c6c82203b33f6": "Notice",
|
||||
"f61e03f047b786d5": "{0} max output tokens must be a positive integer",
|
||||
"f6e1c8b1a6970db5": "Current outbound requests do not use system proxy",
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
"0b0e7478e41fe677": "{0} のツールチップは必須です",
|
||||
"0c3b4cf7aa259edb": "操作に失敗しました",
|
||||
"0d6b7efd5ccefd8a": "モデルチャネルを設定できます。実行ログは次にあります",
|
||||
"0dde813d719dbd01": "ホームページを開けませんでした",
|
||||
"1117a2f86030d03b": "キャッシュの読み書きは Prompt 側の統計に含まれます。",
|
||||
"11afd2a534395b18": "有効",
|
||||
"124be3f86f197802": "Token 使用量",
|
||||
@@ -28,7 +27,6 @@
|
||||
"26a3855aed1d8d17": "サービスは起動していません",
|
||||
"281eb6d08c9960d0": "{0} の思考予算 Token は正の整数である必要があります",
|
||||
"28aeffc70ceb4267": "この画面の表示言語を切り替えます。設定はすぐに反映され、この端末に保存されます",
|
||||
"2a24519398684ed5": "ホームページへ",
|
||||
"2cd0f3be8738a86c": "キャンセル",
|
||||
"2d706f7981b45a7b": "ローカル設定を保存しました",
|
||||
"2f9daa828907b93f": "削除",
|
||||
@@ -39,7 +37,6 @@
|
||||
"3463c5585c246df9": "合計:{0}",
|
||||
"3468b57e3edbc599": "履歴からスキャンした各ターンの summary を集計しています。",
|
||||
"35076178fe79a210": "設定が変更されました。再テストしてください",
|
||||
"358f07b2c1445ab1": "著者からのメッセージ",
|
||||
"37d23612f78a2e63": "今すぐ再起動して更新",
|
||||
"392d0dceb45998d3": "最高",
|
||||
"393df9bb13ea4900": "ヒット",
|
||||
@@ -126,7 +123,6 @@
|
||||
"9196835e388d2550": "すべてテスト",
|
||||
"91cba5c107a51892": "/ 異常",
|
||||
"93e08803675e378b": "モデルID",
|
||||
"93faf55cd25c8319": "このソフトウェアは完全に無料です。もし料金を請求された場合は、詐欺の可能性が高いです。\n著者のホームページ https://space.bilibili.com/311706663/upload/video にアクセスして、更新情報や利用方法などを確認してください。",
|
||||
"942ff2d88baca0c6": "アップデートを確認中...",
|
||||
"970388573a3c88c9": "キャッシュ読み取り:{0} × ${1}/1M = {2}",
|
||||
"9730c15f3c1963a1": "最大",
|
||||
@@ -150,7 +146,6 @@
|
||||
"a693d69af48bfe48": "保存してテスト",
|
||||
"a98585871c5313ff": "表示名",
|
||||
"aa9e366f68d3d097": "低",
|
||||
"ab607d54d86dc789": "著者 leookun",
|
||||
"ac217e4d1ca410f1": "新しいバージョンがあります",
|
||||
"ad79540418be700a": "設定フォルダーを開くか、モデル設定を個別に管理できます",
|
||||
"ae5a738238463a92": "API キーを隠す",
|
||||
@@ -187,7 +182,6 @@
|
||||
"cd7ca5fb221e1c53": "{0}は空にできません",
|
||||
"cfa6c803eb3fc713": "ブラウザでのログインを待っています",
|
||||
"d0325067fed88e5a": "キャッシュヒット率 {0}",
|
||||
"d1bde4a4e057b2c7": "[MainLayout] 作者情報の読み込みに失敗しました",
|
||||
"d20ab96566d33f25": "{0} の表示名は必須です",
|
||||
"d2243e1d44b2a94e": "モデル設定を編集",
|
||||
"d3209b935ae86797": "モデル設定が存在しないため削除できません",
|
||||
@@ -226,6 +220,7 @@
|
||||
"f3fae6cccb9004b1": "カスタムヘッダー名は空にできません",
|
||||
"f474a4108aba4c4c": "サービスを停止",
|
||||
"f4f0ead1116b5b62": "有効化",
|
||||
"f526ab6eff33039a": "作者ページを開けませんでした",
|
||||
"f56c6c82203b33f6": "お知らせ",
|
||||
"f61e03f047b786d5": "{0} の最大出力 Token は正の整数である必要があります",
|
||||
"f6e1c8b1a6970db5": "現在のアウトバウンドリクエストはシステムプロキシを使用していません",
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
"0b0e7478e41fe677": "Текст подсказки {0} не может быть пустым",
|
||||
"0c3b4cf7aa259edb": "Не удалось выполнить операцию",
|
||||
"0d6b7efd5ccefd8a": "Здесь можно настроить каналы моделей. Журналы выполнения находятся в",
|
||||
"0dde813d719dbd01": "Не удалось открыть домашнюю страницу",
|
||||
"1117a2f86030d03b": "Чтение и запись кеша включены в статистику Prompt.",
|
||||
"11afd2a534395b18": "Успешно",
|
||||
"124be3f86f197802": "Использование токенов",
|
||||
@@ -28,7 +27,6 @@
|
||||
"26a3855aed1d8d17": "Сервис не запущен",
|
||||
"281eb6d08c9960d0": "Бюджет токенов рассуждения {0} должен быть положительным целым числом",
|
||||
"28aeffc70ceb4267": "Измените язык интерфейса. Настройка применяется сразу и сохраняется на этом устройстве.",
|
||||
"2a24519398684ed5": "Перейти на домашнюю страницу",
|
||||
"2cd0f3be8738a86c": "Отмена",
|
||||
"2d706f7981b45a7b": "Локальные настройки сохранены",
|
||||
"2f9daa828907b93f": "Удалить",
|
||||
@@ -39,7 +37,6 @@
|
||||
"3463c5585c246df9": "Итого: {0}",
|
||||
"3468b57e3edbc599": "Сводка составлена по данным ходов, найденным в истории.",
|
||||
"35076178fe79a210": "Конфигурация изменена. Выполните проверку снова.",
|
||||
"358f07b2c1445ab1": "Сообщение автора",
|
||||
"37d23612f78a2e63": "Перезапустить и обновить",
|
||||
"392d0dceb45998d3": "Очень высокая",
|
||||
"393df9bb13ea4900": "Попадание",
|
||||
@@ -126,7 +123,6 @@
|
||||
"9196835e388d2550": "Проверить все",
|
||||
"91cba5c107a51892": "/ Ошибочные",
|
||||
"93e08803675e378b": "Идентификатор модели",
|
||||
"93faf55cd25c8319": "Это программное обеспечение полностью бесплатно. Если с вас взяли плату, скорее всего, вас обманули.\\nПосетите страницу автора: https://space.bilibili.com/311706663/upload/video\\nТам публикуются обновления, руководства и другие материалы.",
|
||||
"942ff2d88baca0c6": "Проверка обновлений...",
|
||||
"970388573a3c88c9": "Чтение кеша: {0} × ${1}/1M = {2}",
|
||||
"9730c15f3c1963a1": "Макс.",
|
||||
@@ -150,7 +146,6 @@
|
||||
"a693d69af48bfe48": "Сохранить и проверить",
|
||||
"a98585871c5313ff": "Отображаемое имя",
|
||||
"aa9e366f68d3d097": "Низкая",
|
||||
"ab607d54d86dc789": "Автор leookun",
|
||||
"ac217e4d1ca410f1": "Доступна новая версия",
|
||||
"ad79540418be700a": "Открыть папку настроек или отдельно управлять настройками моделей",
|
||||
"ae5a738238463a92": "Скрыть ключ API",
|
||||
@@ -187,7 +182,6 @@
|
||||
"cd7ca5fb221e1c53": "{0} не может быть пустым",
|
||||
"cfa6c803eb3fc713": "Ожидание входа в браузере",
|
||||
"d0325067fed88e5a": "Доля попаданий в кеш: {0}",
|
||||
"d1bde4a4e057b2c7": "[MainLayout] Не удалось загрузить сведения об авторе",
|
||||
"d20ab96566d33f25": "Отображаемое имя {0} не может быть пустым",
|
||||
"d2243e1d44b2a94e": "Изменить настройки модели",
|
||||
"d3209b935ae86797": "Настройки модели не найдены; удаление невозможно",
|
||||
@@ -226,6 +220,7 @@
|
||||
"f3fae6cccb9004b1": "Имя пользовательского заголовка не может быть пустым",
|
||||
"f474a4108aba4c4c": "Остановить сервис",
|
||||
"f4f0ead1116b5b62": "Включить",
|
||||
"f526ab6eff33039a": "Не удалось открыть страницу автора",
|
||||
"f56c6c82203b33f6": "Уведомление",
|
||||
"f61e03f047b786d5": "Максимальное число выходных токенов {0} должно быть положительным целым числом",
|
||||
"f6e1c8b1a6970db5": "Исходящие запросы не используют системный прокси",
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
"0b0e7478e41fe677": "{0} 的悬停提示不能为空",
|
||||
"0c3b4cf7aa259edb": "操作失败",
|
||||
"0d6b7efd5ccefd8a": "可配置模型渠道;运行日志位于",
|
||||
"0dde813d719dbd01": "打开主页失败",
|
||||
"1117a2f86030d03b": "缓存读写已计入 Prompt 侧统计。",
|
||||
"11afd2a534395b18": "有效",
|
||||
"124be3f86f197802": "Token 消耗",
|
||||
@@ -28,7 +27,6 @@
|
||||
"26a3855aed1d8d17": "服务未启动",
|
||||
"281eb6d08c9960d0": "{0} 的思考预算 Token 必须为正整数",
|
||||
"28aeffc70ceb4267": "切换当前界面显示语言,设置会立即生效并保存在本机",
|
||||
"2a24519398684ed5": "访问主页",
|
||||
"2cd0f3be8738a86c": "取消",
|
||||
"2d706f7981b45a7b": "本地配置已保存",
|
||||
"2f9daa828907b93f": "删除",
|
||||
@@ -39,7 +37,6 @@
|
||||
"3463c5585c246df9": "合计:{0}",
|
||||
"3468b57e3edbc599": "按历史记录里扫描到的回合 summary 汇总。",
|
||||
"35076178fe79a210": "配置已变更,请重新测试",
|
||||
"358f07b2c1445ab1": "作者寄语",
|
||||
"37d23612f78a2e63": "立即重启更新",
|
||||
"392d0dceb45998d3": "极高",
|
||||
"393df9bb13ea4900": "命中",
|
||||
@@ -126,7 +123,6 @@
|
||||
"9196835e388d2550": "测试全部",
|
||||
"91cba5c107a51892": "/ 异常",
|
||||
"93e08803675e378b": "模型标识",
|
||||
"93faf55cd25c8319": "本软件是纯免费软件,如果你被收费,那大概率就是被骗了。\n欢迎点击访问作者主页 https://space.bilibili.com/311706663/upload/video\n查看更多更新动态、使用分享和后续内容。",
|
||||
"942ff2d88baca0c6": "检查更新中...",
|
||||
"970388573a3c88c9": "缓存读取:{0} × ${1}/1M = {2}",
|
||||
"9730c15f3c1963a1": "最大",
|
||||
@@ -150,7 +146,6 @@
|
||||
"a693d69af48bfe48": "保存并测试",
|
||||
"a98585871c5313ff": "显示名称",
|
||||
"aa9e366f68d3d097": "低",
|
||||
"ab607d54d86dc789": "作者 leookun",
|
||||
"ac217e4d1ca410f1": "发现新版本",
|
||||
"ad79540418be700a": "打开设置目录,或单独管理模型配置",
|
||||
"ae5a738238463a92": "隐藏访问密钥",
|
||||
@@ -187,7 +182,6 @@
|
||||
"cd7ca5fb221e1c53": "{0}不能为空",
|
||||
"cfa6c803eb3fc713": "等待浏览器登录",
|
||||
"d0325067fed88e5a": "缓存命中率 {0}",
|
||||
"d1bde4a4e057b2c7": "[MainLayout] 加载作者信息失败",
|
||||
"d20ab96566d33f25": "{0} 的显示名称不能为空",
|
||||
"d2243e1d44b2a94e": "编辑模型配置",
|
||||
"d3209b935ae86797": "模型配置不存在,无法删除",
|
||||
@@ -226,6 +220,7 @@
|
||||
"f3fae6cccb9004b1": "自定义请求头名称不能为空",
|
||||
"f474a4108aba4c4c": "关闭服务",
|
||||
"f4f0ead1116b5b62": "启用",
|
||||
"f526ab6eff33039a": "打开作者地址失败",
|
||||
"f56c6c82203b33f6": "提示",
|
||||
"f61e03f047b786d5": "{0} 的最大输出 Token 必须为正整数",
|
||||
"f6e1c8b1a6970db5": "当前出站请求未使用系统代理",
|
||||
|
||||
@@ -2,11 +2,6 @@
|
||||
import { Browser, Window } from "@wailsio/runtime";
|
||||
import LocaleSelect from "@/components/LocaleSelect.vue";
|
||||
import { useMessage } from "@/composables/useMessage";
|
||||
import { showModal } from "@/composables/useModal";
|
||||
import {
|
||||
getFooterAuthorInfo,
|
||||
openFooterAuthorHome,
|
||||
} from "@/services/clientApi";
|
||||
import {
|
||||
appState,
|
||||
checkForAppUpdates,
|
||||
@@ -14,7 +9,7 @@ import {
|
||||
updateViewState,
|
||||
} from "@/state/appState";
|
||||
import { isWindows } from "@/utils/isWindows";
|
||||
import { computed, onMounted, onUnmounted, ref } from "vue";
|
||||
import { computed, onMounted, onUnmounted } from "vue";
|
||||
import { useRoute } from "vue-router";
|
||||
import Logo from "@/assets/logo.png";
|
||||
|
||||
@@ -24,18 +19,8 @@ const showIcon = computed(() => route.meta.showIcon !== false);
|
||||
const title = computed(() => route.meta.title ?? "Cursor助手|永久免费|自定义API");
|
||||
const directlyClose = computed(() => route.meta.directlyClose === true);
|
||||
const showFooter = computed(() => route.path === "/");
|
||||
const footerAuthorInfo = ref(null);
|
||||
|
||||
const localizedAuthorInfo = computed(() => {
|
||||
if (!footerAuthorInfo.value) return null;
|
||||
return {
|
||||
buttonText: "作者 leookun",
|
||||
dialogTitle: "作者寄语",
|
||||
dialogContent: "本软件是纯免费软件,如果你被收费,那大概率就是被骗了。\n欢迎点击访问作者主页 https://space.bilibili.com/311706663/upload/video\n查看更多更新动态、使用分享和后续内容。",
|
||||
dialogConfirmText: "访问主页",
|
||||
dialogCancelText: "关闭",
|
||||
};
|
||||
});
|
||||
const AUTHOR_REPOSITORY_URL = "https://github.com/leookun/cursor-byok";
|
||||
const AUTHOR_LABEL = "@leookun";
|
||||
const usageDocsURL = "https://docs.leokun.cn";
|
||||
let proxyStateTimer = null;
|
||||
const proxyStatePollIntervalMs = 10000;
|
||||
@@ -99,37 +84,16 @@ async function handleCheckForUpdates() {
|
||||
}
|
||||
}
|
||||
|
||||
async function loadFooterAuthorInfo() {
|
||||
try {
|
||||
footerAuthorInfo.value = await getFooterAuthorInfo();
|
||||
} catch (error) {
|
||||
console.error("[MainLayout] 加载作者信息失败", error);
|
||||
}
|
||||
}
|
||||
|
||||
function showActionError(title, error) {
|
||||
const detail = String(error || "操作失败").trim() || "操作失败";
|
||||
message(`${title}:${detail}`);
|
||||
}
|
||||
|
||||
async function handleOpenAuthorHome() {
|
||||
if (!localizedAuthorInfo.value) {
|
||||
return;
|
||||
}
|
||||
const confirmed = await showModal({
|
||||
title: localizedAuthorInfo.value.dialogTitle,
|
||||
content: localizedAuthorInfo.value.dialogContent,
|
||||
confirmText: localizedAuthorInfo.value.dialogConfirmText,
|
||||
cancelText: localizedAuthorInfo.value.dialogCancelText,
|
||||
showCancel: true,
|
||||
});
|
||||
if (!confirmed) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await openFooterAuthorHome();
|
||||
await Browser.OpenURL(AUTHOR_REPOSITORY_URL);
|
||||
} catch (error) {
|
||||
showActionError("打开主页失败", error);
|
||||
showActionError("打开作者地址失败", error);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,7 +106,6 @@ async function handleOpenUsageDocs() {
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
void loadFooterAuthorInfo();
|
||||
proxyStateTimer = window.setInterval(() => {
|
||||
if (showFooter.value) {
|
||||
void syncServiceState().catch(() => {});
|
||||
@@ -228,13 +191,12 @@ onUnmounted(() => {
|
||||
<span>使用教程</span>
|
||||
</button>
|
||||
<button
|
||||
v-if="localizedAuthorInfo"
|
||||
type="button"
|
||||
class="center-row shrink-0 gap-[6px] cursor-pointer rounded-[6px] px-[6px] py-[3px] transition-colors duration-150 hover:bg-[#1f1f1f] hover:text-[#e5e5e5]"
|
||||
@click="handleOpenAuthorHome"
|
||||
>
|
||||
<span class="icon-[ant-design--bilibili-outlined] text-[14px]"></span>
|
||||
<span>{{ localizedAuthorInfo.buttonText }}</span>
|
||||
<span class="icon-[mdi--github] text-[14px]"></span>
|
||||
<span>{{ AUTHOR_LABEL }}</span>
|
||||
</button>
|
||||
<div
|
||||
v-if="updateViewState.footerDownloading"
|
||||
|
||||
@@ -226,7 +226,7 @@ function normalizeModelAdapterTestResult(source) {
|
||||
rawResponse: asString(raw.rawResponse),
|
||||
testedAt: asString(raw.testedAt),
|
||||
};
|
||||
if (!normalized.summaryText) {
|
||||
if (status === "running" || status === "success") {
|
||||
normalized.summaryText = formatModelAdapterTestSummary(normalized);
|
||||
}
|
||||
if (status === "error" && !normalized.summaryText) {
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 108 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 542 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 643 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 105 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 584 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 651 KiB |
@@ -8,7 +8,6 @@ import (
|
||||
"fmt"
|
||||
"hash/fnv"
|
||||
"io"
|
||||
"math"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"sort"
|
||||
@@ -438,7 +437,6 @@ func (s *ProxyService) TestModelAdapter(adapter serverconfig.ModelAdapterConfig)
|
||||
AdapterID: normalized.ID,
|
||||
RequestHash: requestHash,
|
||||
Status: string(ModelAdapterTestStatusRunning),
|
||||
SummaryText: "测试中...",
|
||||
TestedAt: time.Now().UTC().Format(time.RFC3339Nano),
|
||||
}
|
||||
s.storeAndEmitModelAdapterTestResult(running)
|
||||
@@ -516,7 +514,6 @@ func (s *ProxyService) runModelAdapterTest(adapter serverconfig.ModelAdapterConf
|
||||
TestedAt: time.Now().UTC().Format(time.RFC3339Nano),
|
||||
RawResponse: strings.TrimSpace(metrics.rawResponse),
|
||||
}
|
||||
result.SummaryText = buildModelAdapterTestSummaryText(result)
|
||||
return result, nil
|
||||
}
|
||||
|
||||
@@ -747,13 +744,6 @@ func buildErroredModelAdapterTestResult(adapterID string, requestHash string, er
|
||||
}
|
||||
}
|
||||
|
||||
func buildModelAdapterTestSummaryText(result ModelAdapterTestResult) string {
|
||||
if strings.TrimSpace(result.Status) != string(ModelAdapterTestStatusSuccess) {
|
||||
return firstNonEmptyTrimmed(result.SummaryText, "测试失败")
|
||||
}
|
||||
return fmt.Sprintf("%d t/s | 首字 %s", int(math.Round(maxFloat64(result.TokensPerSecond, 0))), formatModelAdapterTestDuration(result.FirstTextTokenMS))
|
||||
}
|
||||
|
||||
func buildModelAdapterHTTPStatusError(prefix string, resp *http.Response) error {
|
||||
if resp == nil {
|
||||
return fmt.Errorf("%s response is nil", strings.TrimSpace(prefix))
|
||||
@@ -849,17 +839,6 @@ func buildModelAdapterTestErrorSummary(err error) string {
|
||||
}
|
||||
}
|
||||
|
||||
func formatModelAdapterTestDuration(durationMS int64) string {
|
||||
if durationMS < 1000 {
|
||||
if durationMS < 0 {
|
||||
durationMS = 0
|
||||
}
|
||||
return fmt.Sprintf("%d ms", durationMS)
|
||||
}
|
||||
seconds := float64(durationMS) / 1000
|
||||
return fmt.Sprintf("%.1f s", seconds)
|
||||
}
|
||||
|
||||
func estimateBenchmarkTextTokens(text string) int64 {
|
||||
trimmed := strings.TrimSpace(text)
|
||||
if trimmed == "" {
|
||||
@@ -1056,13 +1035,6 @@ func normalizeModelAdapterTestInt(value int) int {
|
||||
return value
|
||||
}
|
||||
|
||||
func maxFloat64(value float64, fallback float64) float64 {
|
||||
if value < fallback {
|
||||
return fallback
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
func firstNonEmptyTrimmed(values ...string) string {
|
||||
for _, value := range values {
|
||||
trimmed := strings.TrimSpace(value)
|
||||
|
||||
Reference in New Issue
Block a user