Files
20260512-skg-tk/web/canvas-app/src/config/providers.js

273 lines
7.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* API Provider Adapters | API 渠道适配器
* 适配不同 API 提供商的请求参数和响应格式
*/
// 渠道适配配置
export const PROVIDERS = {
chatfire: {
label: 'SKG 内部',
defaultBaseUrl: '/api',
// 端点路径
endpoints: {
chat: '/v1/chat/completions',
image: '/v1/images/generations',
video: '/v1/video/generations',
videoQuery: '/v1/video/task/{taskId}'
},
// 火宝渠道请求适配
requestAdapter: {
chat: (params) => {
const adapted = {
model: params.model,
messages: params.messages
}
if (params.temperature !== undefined) adapted.temperature = params.temperature
if (params.max_tokens !== undefined) adapted.max_tokens = params.max_tokens
if (params.stream !== undefined) adapted.stream = params.stream
return adapted
},
image: (params) => {
const adapted = {
model: params.model,
prompt: params.prompt
}
if (params.size) adapted.size = params.size
if (params.n) adapted.n = params.n
if (params.quality) adapted.quality = params.quality
if (params.style) adapted.style = params.style
if (params.image) adapted.image = params.image
return adapted
},
video: (params) => {
const model = params.model || ''
// Seedance 模型 - 使用 content 数组格式
if (model.includes('seedance')) {
const content = []
// 构建完整参数文本
// 格式: prompt --resolution 720p --ratio 16:9 --dur 5 --fps 24 --wm true --seed 11 --cf false
let textPrompt = params.prompt || ''
// 添加 resolution 参数
if (params.resolution) {
textPrompt += ` --resolution ${params.resolution}`
}
// 添加 ratio 参数 (图生视频用 16:9)
if (params.size) {
textPrompt += ` --ratio ${params.size}`
}
// 添加 duration 参数
if (params.seconds) {
textPrompt += ` --dur ${params.seconds}`
}
// 添加 fps (固定 24)
textPrompt += ` --fps 24`
// 添加水印参数 (默认 true)
textPrompt += ` --wm ${params.wm !== false ? 'true' : 'false'}`
// 添加 seed 参数 (可选)
if (params.seed !== undefined) {
textPrompt += ` --seed ${params.seed}`
}
// 添加 cf 参数 (默认 false)
textPrompt += ` --cf ${params.cf === true ? 'true' : 'false'}`
content.push({
type: 'text',
text: textPrompt
})
// 添加参考图(如果有)
if (params.first_frame_image) {
content.push({
type: 'image_url',
image_url: {
url: params.first_frame_image
}
})
}
const adapted = {
model: model,
content: content,
generate_audio: params.generateAudio !== false
}
return adapted
}
// Kling 模型 - 使用 kling 特定格式
if (model.includes('kling')) {
// 将 ratio 转换为 aspect_ratio 格式
const ratioMap = {
'16:9': '16:9',
'9:16': '9:16',
'1:1': '1:1',
'4:3': '4:3',
'3:4': '3:4'
}
const adapted = {
model_name: model,
mode: 'std',
prompt: params.prompt || '',
aspect_ratio: ratioMap[params.size] || '16:9',
duration: params.seconds || 5,
negative_prompt: '',
cfg_scale: 0.5
}
// 添加参考图(如果有)
if (params.first_frame_image) {
adapted.image = params.first_frame_image
}
return adapted
}
// 默认格式veo 等)
const adapted = {
model: params.model,
prompt: params.prompt || ''
}
if (params.first_frame_image) adapted.first_frame_image = params.first_frame_image
if (params.last_frame_image) adapted.last_frame_image = params.last_frame_image
if (params.size) adapted.size = params.size
if (params.seconds) adapted.seconds = params.seconds
return adapted
}
},
// 火宝渠道响应格式
responseAdapter: {
chat: (response) => {
if (response.choices && response.choices.length > 0) {
return response.choices[0].message?.content || ''
}
return ''
},
image: (response) => {
const data = response.data || response
return (Array.isArray(data) ? data : [data]).map(item => ({
url: item.url || item.b64_json || '',
revisedPrompt: item.revised_prompt || ''
}))
},
video: (response) => {
return {
url: response.data?.url || response.url || response.data?.[0]?.url || '',
...response
}
}
}
},
openai: {
label: 'OpenAI',
defaultBaseUrl: 'https://api.openai.com',
// 端点路径
endpoints: {
chat: '/v1/chat/completions',
image: '/v1/images/generations',
video: '/v1/videos',
videoQuery: '/v1/videos/{taskId}'
},
// 请求参数适配
requestAdapter: {
chat: (params) => {
const adapted = {
model: params.model,
messages: params.messages
}
// 添加可选参数
if (params.temperature !== undefined) adapted.temperature = params.temperature
if (params.max_tokens !== undefined) adapted.max_tokens = params.max_tokens
if (params.stream !== undefined) adapted.stream = params.stream
return adapted
},
image: (params) => {
const adapted = {
model: params.model,
prompt: params.prompt
}
if (params.size) adapted.size = params.size
if (params.n) adapted.n = params.n
if (params.quality) adapted.quality = params.quality
if (params.style) adapted.style = params.style
if (params.image) adapted.image = params.image
return adapted
},
video: (params) => {
const adapted = {
model: params.model,
prompt: params.prompt || ''
}
if (params.first_frame_image) adapted.first_frame_image = params.first_frame_image
if (params.last_frame_image) adapted.last_frame_image = params.last_frame_image
if (params.size) adapted.size = params.size
if (params.seconds) adapted.seconds = params.seconds
return adapted
}
},
// 响应数据适配
responseAdapter: {
chat: (response) => {
if (response.choices && response.choices.length > 0) {
return response.choices[0].message?.content || ''
}
return ''
},
image: (response) => {
const data = response.data || response
return (Array.isArray(data) ? data : [data]).map(item => ({
url: item.url || item.b64_json || '',
revisedPrompt: item.revised_prompt || ''
}))
},
video: (response) => {
return {
url: response.data?.url || response.url || response.data?.[0]?.url || '',
...response
}
}
}
},
// 默认使用 OpenAI 格式
default: 'chatfire'
}
// 获取渠道列表
export const getProviderList = () => {
return Object.entries(PROVIDERS)
.filter(([key]) => key !== 'default')
.map(([key, value]) => ({
key,
label: value.label
}))
}
// 获取默认渠道
export const getDefaultProvider = () => {
return PROVIDERS.default || 'chatfire'
}
// 获取渠道的默认 Base URL
export const getDefaultBaseUrl = (providerKey) => {
const config = getProviderConfig(providerKey)
return config.defaultBaseUrl || ''
}
// 获取渠道配置
export const getProviderConfig = (providerKey) => {
return PROVIDERS[providerKey] || PROVIDERS[PROVIDERS.default]
}