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
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -6,3 +6,6 @@ config.json
|
||||||
provider_pools.json
|
provider_pools.json
|
||||||
fetch_system_prompt.txt
|
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 {
|
export default {
|
||||||
testEnvironment: 'node',
|
testEnvironment: 'node',
|
||||||
transform: {
|
transform: {
|
||||||
'^.+\\.js$': 'babel-jest',
|
'^.+\\.(js|mjs)$': 'babel-jest',
|
||||||
},
|
},
|
||||||
transformIgnorePatterns: [
|
transformIgnorePatterns: [
|
||||||
'/node_modules/(?!(uuid)/)', // uuid is an ESM module that needs to be transformed
|
'/node_modules/(?!(uuid)/)', // uuid is an ESM module that needs to be transformed
|
||||||
|
|
@ -15,8 +15,7 @@ export default {
|
||||||
'^(\\.{1,2}/.*)\\.js$': '$1'
|
'^(\\.{1,2}/.*)\\.js$': '$1'
|
||||||
},
|
},
|
||||||
testMatch: [
|
testMatch: [
|
||||||
'**/tests/api-server.test.js',
|
'**/tests/**/*.test.js'
|
||||||
'**/tests/api-integration.test.js'
|
|
||||||
],
|
],
|
||||||
collectCoverageFrom: [
|
collectCoverageFrom: [
|
||||||
'src/**/*.js',
|
'src/**/*.js',
|
||||||
|
|
|
||||||
2
package-lock.json
generated
2
package-lock.json
generated
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"name": "AIClient2API",
|
"name": "AIClient-2-API",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
|
|
|
||||||
|
|
@ -209,6 +209,7 @@ export class GeminiConverter extends BaseConverter {
|
||||||
}
|
}
|
||||||
if (part.functionCall) {
|
if (part.functionCall) {
|
||||||
toolCalls.push({
|
toolCalls.push({
|
||||||
|
index: toolCalls.length,
|
||||||
id: part.functionCall.id || `call_${uuidv4()}`,
|
id: part.functionCall.id || `call_${uuidv4()}`,
|
||||||
type: 'function',
|
type: 'function',
|
||||||
function: {
|
function: {
|
||||||
|
|
@ -231,6 +232,11 @@ export class GeminiConverter extends BaseConverter {
|
||||||
candidate.finishReason.toLowerCase();
|
candidate.finishReason.toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 如果包含工具调用,且完成原因为 stop,则将完成原因修改为 tool_calls
|
||||||
|
if (toolCalls.length > 0 && finishReason === 'stop') {
|
||||||
|
finishReason = 'tool_calls';
|
||||||
|
}
|
||||||
|
|
||||||
// 构建delta对象
|
// 构建delta对象
|
||||||
const delta = {};
|
const delta = {};
|
||||||
if (content) delta.content = content;
|
if (content) delta.content = content;
|
||||||
|
|
|
||||||
|
|
@ -219,7 +219,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script type="module">
|
<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';
|
import { initLanguageSwitcher } from './app/language-switcher.js';
|
||||||
|
|
||||||
// 初始化多语言
|
// 初始化多语言
|
||||||
|
|
@ -246,7 +246,7 @@
|
||||||
option.addEventListener('click', (e) => {
|
option.addEventListener('click', (e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
const lang = option.getAttribute('data-lang');
|
const lang = option.getAttribute('data-lang');
|
||||||
module.setLanguage(lang);
|
setLanguage(lang);
|
||||||
switcher.querySelector('.current-lang').textContent = lang === 'zh-CN' ? '中文' : 'EN';
|
switcher.querySelector('.current-lang').textContent = lang === 'zh-CN' ? '中文' : 'EN';
|
||||||
languageOptions.forEach(opt => opt.classList.remove('active'));
|
languageOptions.forEach(opt => opt.classList.remove('active'));
|
||||||
option.classList.add('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