Compare commits

...

5 Commits

13 changed files with 153 additions and 107 deletions

View File

@@ -67,7 +67,7 @@ jobs:
VERSION=$(git describe --tags)
VERSION=${VERSION#v} # Remove 'v' prefix if present
# Convert to valid semver: take first 3 components and convert rest to prerelease format
# e.g., 0.9.0.9.1-50-g7074ea2e -> 0.9.0-dev.9.1.50.g7074ea2e
# e.g., 0.9.3-patch.1 -> 0.9.3-patch.1
if [[ $VERSION =~ ^([0-9]+)\.([0-9]+)\.([0-9]+)(.*)$ ]]; then
MAJOR=${BASH_REMATCH[1]}
MINOR=${BASH_REMATCH[2]}
@@ -76,17 +76,9 @@ jobs:
VERSION="$MAJOR.$MINOR.$PATCH"
# If there's extra content, parse and convert to prerelease format
# If there's extra content, append it without adding -dev
if [[ -n "$REST" ]]; then
if [[ $REST =~ ^(\..*)?(-[0-9]+-g[0-9a-f]+)$ ]]; then
EXTRA=${BASH_REMATCH[1]}
GIT_SUFFIX=${BASH_REMATCH[2]}
VERSION="$VERSION-dev"
[[ -n "$EXTRA" ]] && VERSION="$VERSION${EXTRA//./.}"
[[ -n "$GIT_SUFFIX" ]] && VERSION="$VERSION${GIT_SUFFIX//-/.}"
else
VERSION="$VERSION-dev${REST//./.}"
fi
VERSION="$VERSION$REST"
fi
fi
npm version $VERSION --no-git-tag-version --allow-same-version

View File

@@ -89,22 +89,23 @@ New API offers a wide range of features, please refer to [Features Introduction]
10. 🤖 Support for more authorization login methods (LinuxDO, Telegram, OIDC)
11. 🔄 Support for Rerank models (Cohere and Jina), [API Documentation](https://docs.newapi.pro/api/jinaai-rerank)
12. ⚡ Support for OpenAI Realtime API (including Azure channels), [API Documentation](https://docs.newapi.pro/api/openai-realtime)
13. ⚡ Support for Claude Messages format, [API Documentation](https://docs.newapi.pro/api/anthropic-chat)
14. Support for entering chat interface via /chat2link route
15. 🧠 Support for setting reasoning effort through model name suffixes:
13. ⚡ Support for **OpenAI Responses** format, [API Documentation](https://docs.newapi.pro/api/openai-responses)
14. Support for **Claude Messages** format, [API Documentation](https://docs.newapi.pro/api/anthropic-chat)
15. Support for **Google Gemini** format, [API Documentation](https://docs.newapi.pro/api/google-gemini-chat/)
16. 🧠 Support for setting reasoning effort through model name suffixes:
1. OpenAI o-series models
- Add `-high` suffix for high reasoning effort (e.g.: `o3-mini-high`)
- Add `-medium` suffix for medium reasoning effort (e.g.: `o3-mini-medium`)
- Add `-low` suffix for low reasoning effort (e.g.: `o3-mini-low`)
2. Claude thinking models
- Add `-thinking` suffix to enable thinking mode (e.g.: `claude-3-7-sonnet-20250219-thinking`)
16. 🔄 Thinking-to-content functionality
17. 🔄 Model rate limiting for users
18. 🔄 Request format conversion functionality, supporting the following three format conversions:
17. 🔄 Thinking-to-content functionality
18. 🔄 Model rate limiting for users
19. 🔄 Request format conversion functionality, supporting the following three format conversions:
1. OpenAI Chat Completions => Claude Messages
2. Claude Messages => OpenAI Chat Completions (can be used for Claude Code to call third-party models)
3. OpenAI Chat Completions => Gemini Chat
19. 💰 Cache billing support, which allows billing at a set ratio when cache is hit:
20. 💰 Cache billing support, which allows billing at a set ratio when cache is hit:
1. Set the `Prompt Cache Ratio` option in `System Settings-Operation Settings`
2. Set `Prompt Cache Ratio` in the channel, range 0-1, e.g., setting to 0.5 means billing at 50% when cache is hit
3. Supported channels:
@@ -134,14 +135,12 @@ For detailed configuration instructions, please refer to [Installation Guide-Env
- `GENERATE_DEFAULT_TOKEN`: Whether to generate initial tokens for newly registered users, default is `false`
- `STREAMING_TIMEOUT`: Streaming response timeout, default is 300 seconds
- `DIFY_DEBUG`: Whether to output workflow and node information for Dify channels, default is `true`
- `FORCE_STREAM_OPTION`: Whether to override client stream_options parameter, default is `true`
- `GET_MEDIA_TOKEN`: Whether to count image tokens, default is `true`
- `GET_MEDIA_TOKEN_NOT_STREAM`: Whether to count image tokens in non-streaming cases, default is `true`
- `UPDATE_TASK`: Whether to update asynchronous tasks (Midjourney, Suno), default is `true`
- `COHERE_SAFETY_SETTING`: Cohere model safety settings, options are `NONE`, `CONTEXTUAL`, `STRICT`, default is `NONE`
- `GEMINI_VISION_MAX_IMAGE_NUM`: Maximum number of images for Gemini models, default is `16`
- `MAX_FILE_DOWNLOAD_MB`: Maximum file download size in MB, default is `20`
- `CRYPTO_SECRET`: Encryption key used for encrypting database content
- `CRYPTO_SECRET`: Encryption key used for encrypting Redis database content
- `AZURE_DEFAULT_API_VERSION`: Azure channel default API version, default is `2025-04-01-preview`
- `NOTIFICATION_LIMIT_DURATION_MINUTE`: Notification limit duration, default is `10` minutes
- `NOTIFY_LIMIT_COUNT`: Maximum number of user notifications within the specified duration, default is `2`
@@ -188,7 +187,7 @@ docker run --name new-api -d --restart always -p 3000:3000 -e SQL_DSN="root:1234
```
## Channel Retry and Cache
Channel retry functionality has been implemented, you can set the number of retries in `Settings->Operation Settings->General Settings`. It is **recommended to enable caching**.
Channel retry functionality has been implemented, you can set the number of retries in `Settings->Operation Settings->General Settings->Failure Retry Count`, **recommended to enable caching** functionality.
### Cache Configuration Method
1. `REDIS_CONN_STRING`: Set Redis as cache
@@ -198,10 +197,11 @@ Channel retry functionality has been implemented, you can set the number of retr
For detailed API documentation, please refer to [API Documentation](https://docs.newapi.pro/api):
- [Chat API](https://docs.newapi.pro/api/openai-chat)
- [Image API](https://docs.newapi.pro/api/openai-image)
- [Rerank API](https://docs.newapi.pro/api/jinaai-rerank)
- [Realtime API](https://docs.newapi.pro/api/openai-realtime)
- [Chat API (Chat Completions)](https://docs.newapi.pro/api/openai-chat)
- [Response API (Responses)](https://docs.newapi.pro/api/openai-responses)
- [Image API (Image)](https://docs.newapi.pro/api/openai-image)
- [Rerank API (Rerank)](https://docs.newapi.pro/api/jinaai-rerank)
- [Realtime Chat API (Realtime)](https://docs.newapi.pro/api/openai-realtime)
- [Claude Chat API](https://docs.newapi.pro/api/anthropic-chat)
- [Google Gemini Chat API](https://docs.newapi.pro/api/google-gemini-chat)

View File

@@ -89,22 +89,23 @@ New API offre un large éventail de fonctionnalités, veuillez vous référer à
10. 🤖 Prise en charge de plus de méthodes de connexion par autorisation (LinuxDO, Telegram, OIDC)
11. 🔄 Prise en charge des modèles Rerank (Cohere et Jina), [Documentation de l'API](https://docs.newapi.pro/api/jinaai-rerank)
12. ⚡ Prise en charge de l'API OpenAI Realtime (y compris les canaux Azure), [Documentation de l'API](https://docs.newapi.pro/api/openai-realtime)
13. ⚡ Prise en charge du format Claude Messages, [Documentation de l'API](https://docs.newapi.pro/api/anthropic-chat)
14. Prise en charge de l'accès à l'interface de discussion via la route /chat2link
15. 🧠 Prise en charge de la définition de l'effort de raisonnement via les suffixes de nom de modèle :
13. ⚡ Prise en charge du format **OpenAI Responses**, [Documentation de l'API](https://docs.newapi.pro/api/openai-responses)
14. Prise en charge du format **Claude Messages**, [Documentation de l'API](https://docs.newapi.pro/api/anthropic-chat)
15. Prise en charge du format **Google Gemini**, [Documentation de l'API](https://docs.newapi.pro/api/google-gemini-chat/)
16. 🧠 Prise en charge de la définition de l'effort de raisonnement via les suffixes de nom de modèle :
1. Modèles de la série o d'OpenAI
- Ajouter le suffixe `-high` pour un effort de raisonnement élevé (par exemple : `o3-mini-high`)
- Ajouter le suffixe `-medium` pour un effort de raisonnement moyen (par exemple : `o3-mini-medium`)
- Ajouter le suffixe `-low` pour un effort de raisonnement faible (par exemple : `o3-mini-low`)
2. Modèles de pensée de Claude
- Ajouter le suffixe `-thinking` pour activer le mode de pensée (par exemple : `claude-3-7-sonnet-20250219-thinking`)
16. 🔄 Fonctionnalité de la pensée au contenu
17. 🔄 Limitation du débit du modèle pour les utilisateurs
18. 🔄 Fonctionnalité de conversion de format de requête, prenant en charge les trois conversions de format suivantes :
17. 🔄 Fonctionnalité de la pensée au contenu
18. 🔄 Limitation du débit du modèle pour les utilisateurs
19. 🔄 Fonctionnalité de conversion de format de requête, prenant en charge les trois conversions de format suivantes :
1. OpenAI Chat Completions => Claude Messages
2. Claude Messages => OpenAI Chat Completions (peut être utilisé pour Claude Code pour appeler des modèles tiers)
3. OpenAI Chat Completions => Gemini Chat
19. 💰 Prise en charge de la facturation du cache, qui permet de facturer à un ratio défini lorsque le cache est atteint :
20. 💰 Prise en charge de la facturation du cache, qui permet de facturer à un ratio défini lorsque le cache est atteint :
1. Définir l'option `Ratio de cache d'invite` dans `Paramètres système->Paramètres de fonctionnement`
2. Définir le `Ratio de cache d'invite` dans le canal, plage de 0 à 1, par exemple, le définir sur 0,5 signifie facturer à 50 % lorsque le cache est atteint
3. Canaux pris en charge :
@@ -134,14 +135,12 @@ Pour des instructions de configuration détaillées, veuillez vous référer à
- `GENERATE_DEFAULT_TOKEN` : S'il faut générer des jetons initiaux pour les utilisateurs nouvellement enregistrés, la valeur par défaut est `false`
- `STREAMING_TIMEOUT` : Délai d'expiration de la réponse en streaming, la valeur par défaut est de 300 secondes
- `DIFY_DEBUG` : S'il faut afficher les informations sur le flux de travail et les nœuds pour les canaux Dify, la valeur par défaut est `true`
- `FORCE_STREAM_OPTION` : S'il faut remplacer le paramètre client stream_options, la valeur par défaut est `true`
- `GET_MEDIA_TOKEN` : S'il faut compter les jetons d'image, la valeur par défaut est `true`
- `GET_MEDIA_TOKEN_NOT_STREAM` : S'il faut compter les jetons d'image dans les cas sans streaming, la valeur par défaut est `true`
- `UPDATE_TASK` : S'il faut mettre à jour les tâches asynchrones (Midjourney, Suno), la valeur par défaut est `true`
- `COHERE_SAFETY_SETTING` : Paramètres de sécurité du modèle Cohere, les options sont `NONE`, `CONTEXTUAL`, `STRICT`, la valeur par défaut est `NONE`
- `GEMINI_VISION_MAX_IMAGE_NUM` : Nombre maximum d'images pour les modèles Gemini, la valeur par défaut est `16`
- `MAX_FILE_DOWNLOAD_MB` : Taille maximale de téléchargement de fichier en Mo, la valeur par défaut est `20`
- `CRYPTO_SECRET` : Clé de chiffrement utilisée pour chiffrer le contenu de la base de données
- `CRYPTO_SECRET` : Clé de chiffrement utilisée pour chiffrer le contenu de la base de données Redis
- `AZURE_DEFAULT_API_VERSION` : Version de l'API par défaut du canal Azure, la valeur par défaut est `2025-04-01-preview`
- `NOTIFICATION_LIMIT_DURATION_MINUTE` : Durée de la limite de notification, la valeur par défaut est de `10` minutes
- `NOTIFY_LIMIT_COUNT` : Nombre maximal de notifications utilisateur dans la durée spécifiée, la valeur par défaut est `2`
@@ -188,7 +187,7 @@ docker run --name new-api -d --restart always -p 3000:3000 -e SQL_DSN="root:1234
```
## Nouvelle tentative de canal et cache
La fonctionnalité de nouvelle tentative de canal a été implémentée, vous pouvez définir le nombre de tentatives dans `Paramètres->Paramètres de fonctionnement->Paramètres généraux`. Il est **recommandé d'activer la mise en cache**.
La fonctionnalité de nouvelle tentative de canal a été implémentée, vous pouvez définir le nombre de tentatives dans `Paramètres->Paramètres de fonctionnement->Paramètres généraux->Nombre de tentatives en cas d'échec`, **recommandé d'activer la fonctionnalité de mise en cache**.
### Méthode de configuration du cache
1. `REDIS_CONN_STRING` : Définir Redis comme cache
@@ -198,10 +197,11 @@ La fonctionnalité de nouvelle tentative de canal a été implémentée, vous po
Pour une documentation détaillée de l'API, veuillez vous référer à [Documentation de l'API](https://docs.newapi.pro/api) :
- [API de discussion](https://docs.newapi.pro/api/openai-chat)
- [API d'image](https://docs.newapi.pro/api/openai-image)
- [API de rerank](https://docs.newapi.pro/api/jinaai-rerank)
- [API en temps réel](https://docs.newapi.pro/api/openai-realtime)
- [API de discussion (Chat Completions)](https://docs.newapi.pro/api/openai-chat)
- [API de réponse (Responses)](https://docs.newapi.pro/api/openai-responses)
- [API d'image (Image)](https://docs.newapi.pro/api/openai-image)
- [API de rerank (Rerank)](https://docs.newapi.pro/api/jinaai-rerank)
- [API de discussion en temps réel (Realtime)](https://docs.newapi.pro/api/openai-realtime)
- [API de discussion Claude](https://docs.newapi.pro/api/anthropic-chat)
- [API de discussion Google Gemini](https://docs.newapi.pro/api/google-gemini-chat)

View File

@@ -89,22 +89,23 @@ New APIは豊富な機能を提供しています。詳細な機能について
10. 🤖 より多くの認証ログイン方法をサポートLinuxDO、Telegram、OIDC
11. 🔄 RerankモデルをサポートCohereとJina、[API ドキュメント](https://docs.newapi.pro/api/jinaai-rerank)
12. ⚡ OpenAI Realtime APIをサポートAzureチャネルを含む、[APIドキュメント](https://docs.newapi.pro/api/openai-realtime)
13.Claude Messages形式をサポート、[APIドキュメント](https://docs.newapi.pro/api/anthropic-chat)
14. /chat2linkルートを使用してチャット画面に入ることをサポート
15. 🧠 モデル名のサフィックスを通じてreasoning effortを設定することをサポート
13.**OpenAI Responses**形式をサポート、[APIドキュメント](https://docs.newapi.pro/api/openai-responses)
14. ⚡ **Claude Messages**形式をサポート、[APIドキュメント](https://docs.newapi.pro/api/anthropic-chat)
15. ⚡ **Google Gemini**形式をサポート、[APIドキュメント](https://docs.newapi.pro/api/google-gemini-chat/)
16. 🧠 モデル名のサフィックスを通じてreasoning effortを設定することをサポート
1. OpenAI oシリーズモデル
- `-high`サフィックスを追加してhigh reasoning effortに設定`o3-mini-high`
- `-medium`サフィックスを追加してmedium reasoning effortに設定`o3-mini-medium`
- `-low`サフィックスを追加してlow reasoning effortに設定`o3-mini-low`
2. Claude思考モデル
- `-thinking`サフィックスを追加して思考モードを有効にする(例:`claude-3-7-sonnet-20250219-thinking`
16. 🔄 思考からコンテンツへの機能
17. 🔄 ユーザーに対するモデルレート制限機能
18. 🔄 リクエストフォーマット変換機能、以下の3つのフォーマット変換をサポート
17. 🔄 思考からコンテンツへの機能
18. 🔄 ユーザーに対するモデルレート制限機能
19. 🔄 リクエストフォーマット変換機能、以下の3つのフォーマット変換をサポート
1. OpenAI Chat Completions => Claude Messages
2. Claude Messages => OpenAI Chat CompletionsClaude Codeがサードパーティモデルを呼び出す際に使用可能
3. OpenAI Chat Completions => Gemini Chat
19. 💰 キャッシュ課金サポート、有効にするとキャッシュがヒットした際に設定された比率で課金できます:
20. 💰 キャッシュ課金サポート、有効にするとキャッシュがヒットした際に設定された比率で課金できます:
1. `システム設定-運営設定``プロンプトキャッシュ倍率`オプションを設定
2. チャネルで`プロンプトキャッシュ倍率`を設定、範囲は0-1、例えば0.5に設定するとキャッシュがヒットした際に50%で課金
3. サポートされているチャネル:
@@ -196,7 +197,8 @@ docker run --name new-api -d --restart always -p 3000:3000 -e SQL_DSN="root:1234
詳細なAPIドキュメントについては[APIドキュメント](https://docs.newapi.pro/api)を参照してください:
- [チャットインターフェースChat](https://docs.newapi.pro/api/openai-chat)
- [チャットインターフェース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)
- [再ランク付けインターフェースRerank](https://docs.newapi.pro/api/jinaai-rerank)
- [リアルタイム対話インターフェースRealtime](https://docs.newapi.pro/api/openai-realtime)

View File

@@ -85,22 +85,23 @@ New API提供了丰富的功能详细特性请参考[特性说明](https://do
10. 🤖 支持更多授权登陆方式LinuxDO,Telegram、OIDC
11. 🔄 支持Rerank模型Cohere和Jina[接口文档](https://docs.newapi.pro/api/jinaai-rerank)
12. ⚡ 支持OpenAI Realtime API包括Azure渠道[接口文档](https://docs.newapi.pro/api/openai-realtime)
13. ⚡ 支持Claude Messages 格式,[接口文档](https://docs.newapi.pro/api/anthropic-chat)
14. 支持使用路由/chat2link进入聊天界面
15. 🧠 支持通过模型名称后缀设置 reasoning effort
13. ⚡ 支持 **OpenAI Responses** 格式,[接口文档](https://docs.newapi.pro/api/openai-responses)
14. ⚡ 支持 **Claude Messages** 格式,[接口文档](https://docs.newapi.pro/api/anthropic-chat)
15. 支持 **Google Gemini** 格式,[接口文档](https://docs.newapi.pro/api/google-gemini-chat/)
16. 🧠 支持通过模型名称后缀设置 reasoning effort
1. OpenAI o系列模型
- 添加后缀 `-high` 设置为 high reasoning effort (例如: `o3-mini-high`)
- 添加后缀 `-medium` 设置为 medium reasoning effort (例如: `o3-mini-medium`)
- 添加后缀 `-low` 设置为 low reasoning effort (例如: `o3-mini-low`)
2. Claude 思考模型
- 添加后缀 `-thinking` 启用思考模式 (例如: `claude-3-7-sonnet-20250219-thinking`)
16. 🔄 思考转内容功能
17. 🔄 针对用户的模型限流功能
18. 🔄 请求格式转换功能,支持以下三种格式转换:
1. OpenAI Chat Completions => Claude Messages
17. 🔄 思考转内容功能
18. 🔄 针对用户的模型限流功能
19. 🔄 请求格式转换功能,支持以下三种格式转换:
1. OpenAI Chat Completions => Claude Messages OpenAI格式调用Claude模型
2. Clade Messages => OpenAI Chat Completions (可用于Claude Code调用第三方模型)
3. OpenAI Chat Completions => Gemini Chat
19. 💰 缓存计费支持,开启后可以在缓存命中时按照设定的比例计费:
3. OpenAI Chat Completions => Gemini Chat OpenAI格式调用Gemini模型
20. 💰 缓存计费支持,开启后可以在缓存命中时按照设定的比例计费:
1.`系统设置-运营设置` 中设置 `提示缓存倍率` 选项
2. 在渠道中设置 `提示缓存倍率`,范围 0-1例如设置为 0.5 表示缓存命中时按照 50% 计费
3. 支持的渠道:
@@ -192,7 +193,8 @@ docker run --name new-api -d --restart always -p 3000:3000 -e SQL_DSN="root:1234
详细接口文档请参考[接口文档](https://docs.newapi.pro/api)
- [聊天接口Chat](https://docs.newapi.pro/api/openai-chat)
- [聊天接口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)
- [重排序接口Rerank](https://docs.newapi.pro/api/jinaai-rerank)
- [实时对话接口Realtime](https://docs.newapi.pro/api/openai-realtime)

View File

@@ -293,12 +293,13 @@ type GeminiChatSafetyRating struct {
type GeminiChatPromptFeedback struct {
SafetyRatings []GeminiChatSafetyRating `json:"safetyRatings"`
BlockReason *string `json:"blockReason,omitempty"`
}
type GeminiChatResponse struct {
Candidates []GeminiChatCandidate `json:"candidates"`
PromptFeedback GeminiChatPromptFeedback `json:"promptFeedback"`
UsageMetadata GeminiUsageMetadata `json:"usageMetadata"`
Candidates []GeminiChatCandidate `json:"candidates"`
PromptFeedback *GeminiChatPromptFeedback `json:"promptFeedback,omitempty"`
UsageMetadata GeminiUsageMetadata `json:"usageMetadata"`
}
type GeminiUsageMetadata struct {

View File

@@ -222,6 +222,12 @@ function checkServerAvailability(port, maxRetries = 30, retryDelay = 1000) {
function startServer() {
return new Promise((resolve, reject) => {
const isDev = process.env.NODE_ENV === 'development';
const userDataPath = app.getPath('userData');
const dataDir = path.join(userDataPath, 'data');
// 设置环境变量供 preload.js 使用
process.env.ELECTRON_DATA_DIR = dataDir;
if (isDev) {
// 开发模式:假设开发者手动启动了 Go 后端和前端开发服务器
@@ -250,8 +256,6 @@ function startServer() {
// 生产模式:启动二进制服务器
const env = { ...process.env, PORT: PORT.toString() };
const userDataPath = app.getPath('userData');
const dataDir = path.join(userDataPath, 'data');
if (!fs.existsSync(dataDir)) {
fs.mkdirSync(dataDir, { recursive: true });

View File

@@ -30,7 +30,7 @@
},
"build": {
"appId": "com.newapi.desktop",
"productName": "New API",
"productName": "New-API-App",
"publish": null,
"directories": {
"output": "dist"

View File

@@ -1,22 +1,11 @@
const { contextBridge } = require('electron');
// 获取数据目录路径(用于显示给用户)
// 使用字符串拼接而不是 path.join 避免模块依赖问题
// 优先使用主进程设置的真实路径,如果没有则回退到手动拼接
function getDataDirPath() {
const platform = process.platform;
const homeDir = process.env.HOME || process.env.USERPROFILE || '';
switch (platform) {
case 'darwin':
return `${homeDir}/Library/Application Support/New API/data`;
case 'win32': {
const appData = process.env.APPDATA || `${homeDir}\\AppData\\Roaming`;
return `${appData}\\New API\\data`;
}
case 'linux':
return `${homeDir}/.config/New API/data`;
default:
return `${homeDir}/.new-api/data`;
// 如果主进程已设置真实路径,直接使用
if (process.env.ELECTRON_DATA_DIR) {
return process.env.ELECTRON_DATA_DIR;
}
}

View File

@@ -1050,7 +1050,12 @@ func GeminiChatHandler(c *gin.Context, info *relaycommon.RelayInfo, resp *http.R
return nil, types.NewOpenAIError(err, types.ErrorCodeBadResponseBody, http.StatusInternalServerError)
}
if len(geminiResponse.Candidates) == 0 {
return nil, types.NewOpenAIError(errors.New("no candidates returned"), types.ErrorCodeBadResponseBody, http.StatusInternalServerError)
//return nil, types.NewOpenAIError(errors.New("no candidates returned"), types.ErrorCodeBadResponseBody, http.StatusInternalServerError)
if geminiResponse.PromptFeedback != nil && geminiResponse.PromptFeedback.BlockReason != nil {
return nil, types.NewOpenAIError(errors.New("request blocked by Gemini API: "+*geminiResponse.PromptFeedback.BlockReason), types.ErrorCodePromptBlocked, http.StatusBadRequest)
} else {
return nil, types.NewOpenAIError(errors.New("empty response from Gemini API"), types.ErrorCodeEmptyResponse, http.StatusInternalServerError)
}
}
fullTextResponse := responseGeminiChat2OpenAI(c, &geminiResponse)
fullTextResponse.Model = info.UpstreamModelName

View File

@@ -636,9 +636,6 @@ func extractTextFromGeminiParts(parts []dto.GeminiPart) string {
func ResponseOpenAI2Gemini(openAIResponse *dto.OpenAITextResponse, info *relaycommon.RelayInfo) *dto.GeminiChatResponse {
geminiResponse := &dto.GeminiChatResponse{
Candidates: make([]dto.GeminiChatCandidate, 0, len(openAIResponse.Choices)),
PromptFeedback: dto.GeminiChatPromptFeedback{
SafetyRatings: []dto.GeminiChatSafetyRating{},
},
UsageMetadata: dto.GeminiUsageMetadata{
PromptTokenCount: openAIResponse.PromptTokens,
CandidatesTokenCount: openAIResponse.CompletionTokens,
@@ -735,9 +732,6 @@ func StreamResponseOpenAI2Gemini(openAIResponse *dto.ChatCompletionsStreamRespon
geminiResponse := &dto.GeminiChatResponse{
Candidates: make([]dto.GeminiChatCandidate, 0, len(openAIResponse.Choices)),
PromptFeedback: dto.GeminiChatPromptFeedback{
SafetyRatings: []dto.GeminiChatSafetyRating{},
},
UsageMetadata: dto.GeminiUsageMetadata{
PromptTokenCount: info.PromptTokens,
CandidatesTokenCount: 0, // 流式响应中可能没有完整的 usage 信息

View File

@@ -69,6 +69,7 @@ const (
ErrorCodeEmptyResponse ErrorCode = "empty_response"
ErrorCodeAwsInvokeError ErrorCode = "aws_invoke_error"
ErrorCodeModelNotFound ErrorCode = "model_not_found"
ErrorCodePromptBlocked ErrorCode = "prompt_blocked"
// sql error
ErrorCodeQueryDataError ErrorCode = "query_data_error"

View File

@@ -18,7 +18,7 @@ For commercial licensing, please contact support@quantumnous.com
*/
import React, { useEffect, useState, useRef } from 'react';
import { Button, Col, Form, Row, Spin, DatePicker } from '@douyinfe/semi-ui';
import { Button, Col, Form, Row, Spin, DatePicker, Typography, Modal } from '@douyinfe/semi-ui';
import dayjs from 'dayjs';
import { useTranslation } from 'react-i18next';
import {
@@ -29,6 +29,8 @@ import {
showWarning,
} from '../../../helpers';
const { Text } = Typography;
export default function SettingsLog(props) {
const { t } = useTranslation();
const [loading, setLoading] = useState(false);
@@ -78,24 +80,75 @@ export default function SettingsLog(props) {
});
}
async function onCleanHistoryLog() {
try {
setLoadingCleanHistoryLog(true);
if (!inputs.historyTimestamp) throw new Error(t('请选择日志记录时间'));
const res = await API.delete(
`/api/log/?target_timestamp=${Date.parse(inputs.historyTimestamp) / 1000}`,
);
const { success, message, data } = res.data;
if (success) {
showSuccess(`${data} ${t('条日志已清理!')}`);
return;
} else {
throw new Error(t('日志清理失败:') + message);
}
} catch (error) {
showError(error.message);
} finally {
setLoadingCleanHistoryLog(false);
if (!inputs.historyTimestamp) {
showError(t('请选择日志记录时间'));
return;
}
const now = dayjs();
const targetDate = dayjs(inputs.historyTimestamp);
const targetTime = targetDate.format('YYYY-MM-DD HH:mm:ss');
const currentTime = now.format('YYYY-MM-DD HH:mm:ss');
const daysDiff = now.diff(targetDate, 'day');
Modal.confirm({
title: t('确认清除历史日志'),
content: (
<div style={{ lineHeight: '1.8' }}>
<p>
<Text>{t('当前时间')}</Text>
<Text strong style={{ color: '#52c41a' }}>{currentTime}</Text>
</p>
<p>
<Text>{t('选择时间')}</Text>
<Text strong type="danger">{targetTime}</Text>
{daysDiff > 0 && (
<Text type="tertiary"> ({t('约')} {daysDiff} {t('天前')})</Text>
)}
</p>
<div style={{
background: '#fff7e6',
border: '1px solid #ffd591',
padding: '12px',
borderRadius: '4px',
marginTop: '12px'
}}>
<Text type="warning" strong> {t('注意')}</Text>
<Text>{t('将删除')} </Text>
<Text strong type="danger">{targetTime}</Text>
{daysDiff > 0 && (
<Text type="tertiary"> ({t('约')} {daysDiff} {t('天前')})</Text>
)}
<Text> {t('之前的所有日志')}</Text>
</div>
<p style={{ marginTop: '12px' }}>
<Text type="danger">{t('此操作不可恢复,请仔细确认时间后再操作!')}</Text>
</p>
</div>
),
okText: t('确认删除'),
cancelText: t('取消'),
okType: 'danger',
onOk: async () => {
try {
setLoadingCleanHistoryLog(true);
const res = await API.delete(
`/api/log/?target_timestamp=${Date.parse(inputs.historyTimestamp) / 1000}`,
);
const { success, message, data } = res.data;
if (success) {
showSuccess(`${data} ${t('条日志已清理!')}`);
return;
} else {
throw new Error(t('日志清理失败:') + message);
}
} catch (error) {
showError(error.message);
} finally {
setLoadingCleanHistoryLog(false);
}
},
});
}
useEffect(() => {
@@ -138,7 +191,7 @@ export default function SettingsLog(props) {
<Col xs={24} sm={12} md={8} lg={8} xl={8}>
<Spin spinning={loadingCleanHistoryLog}>
<Form.DatePicker
label={t('日志记录时间')}
label={t('清除历史日志')}
field={'historyTimestamp'}
type='dateTime'
inputReadOnly={true}
@@ -149,7 +202,10 @@ export default function SettingsLog(props) {
});
}}
/>
<Button size='default' onClick={onCleanHistoryLog}>
<Text type="tertiary" size="small" style={{ display: 'block', marginTop: 4, marginBottom: 8 }}>
{t('将清除选定时间之前的所有日志')}
</Text>
<Button size='default' type='danger' onClick={onCleanHistoryLog}>
{t('清除历史日志')}
</Button>
</Spin>