mirror of
https://github.com/githubhjs/CLIProxyAPIPlus.git
synced 2026-07-13 18:15:24 +00:00
@@ -19,6 +19,17 @@ This project only accepts pull requests that relate to third-party provider supp
|
|||||||
|
|
||||||
If you need to submit any non-third-party provider changes, please open them against the mainline repository.
|
If you need to submit any non-third-party provider changes, please open them against the mainline repository.
|
||||||
|
|
||||||
|
## More choices
|
||||||
|
|
||||||
|
Those projects are ports of CLIProxyAPI or inspired by it:
|
||||||
|
|
||||||
|
### [9Router](https://github.com/decolua/9router)
|
||||||
|
|
||||||
|
A Next.js implementation inspired by CLIProxyAPI, easy to install and use, built from scratch with format translation (OpenAI/Claude/Gemini/Ollama), combo system with auto-fallback, multi-account management with exponential backoff, a Next.js web dashboard, and support for CLI tools (Cursor, Claude Code, Cline, RooCode) - no API keys needed.
|
||||||
|
|
||||||
|
> [!NOTE]
|
||||||
|
> If you have developed a port of CLIProxyAPI or a project inspired by it, please open a PR to add it to this list.
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
||||||
|
|||||||
@@ -19,6 +19,17 @@
|
|||||||
|
|
||||||
如果需要提交任何非第三方供应商支持的 Pull Request,请提交到主线版本。
|
如果需要提交任何非第三方供应商支持的 Pull Request,请提交到主线版本。
|
||||||
|
|
||||||
|
## 更多选择
|
||||||
|
|
||||||
|
以下项目是 CLIProxyAPI 的移植版或受其启发:
|
||||||
|
|
||||||
|
### [9Router](https://github.com/decolua/9router)
|
||||||
|
|
||||||
|
基于 Next.js 的实现,灵感来自 CLIProxyAPI,易于安装使用;自研格式转换(OpenAI/Claude/Gemini/Ollama)、组合系统与自动回退、多账户管理(指数退避)、Next.js Web 控制台,并支持 Cursor、Claude Code、Cline、RooCode 等 CLI 工具,无需 API 密钥。
|
||||||
|
|
||||||
|
> [!NOTE]
|
||||||
|
> 如果你开发了 CLIProxyAPI 的移植或衍生项目,请提交 PR 将其添加到此列表中。
|
||||||
|
|
||||||
## 许可证
|
## 许可证
|
||||||
|
|
||||||
此项目根据 MIT 许可证授权 - 有关详细信息,请参阅 [LICENSE](LICENSE) 文件。
|
此项目根据 MIT 许可证授权 - 有关详细信息,请参阅 [LICENSE](LICENSE) 文件。
|
||||||
+2
-2
@@ -184,7 +184,7 @@ func ConvertOpenAIRequestToAntigravity(modelName string, inputRawJSON []byte, _
|
|||||||
role := m.Get("role").String()
|
role := m.Get("role").String()
|
||||||
content := m.Get("content")
|
content := m.Get("content")
|
||||||
|
|
||||||
if role == "system" && len(arr) > 1 {
|
if (role == "system" || role == "developer") && len(arr) > 1 {
|
||||||
// system -> request.systemInstruction as a user message style
|
// system -> request.systemInstruction as a user message style
|
||||||
if content.Type == gjson.String {
|
if content.Type == gjson.String {
|
||||||
out, _ = sjson.SetBytes(out, "request.systemInstruction.role", "user")
|
out, _ = sjson.SetBytes(out, "request.systemInstruction.role", "user")
|
||||||
@@ -201,7 +201,7 @@ func ConvertOpenAIRequestToAntigravity(modelName string, inputRawJSON []byte, _
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if role == "user" || (role == "system" && len(arr) == 1) {
|
} else if role == "user" || ((role == "system" || role == "developer") && len(arr) == 1) {
|
||||||
// Build single user content node to avoid splitting into multiple contents
|
// Build single user content node to avoid splitting into multiple contents
|
||||||
node := []byte(`{"role":"user","parts":[]}`)
|
node := []byte(`{"role":"user","parts":[]}`)
|
||||||
if content.Type == gjson.String {
|
if content.Type == gjson.String {
|
||||||
|
|||||||
@@ -152,7 +152,7 @@ func ConvertOpenAIRequestToGeminiCLI(modelName string, inputRawJSON []byte, _ bo
|
|||||||
role := m.Get("role").String()
|
role := m.Get("role").String()
|
||||||
content := m.Get("content")
|
content := m.Get("content")
|
||||||
|
|
||||||
if role == "system" && len(arr) > 1 {
|
if (role == "system" || role == "developer") && len(arr) > 1 {
|
||||||
// system -> request.systemInstruction as a user message style
|
// system -> request.systemInstruction as a user message style
|
||||||
if content.Type == gjson.String {
|
if content.Type == gjson.String {
|
||||||
out, _ = sjson.SetBytes(out, "request.systemInstruction.role", "user")
|
out, _ = sjson.SetBytes(out, "request.systemInstruction.role", "user")
|
||||||
@@ -169,7 +169,7 @@ func ConvertOpenAIRequestToGeminiCLI(modelName string, inputRawJSON []byte, _ bo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if role == "user" || (role == "system" && len(arr) == 1) {
|
} else if role == "user" || ((role == "system" || role == "developer") && len(arr) == 1) {
|
||||||
// Build single user content node to avoid splitting into multiple contents
|
// Build single user content node to avoid splitting into multiple contents
|
||||||
node := []byte(`{"role":"user","parts":[]}`)
|
node := []byte(`{"role":"user","parts":[]}`)
|
||||||
if content.Type == gjson.String {
|
if content.Type == gjson.String {
|
||||||
|
|||||||
@@ -170,7 +170,7 @@ func ConvertOpenAIRequestToGemini(modelName string, inputRawJSON []byte, _ bool)
|
|||||||
role := m.Get("role").String()
|
role := m.Get("role").String()
|
||||||
content := m.Get("content")
|
content := m.Get("content")
|
||||||
|
|
||||||
if role == "system" && len(arr) > 1 {
|
if (role == "system" || role == "developer") && len(arr) > 1 {
|
||||||
// system -> system_instruction as a user message style
|
// system -> system_instruction as a user message style
|
||||||
if content.Type == gjson.String {
|
if content.Type == gjson.String {
|
||||||
out, _ = sjson.SetBytes(out, "system_instruction.role", "user")
|
out, _ = sjson.SetBytes(out, "system_instruction.role", "user")
|
||||||
@@ -187,7 +187,7 @@ func ConvertOpenAIRequestToGemini(modelName string, inputRawJSON []byte, _ bool)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if role == "user" || (role == "system" && len(arr) == 1) {
|
} else if role == "user" || ((role == "system" || role == "developer") && len(arr) == 1) {
|
||||||
// Build single user content node to avoid splitting into multiple contents
|
// Build single user content node to avoid splitting into multiple contents
|
||||||
node := []byte(`{"role":"user","parts":[]}`)
|
node := []byte(`{"role":"user","parts":[]}`)
|
||||||
if content.Type == gjson.String {
|
if content.Type == gjson.String {
|
||||||
|
|||||||
Reference in New Issue
Block a user