mirror of
https://github.com/lobehub/lobe-chat.git
synced 2026-06-14 11:40:07 +00:00
💄 style: support Minimax T2I models (#8583)
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { AIChatModelCard } from '@/types/aiModel';
|
||||
import { AIChatModelCard, AIImageModelCard } from '@/types/aiModel';
|
||||
|
||||
const minimaxChatModels: AIChatModelCard[] = [
|
||||
{
|
||||
@@ -51,6 +51,47 @@ const minimaxChatModels: AIChatModelCard[] = [
|
||||
},
|
||||
];
|
||||
|
||||
export const allModels = [...minimaxChatModels];
|
||||
const minimaxImageModels: AIImageModelCard[] = [
|
||||
{
|
||||
description:
|
||||
'全新图像生成模型,画面表现细腻,支持文生图、图生图',
|
||||
displayName: 'Image 01',
|
||||
enabled: true,
|
||||
id: 'image-01',
|
||||
parameters: {
|
||||
aspectRatio: {
|
||||
default: '1:1',
|
||||
enum: ['1:1', '16:9', '4:3', '3:2', '2:3', '3:4', '9:16', '21:9'],
|
||||
},
|
||||
prompt: {
|
||||
default: '',
|
||||
},
|
||||
seed: { default: null },
|
||||
},
|
||||
releasedAt: '2025-02-28',
|
||||
type: 'image',
|
||||
},
|
||||
{
|
||||
description:
|
||||
'图像生成模型,画面表现细腻,支持文生图并进行画风设置',
|
||||
displayName: 'Image 01 Live',
|
||||
enabled: true,
|
||||
id: 'image-01-live',
|
||||
parameters: {
|
||||
aspectRatio: {
|
||||
default: '1:1',
|
||||
enum: ['1:1', '16:9', '4:3', '3:2', '2:3', '3:4', '9:16', '21:9'],
|
||||
},
|
||||
prompt: {
|
||||
default: '',
|
||||
},
|
||||
seed: { default: null },
|
||||
},
|
||||
releasedAt: '2025-02-28',
|
||||
type: 'image',
|
||||
},
|
||||
];
|
||||
|
||||
export const allModels = [...minimaxChatModels, ...minimaxImageModels];
|
||||
|
||||
export default allModels;
|
||||
|
||||
@@ -0,0 +1,553 @@
|
||||
// @vitest-environment edge-runtime
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import { CreateImagePayload } from '../types/image';
|
||||
import { CreateImageOptions } from '../utils/openaiCompatibleFactory';
|
||||
import { createMiniMaxImage } from './createImage';
|
||||
|
||||
// Mock the console.error to avoid polluting test output
|
||||
vi.spyOn(console, 'error').mockImplementation(() => {});
|
||||
|
||||
const mockOptions: CreateImageOptions = {
|
||||
apiKey: 'test-api-key',
|
||||
baseURL: 'https://api.minimaxi.com/v1',
|
||||
provider: 'minimax',
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
// Reset all mocks before each test
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('createMiniMaxImage', () => {
|
||||
describe('Success scenarios', () => {
|
||||
it('should successfully generate image with basic prompt', async () => {
|
||||
const mockImageUrl = 'https://minimax-cdn.com/images/generated/test-image.jpg';
|
||||
|
||||
global.fetch = vi.fn().mockResolvedValueOnce({
|
||||
ok: true,
|
||||
json: async () => ({
|
||||
base_resp: {
|
||||
status_code: 0,
|
||||
status_msg: 'success',
|
||||
},
|
||||
data: {
|
||||
image_urls: [mockImageUrl],
|
||||
},
|
||||
id: 'img-123456',
|
||||
metadata: {
|
||||
failed_count: '0',
|
||||
success_count: '1',
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
const payload: CreateImagePayload = {
|
||||
model: 'image-01',
|
||||
params: {
|
||||
prompt: 'A beautiful sunset over the mountains',
|
||||
},
|
||||
};
|
||||
|
||||
const result = await createMiniMaxImage(payload, mockOptions);
|
||||
|
||||
expect(fetch).toHaveBeenCalledWith(
|
||||
'https://api.minimaxi.com/v1/image_generation',
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': 'Bearer test-api-key',
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
aspect_ratio: undefined,
|
||||
model: 'image-01',
|
||||
n: 1,
|
||||
prompt: 'A beautiful sunset over the mountains',
|
||||
}),
|
||||
},
|
||||
);
|
||||
|
||||
expect(result).toEqual({
|
||||
imageUrl: mockImageUrl,
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle custom aspect ratio', async () => {
|
||||
const mockImageUrl = 'https://minimax-cdn.com/images/generated/custom-ratio.jpg';
|
||||
|
||||
global.fetch = vi.fn().mockResolvedValueOnce({
|
||||
ok: true,
|
||||
json: async () => ({
|
||||
base_resp: {
|
||||
status_code: 0,
|
||||
status_msg: 'success',
|
||||
},
|
||||
data: {
|
||||
image_urls: [mockImageUrl],
|
||||
},
|
||||
id: 'img-custom-ratio',
|
||||
metadata: {
|
||||
failed_count: '0',
|
||||
success_count: '1',
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
const payload: CreateImagePayload = {
|
||||
model: 'image-01',
|
||||
params: {
|
||||
prompt: 'Abstract digital art',
|
||||
aspectRatio: '16:9',
|
||||
},
|
||||
};
|
||||
|
||||
const result = await createMiniMaxImage(payload, mockOptions);
|
||||
|
||||
expect(fetch).toHaveBeenCalledWith(
|
||||
'https://api.minimaxi.com/v1/image_generation',
|
||||
expect.objectContaining({
|
||||
body: JSON.stringify({
|
||||
aspect_ratio: '16:9',
|
||||
model: 'image-01',
|
||||
n: 1,
|
||||
prompt: 'Abstract digital art',
|
||||
}),
|
||||
}),
|
||||
);
|
||||
|
||||
expect(result).toEqual({
|
||||
imageUrl: mockImageUrl,
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle seed value correctly', async () => {
|
||||
const mockImageUrl = 'https://minimax-cdn.com/images/generated/seeded-image.jpg';
|
||||
|
||||
global.fetch = vi.fn().mockResolvedValueOnce({
|
||||
ok: true,
|
||||
json: async () => ({
|
||||
base_resp: {
|
||||
status_code: 0,
|
||||
status_msg: 'success',
|
||||
},
|
||||
data: {
|
||||
image_urls: [mockImageUrl],
|
||||
},
|
||||
id: 'img-seeded',
|
||||
metadata: {
|
||||
failed_count: '0',
|
||||
success_count: '1',
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
const payload: CreateImagePayload = {
|
||||
model: 'image-01',
|
||||
params: {
|
||||
prompt: 'Reproducible image with seed',
|
||||
seed: 42,
|
||||
},
|
||||
};
|
||||
|
||||
const result = await createMiniMaxImage(payload, mockOptions);
|
||||
|
||||
expect(fetch).toHaveBeenCalledWith(
|
||||
'https://api.minimaxi.com/v1/image_generation',
|
||||
expect.objectContaining({
|
||||
body: JSON.stringify({
|
||||
aspect_ratio: undefined,
|
||||
model: 'image-01',
|
||||
n: 1,
|
||||
prompt: 'Reproducible image with seed',
|
||||
seed: 42,
|
||||
}),
|
||||
}),
|
||||
);
|
||||
|
||||
expect(result).toEqual({
|
||||
imageUrl: mockImageUrl,
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle seed value of 0 correctly', async () => {
|
||||
const mockImageUrl = 'https://minimax-cdn.com/images/generated/zero-seed.jpg';
|
||||
|
||||
global.fetch = vi.fn().mockResolvedValueOnce({
|
||||
ok: true,
|
||||
json: async () => ({
|
||||
base_resp: {
|
||||
status_code: 0,
|
||||
status_msg: 'success',
|
||||
},
|
||||
data: {
|
||||
image_urls: [mockImageUrl],
|
||||
},
|
||||
id: 'img-zero-seed',
|
||||
metadata: {
|
||||
failed_count: '0',
|
||||
success_count: '1',
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
const payload: CreateImagePayload = {
|
||||
model: 'image-01',
|
||||
params: {
|
||||
prompt: 'Image with seed 0',
|
||||
seed: 0,
|
||||
},
|
||||
};
|
||||
|
||||
await createMiniMaxImage(payload, mockOptions);
|
||||
|
||||
// Verify that seed: 0 is included in the request
|
||||
expect(fetch).toHaveBeenCalledWith(
|
||||
'https://api.minimaxi.com/v1/image_generation',
|
||||
expect.objectContaining({
|
||||
body: JSON.stringify({
|
||||
aspect_ratio: undefined,
|
||||
model: 'image-01',
|
||||
n: 1,
|
||||
prompt: 'Image with seed 0',
|
||||
seed: 0,
|
||||
}),
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('should handle multiple generated images and return the first one', async () => {
|
||||
const mockImageUrls = [
|
||||
'https://minimax-cdn.com/images/generated/image-1.jpg',
|
||||
'https://minimax-cdn.com/images/generated/image-2.jpg',
|
||||
];
|
||||
|
||||
global.fetch = vi.fn().mockResolvedValueOnce({
|
||||
ok: true,
|
||||
json: async () => ({
|
||||
base_resp: {
|
||||
status_code: 0,
|
||||
status_msg: 'success',
|
||||
},
|
||||
data: {
|
||||
image_urls: mockImageUrls,
|
||||
},
|
||||
id: 'img-multiple',
|
||||
metadata: {
|
||||
failed_count: '0',
|
||||
success_count: '2',
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
const payload: CreateImagePayload = {
|
||||
model: 'image-01',
|
||||
params: {
|
||||
prompt: 'Multiple images test',
|
||||
},
|
||||
};
|
||||
|
||||
const result = await createMiniMaxImage(payload, mockOptions);
|
||||
|
||||
expect(result).toEqual({
|
||||
imageUrl: mockImageUrls[0], // Should return the first image
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle partial failures gracefully', async () => {
|
||||
const mockImageUrl = 'https://minimax-cdn.com/images/generated/partial-success.jpg';
|
||||
|
||||
global.fetch = vi.fn().mockResolvedValueOnce({
|
||||
ok: true,
|
||||
json: async () => ({
|
||||
base_resp: {
|
||||
status_code: 0,
|
||||
status_msg: 'success',
|
||||
},
|
||||
data: {
|
||||
image_urls: [mockImageUrl],
|
||||
},
|
||||
id: 'img-partial',
|
||||
metadata: {
|
||||
failed_count: '2',
|
||||
success_count: '1',
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
const payload: CreateImagePayload = {
|
||||
model: 'image-01',
|
||||
params: {
|
||||
prompt: 'Test partial failure',
|
||||
},
|
||||
};
|
||||
|
||||
const result = await createMiniMaxImage(payload, mockOptions);
|
||||
|
||||
expect(result).toEqual({
|
||||
imageUrl: mockImageUrl,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Error scenarios', () => {
|
||||
it('should handle HTTP error responses', async () => {
|
||||
global.fetch = vi.fn().mockResolvedValueOnce({
|
||||
ok: false,
|
||||
status: 400,
|
||||
statusText: 'Bad Request',
|
||||
json: async () => ({
|
||||
base_resp: {
|
||||
status_code: 1001,
|
||||
status_msg: 'Invalid prompt format',
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
const payload: CreateImagePayload = {
|
||||
model: 'image-01',
|
||||
params: {
|
||||
prompt: 'Invalid prompt',
|
||||
},
|
||||
};
|
||||
|
||||
await expect(createMiniMaxImage(payload, mockOptions)).rejects.toEqual(
|
||||
expect.objectContaining({
|
||||
errorType: 'ProviderBizError',
|
||||
provider: 'minimax',
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('should handle non-JSON error responses', async () => {
|
||||
global.fetch = vi.fn().mockResolvedValueOnce({
|
||||
ok: false,
|
||||
status: 500,
|
||||
statusText: 'Internal Server Error',
|
||||
json: async () => {
|
||||
throw new Error('Failed to parse JSON');
|
||||
},
|
||||
});
|
||||
|
||||
const payload: CreateImagePayload = {
|
||||
model: 'image-01',
|
||||
params: {
|
||||
prompt: 'Test prompt',
|
||||
},
|
||||
};
|
||||
|
||||
await expect(createMiniMaxImage(payload, mockOptions)).rejects.toEqual(
|
||||
expect.objectContaining({
|
||||
errorType: 'ProviderBizError',
|
||||
provider: 'minimax',
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('should handle API error status codes', async () => {
|
||||
global.fetch = vi.fn().mockResolvedValueOnce({
|
||||
ok: true,
|
||||
json: async () => ({
|
||||
base_resp: {
|
||||
status_code: 1002,
|
||||
status_msg: 'Content policy violation',
|
||||
},
|
||||
data: {
|
||||
image_urls: [],
|
||||
},
|
||||
id: 'img-error',
|
||||
metadata: {
|
||||
failed_count: '1',
|
||||
success_count: '0',
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
const payload: CreateImagePayload = {
|
||||
model: 'image-01',
|
||||
params: {
|
||||
prompt: 'Inappropriate content',
|
||||
},
|
||||
};
|
||||
|
||||
await expect(createMiniMaxImage(payload, mockOptions)).rejects.toEqual(
|
||||
expect.objectContaining({
|
||||
errorType: 'ProviderBizError',
|
||||
provider: 'minimax',
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('should handle empty image URLs array', async () => {
|
||||
global.fetch = vi.fn().mockResolvedValueOnce({
|
||||
ok: true,
|
||||
json: async () => ({
|
||||
base_resp: {
|
||||
status_code: 0,
|
||||
status_msg: 'success',
|
||||
},
|
||||
data: {
|
||||
image_urls: [],
|
||||
},
|
||||
id: 'img-empty',
|
||||
metadata: {
|
||||
failed_count: '1',
|
||||
success_count: '0',
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
const payload: CreateImagePayload = {
|
||||
model: 'image-01',
|
||||
params: {
|
||||
prompt: 'Empty result test',
|
||||
},
|
||||
};
|
||||
|
||||
await expect(createMiniMaxImage(payload, mockOptions)).rejects.toEqual(
|
||||
expect.objectContaining({
|
||||
errorType: 'ProviderBizError',
|
||||
provider: 'minimax',
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('should handle missing data field', async () => {
|
||||
global.fetch = vi.fn().mockResolvedValueOnce({
|
||||
ok: true,
|
||||
json: async () => ({
|
||||
base_resp: {
|
||||
status_code: 0,
|
||||
status_msg: 'success',
|
||||
},
|
||||
id: 'img-no-data',
|
||||
metadata: {
|
||||
failed_count: '0',
|
||||
success_count: '1',
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
const payload: CreateImagePayload = {
|
||||
model: 'image-01',
|
||||
params: {
|
||||
prompt: 'Missing data test',
|
||||
},
|
||||
};
|
||||
|
||||
await expect(createMiniMaxImage(payload, mockOptions)).rejects.toEqual(
|
||||
expect.objectContaining({
|
||||
errorType: 'ProviderBizError',
|
||||
provider: 'minimax',
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('should handle null/empty image URL', async () => {
|
||||
global.fetch = vi.fn().mockResolvedValueOnce({
|
||||
ok: true,
|
||||
json: async () => ({
|
||||
base_resp: {
|
||||
status_code: 0,
|
||||
status_msg: 'success',
|
||||
},
|
||||
data: {
|
||||
image_urls: [''], // Empty string URL
|
||||
},
|
||||
id: 'img-empty-url',
|
||||
metadata: {
|
||||
failed_count: '0',
|
||||
success_count: '1',
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
const payload: CreateImagePayload = {
|
||||
model: 'image-01',
|
||||
params: {
|
||||
prompt: 'Empty URL test',
|
||||
},
|
||||
};
|
||||
|
||||
await expect(createMiniMaxImage(payload, mockOptions)).rejects.toEqual(
|
||||
expect.objectContaining({
|
||||
errorType: 'ProviderBizError',
|
||||
provider: 'minimax',
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('should handle network errors', async () => {
|
||||
global.fetch = vi.fn().mockRejectedValueOnce(new Error('Network connection failed'));
|
||||
|
||||
const payload: CreateImagePayload = {
|
||||
model: 'image-01',
|
||||
params: {
|
||||
prompt: 'Network error test',
|
||||
},
|
||||
};
|
||||
|
||||
await expect(createMiniMaxImage(payload, mockOptions)).rejects.toEqual(
|
||||
expect.objectContaining({
|
||||
errorType: 'ProviderBizError',
|
||||
provider: 'minimax',
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('should handle unauthorized access', async () => {
|
||||
global.fetch = vi.fn().mockResolvedValueOnce({
|
||||
ok: false,
|
||||
status: 401,
|
||||
statusText: 'Unauthorized',
|
||||
json: async () => ({
|
||||
base_resp: {
|
||||
status_code: 1003,
|
||||
status_msg: 'Invalid API key',
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
const payload: CreateImagePayload = {
|
||||
model: 'image-01',
|
||||
params: {
|
||||
prompt: 'Unauthorized test',
|
||||
},
|
||||
};
|
||||
|
||||
await expect(createMiniMaxImage(payload, mockOptions)).rejects.toEqual(
|
||||
expect.objectContaining({
|
||||
errorType: 'ProviderBizError',
|
||||
provider: 'minimax',
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('should handle malformed JSON response', async () => {
|
||||
global.fetch = vi.fn().mockResolvedValueOnce({
|
||||
ok: true,
|
||||
json: async () => {
|
||||
throw new Error('Unexpected token in JSON');
|
||||
},
|
||||
});
|
||||
|
||||
const payload: CreateImagePayload = {
|
||||
model: 'image-01',
|
||||
params: {
|
||||
prompt: 'JSON error test',
|
||||
},
|
||||
};
|
||||
|
||||
await expect(createMiniMaxImage(payload, mockOptions)).rejects.toEqual(
|
||||
expect.objectContaining({
|
||||
errorType: 'ProviderBizError',
|
||||
provider: 'minimax',
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,105 @@
|
||||
import createDebug from 'debug';
|
||||
|
||||
import { CreateImagePayload, CreateImageResponse } from '../types/image';
|
||||
import { AgentRuntimeError } from '../utils/createError';
|
||||
import { CreateImageOptions } from '../utils/openaiCompatibleFactory';
|
||||
|
||||
const log = createDebug('lobe-image:minimax');
|
||||
|
||||
interface MiniMaxImageResponse {
|
||||
base_resp: {
|
||||
status_code: number;
|
||||
status_msg: string;
|
||||
};
|
||||
data: {
|
||||
image_urls: string[];
|
||||
};
|
||||
id: string;
|
||||
metadata: {
|
||||
failed_count: string;
|
||||
success_count: string;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create image using MiniMax API
|
||||
*/
|
||||
export async function createMiniMaxImage(
|
||||
payload: CreateImagePayload,
|
||||
options: CreateImageOptions,
|
||||
): Promise<CreateImageResponse> {
|
||||
const { apiKey, baseURL, provider } = options;
|
||||
const { model, params } = payload;
|
||||
|
||||
try {
|
||||
const endpoint = `${baseURL}/image_generation`;
|
||||
|
||||
const response = await fetch(endpoint, {
|
||||
body: JSON.stringify({
|
||||
aspect_ratio: params.aspectRatio,
|
||||
model,
|
||||
n: 1,
|
||||
prompt: params.prompt,
|
||||
//prompt_optimizer: true, // 开启 prompt 自动优化
|
||||
...(typeof params.seed === 'number' ? { seed: params.seed } : {}),
|
||||
}),
|
||||
headers: {
|
||||
'Authorization': `Bearer ${apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
method: 'POST',
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
let errorData;
|
||||
try {
|
||||
errorData = await response.json();
|
||||
} catch {
|
||||
// Failed to parse JSON error response
|
||||
}
|
||||
|
||||
throw new Error(
|
||||
`MiniMax API error (${response.status}): ${errorData?.base_resp || response.statusText}`
|
||||
);
|
||||
}
|
||||
|
||||
const data: MiniMaxImageResponse = await response.json();
|
||||
|
||||
log('Image generation response: %O', data);
|
||||
|
||||
// Check API response status
|
||||
if (data.base_resp.status_code !== 0) {
|
||||
throw new Error(`MiniMax API error: ${data.base_resp.status_msg}`);
|
||||
}
|
||||
|
||||
// Check if we have valid image data
|
||||
if (!data.data?.image_urls || data.data.image_urls.length === 0) {
|
||||
throw new Error('No images generated in response');
|
||||
}
|
||||
|
||||
// Log generation statistics
|
||||
const successCount = parseInt(data.metadata.success_count);
|
||||
const failedCount = parseInt(data.metadata.failed_count);
|
||||
log('Image generation completed: %d successful, %d failed', successCount, failedCount);
|
||||
|
||||
// Return the first generated image URL
|
||||
const imageUrl = data.data.image_urls[0];
|
||||
|
||||
if (!imageUrl) {
|
||||
throw new Error('No valid image URL in response');
|
||||
}
|
||||
|
||||
log('Image generated successfully: %s', imageUrl);
|
||||
|
||||
return { imageUrl };
|
||||
|
||||
} catch (error) {
|
||||
log('Error in createMiniMaxImage: %O', error);
|
||||
|
||||
throw AgentRuntimeError.createImage({
|
||||
error: error as any,
|
||||
errorType: 'ProviderBizError',
|
||||
provider,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ import minimaxChatModels from '@/config/aiModels/minimax';
|
||||
|
||||
import { ModelProvider } from '../types';
|
||||
import { createOpenAICompatibleRuntime } from '../utils/openaiCompatibleFactory';
|
||||
import { createMiniMaxImage } from './createImage';
|
||||
|
||||
export const getMinimaxMaxOutputs = (modelId: string): number | undefined => {
|
||||
const model = minimaxChatModels.find((model) => model.id === modelId);
|
||||
@@ -34,6 +35,7 @@ export const LobeMinimaxAI = createOpenAICompatibleRuntime({
|
||||
} as any;
|
||||
},
|
||||
},
|
||||
createImage: createMiniMaxImage,
|
||||
debug: {
|
||||
chatCompletion: () => process.env.DEBUG_MINIMAX_CHAT_COMPLETION === '1',
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user