mirror of
https://github.com/QuantumNous/new-api.git
synced 2026-04-08 21:27:26 +00:00
Compare commits
21 Commits
v0.10.1-al
...
coderabbit
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
40a3e19a78 | ||
|
|
42109c5840 | ||
|
|
afd9c29ace | ||
|
|
470e0304d8 | ||
|
|
d6e97ab184 | ||
|
|
d8aa327f05 | ||
|
|
28f7a4feef | ||
|
|
5a64ae2a29 | ||
|
|
cc3ba39e72 | ||
|
|
4ee595c448 | ||
|
|
d9634ad2d3 | ||
|
|
a343ce84ee | ||
|
|
e6ec551fbf | ||
|
|
a98aad2501 | ||
|
|
97132de2ca | ||
|
|
b35ae9f693 | ||
|
|
8cb56fc319 | ||
|
|
8e3f9b1faa | ||
|
|
11593bd3da | ||
|
|
e16e7d6fb9 | ||
|
|
39593052b6 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -16,6 +16,7 @@ new-api
|
||||
tiktoken_cache
|
||||
.eslintcache
|
||||
.gocache
|
||||
.gomodcache/
|
||||
.cache
|
||||
web/bun.lock
|
||||
|
||||
|
||||
71
README.en.md
71
README.en.md
@@ -146,7 +146,7 @@ docker run --name new-api -d --restart always \
|
||||
|
||||
🎉 After deployment is complete, visit `http://localhost:3000` to start using!
|
||||
|
||||
📖 For more deployment methods, please refer to [Deployment Guide](https://docs.newapi.pro/installation)
|
||||
📖 For more deployment methods, please refer to [Deployment Guide](https://docs.newapi.pro/en/docs/installation)
|
||||
|
||||
---
|
||||
|
||||
@@ -154,7 +154,7 @@ docker run --name new-api -d --restart always \
|
||||
|
||||
<div align="center">
|
||||
|
||||
### 📖 [Official Documentation](https://docs.newapi.pro/) | [](https://deepwiki.com/QuantumNous/new-api)
|
||||
### 📖 [Official Documentation](https://docs.newapi.pro/en/docs) | [](https://deepwiki.com/QuantumNous/new-api)
|
||||
|
||||
</div>
|
||||
|
||||
@@ -162,17 +162,17 @@ docker run --name new-api -d --restart always \
|
||||
|
||||
| Category | Link |
|
||||
|------|------|
|
||||
| 🚀 Deployment Guide | [Installation Documentation](https://docs.newapi.pro/installation) |
|
||||
| ⚙️ Environment Configuration | [Environment Variables](https://docs.newapi.pro/installation/environment-variables) |
|
||||
| 📡 API Documentation | [API Documentation](https://docs.newapi.pro/api) |
|
||||
| ❓ FAQ | [FAQ](https://docs.newapi.pro/support/faq) |
|
||||
| 💬 Community Interaction | [Communication Channels](https://docs.newapi.pro/support/community-interaction) |
|
||||
| 🚀 Deployment Guide | [Installation Documentation](https://docs.newapi.pro/en/docs/installation) |
|
||||
| ⚙️ Environment Configuration | [Environment Variables](https://docs.newapi.pro/en/docs/installation/config-maintenance/environment-variables) |
|
||||
| 📡 API Documentation | [API Documentation](https://docs.newapi.pro/en/docs/api) |
|
||||
| ❓ FAQ | [FAQ](https://docs.newapi.pro/en/docs/support/faq) |
|
||||
| 💬 Community Interaction | [Communication Channels](https://docs.newapi.pro/en/docs/support/community-interaction) |
|
||||
|
||||
---
|
||||
|
||||
## ✨ Key Features
|
||||
|
||||
> For detailed features, please refer to [Features Introduction](https://docs.newapi.pro/wiki/features-introduction)
|
||||
> For detailed features, please refer to [Features Introduction](https://docs.newapi.pro/en/docs/guide/wiki/basic-concepts/features-introduction)
|
||||
|
||||
### 🎨 Core Functions
|
||||
|
||||
@@ -201,11 +201,11 @@ docker run --name new-api -d --restart always \
|
||||
### 🚀 Advanced Features
|
||||
|
||||
**API Format Support:**
|
||||
- ⚡ [OpenAI Responses](https://docs.newapi.pro/api/openai-responses)
|
||||
- ⚡ [OpenAI Realtime API](https://docs.newapi.pro/api/openai-realtime) (including Azure)
|
||||
- ⚡ [Claude Messages](https://docs.newapi.pro/api/anthropic-chat)
|
||||
- ⚡ [Google Gemini](https://docs.newapi.pro/api/google-gemini-chat/)
|
||||
- 🔄 [Rerank Models](https://docs.newapi.pro/api/jinaai-rerank) (Cohere, Jina)
|
||||
- ⚡ [OpenAI Responses](https://docs.newapi.pro/en/docs/api/ai-model/chat/openai/create-response)
|
||||
- ⚡ [OpenAI Realtime API](https://docs.newapi.pro/en/docs/api/ai-model/realtime/create-realtime-session) (including Azure)
|
||||
- ⚡ [Claude Messages](https://docs.newapi.pro/en/docs/api/ai-model/chat/create-message)
|
||||
- ⚡ [Google Gemini](https://doc.newapi.pro/en/api/google-gemini-chat)
|
||||
- 🔄 [Rerank Models](https://docs.newapi.pro/en/docs/api/ai-model/rerank/create-rerank) (Cohere, Jina)
|
||||
|
||||
**Intelligent Routing:**
|
||||
- ⚖️ Channel weighted random
|
||||
@@ -246,16 +246,16 @@ docker run --name new-api -d --restart always \
|
||||
|
||||
## 🤖 Model Support
|
||||
|
||||
> For details, please refer to [API Documentation - Relay Interface](https://docs.newapi.pro/api)
|
||||
> For details, please refer to [API Documentation - Relay Interface](https://docs.newapi.pro/en/docs/api)
|
||||
|
||||
| Model Type | Description | Documentation |
|
||||
|---------|------|------|
|
||||
| 🤖 OpenAI GPTs | gpt-4-gizmo-* series | - |
|
||||
| 🎨 Midjourney-Proxy | [Midjourney-Proxy(Plus)](https://github.com/novicezk/midjourney-proxy) | [Documentation](https://docs.newapi.pro/api/midjourney-proxy-image) |
|
||||
| 🎵 Suno-API | [Suno API](https://github.com/Suno-API/Suno-API) | [Documentation](https://docs.newapi.pro/api/suno-music) |
|
||||
| 🔄 Rerank | Cohere, Jina | [Documentation](https://docs.newapi.pro/api/jinaai-rerank) |
|
||||
| 💬 Claude | Messages format | [Documentation](https://docs.newapi.pro/api/anthropic-chat) |
|
||||
| 🌐 Gemini | Google Gemini format | [Documentation](https://docs.newapi.pro/api/google-gemini-chat/) |
|
||||
| 🎨 Midjourney-Proxy | [Midjourney-Proxy(Plus)](https://github.com/novicezk/midjourney-proxy) | [Documentation](https://doc.newapi.pro/en/api/midjourney-proxy-image) |
|
||||
| 🎵 Suno-API | [Suno API](https://github.com/Suno-API/Suno-API) | [Documentation](https://doc.newapi.pro/en/api/suno-music) |
|
||||
| 🔄 Rerank | Cohere, Jina | [Documentation](https://docs.newapi.pro/en/docs/api/ai-model/rerank/create-rerank) |
|
||||
| 💬 Claude | Messages format | [Documentation](https://docs.newapi.pro/en/docs/api/ai-model/chat/create-message) |
|
||||
| 🌐 Gemini | Google Gemini format | [Documentation](https://doc.newapi.pro/en/api/google-gemini-chat) |
|
||||
| 🔧 Dify | ChatFlow mode | - |
|
||||
| 🎯 Custom | Supports complete call address | - |
|
||||
|
||||
@@ -264,16 +264,16 @@ docker run --name new-api -d --restart always \
|
||||
<details>
|
||||
<summary>View complete interface list</summary>
|
||||
|
||||
- [Chat Interface (Chat Completions)](https://docs.newapi.pro/api/openai-chat)
|
||||
- [Response Interface (Responses)](https://docs.newapi.pro/api/openai-responses)
|
||||
- [Image Interface (Image)](https://docs.newapi.pro/api/openai-image)
|
||||
- [Audio Interface (Audio)](https://docs.newapi.pro/api/openai-audio)
|
||||
- [Video Interface (Video)](https://docs.newapi.pro/api/openai-video)
|
||||
- [Embedding Interface (Embeddings)](https://docs.newapi.pro/api/openai-embeddings)
|
||||
- [Rerank Interface (Rerank)](https://docs.newapi.pro/api/jinaai-rerank)
|
||||
- [Realtime Conversation (Realtime)](https://docs.newapi.pro/api/openai-realtime)
|
||||
- [Claude Chat](https://docs.newapi.pro/api/anthropic-chat)
|
||||
- [Google Gemini Chat](https://docs.newapi.pro/api/google-gemini-chat/)
|
||||
- [Chat Interface (Chat Completions)](https://docs.newapi.pro/en/docs/api/ai-model/chat/openai/create-chat-completion)
|
||||
- [Response Interface (Responses)](https://docs.newapi.pro/en/docs/api/ai-model/chat/openai/create-response)
|
||||
- [Image Interface (Image)](https://docs.newapi.pro/en/docs/api/ai-model/images/openai/v1-images-generations--post)
|
||||
- [Audio Interface (Audio)](https://docs.newapi.pro/en/docs/api/ai-model/audio/openai/create-transcription)
|
||||
- [Video Interface (Video)](https://docs.newapi.pro/en/docs/api/ai-model/videos/create-video-generation)
|
||||
- [Embedding Interface (Embeddings)](https://docs.newapi.pro/en/docs/api/ai-model/embeddings/create-embedding)
|
||||
- [Rerank Interface (Rerank)](https://docs.newapi.pro/en/docs/api/ai-model/rerank/create-rerank)
|
||||
- [Realtime Conversation (Realtime)](https://docs.newapi.pro/en/docs/api/ai-model/realtime/create-realtime-session)
|
||||
- [Claude Chat](https://docs.newapi.pro/en/docs/api/ai-model/chat/create-message)
|
||||
- [Google Gemini Chat](https://doc.newapi.pro/en/api/google-gemini-chat)
|
||||
|
||||
</details>
|
||||
|
||||
@@ -305,10 +305,11 @@ docker run --name new-api -d --restart always \
|
||||
| `REDIS_CONN_STRING` | Redis connection string | - |
|
||||
| `STREAMING_TIMEOUT` | Streaming timeout (seconds) | `300` |
|
||||
| `STREAM_SCANNER_MAX_BUFFER_MB` | Max per-line buffer (MB) for the stream scanner; increase when upstream sends huge image/base64 payloads | `64` |
|
||||
| `MAX_REQUEST_BODY_MB` | Max request body size (MB, counted **after decompression**; prevents huge requests/zip bombs from exhausting memory). Exceeding it returns `413` | `32` |
|
||||
| `AZURE_DEFAULT_API_VERSION` | Azure API version | `2025-04-01-preview` |
|
||||
| `ERROR_LOG_ENABLED` | Error log switch | `false` |
|
||||
|
||||
📖 **Complete configuration:** [Environment Variables Documentation](https://docs.newapi.pro/installation/environment-variables)
|
||||
📖 **Complete configuration:** [Environment Variables Documentation](https://docs.newapi.pro/en/docs/installation/config-maintenance/environment-variables)
|
||||
|
||||
</details>
|
||||
|
||||
@@ -410,10 +411,10 @@ docker run --name new-api -d --restart always \
|
||||
|
||||
| Resource | Link |
|
||||
|------|------|
|
||||
| 📘 FAQ | [FAQ](https://docs.newapi.pro/support/faq) |
|
||||
| 💬 Community Interaction | [Communication Channels](https://docs.newapi.pro/support/community-interaction) |
|
||||
| 🐛 Issue Feedback | [Issue Feedback](https://docs.newapi.pro/support/feedback-issues) |
|
||||
| 📚 Complete Documentation | [Official Documentation](https://docs.newapi.pro/support) |
|
||||
| 📘 FAQ | [FAQ](https://docs.newapi.pro/en/docs/support/faq) |
|
||||
| 💬 Community Interaction | [Communication Channels](https://docs.newapi.pro/en/docs/support/community-interaction) |
|
||||
| 🐛 Issue Feedback | [Issue Feedback](https://docs.newapi.pro/en/docs/support/feedback-issues) |
|
||||
| 📚 Complete Documentation | [Official Documentation](https://docs.newapi.pro/en/docs) |
|
||||
|
||||
### 🤝 Contribution Guide
|
||||
|
||||
@@ -442,7 +443,7 @@ Welcome all forms of contribution!
|
||||
|
||||
If this project is helpful to you, welcome to give us a ⭐️ Star!
|
||||
|
||||
**[Official Documentation](https://docs.newapi.pro/)** • **[Issue Feedback](https://github.com/Calcium-Ion/new-api/issues)** • **[Latest Release](https://github.com/Calcium-Ion/new-api/releases)**
|
||||
**[Official Documentation](https://docs.newapi.pro/en/docs)** • **[Issue Feedback](https://github.com/Calcium-Ion/new-api/issues)** • **[Latest Release](https://github.com/Calcium-Ion/new-api/releases)**
|
||||
|
||||
<sub>Built with ❤️ by QuantumNous</sub>
|
||||
|
||||
|
||||
71
README.fr.md
71
README.fr.md
@@ -146,7 +146,7 @@ docker run --name new-api -d --restart always \
|
||||
|
||||
🎉 Après le déploiement, visitez `http://localhost:3000` pour commencer à utiliser!
|
||||
|
||||
📖 Pour plus de méthodes de déploiement, veuillez vous référer à [Guide de déploiement](https://docs.newapi.pro/installation)
|
||||
📖 Pour plus de méthodes de déploiement, veuillez vous référer à [Guide de déploiement](https://docs.newapi.pro/en/docs/installation)
|
||||
|
||||
---
|
||||
|
||||
@@ -154,7 +154,7 @@ docker run --name new-api -d --restart always \
|
||||
|
||||
<div align="center">
|
||||
|
||||
### 📖 [Documentation officielle](https://docs.newapi.pro/) | [](https://deepwiki.com/QuantumNous/new-api)
|
||||
### 📖 [Documentation officielle](https://docs.newapi.pro/en/docs) | [](https://deepwiki.com/QuantumNous/new-api)
|
||||
|
||||
</div>
|
||||
|
||||
@@ -162,17 +162,17 @@ docker run --name new-api -d --restart always \
|
||||
|
||||
| Catégorie | Lien |
|
||||
|------|------|
|
||||
| 🚀 Guide de déploiement | [Documentation d'installation](https://docs.newapi.pro/installation) |
|
||||
| ⚙️ Configuration de l'environnement | [Variables d'environnement](https://docs.newapi.pro/installation/environment-variables) |
|
||||
| 📡 Documentation de l'API | [Documentation de l'API](https://docs.newapi.pro/api) |
|
||||
| ❓ FAQ | [FAQ](https://docs.newapi.pro/support/faq) |
|
||||
| 💬 Interaction avec la communauté | [Canaux de communication](https://docs.newapi.pro/support/community-interaction) |
|
||||
| 🚀 Guide de déploiement | [Documentation d'installation](https://docs.newapi.pro/en/docs/installation) |
|
||||
| ⚙️ Configuration de l'environnement | [Variables d'environnement](https://docs.newapi.pro/en/docs/installation/config-maintenance/environment-variables) |
|
||||
| 📡 Documentation de l'API | [Documentation de l'API](https://docs.newapi.pro/en/docs/api) |
|
||||
| ❓ FAQ | [FAQ](https://docs.newapi.pro/en/docs/support/faq) |
|
||||
| 💬 Interaction avec la communauté | [Canaux de communication](https://docs.newapi.pro/en/docs/support/community-interaction) |
|
||||
|
||||
---
|
||||
|
||||
## ✨ Fonctionnalités clés
|
||||
|
||||
> Pour les fonctionnalités détaillées, veuillez vous référer à [Présentation des fonctionnalités](https://docs.newapi.pro/wiki/features-introduction) |
|
||||
> Pour les fonctionnalités détaillées, veuillez vous référer à [Présentation des fonctionnalités](https://docs.newapi.pro/en/docs/guide/wiki/basic-concepts/features-introduction) |
|
||||
|
||||
### 🎨 Fonctions principales
|
||||
|
||||
@@ -200,11 +200,11 @@ docker run --name new-api -d --restart always \
|
||||
### 🚀 Fonctionnalités avancées
|
||||
|
||||
**Prise en charge des formats d'API:**
|
||||
- ⚡ [OpenAI Responses](https://docs.newapi.pro/api/openai-responses)
|
||||
- ⚡ [OpenAI Realtime API](https://docs.newapi.pro/api/openai-realtime) (y compris Azure)
|
||||
- ⚡ [Claude Messages](https://docs.newapi.pro/api/anthropic-chat)
|
||||
- ⚡ [Google Gemini](https://docs.newapi.pro/api/google-gemini-chat/)
|
||||
- 🔄 [Modèles Rerank](https://docs.newapi.pro/api/jinaai-rerank) (Cohere, Jina)
|
||||
- ⚡ [OpenAI Responses](https://docs.newapi.pro/en/docs/api/ai-model/chat/openai/create-response)
|
||||
- ⚡ [OpenAI Realtime API](https://docs.newapi.pro/en/docs/api/ai-model/realtime/create-realtime-session) (y compris Azure)
|
||||
- ⚡ [Claude Messages](https://docs.newapi.pro/en/docs/api/ai-model/chat/create-message)
|
||||
- ⚡ [Google Gemini](https://doc.newapi.pro/en/api/google-gemini-chat)
|
||||
- 🔄 [Modèles Rerank](https://docs.newapi.pro/en/docs/api/ai-model/rerank/create-rerank) (Cohere, Jina)
|
||||
|
||||
**Routage intelligent:**
|
||||
- ⚖️ Sélection aléatoire pondérée des canaux
|
||||
@@ -242,16 +242,16 @@ docker run --name new-api -d --restart always \
|
||||
|
||||
## 🤖 Prise en charge des modèles
|
||||
|
||||
> Pour les détails, veuillez vous référer à [Documentation de l'API - Interface de relais](https://docs.newapi.pro/api)
|
||||
> Pour les détails, veuillez vous référer à [Documentation de l'API - Interface de relais](https://docs.newapi.pro/en/docs/api)
|
||||
|
||||
| Type de modèle | Description | Documentation |
|
||||
|---------|------|------|
|
||||
| 🤖 OpenAI GPTs | série gpt-4-gizmo-* | - |
|
||||
| 🎨 Midjourney-Proxy | [Midjourney-Proxy(Plus)](https://github.com/novicezk/midjourney-proxy) | [Documentation](https://docs.newapi.pro/api/midjourney-proxy-image) |
|
||||
| 🎵 Suno-API | [Suno API](https://github.com/Suno-API/Suno-API) | [Documentation](https://docs.newapi.pro/api/suno-music) |
|
||||
| 🔄 Rerank | Cohere, Jina | [Documentation](https://docs.newapi.pro/api/jinaai-rerank) |
|
||||
| 💬 Claude | Format Messages | [Documentation](https://docs.newapi.pro/api/anthropic-chat) |
|
||||
| 🌐 Gemini | Format Google Gemini | [Documentation](https://docs.newapi.pro/api/google-gemini-chat/) |
|
||||
| 🎨 Midjourney-Proxy | [Midjourney-Proxy(Plus)](https://github.com/novicezk/midjourney-proxy) | [Documentation](https://doc.newapi.pro/en/api/midjourney-proxy-image) |
|
||||
| 🎵 Suno-API | [Suno API](https://github.com/Suno-API/Suno-API) | [Documentation](https://doc.newapi.pro/en/api/suno-music) |
|
||||
| 🔄 Rerank | Cohere, Jina | [Documentation](https://docs.newapi.pro/en/docs/api/ai-model/rerank/create-rerank) |
|
||||
| 💬 Claude | Format Messages | [Documentation](https://docs.newapi.pro/en/docs/api/ai-model/chat/create-message) |
|
||||
| 🌐 Gemini | Format Google Gemini | [Documentation](https://doc.newapi.pro/en/api/google-gemini-chat) |
|
||||
| 🔧 Dify | Mode ChatFlow | - |
|
||||
| 🎯 Personnalisé | Prise en charge de l'adresse d'appel complète | - |
|
||||
|
||||
@@ -260,16 +260,16 @@ docker run --name new-api -d --restart always \
|
||||
<details>
|
||||
<summary>Voir la liste complète des interfaces</summary>
|
||||
|
||||
- [Interface de discussion (Chat Completions)](https://docs.newapi.pro/api/openai-chat)
|
||||
- [Interface de réponse (Responses)](https://docs.newapi.pro/api/openai-responses)
|
||||
- [Interface d'image (Image)](https://docs.newapi.pro/api/openai-image)
|
||||
- [Interface audio (Audio)](https://docs.newapi.pro/api/openai-audio)
|
||||
- [Interface vidéo (Video)](https://docs.newapi.pro/api/openai-video)
|
||||
- [Interface d'incorporation (Embeddings)](https://docs.newapi.pro/api/openai-embeddings)
|
||||
- [Interface de rerank (Rerank)](https://docs.newapi.pro/api/jinaai-rerank)
|
||||
- [Conversation en temps réel (Realtime)](https://docs.newapi.pro/api/openai-realtime)
|
||||
- [Discussion Claude](https://docs.newapi.pro/api/anthropic-chat)
|
||||
- [Discussion Google Gemini](https://docs.newapi.pro/api/google-gemini-chat/)
|
||||
- [Interface de discussion (Chat Completions)](https://docs.newapi.pro/en/docs/api/ai-model/chat/openai/create-chat-completion)
|
||||
- [Interface de réponse (Responses)](https://docs.newapi.pro/en/docs/api/ai-model/chat/openai/create-response)
|
||||
- [Interface d'image (Image)](https://docs.newapi.pro/en/docs/api/ai-model/images/openai/v1-images-generations--post)
|
||||
- [Interface audio (Audio)](https://docs.newapi.pro/en/docs/api/ai-model/audio/openai/create-transcription)
|
||||
- [Interface vidéo (Video)](https://docs.newapi.pro/en/docs/api/ai-model/videos/create-video-generation)
|
||||
- [Interface d'incorporation (Embeddings)](https://docs.newapi.pro/en/docs/api/ai-model/embeddings/create-embedding)
|
||||
- [Interface de rerank (Rerank)](https://docs.newapi.pro/en/docs/api/ai-model/rerank/create-rerank)
|
||||
- [Conversation en temps réel (Realtime)](https://docs.newapi.pro/en/docs/api/ai-model/realtime/create-realtime-session)
|
||||
- [Discussion Claude](https://docs.newapi.pro/en/docs/api/ai-model/chat/create-message)
|
||||
- [Discussion Google Gemini](https://doc.newapi.pro/en/api/google-gemini-chat)
|
||||
|
||||
</details>
|
||||
|
||||
@@ -301,10 +301,11 @@ docker run --name new-api -d --restart always \
|
||||
| `REDIS_CONN_STRING` | Chaine de connexion Redis | - |
|
||||
| `STREAMING_TIMEOUT` | Délai d'expiration du streaming (secondes) | `300` |
|
||||
| `STREAM_SCANNER_MAX_BUFFER_MB` | Taille max du buffer par ligne (Mo) pour le scanner SSE ; à augmenter quand les sorties image/base64 sont très volumineuses (ex. images 4K) | `64` |
|
||||
| `MAX_REQUEST_BODY_MB` | Taille maximale du corps de requête (Mo, comptée **après décompression** ; évite les requêtes énormes/zip bombs qui saturent la mémoire). Dépassement ⇒ `413` | `32` |
|
||||
| `AZURE_DEFAULT_API_VERSION` | Version de l'API Azure | `2025-04-01-preview` |
|
||||
| `ERROR_LOG_ENABLED` | Interrupteur du journal d'erreurs | `false` |
|
||||
|
||||
📖 **Configuration complète:** [Documentation des variables d'environnement](https://docs.newapi.pro/installation/environment-variables)
|
||||
📖 **Configuration complète:** [Documentation des variables d'environnement](https://docs.newapi.pro/en/docs/installation/config-maintenance/environment-variables)
|
||||
|
||||
</details>
|
||||
|
||||
@@ -404,10 +405,10 @@ docker run --name new-api -d --restart always \
|
||||
|
||||
| Ressource | Lien |
|
||||
|------|------|
|
||||
| 📘 FAQ | [FAQ](https://docs.newapi.pro/support/faq) |
|
||||
| 💬 Interaction avec la communauté | [Canaux de communication](https://docs.newapi.pro/support/community-interaction) |
|
||||
| 🐛 Commentaires sur les problèmes | [Commentaires sur les problèmes](https://docs.newapi.pro/support/feedback-issues) |
|
||||
| 📚 Documentation complète | [Documentation officielle](https://docs.newapi.pro/support) |
|
||||
| 📘 FAQ | [FAQ](https://docs.newapi.pro/en/docs/support/faq) |
|
||||
| 💬 Interaction avec la communauté | [Canaux de communication](https://docs.newapi.pro/en/docs/support/community-interaction) |
|
||||
| 🐛 Commentaires sur les problèmes | [Commentaires sur les problèmes](https://docs.newapi.pro/en/docs/support/feedback-issues) |
|
||||
| 📚 Documentation complète | [Documentation officielle](https://docs.newapi.pro/en/docs) |
|
||||
|
||||
### 🤝 Guide de contribution
|
||||
|
||||
@@ -436,7 +437,7 @@ Bienvenue à toutes les formes de contribution!
|
||||
|
||||
Si ce projet vous est utile, bienvenue à nous donner une ⭐️ Étoile!
|
||||
|
||||
**[Documentation officielle](https://docs.newapi.pro/)** • **[Commentaires sur les problèmes](https://github.com/Calcium-Ion/new-api/issues)** • **[Dernière version](https://github.com/Calcium-Ion/new-api/releases)**
|
||||
**[Documentation officielle](https://docs.newapi.pro/en/docs)** • **[Commentaires sur les problèmes](https://github.com/Calcium-Ion/new-api/issues)** • **[Dernière version](https://github.com/Calcium-Ion/new-api/releases)**
|
||||
|
||||
<sub>Construit avec ❤️ par QuantumNous</sub>
|
||||
|
||||
|
||||
79
README.ja.md
79
README.ja.md
@@ -146,7 +146,7 @@ docker run --name new-api -d --restart always \
|
||||
|
||||
🎉 デプロイが完了したら、`http://localhost:3000` にアクセスして使用を開始してください!
|
||||
|
||||
📖 その他のデプロイ方法については[デプロイガイド](https://docs.newapi.pro/installation)を参照してください。
|
||||
📖 その他のデプロイ方法については[デプロイガイド](https://docs.newapi.pro/ja/docs/installation)を参照してください。
|
||||
|
||||
---
|
||||
|
||||
@@ -154,7 +154,7 @@ docker run --name new-api -d --restart always \
|
||||
|
||||
<div align="center">
|
||||
|
||||
### 📖 [公式ドキュメント](https://docs.newapi.pro/) | [](https://deepwiki.com/QuantumNous/new-api)
|
||||
### 📖 [公式ドキュメント](https://docs.newapi.pro/ja/docs) | [](https://deepwiki.com/QuantumNous/new-api)
|
||||
|
||||
</div>
|
||||
|
||||
@@ -162,17 +162,17 @@ docker run --name new-api -d --restart always \
|
||||
|
||||
| カテゴリ | リンク |
|
||||
|------|------|
|
||||
| 🚀 デプロイガイド | [インストールドキュメント](https://docs.newapi.pro/installation) |
|
||||
| ⚙️ 環境設定 | [環境変数](https://docs.newapi.pro/installation/environment-variables) |
|
||||
| 📡 APIドキュメント | [APIドキュメント](https://docs.newapi.pro/api) |
|
||||
| ❓ よくある質問 | [FAQ](https://docs.newapi.pro/support/faq) |
|
||||
| 💬 コミュニティ交流 | [交流チャネル](https://docs.newapi.pro/support/community-interaction) |
|
||||
| 🚀 デプロイガイド | [インストールドキュメント](https://docs.newapi.pro/ja/docs/installation) |
|
||||
| ⚙️ 環境設定 | [環境変数](https://docs.newapi.pro/ja/docs/installation/config-maintenance/environment-variables) |
|
||||
| 📡 APIドキュメント | [APIドキュメント](https://docs.newapi.pro/ja/docs/api) |
|
||||
| ❓ よくある質問 | [FAQ](https://docs.newapi.pro/ja/docs/support/faq) |
|
||||
| 💬 コミュニティ交流 | [交流チャネル](https://docs.newapi.pro/ja/docs/support/community-interaction) |
|
||||
|
||||
---
|
||||
|
||||
## ✨ 主な機能
|
||||
|
||||
> 詳細な機能については[機能説明](https://docs.newapi.pro/wiki/features-introduction)を参照してください。
|
||||
> 詳細な機能については[機能説明](https://docs.newapi.pro/ja/docs/guide/wiki/basic-concepts/features-introduction)を参照してください。
|
||||
|
||||
### 🎨 コア機能
|
||||
|
||||
@@ -202,15 +202,15 @@ docker run --name new-api -d --restart always \
|
||||
### 🚀 高度な機能
|
||||
|
||||
**APIフォーマットサポート:**
|
||||
- ⚡ [OpenAI Responses](https://docs.newapi.pro/api/openai-responses)
|
||||
- ⚡ [OpenAI Realtime API](https://docs.newapi.pro/api/openai-realtime)(Azureを含む)
|
||||
- ⚡ [Claude Messages](https://docs.newapi.pro/api/anthropic-chat)
|
||||
- ⚡ [Google Gemini](https://docs.newapi.pro/api/google-gemini-chat/)
|
||||
- 🔄 [Rerankモデル](https://docs.newapi.pro/api/jinaai-rerank)
|
||||
- ⚡ [OpenAI Realtime API](https://docs.newapi.pro/api/openai-realtime)
|
||||
- ⚡ [Claude Messages](https://docs.newapi.pro/api/anthropic-chat)
|
||||
- ⚡ [Google Gemini](https://docs.newapi.pro/api/google-gemini-chat/)
|
||||
- 🔄 [Rerankモデル](https://docs.newapi.pro/api/jinaai-rerank)(Cohere、Jina)
|
||||
- ⚡ [OpenAI Responses](https://docs.newapi.pro/ja/docs/api/ai-model/chat/openai/create-response)
|
||||
- ⚡ [OpenAI Realtime API](https://docs.newapi.pro/ja/docs/api/ai-model/realtime/create-realtime-session)(Azureを含む)
|
||||
- ⚡ [Claude Messages](https://docs.newapi.pro/ja/docs/api/ai-model/chat/create-message)
|
||||
- ⚡ [Google Gemini](https://doc.newapi.pro/ja/api/google-gemini-chat)
|
||||
- 🔄 [Rerankモデル](https://docs.newapi.pro/ja/docs/api/ai-model/rerank/create-rerank)
|
||||
- ⚡ [OpenAI Realtime API](https://docs.newapi.pro/ja/docs/api/ai-model/realtime/create-realtime-session)
|
||||
- ⚡ [Claude Messages](https://docs.newapi.pro/ja/docs/api/ai-model/chat/create-message)
|
||||
- ⚡ [Google Gemini](https://doc.newapi.pro/ja/api/google-gemini-chat)
|
||||
- 🔄 [Rerankモデル](https://docs.newapi.pro/ja/docs/api/ai-model/rerank/create-rerank)(Cohere、Jina)
|
||||
|
||||
**インテリジェントルーティング:**
|
||||
- ⚖️ チャネル重み付けランダム
|
||||
@@ -251,16 +251,16 @@ docker run --name new-api -d --restart always \
|
||||
|
||||
## 🤖 モデルサポート
|
||||
|
||||
> 詳細については[APIドキュメント - 中継インターフェース](https://docs.newapi.pro/api)
|
||||
> 詳細については[APIドキュメント - 中継インターフェース](https://docs.newapi.pro/ja/docs/api)
|
||||
|
||||
| モデルタイプ | 説明 | ドキュメント |
|
||||
|---------|------|------|
|
||||
| 🤖 OpenAI GPTs | gpt-4-gizmo-* シリーズ | - |
|
||||
| 🎨 Midjourney-Proxy | [Midjourney-Proxy(Plus)](https://github.com/novicezk/midjourney-proxy) | [ドキュメント](https://docs.newapi.pro/api/midjourney-proxy-image) |
|
||||
| 🎵 Suno-API | [Suno API](https://github.com/Suno-API/Suno-API) | [ドキュメント](https://docs.newapi.pro/api/suno-music) |
|
||||
| 🔄 Rerank | Cohere、Jina | [ドキュメント](https://docs.newapi.pro/api/jinaai-rerank) |
|
||||
| 💬 Claude | Messagesフォーマット | [ドキュメント](https://docs.newapi.pro/api/suno-music) |
|
||||
| 🌐 Gemini | Google Geminiフォーマット | [ドキュメント](https://docs.newapi.pro/api/google-gemini-chat/) |
|
||||
| 🎨 Midjourney-Proxy | [Midjourney-Proxy(Plus)](https://github.com/novicezk/midjourney-proxy) | [ドキュメント](https://doc.newapi.pro/ja/api/midjourney-proxy-image) |
|
||||
| 🎵 Suno-API | [Suno API](https://github.com/Suno-API/Suno-API) | [ドキュメント](https://doc.newapi.pro/ja/api/suno-music) |
|
||||
| 🔄 Rerank | Cohere、Jina | [ドキュメント](https://docs.newapi.pro/ja/docs/api/ai-model/rerank/create-rerank) |
|
||||
| 💬 Claude | Messagesフォーマット | [ドキュメント](https://docs.newapi.pro/ja/docs/api/ai-model/chat/create-message) |
|
||||
| 🌐 Gemini | Google Geminiフォーマット | [ドキュメント](https://doc.newapi.pro/ja/api/google-gemini-chat) |
|
||||
| 🔧 Dify | ChatFlowモード | - |
|
||||
| 🎯 カスタム | 完全な呼び出しアドレスの入力をサポート | - |
|
||||
|
||||
@@ -269,16 +269,16 @@ docker run --name new-api -d --restart always \
|
||||
<details>
|
||||
<summary>完全なインターフェースリストを表示</summary>
|
||||
|
||||
- [チャットインターフェース (Chat Completions)](https://docs.newapi.pro/api/openai-chat)
|
||||
- [レスポンスインターフェース (Responses)](https://docs.newapi.pro/api/openai-responses)
|
||||
- [イメージインターフェース (Image)](https://docs.newapi.pro/api/openai-image)
|
||||
- [オーディオインターフェース (Audio)](https://docs.newapi.pro/api/openai-audio)
|
||||
- [ビデオインターフェース (Video)](https://docs.newapi.pro/api/openai-video)
|
||||
- [エンベッドインターフェース (Embeddings)](https://docs.newapi.pro/api/openai-embeddings)
|
||||
- [再ランク付けインターフェース (Rerank)](https://docs.newapi.pro/api/jinaai-rerank)
|
||||
- [リアルタイム対話インターフェース (Realtime)](https://docs.newapi.pro/api/openai-realtime)
|
||||
- [Claudeチャット](https://docs.newapi.pro/api/anthropic-chat)
|
||||
- [Google Geminiチャット](https://docs.newapi.pro/api/google-gemini-chat/)
|
||||
- [チャットインターフェース (Chat Completions)](https://docs.newapi.pro/ja/docs/api/ai-model/chat/openai/create-chat-completion)
|
||||
- [レスポンスインターフェース (Responses)](https://docs.newapi.pro/ja/docs/api/ai-model/chat/openai/create-response)
|
||||
- [イメージインターフェース (Image)](https://docs.newapi.pro/ja/docs/api/ai-model/images/openai/v1-images-generations--post)
|
||||
- [オーディオインターフェース (Audio)](https://docs.newapi.pro/ja/docs/api/ai-model/audio/openai/create-transcription)
|
||||
- [ビデオインターフェース (Video)](https://docs.newapi.pro/ja/docs/api/ai-model/videos/create-video-generation)
|
||||
- [エンベッドインターフェース (Embeddings)](https://docs.newapi.pro/ja/docs/api/ai-model/embeddings/create-embedding)
|
||||
- [再ランク付けインターフェース (Rerank)](https://docs.newapi.pro/ja/docs/api/ai-model/rerank/create-rerank)
|
||||
- [リアルタイム対話インターフェース (Realtime)](https://docs.newapi.pro/ja/docs/api/ai-model/realtime/create-realtime-session)
|
||||
- [Claudeチャット](https://docs.newapi.pro/ja/docs/api/ai-model/chat/create-message)
|
||||
- [Google Geminiチャット](https://doc.newapi.pro/ja/api/google-gemini-chat)
|
||||
|
||||
</details>
|
||||
|
||||
@@ -310,10 +310,11 @@ docker run --name new-api -d --restart always \
|
||||
| `REDIS_CONN_STRING` | Redis接続文字列 | - |
|
||||
| `STREAMING_TIMEOUT` | ストリーミング応答のタイムアウト時間(秒) | `300` |
|
||||
| `STREAM_SCANNER_MAX_BUFFER_MB` | ストリームスキャナの1行あたりバッファ上限(MB)。4K画像など巨大なbase64 `data:` ペイロードを扱う場合は値を増加させてください | `64` |
|
||||
| `MAX_REQUEST_BODY_MB` | リクエストボディ最大サイズ(MB、**解凍後**に計測。巨大リクエスト/zip bomb によるメモリ枯渇を防止)。超過時は `413` | `32` |
|
||||
| `AZURE_DEFAULT_API_VERSION` | Azure APIバージョン | `2025-04-01-preview` |
|
||||
| `ERROR_LOG_ENABLED` | エラーログスイッチ | `false` |
|
||||
|
||||
📖 **完全な設定:** [環境変数ドキュメント](https://docs.newapi.pro/installation/environment-variables)
|
||||
📖 **完全な設定:** [環境変数ドキュメント](https://docs.newapi.pro/ja/docs/installation/config-maintenance/environment-variables)
|
||||
|
||||
</details>
|
||||
|
||||
@@ -413,10 +414,10 @@ docker run --name new-api -d --restart always \
|
||||
|
||||
| リソース | リンク |
|
||||
|------|------|
|
||||
| 📘 よくある質問 | [FAQ](https://docs.newapi.pro/support/faq) |
|
||||
| 💬 コミュニティ交流 | [交流チャネル](https://docs.newapi.pro/support/community-interaction) |
|
||||
| 🐛 問題のフィードバック | [問題フィードバック](https://docs.newapi.pro/support/feedback-issues) |
|
||||
| 📚 完全なドキュメント | [公式ドキュメント](https://docs.newapi.pro/support) |
|
||||
| 📘 よくある質問 | [FAQ](https://docs.newapi.pro/ja/docs/support/faq) |
|
||||
| 💬 コミュニティ交流 | [交流チャネル](https://docs.newapi.pro/ja/docs/support/community-interaction) |
|
||||
| 🐛 問題のフィードバック | [問題フィードバック](https://docs.newapi.pro/ja/docs/support/feedback-issues) |
|
||||
| 📚 完全なドキュメント | [公式ドキュメント](https://docs.newapi.pro/ja/docs) |
|
||||
|
||||
### 🤝 貢献ガイド
|
||||
|
||||
@@ -445,7 +446,7 @@ docker run --name new-api -d --restart always \
|
||||
|
||||
このプロジェクトがあなたのお役に立てたなら、ぜひ ⭐️ スターをください!
|
||||
|
||||
**[公式ドキュメント](https://docs.newapi.pro/)** • **[問題フィードバック](https://github.com/Calcium-Ion/new-api/issues)** • **[最新リリース](https://github.com/Calcium-Ion/new-api/releases)**
|
||||
**[公式ドキュメント](https://docs.newapi.pro/ja/docs)** • **[問題フィードバック](https://github.com/Calcium-Ion/new-api/issues)** • **[最新リリース](https://github.com/Calcium-Ion/new-api/releases)**
|
||||
|
||||
<sub>❤️ で構築された QuantumNous</sub>
|
||||
|
||||
|
||||
71
README.md
71
README.md
@@ -146,7 +146,7 @@ docker run --name new-api -d --restart always \
|
||||
|
||||
🎉 部署完成后,访问 `http://localhost:3000` 即可使用!
|
||||
|
||||
📖 更多部署方式请参考 [部署指南](https://docs.newapi.pro/installation)
|
||||
📖 更多部署方式请参考 [部署指南](https://docs.newapi.pro/zh/docs/installation)
|
||||
|
||||
---
|
||||
|
||||
@@ -154,7 +154,7 @@ docker run --name new-api -d --restart always \
|
||||
|
||||
<div align="center">
|
||||
|
||||
### 📖 [官方文档](https://docs.newapi.pro/) | [](https://deepwiki.com/QuantumNous/new-api)
|
||||
### 📖 [官方文档](https://docs.newapi.pro/zh/docs) | [](https://deepwiki.com/QuantumNous/new-api)
|
||||
|
||||
</div>
|
||||
|
||||
@@ -162,17 +162,17 @@ docker run --name new-api -d --restart always \
|
||||
|
||||
| 分类 | 链接 |
|
||||
|------|------|
|
||||
| 🚀 部署指南 | [安装文档](https://docs.newapi.pro/installation) |
|
||||
| ⚙️ 环境配置 | [环境变量](https://docs.newapi.pro/installation/environment-variables) |
|
||||
| 📡 接口文档 | [API 文档](https://docs.newapi.pro/api) |
|
||||
| ❓ 常见问题 | [FAQ](https://docs.newapi.pro/support/faq) |
|
||||
| 💬 社区交流 | [交流渠道](https://docs.newapi.pro/support/community-interaction) |
|
||||
| 🚀 部署指南 | [安装文档](https://docs.newapi.pro/zh/docs/installation) |
|
||||
| ⚙️ 环境配置 | [环境变量](https://docs.newapi.pro/zh/docs/installation/config-maintenance/environment-variables) |
|
||||
| 📡 接口文档 | [API 文档](https://docs.newapi.pro/zh/docs/api) |
|
||||
| ❓ 常见问题 | [FAQ](https://docs.newapi.pro/zh/docs/support/faq) |
|
||||
| 💬 社区交流 | [交流渠道](https://docs.newapi.pro/zh/docs/support/community-interaction) |
|
||||
|
||||
---
|
||||
|
||||
## ✨ 主要特性
|
||||
|
||||
> 详细特性请参考 [特性说明](https://docs.newapi.pro/wiki/features-introduction)
|
||||
> 详细特性请参考 [特性说明](https://docs.newapi.pro/zh/docs/guide/wiki/basic-concepts/features-introduction)
|
||||
|
||||
### 🎨 核心功能
|
||||
|
||||
@@ -202,11 +202,11 @@ docker run --name new-api -d --restart always \
|
||||
### 🚀 高级功能
|
||||
|
||||
**API 格式支持:**
|
||||
- ⚡ [OpenAI Responses](https://docs.newapi.pro/api/openai-responses)
|
||||
- ⚡ [OpenAI Realtime API](https://docs.newapi.pro/api/openai-realtime)(含 Azure)
|
||||
- ⚡ [Claude Messages](https://docs.newapi.pro/api/anthropic-chat)
|
||||
- ⚡ [Google Gemini](https://docs.newapi.pro/api/google-gemini-chat/)
|
||||
- 🔄 [Rerank 模型](https://docs.newapi.pro/api/jinaai-rerank)(Cohere、Jina)
|
||||
- ⚡ [OpenAI Responses](https://docs.newapi.pro/zh/docs/api/ai-model/chat/openai/create-response)
|
||||
- ⚡ [OpenAI Realtime API](https://docs.newapi.pro/zh/docs/api/ai-model/realtime/create-realtime-session)(含 Azure)
|
||||
- ⚡ [Claude Messages](https://docs.newapi.pro/zh/docs/api/ai-model/chat/create-message)
|
||||
- ⚡ [Google Gemini](https://doc.newapi.pro/api/google-gemini-chat)
|
||||
- 🔄 [Rerank 模型](https://docs.newapi.pro/zh/docs/api/ai-model/rerank/create-rerank)(Cohere、Jina)
|
||||
|
||||
**智能路由:**
|
||||
- ⚖️ 渠道加权随机
|
||||
@@ -247,16 +247,16 @@ docker run --name new-api -d --restart always \
|
||||
|
||||
## 🤖 模型支持
|
||||
|
||||
> 详情请参考 [接口文档 - 中继接口](https://docs.newapi.pro/api)
|
||||
> 详情请参考 [接口文档 - 中继接口](https://docs.newapi.pro/zh/docs/api)
|
||||
|
||||
| 模型类型 | 说明 | 文档 |
|
||||
|---------|------|------|
|
||||
| 🤖 OpenAI GPTs | gpt-4-gizmo-* 系列 | - |
|
||||
| 🎨 Midjourney-Proxy | [Midjourney-Proxy(Plus)](https://github.com/novicezk/midjourney-proxy) | [文档](https://docs.newapi.pro/api/midjourney-proxy-image) |
|
||||
| 🎵 Suno-API | [Suno API](https://github.com/Suno-API/Suno-API) | [文档](https://docs.newapi.pro/api/suno-music) |
|
||||
| 🔄 Rerank | Cohere、Jina | [文档](https://docs.newapi.pro/api/jinaai-rerank) |
|
||||
| 💬 Claude | Messages 格式 | [文档](https://docs.newapi.pro/api/anthropic-chat) |
|
||||
| 🌐 Gemini | Google Gemini 格式 | [文档](https://docs.newapi.pro/api/google-gemini-chat/) |
|
||||
| 🎨 Midjourney-Proxy | [Midjourney-Proxy(Plus)](https://github.com/novicezk/midjourney-proxy) | [文档](https://doc.newapi.pro/api/midjourney-proxy-image) |
|
||||
| 🎵 Suno-API | [Suno API](https://github.com/Suno-API/Suno-API) | [文档](https://doc.newapi.pro/api/suno-music) |
|
||||
| 🔄 Rerank | Cohere、Jina | [文档](https://docs.newapi.pro/zh/docs/api/ai-model/rerank/create-rerank) |
|
||||
| 💬 Claude | Messages 格式 | [文档](https://docs.newapi.pro/zh/docs/api/ai-model/chat/create-message) |
|
||||
| 🌐 Gemini | Google Gemini 格式 | [文档](https://doc.newapi.pro/api/google-gemini-chat) |
|
||||
| 🔧 Dify | ChatFlow 模式 | - |
|
||||
| 🎯 自定义 | 支持完整调用地址 | - |
|
||||
|
||||
@@ -265,16 +265,16 @@ docker run --name new-api -d --restart always \
|
||||
<details>
|
||||
<summary>查看完整接口列表</summary>
|
||||
|
||||
- [聊天接口 (Chat Completions)](https://docs.newapi.pro/api/openai-chat)
|
||||
- [响应接口 (Responses)](https://docs.newapi.pro/api/openai-responses)
|
||||
- [图像接口 (Image)](https://docs.newapi.pro/api/openai-image)
|
||||
- [音频接口 (Audio)](https://docs.newapi.pro/api/openai-audio)
|
||||
- [视频接口 (Video)](https://docs.newapi.pro/api/openai-video)
|
||||
- [嵌入接口 (Embeddings)](https://docs.newapi.pro/api/openai-embeddings)
|
||||
- [重排序接口 (Rerank)](https://docs.newapi.pro/api/jinaai-rerank)
|
||||
- [实时对话 (Realtime)](https://docs.newapi.pro/api/openai-realtime)
|
||||
- [Claude 聊天](https://docs.newapi.pro/api/anthropic-chat)
|
||||
- [Google Gemini 聊天](https://docs.newapi.pro/api/google-gemini-chat)
|
||||
- [聊天接口 (Chat Completions)](https://docs.newapi.pro/zh/docs/api/ai-model/chat/openai/create-chat-completion)
|
||||
- [响应接口 (Responses)](https://docs.newapi.pro/zh/docs/api/ai-model/chat/openai/create-response)
|
||||
- [图像接口 (Image)](https://docs.newapi.pro/zh/docs/api/ai-model/images/openai/v1-images-generations--post)
|
||||
- [音频接口 (Audio)](https://docs.newapi.pro/zh/docs/api/ai-model/audio/openai/create-transcription)
|
||||
- [视频接口 (Video)](https://docs.newapi.pro/zh/docs/api/ai-model/videos/create-video-generation)
|
||||
- [嵌入接口 (Embeddings)](https://docs.newapi.pro/zh/docs/api/ai-model/embeddings/create-embedding)
|
||||
- [重排序接口 (Rerank)](https://docs.newapi.pro/zh/docs/api/ai-model/rerank/create-rerank)
|
||||
- [实时对话 (Realtime)](https://docs.newapi.pro/zh/docs/api/ai-model/realtime/create-realtime-session)
|
||||
- [Claude 聊天](https://docs.newapi.pro/zh/docs/api/ai-model/chat/create-message)
|
||||
- [Google Gemini 聊天](https://doc.newapi.pro/api/google-gemini-chat)
|
||||
|
||||
</details>
|
||||
|
||||
@@ -306,10 +306,11 @@ docker run --name new-api -d --restart always \
|
||||
| `REDIS_CONN_STRING` | Redis 连接字符串 | - |
|
||||
| `STREAMING_TIMEOUT` | 流式超时时间(秒) | `300` |
|
||||
| `STREAM_SCANNER_MAX_BUFFER_MB` | 流式扫描器单行最大缓冲(MB),图像生成等超大 `data:` 片段(如 4K 图片 base64)需适当调大 | `64` |
|
||||
| `MAX_REQUEST_BODY_MB` | 请求体最大大小(MB,**解压后**计;防止超大请求/zip bomb 导致内存暴涨),超过将返回 `413` | `32` |
|
||||
| `AZURE_DEFAULT_API_VERSION` | Azure API 版本 | `2025-04-01-preview` |
|
||||
| `ERROR_LOG_ENABLED` | 错误日志开关 | `false` |
|
||||
|
||||
📖 **完整配置:** [环境变量文档](https://docs.newapi.pro/installation/environment-variables)
|
||||
📖 **完整配置:** [环境变量文档](https://docs.newapi.pro/zh/docs/installation/config-maintenance/environment-variables)
|
||||
|
||||
</details>
|
||||
|
||||
@@ -411,10 +412,10 @@ docker run --name new-api -d --restart always \
|
||||
|
||||
| 资源 | 链接 |
|
||||
|------|------|
|
||||
| 📘 常见问题 | [FAQ](https://docs.newapi.pro/support/faq) |
|
||||
| 💬 社区交流 | [交流渠道](https://docs.newapi.pro/support/community-interaction) |
|
||||
| 🐛 反馈问题 | [问题反馈](https://docs.newapi.pro/support/feedback-issues) |
|
||||
| 📚 完整文档 | [官方文档](https://docs.newapi.pro/support) |
|
||||
| 📘 常见问题 | [FAQ](https://docs.newapi.pro/zh/docs/support/faq) |
|
||||
| 💬 社区交流 | [交流渠道](https://docs.newapi.pro/zh/docs/support/community-interaction) |
|
||||
| 🐛 反馈问题 | [问题反馈](https://docs.newapi.pro/zh/docs/support/feedback-issues) |
|
||||
| 📚 完整文档 | [官方文档](https://docs.newapi.pro/zh/docs) |
|
||||
|
||||
### 🤝 贡献指南
|
||||
|
||||
@@ -443,7 +444,7 @@ docker run --name new-api -d --restart always \
|
||||
|
||||
如果这个项目对你有帮助,欢迎给我们一个 ⭐️ Star!
|
||||
|
||||
**[官方文档](https://docs.newapi.pro/)** • **[问题反馈](https://github.com/Calcium-Ion/new-api/issues)** • **[最新发布](https://github.com/Calcium-Ion/new-api/releases)**
|
||||
**[官方文档](https://docs.newapi.pro/zh/docs)** • **[问题反馈](https://github.com/Calcium-Ion/new-api/issues)** • **[最新发布](https://github.com/Calcium-Ion/new-api/releases)**
|
||||
|
||||
<sub>Built with ❤️ by QuantumNous</sub>
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ package common
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"mime"
|
||||
"mime/multipart"
|
||||
@@ -12,24 +12,61 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/QuantumNous/new-api/constant"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
const KeyRequestBody = "key_request_body"
|
||||
|
||||
func GetRequestBody(c *gin.Context) ([]byte, error) {
|
||||
requestBody, _ := c.Get(KeyRequestBody)
|
||||
if requestBody != nil {
|
||||
return requestBody.([]byte), nil
|
||||
var ErrRequestBodyTooLarge = errors.New("request body too large")
|
||||
|
||||
func IsRequestBodyTooLargeError(err error) bool {
|
||||
if err == nil {
|
||||
return false
|
||||
}
|
||||
requestBody, err := io.ReadAll(c.Request.Body)
|
||||
if errors.Is(err, ErrRequestBodyTooLarge) {
|
||||
return true
|
||||
}
|
||||
var mbe *http.MaxBytesError
|
||||
return errors.As(err, &mbe)
|
||||
}
|
||||
|
||||
func GetRequestBody(c *gin.Context) ([]byte, error) {
|
||||
cached, exists := c.Get(KeyRequestBody)
|
||||
if exists && cached != nil {
|
||||
if b, ok := cached.([]byte); ok {
|
||||
return b, nil
|
||||
}
|
||||
}
|
||||
maxMB := constant.MaxRequestBodyMB
|
||||
if maxMB < 0 {
|
||||
// no limit
|
||||
body, err := io.ReadAll(c.Request.Body)
|
||||
_ = c.Request.Body.Close()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.Set(KeyRequestBody, body)
|
||||
return body, nil
|
||||
}
|
||||
maxBytes := int64(maxMB) << 20
|
||||
|
||||
limited := io.LimitReader(c.Request.Body, maxBytes+1)
|
||||
body, err := io.ReadAll(limited)
|
||||
if err != nil {
|
||||
_ = c.Request.Body.Close()
|
||||
if IsRequestBodyTooLargeError(err) {
|
||||
return nil, errors.Wrap(ErrRequestBodyTooLarge, fmt.Sprintf("request body exceeds %d MB", maxMB))
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
_ = c.Request.Body.Close()
|
||||
c.Set(KeyRequestBody, requestBody)
|
||||
return requestBody.([]byte), nil
|
||||
if int64(len(body)) > maxBytes {
|
||||
return nil, errors.Wrap(ErrRequestBodyTooLarge, fmt.Sprintf("request body exceeds %d MB", maxMB))
|
||||
}
|
||||
c.Set(KeyRequestBody, body)
|
||||
return body, nil
|
||||
}
|
||||
|
||||
func UnmarshalBodyReusable(c *gin.Context, v any) error {
|
||||
|
||||
@@ -117,6 +117,8 @@ func initConstantEnv() {
|
||||
constant.DifyDebug = GetEnvOrDefaultBool("DIFY_DEBUG", true)
|
||||
constant.MaxFileDownloadMB = GetEnvOrDefault("MAX_FILE_DOWNLOAD_MB", 20)
|
||||
constant.StreamScannerMaxBufferMB = GetEnvOrDefault("STREAM_SCANNER_MAX_BUFFER_MB", 64)
|
||||
// MaxRequestBodyMB 请求体最大大小(解压后),用于防止超大请求/zip bomb导致内存暴涨
|
||||
constant.MaxRequestBodyMB = GetEnvOrDefault("MAX_REQUEST_BODY_MB", 64)
|
||||
// ForceStreamOption 覆盖请求参数,强制返回usage信息
|
||||
constant.ForceStreamOption = GetEnvOrDefaultBool("FORCE_STREAM_OPTION", true)
|
||||
constant.CountToken = GetEnvOrDefaultBool("CountToken", true)
|
||||
|
||||
29
common/ip.go
29
common/ip.go
@@ -2,6 +2,15 @@ package common
|
||||
|
||||
import "net"
|
||||
|
||||
func IsIP(s string) bool {
|
||||
ip := net.ParseIP(s)
|
||||
return ip != nil
|
||||
}
|
||||
|
||||
func ParseIP(s string) net.IP {
|
||||
return net.ParseIP(s)
|
||||
}
|
||||
|
||||
func IsPrivateIP(ip net.IP) bool {
|
||||
if ip.IsLoopback() || ip.IsLinkLocalUnicast() || ip.IsLinkLocalMulticast() {
|
||||
return true
|
||||
@@ -20,3 +29,23 @@ func IsPrivateIP(ip net.IP) bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func IsIpInCIDRList(ip net.IP, cidrList []string) bool {
|
||||
for _, cidr := range cidrList {
|
||||
_, network, err := net.ParseCIDR(cidr)
|
||||
if err != nil {
|
||||
// 尝试作为单个IP处理
|
||||
if whitelistIP := net.ParseIP(cidr); whitelistIP != nil {
|
||||
if ip.Equal(whitelistIP) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if network.Contains(ip) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -186,23 +186,7 @@ func isIPListed(ip net.IP, list []string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, whitelistCIDR := range list {
|
||||
_, network, err := net.ParseCIDR(whitelistCIDR)
|
||||
if err != nil {
|
||||
// 尝试作为单个IP处理
|
||||
if whitelistIP := net.ParseIP(whitelistCIDR); whitelistIP != nil {
|
||||
if ip.Equal(whitelistIP) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if network.Contains(ip) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
return IsIpInCIDRList(ip, list)
|
||||
}
|
||||
|
||||
// IsIPAccessAllowed 检查IP是否允许访问
|
||||
|
||||
@@ -217,11 +217,6 @@ func IntMax(a int, b int) int {
|
||||
}
|
||||
}
|
||||
|
||||
func IsIP(s string) bool {
|
||||
ip := net.ParseIP(s)
|
||||
return ip != nil
|
||||
}
|
||||
|
||||
func GetUUID() string {
|
||||
code := uuid.New().String()
|
||||
code = strings.Replace(code, "-", "", -1)
|
||||
|
||||
@@ -9,6 +9,7 @@ var CountToken bool
|
||||
var GetMediaToken bool
|
||||
var GetMediaTokenNotStream bool
|
||||
var UpdateTask bool
|
||||
var MaxRequestBodyMB int
|
||||
var AzureDefaultAPIVersion string
|
||||
var GeminiVisionMaxImageNum int
|
||||
var NotifyLimitCount int
|
||||
|
||||
@@ -40,6 +40,13 @@ type testResult struct {
|
||||
newAPIError *types.NewAPIError
|
||||
}
|
||||
|
||||
// testChannel executes a test request against the given channel using the provided testModel and optional endpointType,
|
||||
// and returns a testResult containing the test context and any encountered error information.
|
||||
// It selects or derives a model when testModel is empty, auto-detects the request endpoint (chat, responses, embeddings, images, rerank) when endpointType is not specified,
|
||||
// converts and relays the request to the upstream adapter, and parses the upstream response to collect usage and pricing information.
|
||||
// On upstream responses that indicate the chat/completions `messages` parameter is unsupported and endpointType was not specified, it will retry the test using the Responses API.
|
||||
// The function records consumption logs and returns a testResult with a populated context on success, or with localErr/newAPIError set on failure;
|
||||
// for channel types that are not supported for testing it returns a localErr explaining that the channel test is not supported.
|
||||
func testChannel(channel *model.Channel, testModel string, endpointType string) testResult {
|
||||
tik := time.Now()
|
||||
var unsupportedTestChannelTypes = []int{
|
||||
@@ -75,6 +82,8 @@ func testChannel(channel *model.Channel, testModel string, endpointType string)
|
||||
}
|
||||
}
|
||||
|
||||
originTestModel := testModel
|
||||
|
||||
requestPath := "/v1/chat/completions"
|
||||
|
||||
// 如果指定了端点类型,使用指定的端点类型
|
||||
@@ -84,6 +93,10 @@ func testChannel(channel *model.Channel, testModel string, endpointType string)
|
||||
}
|
||||
} else {
|
||||
// 如果没有指定端点类型,使用原有的自动检测逻辑
|
||||
if common.IsOpenAIResponseOnlyModel(testModel) {
|
||||
requestPath = "/v1/responses"
|
||||
}
|
||||
|
||||
// 先判断是否为 Embedding 模型
|
||||
if strings.Contains(strings.ToLower(testModel), "embedding") ||
|
||||
strings.HasPrefix(testModel, "m3e") || // m3e 系列模型
|
||||
@@ -319,6 +332,13 @@ func testChannel(channel *model.Channel, testModel string, endpointType string)
|
||||
httpResp = resp.(*http.Response)
|
||||
if httpResp.StatusCode != http.StatusOK {
|
||||
err := service.RelayErrorHandler(c.Request.Context(), httpResp, true)
|
||||
// 自动检测模式下,如果上游不支持 chat.completions 的 messages 参数,尝试切换到 Responses API 再测一次。
|
||||
if endpointType == "" && requestPath == "/v1/chat/completions" && err != nil {
|
||||
lowerErr := strings.ToLower(err.Error())
|
||||
if strings.Contains(lowerErr, "unsupported parameter") && strings.Contains(lowerErr, "messages") {
|
||||
return testChannel(channel, originTestModel, string(constant.EndpointTypeOpenAIResponse))
|
||||
}
|
||||
}
|
||||
return testResult{
|
||||
context: c,
|
||||
localErr: err,
|
||||
@@ -389,6 +409,7 @@ func testChannel(channel *model.Channel, testModel string, endpointType string)
|
||||
}
|
||||
}
|
||||
|
||||
// for embedding models, and otherwise a chat/completion request with model-specific token limit heuristics.
|
||||
func buildTestRequest(model string, endpointType string) dto.Request {
|
||||
// 根据端点类型构建不同的测试请求
|
||||
if endpointType != "" {
|
||||
@@ -417,9 +438,12 @@ func buildTestRequest(model string, endpointType string) dto.Request {
|
||||
}
|
||||
case constant.EndpointTypeOpenAIResponse:
|
||||
// 返回 OpenAIResponsesRequest
|
||||
maxOutputTokens := uint(10)
|
||||
return &dto.OpenAIResponsesRequest{
|
||||
Model: model,
|
||||
Input: json.RawMessage("\"hi\""),
|
||||
Model: model,
|
||||
Input: json.RawMessage(`[{"role":"user","content":"hi"}]`),
|
||||
MaxOutputTokens: maxOutputTokens,
|
||||
Stream: true,
|
||||
}
|
||||
case constant.EndpointTypeAnthropic, constant.EndpointTypeGemini, constant.EndpointTypeOpenAI:
|
||||
// 返回 GeneralOpenAIRequest
|
||||
@@ -442,6 +466,16 @@ func buildTestRequest(model string, endpointType string) dto.Request {
|
||||
}
|
||||
|
||||
// 自动检测逻辑(保持原有行为)
|
||||
if common.IsOpenAIResponseOnlyModel(model) {
|
||||
maxOutputTokens := uint(10)
|
||||
return &dto.OpenAIResponsesRequest{
|
||||
Model: model,
|
||||
Input: json.RawMessage(`[{"role":"user","content":"hi"}]`),
|
||||
MaxOutputTokens: maxOutputTokens,
|
||||
Stream: true,
|
||||
}
|
||||
}
|
||||
|
||||
// 先判断是否为 Embedding 模型
|
||||
if strings.Contains(strings.ToLower(model), "embedding") ||
|
||||
strings.HasPrefix(model, "m3e") ||
|
||||
@@ -640,4 +674,4 @@ func AutomaticallyTestChannels() {
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -114,7 +114,7 @@ func DiscordOAuth(c *gin.Context) {
|
||||
DiscordBind(c)
|
||||
return
|
||||
}
|
||||
if !system_setting.GetDiscordSettings().Enabled {
|
||||
if !system_setting.GetDiscordSettings().Enabled {
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"success": false,
|
||||
"message": "管理员未开启通过 Discord 登录以及注册",
|
||||
|
||||
@@ -2,6 +2,7 @@ package controller
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
@@ -104,7 +105,12 @@ func Relay(c *gin.Context, relayFormat types.RelayFormat) {
|
||||
|
||||
request, err := helper.GetAndValidateRequest(c, relayFormat)
|
||||
if err != nil {
|
||||
newAPIError = types.NewError(err, types.ErrorCodeInvalidRequest)
|
||||
// Map "request body too large" to 413 so clients can handle it correctly
|
||||
if common.IsRequestBodyTooLargeError(err) || errors.Is(err, common.ErrRequestBodyTooLarge) {
|
||||
newAPIError = types.NewErrorWithStatusCode(err, types.ErrorCodeReadRequestBodyFailed, http.StatusRequestEntityTooLarge, types.ErrOptionWithSkipRetry())
|
||||
} else {
|
||||
newAPIError = types.NewError(err, types.ErrorCodeInvalidRequest)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -114,9 +120,17 @@ func Relay(c *gin.Context, relayFormat types.RelayFormat) {
|
||||
return
|
||||
}
|
||||
|
||||
meta := request.GetTokenCountMeta()
|
||||
needSensitiveCheck := setting.ShouldCheckPromptSensitive()
|
||||
needCountToken := constant.CountToken
|
||||
// Avoid building huge CombineText (strings.Join) when token counting and sensitive check are both disabled.
|
||||
var meta *types.TokenCountMeta
|
||||
if needSensitiveCheck || needCountToken {
|
||||
meta = request.GetTokenCountMeta()
|
||||
} else {
|
||||
meta = fastTokenCountMetaForPricing(request)
|
||||
}
|
||||
|
||||
if setting.ShouldCheckPromptSensitive() {
|
||||
if needSensitiveCheck && meta != nil {
|
||||
contains, words := service.CheckSensitiveText(meta.CombineText)
|
||||
if contains {
|
||||
logger.LogWarn(c, fmt.Sprintf("user sensitive words detected: %s", strings.Join(words, ", ")))
|
||||
@@ -165,15 +179,24 @@ func Relay(c *gin.Context, relayFormat types.RelayFormat) {
|
||||
}
|
||||
|
||||
for ; retryParam.GetRetry() <= common.RetryTimes; retryParam.IncreaseRetry() {
|
||||
channel, err := getChannel(c, relayInfo, retryParam)
|
||||
if err != nil {
|
||||
logger.LogError(c, err.Error())
|
||||
newAPIError = err
|
||||
channel, channelErr := getChannel(c, relayInfo, retryParam)
|
||||
if channelErr != nil {
|
||||
logger.LogError(c, channelErr.Error())
|
||||
newAPIError = channelErr
|
||||
break
|
||||
}
|
||||
|
||||
addUsedChannel(c, channel.Id)
|
||||
requestBody, _ := common.GetRequestBody(c)
|
||||
requestBody, bodyErr := common.GetRequestBody(c)
|
||||
if bodyErr != nil {
|
||||
// Ensure consistent 413 for oversized bodies even when error occurs later (e.g., retry path)
|
||||
if common.IsRequestBodyTooLargeError(bodyErr) || errors.Is(bodyErr, common.ErrRequestBodyTooLarge) {
|
||||
newAPIError = types.NewErrorWithStatusCode(bodyErr, types.ErrorCodeReadRequestBodyFailed, http.StatusRequestEntityTooLarge, types.ErrOptionWithSkipRetry())
|
||||
} else {
|
||||
newAPIError = types.NewErrorWithStatusCode(bodyErr, types.ErrorCodeReadRequestBodyFailed, http.StatusBadRequest, types.ErrOptionWithSkipRetry())
|
||||
}
|
||||
break
|
||||
}
|
||||
c.Request.Body = io.NopCloser(bytes.NewBuffer(requestBody))
|
||||
|
||||
switch relayFormat {
|
||||
@@ -218,6 +241,33 @@ func addUsedChannel(c *gin.Context, channelId int) {
|
||||
c.Set("use_channel", useChannel)
|
||||
}
|
||||
|
||||
func fastTokenCountMetaForPricing(request dto.Request) *types.TokenCountMeta {
|
||||
if request == nil {
|
||||
return &types.TokenCountMeta{}
|
||||
}
|
||||
meta := &types.TokenCountMeta{
|
||||
TokenType: types.TokenTypeTokenizer,
|
||||
}
|
||||
switch r := request.(type) {
|
||||
case *dto.GeneralOpenAIRequest:
|
||||
if r.MaxCompletionTokens > r.MaxTokens {
|
||||
meta.MaxTokens = int(r.MaxCompletionTokens)
|
||||
} else {
|
||||
meta.MaxTokens = int(r.MaxTokens)
|
||||
}
|
||||
case *dto.OpenAIResponsesRequest:
|
||||
meta.MaxTokens = int(r.MaxOutputTokens)
|
||||
case *dto.ClaudeRequest:
|
||||
meta.MaxTokens = int(r.MaxTokens)
|
||||
case *dto.ImageRequest:
|
||||
// Pricing for image requests depends on ImagePriceRatio; safe to compute even when CountToken is disabled.
|
||||
return r.GetTokenCountMeta()
|
||||
default:
|
||||
// Best-effort: leave CombineText empty to avoid large allocations.
|
||||
}
|
||||
return meta
|
||||
}
|
||||
|
||||
func getChannel(c *gin.Context, info *relaycommon.RelayInfo, retryParam *service.RetryParam) (*model.Channel, *types.NewAPIError) {
|
||||
if info.ChannelMeta == nil {
|
||||
autoBan := c.GetBool("auto_ban")
|
||||
@@ -432,7 +482,15 @@ func RelayTask(c *gin.Context) {
|
||||
logger.LogInfo(c, fmt.Sprintf("using channel #%d to retry (remain times %d)", channel.Id, retryParam.GetRetry()))
|
||||
//middleware.SetupContextForSelectedChannel(c, channel, originalModel)
|
||||
|
||||
requestBody, _ := common.GetRequestBody(c)
|
||||
requestBody, err := common.GetRequestBody(c)
|
||||
if err != nil {
|
||||
if common.IsRequestBodyTooLargeError(err) || errors.Is(err, common.ErrRequestBodyTooLarge) {
|
||||
taskErr = service.TaskErrorWrapperLocal(err, "read_request_body_failed", http.StatusRequestEntityTooLarge)
|
||||
} else {
|
||||
taskErr = service.TaskErrorWrapperLocal(err, "read_request_body_failed", http.StatusBadRequest)
|
||||
}
|
||||
break
|
||||
}
|
||||
c.Request.Body = io.NopCloser(bytes.NewBuffer(requestBody))
|
||||
taskErr = taskRelayHandler(c, relayInfo)
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ func UpdateSunoTaskAll(ctx context.Context, taskChannelM map[int][]string, taskM
|
||||
for channelId, taskIds := range taskChannelM {
|
||||
err := updateSunoTaskAll(ctx, channelId, taskIds, taskM)
|
||||
if err != nil {
|
||||
logger.LogError(ctx, fmt.Sprintf("渠道 #%d 更新异步任务失败: %d", channelId, err.Error()))
|
||||
logger.LogError(ctx, fmt.Sprintf("渠道 #%d 更新异步任务失败: %s", channelId, err.Error()))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@@ -141,7 +141,7 @@ func updateSunoTaskAll(ctx context.Context, channelId int, taskIds []string, tas
|
||||
return err
|
||||
}
|
||||
if !responseItems.IsSuccess() {
|
||||
common.SysLog(fmt.Sprintf("渠道 #%d 未完成的任务有: %d, 成功获取到任务数: %d", channelId, len(taskIds), string(responseBody)))
|
||||
common.SysLog(fmt.Sprintf("渠道 #%d 未完成的任务有: %d, 成功获取到任务数: %s", channelId, len(taskIds), string(responseBody)))
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -7,12 +7,12 @@ import (
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"github.com/QuantumNous/new-api/common"
|
||||
"github.com/QuantumNous/new-api/model"
|
||||
"github.com/QuantumNous/new-api/setting"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
@@ -2,12 +2,14 @@ package middleware
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/QuantumNous/new-api/common"
|
||||
"github.com/QuantumNous/new-api/constant"
|
||||
"github.com/QuantumNous/new-api/logger"
|
||||
"github.com/QuantumNous/new-api/model"
|
||||
"github.com/QuantumNous/new-api/service"
|
||||
"github.com/QuantumNous/new-api/setting/ratio_setting"
|
||||
@@ -240,13 +242,20 @@ func TokenAuth() func(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
allowIpsMap := token.GetIpLimitsMap()
|
||||
if len(allowIpsMap) != 0 {
|
||||
allowIps := token.GetIpLimits()
|
||||
if len(allowIps) > 0 {
|
||||
clientIp := c.ClientIP()
|
||||
if _, ok := allowIpsMap[clientIp]; !ok {
|
||||
logger.LogDebug(c, "Token has IP restrictions, checking client IP %s", clientIp)
|
||||
ip := net.ParseIP(clientIp)
|
||||
if ip == nil {
|
||||
abortWithOpenAiMessage(c, http.StatusForbidden, "无法解析客户端 IP 地址")
|
||||
return
|
||||
}
|
||||
if common.IsIpInCIDRList(ip, allowIps) == false {
|
||||
abortWithOpenAiMessage(c, http.StatusForbidden, "您的 IP 不在令牌允许访问的列表中")
|
||||
return
|
||||
}
|
||||
logger.LogDebug(c, "Client IP %s passed the token IP restrictions check", clientIp)
|
||||
}
|
||||
|
||||
userCache, err := model.GetUserCache(token.UserId)
|
||||
|
||||
@@ -162,7 +162,7 @@ func getModelRequest(c *gin.Context) (*ModelRequest, bool, error) {
|
||||
}
|
||||
midjourneyModel, mjErr, success := service.GetMjRequestModel(relayMode, &midjourneyRequest)
|
||||
if mjErr != nil {
|
||||
return nil, false, fmt.Errorf(mjErr.Description)
|
||||
return nil, false, fmt.Errorf("%s", mjErr.Description)
|
||||
}
|
||||
if midjourneyModel == "" {
|
||||
if !success {
|
||||
|
||||
@@ -5,32 +5,69 @@ import (
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/QuantumNous/new-api/constant"
|
||||
"github.com/andybalholm/brotli"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type readCloser struct {
|
||||
io.Reader
|
||||
closeFn func() error
|
||||
}
|
||||
|
||||
func (rc *readCloser) Close() error {
|
||||
if rc.closeFn != nil {
|
||||
return rc.closeFn()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DecompressRequestMiddleware() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
if c.Request.Body == nil || c.Request.Method == http.MethodGet {
|
||||
c.Next()
|
||||
return
|
||||
}
|
||||
maxMB := constant.MaxRequestBodyMB
|
||||
if maxMB <= 0 {
|
||||
maxMB = 32
|
||||
}
|
||||
maxBytes := int64(maxMB) << 20
|
||||
|
||||
origBody := c.Request.Body
|
||||
wrapMaxBytes := func(body io.ReadCloser) io.ReadCloser {
|
||||
return http.MaxBytesReader(c.Writer, body, maxBytes)
|
||||
}
|
||||
|
||||
switch c.GetHeader("Content-Encoding") {
|
||||
case "gzip":
|
||||
gzipReader, err := gzip.NewReader(c.Request.Body)
|
||||
gzipReader, err := gzip.NewReader(origBody)
|
||||
if err != nil {
|
||||
_ = origBody.Close()
|
||||
c.AbortWithStatus(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
defer gzipReader.Close()
|
||||
|
||||
// Replace the request body with the decompressed data
|
||||
c.Request.Body = io.NopCloser(gzipReader)
|
||||
// Replace the request body with the decompressed data, and enforce a max size (post-decompression).
|
||||
c.Request.Body = wrapMaxBytes(&readCloser{
|
||||
Reader: gzipReader,
|
||||
closeFn: func() error {
|
||||
_ = gzipReader.Close()
|
||||
return origBody.Close()
|
||||
},
|
||||
})
|
||||
c.Request.Header.Del("Content-Encoding")
|
||||
case "br":
|
||||
reader := brotli.NewReader(c.Request.Body)
|
||||
c.Request.Body = io.NopCloser(reader)
|
||||
reader := brotli.NewReader(origBody)
|
||||
c.Request.Body = wrapMaxBytes(&readCloser{
|
||||
Reader: reader,
|
||||
closeFn: func() error {
|
||||
return origBody.Close()
|
||||
},
|
||||
})
|
||||
c.Request.Header.Del("Content-Encoding")
|
||||
default:
|
||||
// Even for uncompressed bodies, enforce a max size to avoid huge request allocations.
|
||||
c.Request.Body = wrapMaxBytes(origBody)
|
||||
}
|
||||
|
||||
// Continue processing the request
|
||||
|
||||
@@ -254,6 +254,9 @@ func (channel *Channel) Save() error {
|
||||
}
|
||||
|
||||
func (channel *Channel) SaveWithoutKey() error {
|
||||
if channel.Id == 0 {
|
||||
return errors.New("channel ID is 0")
|
||||
}
|
||||
return DB.Omit("key").Save(channel).Error
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/QuantumNous/new-api/common"
|
||||
|
||||
"github.com/bytedance/gopkg/util/gopool"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
@@ -35,26 +34,26 @@ func (token *Token) Clean() {
|
||||
token.Key = ""
|
||||
}
|
||||
|
||||
func (token *Token) GetIpLimitsMap() map[string]any {
|
||||
func (token *Token) GetIpLimits() []string {
|
||||
// delete empty spaces
|
||||
//split with \n
|
||||
ipLimitsMap := make(map[string]any)
|
||||
ipLimits := make([]string, 0)
|
||||
if token.AllowIps == nil {
|
||||
return ipLimitsMap
|
||||
return ipLimits
|
||||
}
|
||||
cleanIps := strings.ReplaceAll(*token.AllowIps, " ", "")
|
||||
if cleanIps == "" {
|
||||
return ipLimitsMap
|
||||
return ipLimits
|
||||
}
|
||||
ips := strings.Split(cleanIps, "\n")
|
||||
for _, ip := range ips {
|
||||
ip = strings.TrimSpace(ip)
|
||||
ip = strings.ReplaceAll(ip, ",", "")
|
||||
if common.IsIP(ip) {
|
||||
ipLimitsMap[ip] = true
|
||||
if ip != "" {
|
||||
ipLimits = append(ipLimits, ip)
|
||||
}
|
||||
}
|
||||
return ipLimitsMap
|
||||
return ipLimits
|
||||
}
|
||||
|
||||
func GetAllUserTokens(userId int, startIdx int, num int) ([]*Token, error) {
|
||||
@@ -113,7 +112,12 @@ func ValidateUserToken(key string) (token *Token, err error) {
|
||||
}
|
||||
return token, nil
|
||||
}
|
||||
return nil, errors.New("无效的令牌")
|
||||
common.SysLog("ValidateUserToken: failed to get token: " + err.Error())
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, errors.New("无效的令牌")
|
||||
} else {
|
||||
return nil, errors.New("无效的令牌,数据库查询出错,请联系管理员")
|
||||
}
|
||||
}
|
||||
|
||||
func GetTokenByIds(id int, userId int) (*Token, error) {
|
||||
|
||||
@@ -18,7 +18,7 @@ var awsModelIDMap = map[string]string{
|
||||
"claude-opus-4-1-20250805": "anthropic.claude-opus-4-1-20250805-v1:0",
|
||||
"claude-sonnet-4-5-20250929": "anthropic.claude-sonnet-4-5-20250929-v1:0",
|
||||
"claude-haiku-4-5-20251001": "anthropic.claude-haiku-4-5-20251001-v1:0",
|
||||
"claude-opus-4-5-20251101": "anthropic.claude-opus-4-5-20251101-v1:0",
|
||||
"claude-opus-4-5-20251101": "anthropic.claude-opus-4-5-20251101-v1:0",
|
||||
// Nova models
|
||||
"nova-micro-v1:0": "amazon.nova-micro-v1:0",
|
||||
"nova-lite-v1:0": "amazon.nova-lite-v1:0",
|
||||
|
||||
@@ -150,7 +150,7 @@ func baiduHandler(c *gin.Context, info *relaycommon.RelayInfo, resp *http.Respon
|
||||
return types.NewError(err, types.ErrorCodeBadResponseBody), nil
|
||||
}
|
||||
if baiduResponse.ErrorMsg != "" {
|
||||
return types.NewError(fmt.Errorf(baiduResponse.ErrorMsg), types.ErrorCodeBadResponseBody), nil
|
||||
return types.NewError(fmt.Errorf("%s", baiduResponse.ErrorMsg), types.ErrorCodeBadResponseBody), nil
|
||||
}
|
||||
fullTextResponse := responseBaidu2OpenAI(&baiduResponse)
|
||||
jsonResponse, err := json.Marshal(fullTextResponse)
|
||||
@@ -175,7 +175,7 @@ func baiduEmbeddingHandler(c *gin.Context, info *relaycommon.RelayInfo, resp *ht
|
||||
return types.NewError(err, types.ErrorCodeBadResponseBody), nil
|
||||
}
|
||||
if baiduResponse.ErrorMsg != "" {
|
||||
return types.NewError(fmt.Errorf(baiduResponse.ErrorMsg), types.ErrorCodeBadResponseBody), nil
|
||||
return types.NewError(fmt.Errorf("%s", baiduResponse.ErrorMsg), types.ErrorCodeBadResponseBody), nil
|
||||
}
|
||||
fullTextResponse := embeddingResponseBaidu2OpenAI(&baiduResponse)
|
||||
jsonResponse, err := json.Marshal(fullTextResponse)
|
||||
|
||||
@@ -208,7 +208,7 @@ func handleCozeEvent(c *gin.Context, event string, data string, responseText *st
|
||||
return
|
||||
}
|
||||
|
||||
common.SysLog(fmt.Sprintf("stream event error: ", errorData.Code, errorData.Message))
|
||||
common.SysLog(fmt.Sprintf("stream event error: %v %v", errorData.Code, errorData.Message))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -196,7 +196,7 @@ func (a *TaskAdaptor) DoResponse(c *gin.Context, resp *http.Response, info *rela
|
||||
}
|
||||
|
||||
if jResp.Code != 10000 {
|
||||
taskErr = service.TaskErrorWrapper(fmt.Errorf(jResp.Message), fmt.Sprintf("%d", jResp.Code), http.StatusInternalServerError)
|
||||
taskErr = service.TaskErrorWrapper(fmt.Errorf("%s", jResp.Message), fmt.Sprintf("%d", jResp.Code), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -186,7 +186,7 @@ func (a *TaskAdaptor) DoResponse(c *gin.Context, resp *http.Response, info *rela
|
||||
return
|
||||
}
|
||||
if kResp.Code != 0 {
|
||||
taskErr = service.TaskErrorWrapperLocal(fmt.Errorf(kResp.Message), "task_failed", http.StatusBadRequest)
|
||||
taskErr = service.TaskErrorWrapperLocal(fmt.Errorf("%s", kResp.Message), "task_failed", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
ov := dto.NewOpenAIVideo()
|
||||
|
||||
@@ -105,7 +105,7 @@ func (a *TaskAdaptor) DoResponse(c *gin.Context, resp *http.Response, info *rela
|
||||
return
|
||||
}
|
||||
if !sunoResponse.IsSuccess() {
|
||||
taskErr = service.TaskErrorWrapper(fmt.Errorf(sunoResponse.Message), sunoResponse.Code, http.StatusInternalServerError)
|
||||
taskErr = service.TaskErrorWrapper(fmt.Errorf("%s", sunoResponse.Message), sunoResponse.Code, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -51,10 +51,43 @@ type Adaptor struct {
|
||||
}
|
||||
|
||||
func (a *Adaptor) ConvertGeminiRequest(c *gin.Context, info *relaycommon.RelayInfo, request *dto.GeminiChatRequest) (any, error) {
|
||||
// Vertex AI does not support functionResponse.id; keep it stripped here for consistency.
|
||||
if model_setting.GetGeminiSettings().RemoveFunctionResponseIdEnabled {
|
||||
removeFunctionResponseID(request)
|
||||
}
|
||||
geminiAdaptor := gemini.Adaptor{}
|
||||
return geminiAdaptor.ConvertGeminiRequest(c, info, request)
|
||||
}
|
||||
|
||||
func removeFunctionResponseID(request *dto.GeminiChatRequest) {
|
||||
if request == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if len(request.Contents) > 0 {
|
||||
for i := range request.Contents {
|
||||
if len(request.Contents[i].Parts) == 0 {
|
||||
continue
|
||||
}
|
||||
for j := range request.Contents[i].Parts {
|
||||
part := &request.Contents[i].Parts[j]
|
||||
if part.FunctionResponse == nil {
|
||||
continue
|
||||
}
|
||||
if len(part.FunctionResponse.ID) > 0 {
|
||||
part.FunctionResponse.ID = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(request.Requests) > 0 {
|
||||
for i := range request.Requests {
|
||||
removeFunctionResponseID(&request.Requests[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (a *Adaptor) ConvertClaudeRequest(c *gin.Context, info *relaycommon.RelayInfo, request *dto.ClaudeRequest) (any, error) {
|
||||
if v, ok := claudeModelMap[info.UpstreamModelName]; ok {
|
||||
c.Set("request_model", v)
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"github.com/QuantumNous/new-api/constant"
|
||||
"github.com/QuantumNous/new-api/dto"
|
||||
relayconstant "github.com/QuantumNous/new-api/relay/constant"
|
||||
"github.com/QuantumNous/new-api/setting/model_setting"
|
||||
"github.com/QuantumNous/new-api/types"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
@@ -634,3 +635,47 @@ func RemoveDisabledFields(jsonData []byte, channelOtherSettings dto.ChannelOther
|
||||
}
|
||||
return jsonDataAfter, nil
|
||||
}
|
||||
|
||||
// RemoveGeminiDisabledFields removes disabled fields from Gemini request JSON data
|
||||
// Currently supports removing functionResponse.id field which Vertex AI does not support
|
||||
func RemoveGeminiDisabledFields(jsonData []byte) ([]byte, error) {
|
||||
if !model_setting.GetGeminiSettings().RemoveFunctionResponseIdEnabled {
|
||||
return jsonData, nil
|
||||
}
|
||||
|
||||
var data map[string]interface{}
|
||||
if err := common.Unmarshal(jsonData, &data); err != nil {
|
||||
common.SysError("RemoveGeminiDisabledFields Unmarshal error: " + err.Error())
|
||||
return jsonData, nil
|
||||
}
|
||||
|
||||
// Process contents array
|
||||
// Handle both camelCase (functionResponse) and snake_case (function_response)
|
||||
if contents, ok := data["contents"].([]interface{}); ok {
|
||||
for _, content := range contents {
|
||||
if contentMap, ok := content.(map[string]interface{}); ok {
|
||||
if parts, ok := contentMap["parts"].([]interface{}); ok {
|
||||
for _, part := range parts {
|
||||
if partMap, ok := part.(map[string]interface{}); ok {
|
||||
// Check functionResponse (camelCase)
|
||||
if funcResp, ok := partMap["functionResponse"].(map[string]interface{}); ok {
|
||||
delete(funcResp, "id")
|
||||
}
|
||||
// Check function_response (snake_case)
|
||||
if funcResp, ok := partMap["function_response"].(map[string]interface{}); ok {
|
||||
delete(funcResp, "id")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
jsonDataAfter, err := common.Marshal(data)
|
||||
if err != nil {
|
||||
common.SysError("RemoveGeminiDisabledFields Marshal error: " + err.Error())
|
||||
return jsonData, nil
|
||||
}
|
||||
return jsonDataAfter, nil
|
||||
}
|
||||
|
||||
@@ -110,6 +110,8 @@ func GetAndValidateEmbeddingRequest(c *gin.Context, relayMode int) (*dto.Embeddi
|
||||
return embeddingRequest, nil
|
||||
}
|
||||
|
||||
// GetAndValidateResponsesRequest parses the HTTP request body into an OpenAIResponsesRequest and ensures the Model field is provided.
|
||||
// It returns the parsed request, or an error if the body cannot be parsed or the Model is empty.
|
||||
func GetAndValidateResponsesRequest(c *gin.Context) (*dto.OpenAIResponsesRequest, error) {
|
||||
request := &dto.OpenAIResponsesRequest{}
|
||||
err := common.UnmarshalBodyReusable(c, request)
|
||||
@@ -119,9 +121,6 @@ func GetAndValidateResponsesRequest(c *gin.Context) (*dto.OpenAIResponsesRequest
|
||||
if request.Model == "" {
|
||||
return nil, errors.New("model is required")
|
||||
}
|
||||
if request.Input == nil {
|
||||
return nil, errors.New("input is required")
|
||||
}
|
||||
return request, nil
|
||||
}
|
||||
|
||||
@@ -324,4 +323,4 @@ func GetAndValidateGeminiBatchEmbeddingRequest(c *gin.Context) (*dto.GeminiBatch
|
||||
return nil, err
|
||||
}
|
||||
return request, nil
|
||||
}
|
||||
}
|
||||
@@ -196,7 +196,7 @@ func RelayTaskSubmit(c *gin.Context, info *relaycommon.RelayInfo) (taskErr *dto.
|
||||
// handle response
|
||||
if resp != nil && resp.StatusCode != http.StatusOK {
|
||||
responseBody, _ := io.ReadAll(resp.Body)
|
||||
taskErr = service.TaskErrorWrapper(fmt.Errorf(string(responseBody)), "fail_to_fetch_task", resp.StatusCode)
|
||||
taskErr = service.TaskErrorWrapper(fmt.Errorf("%s", string(responseBody)), "fail_to_fetch_task", resp.StatusCode)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -81,11 +81,24 @@ func ClaudeErrorWrapperLocal(err error, code string, statusCode int) *dto.Claude
|
||||
return claudeErr
|
||||
}
|
||||
|
||||
// RelayErrorHandler converts an HTTP error response into a structured types.NewAPIError.
|
||||
// It returns a NewAPIError initialized with the response status code and one of:
|
||||
// - an Err describing an absent or unreadable body,
|
||||
// - an Err containing the unmarshaled error message (or status + raw body when showBodyWhenFail is true), or
|
||||
// - an embedded OpenAI-style error when the response body contains a compatible error object.
|
||||
// The returned NewAPIError's status code reflects resp.StatusCode.
|
||||
func RelayErrorHandler(ctx context.Context, resp *http.Response, showBodyWhenFail bool) (newApiErr *types.NewAPIError) {
|
||||
newApiErr = types.InitOpenAIError(types.ErrorCodeBadResponseStatusCode, resp.StatusCode)
|
||||
|
||||
if resp.Body == nil {
|
||||
newApiErr.Err = errors.New("response body is nil")
|
||||
return
|
||||
}
|
||||
|
||||
responseBody, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
CloseResponseBodyGracefully(resp)
|
||||
newApiErr.Err = fmt.Errorf("read response body failed: %w", err)
|
||||
return
|
||||
}
|
||||
CloseResponseBodyGracefully(resp)
|
||||
@@ -156,4 +169,4 @@ func TaskErrorWrapper(err error, code string, statusCode int) *dto.TaskError {
|
||||
}
|
||||
|
||||
return taskError
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"github.com/QuantumNous/new-api/setting/config"
|
||||
)
|
||||
|
||||
// GeminiSettings 定义Gemini模型的配置
|
||||
// GeminiSettings defines Gemini model configuration. 注意bool要以enabled结尾才可以生效编辑
|
||||
type GeminiSettings struct {
|
||||
SafetySettings map[string]string `json:"safety_settings"`
|
||||
VersionSettings map[string]string `json:"version_settings"`
|
||||
@@ -12,6 +12,7 @@ type GeminiSettings struct {
|
||||
ThinkingAdapterEnabled bool `json:"thinking_adapter_enabled"`
|
||||
ThinkingAdapterBudgetTokensPercentage float64 `json:"thinking_adapter_budget_tokens_percentage"`
|
||||
FunctionCallThoughtSignatureEnabled bool `json:"function_call_thought_signature_enabled"`
|
||||
RemoveFunctionResponseIdEnabled bool `json:"remove_function_response_id_enabled"`
|
||||
}
|
||||
|
||||
// 默认配置
|
||||
@@ -30,6 +31,7 @@ var defaultGeminiSettings = GeminiSettings{
|
||||
ThinkingAdapterEnabled: false,
|
||||
ThinkingAdapterBudgetTokensPercentage: 0.6,
|
||||
FunctionCallThoughtSignatureEnabled: true,
|
||||
RemoveFunctionResponseIdEnabled: true,
|
||||
}
|
||||
|
||||
// 全局实例
|
||||
|
||||
@@ -3,9 +3,9 @@ package system_setting
|
||||
import "github.com/QuantumNous/new-api/setting/config"
|
||||
|
||||
type DiscordSettings struct {
|
||||
Enabled bool `json:"enabled"`
|
||||
ClientId string `json:"client_id"`
|
||||
ClientSecret string `json:"client_secret"`
|
||||
Enabled bool `json:"enabled"`
|
||||
ClientId string `json:"client_id"`
|
||||
ClientSecret string `json:"client_secret"`
|
||||
}
|
||||
|
||||
// 默认配置
|
||||
|
||||
@@ -94,6 +94,14 @@ type NewAPIError struct {
|
||||
StatusCode int
|
||||
}
|
||||
|
||||
// Unwrap enables errors.Is / errors.As to work with NewAPIError by exposing the underlying error.
|
||||
func (e *NewAPIError) Unwrap() error {
|
||||
if e == nil {
|
||||
return nil
|
||||
}
|
||||
return e.Err
|
||||
}
|
||||
|
||||
func (e *NewAPIError) GetErrorCode() ErrorCode {
|
||||
if e == nil {
|
||||
return ""
|
||||
|
||||
51
web/bun.lock
51
web/bun.lock
@@ -48,6 +48,7 @@
|
||||
"@so1ve/prettier-config": "^3.1.0",
|
||||
"@vitejs/plugin-react": "^4.2.1",
|
||||
"autoprefixer": "^10.4.21",
|
||||
"code-inspector-plugin": "^1.3.3",
|
||||
"eslint": "8.57.0",
|
||||
"eslint-plugin-header": "^3.1.1",
|
||||
"eslint-plugin-react-hooks": "^5.2.0",
|
||||
@@ -139,6 +140,18 @@
|
||||
|
||||
"@chevrotain/utils": ["@chevrotain/utils@11.0.3", "", {}, "sha512-YslZMgtJUyuMbZ+aKvfF3x1f5liK4mWNxghFRv7jqRR9C3R3fAOGTTKvxXDa2Y1s9zSbcpuO0cAxDYsc9SrXoQ=="],
|
||||
|
||||
"@code-inspector/core": ["@code-inspector/core@1.3.3", "", { "dependencies": { "@vue/compiler-dom": "^3.5.13", "chalk": "^4.1.1", "dotenv": "^16.1.4", "launch-ide": "1.3.0", "portfinder": "^1.0.28" } }, "sha512-1SUCY/XiJ3LuA9TPfS9i7/cUcmdLsgB0chuDcP96ixB2tvYojzgCrglP7CHUGZa1dtWuRLuCiDzkclLetpV4ew=="],
|
||||
|
||||
"@code-inspector/esbuild": ["@code-inspector/esbuild@1.3.3", "", { "dependencies": { "@code-inspector/core": "1.3.3" } }, "sha512-GzX5LQbvh9DXINSUyWymG8Y7u5Tq4oJAnnrCoRiYxQvKBUuu2qVMzpZHIA2iDGxvazgZvr2OK+Sh/We4LutViA=="],
|
||||
|
||||
"@code-inspector/mako": ["@code-inspector/mako@1.3.3", "", { "dependencies": { "@code-inspector/core": "1.3.3" } }, "sha512-YPTHwpDtz9zn1vimMcJFCM6ELdBoivY7t2GzgY/iCTfgm6pu1H+oWZiBC35edqYAB7+xE8frspnNsmBhsrA36A=="],
|
||||
|
||||
"@code-inspector/turbopack": ["@code-inspector/turbopack@1.3.3", "", { "dependencies": { "@code-inspector/core": "1.3.3", "@code-inspector/webpack": "1.3.3" } }, "sha512-XhqsMtts/Int64LkpO00b4rlg1bw0otlRebX8dSVgZfsujj+Jdv2ngKmQ6RBN3vgj/zV7BfgBLeGgJn7D1kT3A=="],
|
||||
|
||||
"@code-inspector/vite": ["@code-inspector/vite@1.3.3", "", { "dependencies": { "@code-inspector/core": "1.3.3", "chalk": "4.1.1" } }, "sha512-phsHVYBsxAhfi6jJ+vpmxuF6jYMuVbozs5e8pkEJL2hQyGVkzP77vfCh1wzmQHcmKUKb2tlrFcvAsRb7oA1W7w=="],
|
||||
|
||||
"@code-inspector/webpack": ["@code-inspector/webpack@1.3.3", "", { "dependencies": { "@code-inspector/core": "1.3.3" } }, "sha512-qYih7syRXgM45KaWFNNk5Ed4WitVQHCI/2s/DZMFaF1Y2FA9qd1wPGiggNeqdcUsjf9TvVBQw/89gPQZIGwSqQ=="],
|
||||
|
||||
"@dnd-kit/accessibility": ["@dnd-kit/accessibility@3.1.1", "", { "dependencies": { "tslib": "^2.0.0" }, "peerDependencies": { "react": ">=16.8.0" } }, "sha512-2P+YgaXF+gRsIihwwY1gCsQSYnu9Zyj2py8kY5fFvUM1qm2WA2u639R6YNVfU4GWr+ZM5mqEsfHZZLoRONbemw=="],
|
||||
|
||||
"@dnd-kit/core": ["@dnd-kit/core@6.3.1", "", { "dependencies": { "@dnd-kit/accessibility": "^3.1.1", "@dnd-kit/utilities": "^3.2.2", "tslib": "^2.0.0" }, "peerDependencies": { "react": ">=16.8.0", "react-dom": ">=16.8.0" } }, "sha512-xkGBRQQab4RLwgXxoqETICr6S5JlogafbhNsidmrkVv2YRs5MLwpjoF2qpiGjQt8S9AoxtIV603s0GIUpY5eYQ=="],
|
||||
@@ -713,6 +726,12 @@
|
||||
|
||||
"@vitejs/plugin-react": ["@vitejs/plugin-react@4.3.4", "", { "dependencies": { "@babel/core": "^7.26.0", "@babel/plugin-transform-react-jsx-self": "^7.25.9", "@babel/plugin-transform-react-jsx-source": "^7.25.9", "@types/babel__core": "^7.20.5", "react-refresh": "^0.14.2" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0" } }, "sha512-SCCPBJtYLdE8PX/7ZQAs1QAZ8Jqwih+0VBLum1EGqmCCQal+MIUqLCzj3ZUy8ufbC0cAM4LRlSTm7IQJwWT4ug=="],
|
||||
|
||||
"@vue/compiler-core": ["@vue/compiler-core@3.5.26", "", { "dependencies": { "@babel/parser": "^7.28.5", "@vue/shared": "3.5.26", "entities": "^7.0.0", "estree-walker": "^2.0.2", "source-map-js": "^1.2.1" } }, "sha512-vXyI5GMfuoBCnv5ucIT7jhHKl55Y477yxP6fc4eUswjP8FG3FFVFd41eNDArR+Uk3QKn2Z85NavjaxLxOC19/w=="],
|
||||
|
||||
"@vue/compiler-dom": ["@vue/compiler-dom@3.5.26", "", { "dependencies": { "@vue/compiler-core": "3.5.26", "@vue/shared": "3.5.26" } }, "sha512-y1Tcd3eXs834QjswshSilCBnKGeQjQXB6PqFn/1nxcQw4pmG42G8lwz+FZPAZAby6gZeHSt/8LMPfZ4Rb+Bd/A=="],
|
||||
|
||||
"@vue/shared": ["@vue/shared@3.5.26", "", {}, "sha512-7Z6/y3uFI5PRoKeorTOSXKcDj0MSasfNNltcslbFrPpcw6aXRUALq4IfJlaTRspiWIUOEZbrpM+iQGmCOiWe4A=="],
|
||||
|
||||
"abs-svg-path": ["abs-svg-path@0.1.1", "", {}, "sha512-d8XPSGjfyzlXC3Xx891DJRyZfqk5JU0BJrDQcsWomFIV1/BIzPW5HDH5iDdWpqWaav0YVIEzT1RHTwWr0FFshA=="],
|
||||
|
||||
"acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="],
|
||||
@@ -747,6 +766,8 @@
|
||||
|
||||
"astring": ["astring@1.9.0", "", { "bin": { "astring": "bin/astring" } }, "sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg=="],
|
||||
|
||||
"async": ["async@3.2.6", "", {}, "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA=="],
|
||||
|
||||
"async-validator": ["async-validator@3.5.2", "", {}, "sha512-8eLCg00W9pIRZSB781UUX/H6Oskmm8xloZfr09lz5bikRpBVDlJ3hRVuxxP1SxcwsEYfJ4IU8Q19Y8/893r3rQ=="],
|
||||
|
||||
"asynckit": ["asynckit@0.4.0", "", {}, "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="],
|
||||
@@ -793,7 +814,7 @@
|
||||
|
||||
"ccount": ["ccount@2.0.1", "", {}, "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg=="],
|
||||
|
||||
"chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="],
|
||||
"chalk": ["chalk@4.1.1", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg=="],
|
||||
|
||||
"character-entities": ["character-entities@2.0.2", "", {}, "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ=="],
|
||||
|
||||
@@ -825,6 +846,8 @@
|
||||
|
||||
"clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="],
|
||||
|
||||
"code-inspector-plugin": ["code-inspector-plugin@1.3.3", "", { "dependencies": { "@code-inspector/core": "1.3.3", "@code-inspector/esbuild": "1.3.3", "@code-inspector/mako": "1.3.3", "@code-inspector/turbopack": "1.3.3", "@code-inspector/vite": "1.3.3", "@code-inspector/webpack": "1.3.3", "chalk": "4.1.1" } }, "sha512-yDi84v5tgXFSZLLXqHl/Mc2qy9d2CxcYhIaP192NhqTG1zA5uVtiNIzvDAXh5Vaqy8QGYkvBfbG/i55b/sXaSQ=="],
|
||||
|
||||
"collapse-white-space": ["collapse-white-space@2.1.0", "", {}, "sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw=="],
|
||||
|
||||
"color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="],
|
||||
@@ -975,6 +998,8 @@
|
||||
|
||||
"dompurify": ["dompurify@3.2.6", "", { "optionalDependencies": { "@types/trusted-types": "^2.0.7" } }, "sha512-/2GogDQlohXPZe6D6NOgQvXLPSYBqIWMnZ8zzOhn09REE4eyAzb+Hed3jhoM9OkuaJ8P6ZGTTVWQKAi8ieIzfQ=="],
|
||||
|
||||
"dotenv": ["dotenv@16.6.1", "", {}, "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow=="],
|
||||
|
||||
"dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="],
|
||||
|
||||
"eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="],
|
||||
@@ -985,7 +1010,7 @@
|
||||
|
||||
"emoji-regex": ["emoji-regex@10.4.0", "", {}, "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw=="],
|
||||
|
||||
"entities": ["entities@6.0.0", "", {}, "sha512-aKstq2TDOndCn4diEyp9Uq/Flu2i1GlLkc6XIDQSDMuaFE3OPW5OphLCyQ5SpSJZTb4reN+kTcYru5yIfXoRPw=="],
|
||||
"entities": ["entities@7.0.0", "", {}, "sha512-FDWG5cmEYf2Z00IkYRhbFrwIwvdFKH07uV8dvNy0omp/Qb1xcyCWp2UDtcwJF4QZZvk0sLudP6/hAu42TaqVhQ=="],
|
||||
|
||||
"error-ex": ["error-ex@1.3.2", "", { "dependencies": { "is-arrayish": "^0.2.1" } }, "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g=="],
|
||||
|
||||
@@ -1305,6 +1330,8 @@
|
||||
|
||||
"langium": ["langium@3.3.1", "", { "dependencies": { "chevrotain": "~11.0.3", "chevrotain-allstar": "~0.3.0", "vscode-languageserver": "~9.0.1", "vscode-languageserver-textdocument": "~1.0.11", "vscode-uri": "~3.0.8" } }, "sha512-QJv/h939gDpvT+9SiLVlY7tZC3xB2qK57v0J04Sh9wpMb6MP1q8gB21L3WIo8T5P1MSMg3Ep14L7KkDCFG3y4w=="],
|
||||
|
||||
"launch-ide": ["launch-ide@1.3.0", "", { "dependencies": { "chalk": "^4.1.1", "dotenv": "^16.1.4" } }, "sha512-pxiF+HVNMV0dDc6Z0q89RDmzMF9XmSGaOn4ueTegjMy3cUkezc3zrki5PCiz68zZIqAuhW7iwoWX7JO4Kn6B0A=="],
|
||||
|
||||
"layout-base": ["layout-base@1.0.2", "", {}, "sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg=="],
|
||||
|
||||
"leva": ["leva@0.10.0", "", { "dependencies": { "@radix-ui/react-portal": "1.0.2", "@radix-ui/react-tooltip": "1.0.5", "@stitches/react": "^1.2.8", "@use-gesture/react": "^10.2.5", "colord": "^2.9.2", "dequal": "^2.0.2", "merge-value": "^1.0.0", "react-colorful": "^5.5.1", "react-dropzone": "^12.0.0", "v8n": "^1.3.3", "zustand": "^3.6.9" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } }, "sha512-RiNJWmeqQdKIeHuVXgshmxIHu144a2AMYtLxKf8Nm1j93pisDPexuQDHKNdQlbo37wdyDQibLjY9JKGIiD7gaw=="],
|
||||
@@ -1595,6 +1622,8 @@
|
||||
|
||||
"polished": ["polished@4.3.1", "", { "dependencies": { "@babel/runtime": "^7.17.8" } }, "sha512-OBatVyC/N7SCW/FaDHrSd+vn0o5cS855TOmYi4OkdWUMSJCET/xip//ch8xGUvtr3i44X9LVyWwQlRMTN3pwSA=="],
|
||||
|
||||
"portfinder": ["portfinder@1.0.38", "", { "dependencies": { "async": "^3.2.6", "debug": "^4.3.6" } }, "sha512-rEwq/ZHlJIKw++XtLAO8PPuOQA/zaPJOZJ37BVuN97nLpMJeuDVLVGRwbFoBgLudgdTMP2hdRJP++H+8QOA3vg=="],
|
||||
|
||||
"postcss": ["postcss@8.5.3", "", { "dependencies": { "nanoid": "^3.3.8", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A=="],
|
||||
|
||||
"postcss-import": ["postcss-import@15.1.0", "", { "dependencies": { "postcss-value-parser": "^4.0.0", "read-cache": "^1.0.0", "resolve": "^1.1.7" }, "peerDependencies": { "postcss": "^8.0.0" } }, "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew=="],
|
||||
@@ -2081,6 +2110,8 @@
|
||||
|
||||
"@babel/traverse/globals": ["globals@11.12.0", "", {}, "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA=="],
|
||||
|
||||
"@code-inspector/core/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="],
|
||||
|
||||
"@douyinfe/semi-foundation/remark-gfm": ["remark-gfm@4.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-gfm": "^3.0.0", "micromark-extension-gfm": "^3.0.0", "remark-parse": "^11.0.0", "remark-stringify": "^11.0.0", "unified": "^11.0.0" } }, "sha512-U92vJgBPkbw4Zfu/IiW2oTZLSL3Zpv+uI7My2eq8JxKgqraFdU8YUGicEJCEgSbeaG+QDFqIcwwfMTOEelPxuA=="],
|
||||
|
||||
"@emotion/babel-plugin/@emotion/hash": ["@emotion/hash@0.9.2", "", {}, "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g=="],
|
||||
@@ -2131,6 +2162,10 @@
|
||||
|
||||
"@visactor/vrender-kits/roughjs": ["roughjs@4.5.2", "", { "dependencies": { "path-data-parser": "^0.1.0", "points-on-curve": "^0.2.0", "points-on-path": "^0.2.1" } }, "sha512-2xSlLDKdsWyFxrveYWk9YQ/Y9UfK38EAMRNkYkMqYBJvPX8abCa9PN0x3w02H8Oa6/0bcZICJU+U95VumPqseg=="],
|
||||
|
||||
"@vue/compiler-core/@babel/parser": ["@babel/parser@7.28.5", "", { "dependencies": { "@babel/types": "^7.28.5" }, "bin": "./bin/babel-parser.js" }, "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ=="],
|
||||
|
||||
"@vue/compiler-core/estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="],
|
||||
|
||||
"antd/rc-collapse": ["rc-collapse@3.9.0", "", { "dependencies": { "@babel/runtime": "^7.10.1", "classnames": "2.x", "rc-motion": "^2.3.4", "rc-util": "^5.27.0" }, "peerDependencies": { "react": ">=16.9.0", "react-dom": ">=16.9.0" } }, "sha512-swDdz4QZ4dFTo4RAUMLL50qP0EY62N2kvmk2We5xYdRwcRn8WcYtuetCJpwpaCbUfUt5+huLpVxhvmnK+PHrkA=="],
|
||||
|
||||
"antd/scroll-into-view-if-needed": ["scroll-into-view-if-needed@3.1.0", "", { "dependencies": { "compute-scroll-into-view": "^3.0.2" } }, "sha512-49oNpRjWRvnU8NyGVmUaYG4jtTkNonFZI86MmGRDqBphEK2EXT9gdEUoQPZhuBM8yWHxCWbobltqYO5M4XrUvQ=="],
|
||||
@@ -2155,6 +2190,8 @@
|
||||
|
||||
"esast-util-from-js/acorn": ["acorn@8.14.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA=="],
|
||||
|
||||
"eslint/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="],
|
||||
|
||||
"extend-shallow/is-extendable": ["is-extendable@0.1.1", "", {}, "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw=="],
|
||||
|
||||
"fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
|
||||
@@ -2181,6 +2218,8 @@
|
||||
|
||||
"katex/commander": ["commander@8.3.0", "", {}, "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww=="],
|
||||
|
||||
"launch-ide/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="],
|
||||
|
||||
"leva/react-dropzone": ["react-dropzone@12.1.0", "", { "dependencies": { "attr-accept": "^2.2.2", "file-selector": "^0.5.0", "prop-types": "^15.8.1" }, "peerDependencies": { "react": ">= 16.8" } }, "sha512-iBYHA1rbopIvtzokEX4QubO6qk5IF/x3BtKGu74rF2JkQDXnwC4uO/lHKpaw4PJIV6iIAYOlwLv2FpiGyqHNog=="],
|
||||
|
||||
"mdast-util-find-and-replace/escape-string-regexp": ["escape-string-regexp@5.0.0", "", {}, "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw=="],
|
||||
@@ -2201,6 +2240,8 @@
|
||||
|
||||
"parse-entities/@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="],
|
||||
|
||||
"parse5/entities": ["entities@6.0.0", "", {}, "sha512-aKstq2TDOndCn4diEyp9Uq/Flu2i1GlLkc6XIDQSDMuaFE3OPW5OphLCyQ5SpSJZTb4reN+kTcYru5yIfXoRPw=="],
|
||||
|
||||
"path-scurry/lru-cache": ["lru-cache@11.2.2", "", {}, "sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg=="],
|
||||
|
||||
"prettier-package-json/commander": ["commander@4.1.1", "", {}, "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA=="],
|
||||
@@ -2269,6 +2310,8 @@
|
||||
|
||||
"@radix-ui/react-primitive/@radix-ui/react-slot/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.0.0", "", { "dependencies": { "@babel/runtime": "^7.13.10" }, "peerDependencies": { "react": "^16.8 || ^17.0 || ^18.0" } }, "sha512-0KaSv6sx787/hK3eF53iOkiSLwAGlFMx5lotrqD2pTjB18KbybKoEIgkNZTKC60YECDQTKGTRcDBILwZVqVKvA=="],
|
||||
|
||||
"@vue/compiler-core/@babel/parser/@babel/types": ["@babel/types@7.28.5", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA=="],
|
||||
|
||||
"antd/scroll-into-view-if-needed/compute-scroll-into-view": ["compute-scroll-into-view@3.1.1", "", {}, "sha512-VRhuHOLoKYOy4UbilLbUzbYg93XLjv2PncJC50EuTWPA3gaja1UjBsUP/D/9/juV3vQFr6XBEzn9KCAHdUvOHw=="],
|
||||
|
||||
"cytoscape-fcose/cose-base/layout-base": ["layout-base@2.0.1", "", {}, "sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg=="],
|
||||
@@ -2325,6 +2368,10 @@
|
||||
|
||||
"@radix-ui/react-popper/@floating-ui/react-dom/@floating-ui/dom/@floating-ui/core": ["@floating-ui/core@0.7.3", "", {}, "sha512-buc8BXHmG9l82+OQXOFU3Kr2XQx9ys01U/Q9HMIrZ300iLc8HLMgh7dcCqgYzAzf4BkoQvDcXf5Y+CuEZ5JBYg=="],
|
||||
|
||||
"@vue/compiler-core/@babel/parser/@babel/types/@babel/helper-string-parser": ["@babel/helper-string-parser@7.27.1", "", {}, "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA=="],
|
||||
|
||||
"@vue/compiler-core/@babel/parser/@babel/types/@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="],
|
||||
|
||||
"simplify-geojson/concat-stream/readable-stream/string_decoder": ["string_decoder@0.10.31", "", {}, "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ=="],
|
||||
|
||||
"sucrase/glob/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="],
|
||||
|
||||
@@ -78,15 +78,16 @@
|
||||
"@so1ve/prettier-config": "^3.1.0",
|
||||
"@vitejs/plugin-react": "^4.2.1",
|
||||
"autoprefixer": "^10.4.21",
|
||||
"code-inspector-plugin": "^1.3.3",
|
||||
"eslint": "8.57.0",
|
||||
"eslint-plugin-header": "^3.1.1",
|
||||
"eslint-plugin-react-hooks": "^5.2.0",
|
||||
"i18next-cli": "^1.10.3",
|
||||
"postcss": "^8.5.3",
|
||||
"prettier": "^3.0.0",
|
||||
"tailwindcss": "^3",
|
||||
"typescript": "4.4.2",
|
||||
"vite": "^5.2.0",
|
||||
"i18next-cli": "^1.10.3"
|
||||
"vite": "^5.2.0"
|
||||
},
|
||||
"prettier": {
|
||||
"singleQuote": true,
|
||||
|
||||
@@ -32,6 +32,7 @@ const ModelSetting = () => {
|
||||
'gemini.safety_settings': '',
|
||||
'gemini.version_settings': '',
|
||||
'gemini.supported_imagine_models': '',
|
||||
'gemini.remove_function_response_id_enabled': true,
|
||||
'claude.model_headers_settings': '',
|
||||
'claude.thinking_adapter_enabled': true,
|
||||
'claude.default_max_tokens': '',
|
||||
@@ -64,6 +65,7 @@ const ModelSetting = () => {
|
||||
item.value = JSON.stringify(JSON.parse(item.value), null, 2);
|
||||
}
|
||||
}
|
||||
// Keep boolean config keys ending with enabled/Enabled so UI parses correctly.
|
||||
if (item.key.endsWith('Enabled') || item.key.endsWith('enabled')) {
|
||||
newInputs[item.key] = toBoolean(item.value);
|
||||
} else {
|
||||
|
||||
@@ -1604,7 +1604,7 @@ const EditChannelModal = (props) => {
|
||||
>
|
||||
{() => (
|
||||
<Spin spinning={loading}>
|
||||
<div className='p-2' ref={formContainerRef}>
|
||||
<div className='p-2 space-y-3' ref={formContainerRef}>
|
||||
<div ref={(el) => (formSectionRefs.current.basicInfo = el)}>
|
||||
<Card className='!rounded-2xl shadow-sm border-0 mb-6'>
|
||||
{/* Header: Basic Info */}
|
||||
|
||||
@@ -557,11 +557,11 @@ const EditTokenModal = (props) => {
|
||||
<Col span={24}>
|
||||
<Form.TextArea
|
||||
field='allow_ips'
|
||||
label={t('IP白名单')}
|
||||
label={t('IP白名单(支持CIDR表达式)')}
|
||||
placeholder={t('允许的IP,一行一个,不填写则不限制')}
|
||||
autosize
|
||||
rows={1}
|
||||
extraText={t('请勿过度信任此功能,IP可能被伪造')}
|
||||
extraText={t('请勿过度信任此功能,IP可能被伪造,请配合nginx和cdn等网关使用')}
|
||||
showClear
|
||||
style={{ width: '100%' }}
|
||||
/>
|
||||
|
||||
@@ -97,7 +97,7 @@
|
||||
"Homepage URL 填": "Fill in the Homepage URL",
|
||||
"ID": "ID",
|
||||
"IP": "IP",
|
||||
"IP白名单": "IP whitelist",
|
||||
"IP白名单(支持CIDR表达式)": "IP whitelist (supports CIDR expressions)",
|
||||
"IP限制": "IP restrictions",
|
||||
"IP黑名单": "IP blacklist",
|
||||
"JSON": "JSON",
|
||||
@@ -153,6 +153,7 @@
|
||||
"URL链接": "URL Link",
|
||||
"USD (美元)": "USD (US Dollar)",
|
||||
"User Info Endpoint": "User Info Endpoint",
|
||||
"Vertex AI 不支持 functionResponse.id 字段,开启后将自动移除该字段": "Vertex AI does not support the functionResponse.id field. When enabled, this field will be automatically removed",
|
||||
"Webhook 密钥": "Webhook Secret",
|
||||
"Webhook 签名密钥": "Webhook Signature Key",
|
||||
"Webhook地址": "Webhook URL",
|
||||
@@ -1510,6 +1511,7 @@
|
||||
"私有IP访问详细说明": "⚠️ Security Warning: Enabling this allows access to internal network resources (localhost, private networks). Only enable if you need to access internal services and understand the security implications.",
|
||||
"私有部署地址": "Private Deployment Address",
|
||||
"秒": "Second",
|
||||
"移除 functionResponse.id 字段": "Remove functionResponse.id Field",
|
||||
"移除 One API 的版权标识必须首先获得授权,项目维护需要花费大量精力,如果本项目对你有意义,请主动支持本项目": "Removal of One API copyright mark must first be authorized. Project maintenance requires a lot of effort. If this project is meaningful to you, please actively support it.",
|
||||
"窗口处理": "window handling",
|
||||
"窗口等待": "window wait",
|
||||
@@ -1752,7 +1754,7 @@
|
||||
"请先阅读并同意用户协议和隐私政策": "Please read and agree to the user agreement and privacy policy first",
|
||||
"请再次输入新密码": "Please enter the new password again",
|
||||
"请前往个人设置 → 安全设置进行配置。": "Please go to Personal Settings → Security Settings to configure.",
|
||||
"请勿过度信任此功能,IP可能被伪造": "Do not over-trust this feature, IP can be spoofed",
|
||||
"请勿过度信任此功能,IP可能被伪造,请配合nginx和cdn等网关使用": "Do not over-trust this feature, IP can be spoofed, please use it in conjunction with gateways such as nginx and CDN",
|
||||
"请在系统设置页面编辑分组倍率以添加新的分组:": "Please edit Group ratios in system settings to add new groups:",
|
||||
"请填写完整的产品信息": "Please fill in complete product information",
|
||||
"请填写完整的管理员账号信息": "Please fill in the complete administrator account information",
|
||||
|
||||
@@ -99,7 +99,7 @@
|
||||
"Homepage URL 填": "Remplir l'URL de la page d'accueil",
|
||||
"ID": "ID",
|
||||
"IP": "IP",
|
||||
"IP白名单": "Liste blanche d'adresses IP",
|
||||
"IP白名单(支持CIDR表达式)": "Liste blanche d'adresses IP (prise en charge des expressions CIDR)",
|
||||
"IP限制": "Restrictions d'IP",
|
||||
"IP黑名单": "Liste noire d'adresses IP",
|
||||
"JSON": "JSON",
|
||||
@@ -154,6 +154,7 @@
|
||||
"URL链接": "Lien URL",
|
||||
"USD (美元)": "USD (Dollar US)",
|
||||
"User Info Endpoint": "Point de terminaison des informations utilisateur",
|
||||
"Vertex AI 不支持 functionResponse.id 字段,开启后将自动移除该字段": "Vertex AI ne prend pas en charge le champ functionResponse.id. Lorsqu'il est activé, ce champ sera automatiquement supprimé",
|
||||
"Webhook 密钥": "Clé Webhook",
|
||||
"Webhook 签名密钥": "Clé de signature Webhook",
|
||||
"Webhook地址": "URL du Webhook",
|
||||
@@ -1520,6 +1521,7 @@
|
||||
"私有IP访问详细说明": "⚠️ Avertissement de sécurité : l'activation de cette option autorise l'accès aux ressources du réseau interne (localhost, réseaux privés). N'activez cette option que si vous devez accéder à des services internes et que vous comprenez les implications en matière de sécurité.",
|
||||
"私有部署地址": "Adresse de déploiement privée",
|
||||
"秒": "Seconde",
|
||||
"移除 functionResponse.id 字段": "Supprimer le champ functionResponse.id",
|
||||
"移除 One API 的版权标识必须首先获得授权,项目维护需要花费大量精力,如果本项目对你有意义,请主动支持本项目": "La suppression de la marque de copyright de One API doit d'abord être autorisée. La maintenance du projet demande beaucoup d'efforts. Si ce projet a du sens pour vous, veuillez le soutenir activement.",
|
||||
"窗口处理": "gestion des fenêtres",
|
||||
"窗口等待": "attente de la fenêtre",
|
||||
@@ -1762,7 +1764,7 @@
|
||||
"请先阅读并同意用户协议和隐私政策": "Veuillez d'abord lire et accepter l'accord utilisateur et la politique de confidentialité",
|
||||
"请再次输入新密码": "Veuillez saisir à nouveau le nouveau mot de passe",
|
||||
"请前往个人设置 → 安全设置进行配置。": "Veuillez aller dans Paramètres personnels → Paramètres de sécurité pour configurer.",
|
||||
"请勿过度信任此功能,IP可能被伪造": "Ne faites pas trop confiance à cette fonctionnalité, l'IP peut être usurpée",
|
||||
"请勿过度信任此功能,IP可能被伪造,请配合nginx和cdn等网关使用": "Ne faites pas trop confiance à cette fonctionnalité, l'IP peut être usurpée, veuillez l'utiliser en conjonction avec des passerelles telles que nginx et cdn",
|
||||
"请在系统设置页面编辑分组倍率以添加新的分组:": "Veuillez modifier les ratios de groupe dans les paramètres système pour ajouter de nouveaux groupes :",
|
||||
"请填写完整的产品信息": "Veuillez renseigner l'ensemble des informations produit",
|
||||
"请填写完整的管理员账号信息": "Veuillez remplir les informations complètes du compte administrateur",
|
||||
|
||||
@@ -82,7 +82,7 @@
|
||||
"Homepage URL 填": "ホームページURLを入力してください",
|
||||
"ID": "ID",
|
||||
"IP": "IP",
|
||||
"IP白名单": "IPホワイトリスト",
|
||||
"IP白名单(支持CIDR表达式)": "IPホワイトリスト(CIDR表記に対応)",
|
||||
"IP限制": "IP制限",
|
||||
"IP黑名单": "IPブラックリスト",
|
||||
"JSON": "JSON",
|
||||
@@ -136,6 +136,7 @@
|
||||
"Uptime Kuma监控分类管理,可以配置多个监控分类用于服务状态展示(最多20个)": "Uptime Kumaの監視分類管理:サービスステータス表示用に、複数の監視分類を設定できます(最大20個)",
|
||||
"URL链接": "URL",
|
||||
"User Info Endpoint": "User Info Endpoint",
|
||||
"Vertex AI 不支持 functionResponse.id 字段,开启后将自动移除该字段": "Vertex AIはfunctionResponse.idフィールドをサポートしていません。有効にすると、このフィールドは自動的に削除されます",
|
||||
"Webhook 签名密钥": "Webhook署名シークレット",
|
||||
"Webhook地址": "Webhook URL",
|
||||
"Webhook地址必须以https://开头": "Webhook URLは、https://で始まることが必須です",
|
||||
@@ -1440,6 +1441,7 @@
|
||||
"私有IP访问详细说明": "プライベートIPアクセスの詳細説明",
|
||||
"私有部署地址": "プライベートデプロイ先URL",
|
||||
"秒": "秒",
|
||||
"移除 functionResponse.id 字段": "functionResponse.idフィールドを削除",
|
||||
"移除 One API 的版权标识必须首先获得授权,项目维护需要花费大量精力,如果本项目对你有意义,请主动支持本项目": "One APIの著作権表示を削除するには、事前の許可が必要です。プロジェクトの維持には多大な労力がかかります。もしこのプロジェクトがあなたにとって有意義でしたら、積極的なご支援をお願いいたします",
|
||||
"窗口处理": "ウィンドウ処理",
|
||||
"窗口等待": "ウィンドウ待機中",
|
||||
@@ -1669,7 +1671,7 @@
|
||||
"请先阅读并同意用户协议和隐私政策": "まずユーザー利用規約とプライバシーポリシーをご確認の上、同意してください",
|
||||
"请再次输入新密码": "新しいパスワードを再入力してください",
|
||||
"请前往个人设置 → 安全设置进行配置。": "アカウント設定 → セキュリティ設定 にて設定してください。",
|
||||
"请勿过度信任此功能,IP可能被伪造": "IPは偽装される可能性があるため、この機能を過信しないでください",
|
||||
"请勿过度信任此功能,IP可能被伪造,请配合nginx和cdn等网关使用": "IPは偽装される可能性があるため、この機能を過信しないでください。nginxやCDNなどのゲートウェイと組み合わせて使用してください。",
|
||||
"请在系统设置页面编辑分组倍率以添加新的分组:": "新規グループを追加するには、システム設定ページでグループ倍率を編集してください:",
|
||||
"请填写完整的管理员账号信息": "管理者アカウント情報をすべて入力してください",
|
||||
"请填写密钥": "APIキーを入力してください",
|
||||
|
||||
@@ -101,7 +101,7 @@
|
||||
"Homepage URL 填": "URL домашней страницы:",
|
||||
"ID": "ID",
|
||||
"IP": "IP",
|
||||
"IP白名单": "Белый список IP",
|
||||
"IP白名单(支持CIDR表达式)": "Белый список IP (поддерживает выражения CIDR)",
|
||||
"IP限制": "Ограничения IP",
|
||||
"IP黑名单": "Черный список IP",
|
||||
"JSON": "JSON",
|
||||
@@ -156,6 +156,7 @@
|
||||
"URL链接": "URL ссылка",
|
||||
"USD (美元)": "USD (доллар США)",
|
||||
"User Info Endpoint": "Конечная точка информации о пользователе",
|
||||
"Vertex AI 不支持 functionResponse.id 字段,开启后将自动移除该字段": "Vertex AI не поддерживает поле functionResponse.id. При включении это поле будет автоматически удалено",
|
||||
"Webhook 密钥": "Секрет вебхука",
|
||||
"Webhook 签名密钥": "Ключ подписи Webhook",
|
||||
"Webhook地址": "Адрес Webhook",
|
||||
@@ -1531,6 +1532,7 @@
|
||||
"私有IP访问详细说明": "⚠️ Предупреждение безопасности: включение этой опции позволит доступ к ресурсам внутренней сети (localhost, частные сети). Включайте только при необходимости доступа к внутренним службам и понимании рисков безопасности.",
|
||||
"私有部署地址": "Адрес частного развёртывания",
|
||||
"秒": "секунда",
|
||||
"移除 functionResponse.id 字段": "Удалить поле functionResponse.id",
|
||||
"移除 One API 的版权标识必须首先获得授权,项目维护需要花费大量精力,如果本项目对你有意义,请主动支持本项目": "Удаление авторских знаков One API требует предварительного разрешения, поддержка проекта требует больших усилий, если этот проект важен для вас, пожалуйста, поддержите его",
|
||||
"窗口处理": "Обработка окна",
|
||||
"窗口等待": "Ожидание окна",
|
||||
@@ -1773,7 +1775,7 @@
|
||||
"请先阅读并同意用户协议和隐私政策": "Пожалуйста, сначала прочтите и согласитесь с пользовательским соглашением и политикой конфиденциальности",
|
||||
"请再次输入新密码": "Пожалуйста, введите новый пароль ещё раз",
|
||||
"请前往个人设置 → 安全设置进行配置。": "Пожалуйста, перейдите в Личные настройки → Настройки безопасности для конфигурации.",
|
||||
"请勿过度信任此功能,IP可能被伪造": "Не доверяйте этой функции чрезмерно, IP может быть подделан",
|
||||
"请勿过度信任此功能,IP可能被伪造,请配合nginx和cdn等网关使用": "Не доверяйте этой функции чрезмерно, IP может быть подделан, используйте её вместе с nginx и CDN и другими шлюзами",
|
||||
"请在系统设置页面编辑分组倍率以添加新的分组:": "Пожалуйста, отредактируйте коэффициенты групп на странице системных настроек для добавления новой группы:",
|
||||
"请填写完整的产品信息": "Пожалуйста, заполните всю информацию о продукте",
|
||||
"请填写完整的管理员账号信息": "Пожалуйста, заполните полную информацию об учётной записи администратора",
|
||||
|
||||
@@ -82,7 +82,7 @@
|
||||
"Homepage URL 填": "Điền URL trang chủ",
|
||||
"ID": "ID",
|
||||
"IP": "IP",
|
||||
"IP白名单": "Danh sách trắng IP",
|
||||
"IP白名单(支持CIDR表达式)": "Danh sách trắng IP (hỗ trợ biểu thức CIDR)",
|
||||
"IP限制": "Hạn chế IP",
|
||||
"IP黑名单": "Danh sách đen IP",
|
||||
"JSON": "JSON",
|
||||
@@ -136,6 +136,7 @@
|
||||
"Uptime Kuma监控分类管理,可以配置多个监控分类用于服务状态展示(最多20个)": "Quản lý danh mục giám sát Uptime Kuma, bạn có thể cấu hình nhiều danh mục giám sát để hiển thị trạng thái dịch vụ (tối đa 20)",
|
||||
"URL链接": "Liên kết URL",
|
||||
"User Info Endpoint": "User Info Endpoint",
|
||||
"Vertex AI 不支持 functionResponse.id 字段,开启后将自动移除该字段": "Vertex AI không hỗ trợ trường functionResponse.id. Khi bật, trường này sẽ tự động bị xóa",
|
||||
"Webhook 签名密钥": "Khóa chữ ký Webhook",
|
||||
"Webhook地址": "URL Webhook",
|
||||
"Webhook地址必须以https://开头": "URL Webhook phải bắt đầu bằng https://",
|
||||
@@ -1987,7 +1988,7 @@
|
||||
"请先阅读并同意用户协议和隐私政策": "Vui lòng đọc và đồng ý với thỏa thuận người dùng và chính sách bảo mật trước",
|
||||
"请再次输入新密码": "Vui lòng nhập lại mật khẩu mới",
|
||||
"请前往个人设置 → 安全设置进行配置。": "Vui lòng truy cập Cài đặt cá nhân → Cài đặt bảo mật để cấu hình.",
|
||||
"请勿过度信任此功能,IP可能被伪造": "Đừng quá tin tưởng tính năng này, IP có thể bị giả mạo",
|
||||
"请勿过度信任此功能,IP可能被伪造,请配合nginx和cdn等网关使用": "Đừng quá tin tưởng tính năng này, IP có thể bị giả mạo, vui lòng sử dụng cùng với nginx và các cổng khác như cdn",
|
||||
"请在系统设置页面编辑分组倍率以添加新的分组:": "Vui lòng chỉnh sửa tỷ lệ nhóm trên trang cài đặt hệ thống để thêm nhóm mới:",
|
||||
"请填写完整的管理员账号信息": "Vui lòng điền đầy đủ thông tin tài khoản quản trị viên",
|
||||
"请填写密钥": "Vui lòng điền khóa",
|
||||
@@ -2648,6 +2649,7 @@
|
||||
"私有IP访问详细说明": "⚠️ Cảnh báo bảo mật: Bật tính năng này cho phép truy cập vào tài nguyên mạng nội bộ (localhost, mạng riêng). Chỉ bật nếu bạn cần truy cập các dịch vụ nội bộ và hiểu rõ các rủi ro bảo mật.",
|
||||
"私有部署地址": "Địa chỉ triển khai riêng",
|
||||
"秒": "Giây",
|
||||
"移除 functionResponse.id 字段": "Xóa trường functionResponse.id",
|
||||
"移除 One API 的版权标识必须首先获得授权,项目维护需要花费大量精力,如果本项目对你有意义,请主动支持本项目": "Việc xóa dấu bản quyền One API trước tiên phải được ủy quyền. Việc bảo trì dự án đòi hỏi rất nhiều nỗ lực. Nếu dự án này có ý nghĩa với bạn, vui lòng chủ động ủng hộ dự án này.",
|
||||
"窗口处理": "xử lý cửa sổ",
|
||||
"窗口等待": "chờ cửa sổ",
|
||||
|
||||
@@ -95,7 +95,7 @@
|
||||
"Homepage URL 填": "Homepage URL 填",
|
||||
"ID": "ID",
|
||||
"IP": "IP",
|
||||
"IP白名单": "IP白名单",
|
||||
"IP白名单(支持CIDR表达式)": "IP白名单(支持CIDR表达式)",
|
||||
"IP限制": "IP限制",
|
||||
"IP黑名单": "IP黑名单",
|
||||
"JSON": "JSON",
|
||||
@@ -150,6 +150,7 @@
|
||||
"URL链接": "URL链接",
|
||||
"USD (美元)": "USD (美元)",
|
||||
"User Info Endpoint": "User Info Endpoint",
|
||||
"Vertex AI 不支持 functionResponse.id 字段,开启后将自动移除该字段": "Vertex AI 不支持 functionResponse.id 字段,开启后将自动移除该字段",
|
||||
"Webhook 密钥": "Webhook 密钥",
|
||||
"Webhook 签名密钥": "Webhook 签名密钥",
|
||||
"Webhook地址": "Webhook地址",
|
||||
@@ -1498,6 +1499,7 @@
|
||||
"私有IP访问详细说明": "⚠️ 安全警告:启用此选项将允许访问内网资源(本地主机、私有网络)。仅在需要访问内部服务且了解安全风险的情况下启用。",
|
||||
"私有部署地址": "私有部署地址",
|
||||
"秒": "秒",
|
||||
"移除 functionResponse.id 字段": "移除 functionResponse.id 字段",
|
||||
"移除 One API 的版权标识必须首先获得授权,项目维护需要花费大量精力,如果本项目对你有意义,请主动支持本项目": "移除 One API 的版权标识必须首先获得授权,项目维护需要花费大量精力,如果本项目对你有意义,请主动支持本项目",
|
||||
"窗口处理": "窗口处理",
|
||||
"窗口等待": "窗口等待",
|
||||
@@ -1740,7 +1742,7 @@
|
||||
"请先阅读并同意用户协议和隐私政策": "请先阅读并同意用户协议和隐私政策",
|
||||
"请再次输入新密码": "请再次输入新密码",
|
||||
"请前往个人设置 → 安全设置进行配置。": "请前往个人设置 → 安全设置进行配置。",
|
||||
"请勿过度信任此功能,IP可能被伪造": "请勿过度信任此功能,IP可能被伪造",
|
||||
"请勿过度信任此功能,IP可能被伪造,请配合nginx和cdn等网关使用": "请勿过度信任此功能,IP可能被伪造,请配合nginx和cdn等网关使用",
|
||||
"请在系统设置页面编辑分组倍率以添加新的分组:": "请在系统设置页面编辑分组倍率以添加新的分组:",
|
||||
"请填写完整的产品信息": "请填写完整的产品信息",
|
||||
"请填写完整的管理员账号信息": "请填写完整的管理员账号信息",
|
||||
|
||||
@@ -46,6 +46,7 @@ const DEFAULT_GEMINI_INPUTS = {
|
||||
'gemini.thinking_adapter_enabled': false,
|
||||
'gemini.thinking_adapter_budget_tokens_percentage': 0.6,
|
||||
'gemini.function_call_thought_signature_enabled': true,
|
||||
'gemini.remove_function_response_id_enabled': true,
|
||||
};
|
||||
|
||||
export default function SettingGeminiModel(props) {
|
||||
@@ -186,6 +187,23 @@ export default function SettingGeminiModel(props) {
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row>
|
||||
<Col span={16}>
|
||||
<Form.Switch
|
||||
label={t('移除 functionResponse.id 字段')}
|
||||
field={'gemini.remove_function_response_id_enabled'}
|
||||
extraText={t(
|
||||
'Vertex AI 不支持 functionResponse.id 字段,开启后将自动移除该字段',
|
||||
)}
|
||||
onChange={(value) =>
|
||||
setInputs({
|
||||
...inputs,
|
||||
'gemini.remove_function_response_id_enabled': value,
|
||||
})
|
||||
}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row>
|
||||
<Col xs={24} sm={12} md={8} lg={8} xl={8}>
|
||||
<Form.TextArea
|
||||
|
||||
@@ -21,6 +21,7 @@ import react from '@vitejs/plugin-react';
|
||||
import { defineConfig, transformWithEsbuild } from 'vite';
|
||||
import pkg from '@douyinfe/vite-plugin-semi';
|
||||
import path from 'path';
|
||||
import { codeInspectorPlugin } from 'code-inspector-plugin';
|
||||
const { vitePluginSemi } = pkg;
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
@@ -31,6 +32,9 @@ export default defineConfig({
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
codeInspectorPlugin({
|
||||
bundler: 'vite',
|
||||
}),
|
||||
{
|
||||
name: 'treat-js-files-as-jsx',
|
||||
async transform(code, id) {
|
||||
|
||||
Reference in New Issue
Block a user