Merge pull request #124 from lemon07r/main
refactor: directly import and use `setLanguage` from i18n module in l…
This commit is contained in:
commit
db08148137
8 changed files with 105 additions and 7 deletions
5
.gitignore
vendored
5
.gitignore
vendored
|
|
@ -5,4 +5,7 @@ CLAUDE.md
|
|||
config.json
|
||||
provider_pools.json
|
||||
fetch_system_prompt.txt
|
||||
input_system_prompt.txt
|
||||
input_system_prompt.txt
|
||||
token-store.json
|
||||
usage-cache.json
|
||||
*_oauth_creds.json
|
||||
0
install-and-run.bat
Normal file → Executable file
0
install-and-run.bat
Normal file → Executable file
0
install-and-run.sh
Normal file → Executable file
0
install-and-run.sh
Normal file → Executable file
|
|
@ -1,7 +1,7 @@
|
|||
export default {
|
||||
testEnvironment: 'node',
|
||||
transform: {
|
||||
'^.+\\.js$': 'babel-jest',
|
||||
'^.+\\.(js|mjs)$': 'babel-jest',
|
||||
},
|
||||
transformIgnorePatterns: [
|
||||
'/node_modules/(?!(uuid)/)', // uuid is an ESM module that needs to be transformed
|
||||
|
|
@ -15,8 +15,7 @@ export default {
|
|||
'^(\\.{1,2}/.*)\\.js$': '$1'
|
||||
},
|
||||
testMatch: [
|
||||
'**/tests/api-server.test.js',
|
||||
'**/tests/api-integration.test.js'
|
||||
'**/tests/**/*.test.js'
|
||||
],
|
||||
collectCoverageFrom: [
|
||||
'src/**/*.js',
|
||||
|
|
|
|||
2
package-lock.json
generated
2
package-lock.json
generated
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"name": "AIClient2API",
|
||||
"name": "AIClient-2-API",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
|
|
|
|||
|
|
@ -209,6 +209,7 @@ export class GeminiConverter extends BaseConverter {
|
|||
}
|
||||
if (part.functionCall) {
|
||||
toolCalls.push({
|
||||
index: toolCalls.length,
|
||||
id: part.functionCall.id || `call_${uuidv4()}`,
|
||||
type: 'function',
|
||||
function: {
|
||||
|
|
@ -231,6 +232,11 @@ export class GeminiConverter extends BaseConverter {
|
|||
candidate.finishReason.toLowerCase();
|
||||
}
|
||||
|
||||
// 如果包含工具调用,且完成原因为 stop,则将完成原因修改为 tool_calls
|
||||
if (toolCalls.length > 0 && finishReason === 'stop') {
|
||||
finishReason = 'tool_calls';
|
||||
}
|
||||
|
||||
// 构建delta对象
|
||||
const delta = {};
|
||||
if (content) delta.content = content;
|
||||
|
|
|
|||
|
|
@ -219,7 +219,7 @@
|
|||
</div>
|
||||
|
||||
<script type="module">
|
||||
import { initI18n, t } from './app/i18n.js';
|
||||
import { initI18n, t, setLanguage } from './app/i18n.js';
|
||||
import { initLanguageSwitcher } from './app/language-switcher.js';
|
||||
|
||||
// 初始化多语言
|
||||
|
|
@ -246,7 +246,7 @@
|
|||
option.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
const lang = option.getAttribute('data-lang');
|
||||
module.setLanguage(lang);
|
||||
setLanguage(lang);
|
||||
switcher.querySelector('.current-lang').textContent = lang === 'zh-CN' ? '中文' : 'EN';
|
||||
languageOptions.forEach(opt => opt.classList.remove('active'));
|
||||
option.classList.add('active');
|
||||
|
|
|
|||
90
tests/gemini-converter.test.js
Normal file
90
tests/gemini-converter.test.js
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
|
||||
import GeminiConverter from '../src/converters/strategies/GeminiConverter.js';
|
||||
import { jest } from '@jest/globals';
|
||||
|
||||
describe('GeminiConverter', () => {
|
||||
let converter;
|
||||
|
||||
beforeEach(() => {
|
||||
converter = new GeminiConverter();
|
||||
});
|
||||
|
||||
test('toOpenAIStreamChunk adds index to tool_calls', () => {
|
||||
const geminiChunk = {
|
||||
candidates: [{
|
||||
content: {
|
||||
parts: [{
|
||||
functionCall: {
|
||||
name: 'test_tool',
|
||||
args: { param: 'value' }
|
||||
}
|
||||
}]
|
||||
}
|
||||
}]
|
||||
};
|
||||
|
||||
const result = converter.toOpenAIStreamChunk(geminiChunk, 'gemini-pro');
|
||||
|
||||
expect(result).not.toBeNull();
|
||||
expect(result.choices[0].delta).toHaveProperty('tool_calls');
|
||||
expect(result.choices[0].delta.tool_calls).toHaveLength(1);
|
||||
expect(result.choices[0].delta.tool_calls[0]).toHaveProperty('index');
|
||||
expect(result.choices[0].delta.tool_calls[0].index).toBe(0);
|
||||
expect(result.choices[0].delta.tool_calls[0].function.name).toBe('test_tool');
|
||||
});
|
||||
|
||||
test('toOpenAIStreamChunk handles multiple tool_calls with correct indices', () => {
|
||||
const geminiChunk = {
|
||||
candidates: [{
|
||||
content: {
|
||||
parts: [
|
||||
{
|
||||
functionCall: {
|
||||
name: 'tool_one',
|
||||
args: {}
|
||||
}
|
||||
},
|
||||
{
|
||||
functionCall: {
|
||||
name: 'tool_two',
|
||||
args: {}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}]
|
||||
};
|
||||
|
||||
const result = converter.toOpenAIStreamChunk(geminiChunk, 'gemini-pro');
|
||||
|
||||
expect(result).not.toBeNull();
|
||||
expect(result.choices[0].delta.tool_calls).toHaveLength(2);
|
||||
|
||||
expect(result.choices[0].delta.tool_calls[0].index).toBe(0);
|
||||
expect(result.choices[0].delta.tool_calls[0].function.name).toBe('tool_one');
|
||||
|
||||
expect(result.choices[0].delta.tool_calls[1].index).toBe(1);
|
||||
expect(result.choices[0].delta.tool_calls[1].function.name).toBe('tool_two');
|
||||
});
|
||||
|
||||
test('toOpenAIStreamChunk sets finish_reason to tool_calls when tool calls are present and finishReason is STOP', () => {
|
||||
const geminiChunk = {
|
||||
candidates: [{
|
||||
finishReason: 'STOP',
|
||||
content: {
|
||||
parts: [{
|
||||
functionCall: {
|
||||
name: 'test_tool',
|
||||
args: {}
|
||||
}
|
||||
}]
|
||||
}
|
||||
}]
|
||||
};
|
||||
|
||||
const result = converter.toOpenAIStreamChunk(geminiChunk, 'gemini-pro');
|
||||
|
||||
expect(result).not.toBeNull();
|
||||
expect(result.choices[0].finish_reason).toBe('tool_calls');
|
||||
});
|
||||
});
|
||||
Loading…
Reference in a new issue