Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ Star us, and you will receive all release notifications from GitHub without any
🎬 One-Prompt Image & Video Generation
Turn one prompt into complete images or videos in seconds.

-Supports GPT-4o, Midjourney, VEO3, Kling,veo3,seedance etc.
-Supports GPT-4o, MiniMax, Midjourney, VEO3, Kling,veo3,seedance etc.

-Auto-optimized prompts & multi-turn refinement

Expand Down
2 changes: 1 addition & 1 deletion README_zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
由大语言模型(LLM)驱动,Jaaz 能理解你的想法并生成优化的提示词,用于创作高质量的图像或故事板。

混合模型部署
支持通过 Ollama、ComfyUI 运行本地模型,也支持 Replicate、OpenAI 或 Claude 等远程 API。可实现 100% 本地运行或连接到云端。
支持通过 Ollama、ComfyUI 运行本地模型,也支持 Replicate、OpenAI、ClaudeMiniMax 等远程 API。可实现 100% 本地运行或连接到云端。

轻松接入所有最强 API
登录后,你可以使用所有最新的模型(gpt-image-1, flux kntext, google……)。
Expand Down
12 changes: 12 additions & 0 deletions react/src/components/settings/AddProviderDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,18 @@ const PROVIDER_OPTIONS = [
},
},
},
{
value: 'minimax',
label: 'MiniMax',
data: {
apiUrl: 'https://api.minimax.io/v1/',
models: {
'MiniMax-M2.7': { type: 'text' },
'MiniMax-M2.5': { type: 'text' },
'MiniMax-M2.5-highspeed': { type: 'text' },
},
},
},
{
value: '硅基流动',
label: '硅基流动 (SiliconFlow)',
Expand Down
4 changes: 4 additions & 0 deletions react/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ export const PROVIDER_NAME_MAPPING: {
name: 'ComfyUI',
icon: 'https://framerusercontent.com/images/3cNQMWKzIhIrQ5KErBm7dSmbd2w.png',
},
minimax: {
name: 'MiniMax',
icon: 'https://www.minimaxi.com/favicon.ico',
},
}

// Tool call name mapping
Expand Down
10 changes: 10 additions & 0 deletions server/services/config_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,16 @@ class ProviderConfig(TypedDict, total=False):
'api_key': '',
'max_tokens': 8192,
},
'minimax': {
'models': {
'MiniMax-M2.7': {'type': 'text'},
'MiniMax-M2.5': {'type': 'text'},
'MiniMax-M2.5-highspeed': {'type': 'text'},
},
'url': 'https://api.minimax.io/v1/',
'api_key': '',
'max_tokens': 8192,
},

}

Expand Down
Empty file added server/tests/__init__.py
Empty file.
74 changes: 74 additions & 0 deletions server/tests/test_minimax_integration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
"""Integration tests for MiniMax provider.

These tests verify actual MiniMax API connectivity.
Requires MINIMAX_API_KEY environment variable to be set.
"""
import os
import sys
import unittest

sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))

MINIMAX_API_KEY = os.environ.get('MINIMAX_API_KEY', '')


@unittest.skipUnless(MINIMAX_API_KEY, 'MINIMAX_API_KEY not set')
class TestMiniMaxAPIIntegration(unittest.TestCase):
"""Integration tests that call the real MiniMax API."""

def test_minimax_chat_completion(self):
"""Test basic chat completion via OpenAI-compatible API."""
from openai import OpenAI

client = OpenAI(
api_key=MINIMAX_API_KEY,
base_url='https://api.minimax.io/v1/',
)
response = client.chat.completions.create(
model='MiniMax-M2.5-highspeed',
messages=[{'role': 'user', 'content': 'Say hello in one word.'}],
max_tokens=10,
temperature=0,
)
self.assertIsNotNone(response.choices)
self.assertGreater(len(response.choices), 0)
self.assertIsNotNone(response.choices[0].message.content)

def test_minimax_model_list(self):
"""Test that MiniMax models are accessible."""
from openai import OpenAI

client = OpenAI(
api_key=MINIMAX_API_KEY,
base_url='https://api.minimax.io/v1/',
)
# Verify the API endpoint responds
response = client.chat.completions.create(
model='MiniMax-M2.5-highspeed',
messages=[{'role': 'user', 'content': 'Hi'}],
max_tokens=5,
temperature=0,
)
self.assertEqual(response.model, 'MiniMax-M2.5-highspeed')

def test_minimax_streaming(self):
"""Test streaming chat completion."""
from openai import OpenAI

client = OpenAI(
api_key=MINIMAX_API_KEY,
base_url='https://api.minimax.io/v1/',
)
stream = client.chat.completions.create(
model='MiniMax-M2.5-highspeed',
messages=[{'role': 'user', 'content': 'Say hi.'}],
max_tokens=10,
temperature=0,
stream=True,
)
chunks = list(stream)
self.assertGreater(len(chunks), 0)


if __name__ == '__main__':
unittest.main()
132 changes: 132 additions & 0 deletions server/tests/test_minimax_provider.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
"""Unit tests for MiniMax provider integration."""
import os
import sys
import unittest

# Add server directory to path
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))


class TestMiniMaxDefaultConfig(unittest.TestCase):
"""Test that MiniMax is properly configured in DEFAULT_PROVIDERS_CONFIG."""

def setUp(self):
from services.config_service import DEFAULT_PROVIDERS_CONFIG
self.config = DEFAULT_PROVIDERS_CONFIG

def test_minimax_provider_exists(self):
self.assertIn('minimax', self.config)

def test_minimax_url(self):
self.assertEqual(
self.config['minimax']['url'],
'https://api.minimax.io/v1/'
)

def test_minimax_has_text_models(self):
models = self.config['minimax']['models']
self.assertIn('MiniMax-M2.7', models)
self.assertIn('MiniMax-M2.5', models)
self.assertIn('MiniMax-M2.5-highspeed', models)

def test_minimax_models_are_text_type(self):
models = self.config['minimax']['models']
for model_name, model_config in models.items():
self.assertEqual(
model_config.get('type'), 'text',
f"Model {model_name} should be type 'text'"
)

def test_minimax_has_empty_api_key(self):
self.assertEqual(self.config['minimax']['api_key'], '')

def test_minimax_max_tokens(self):
self.assertEqual(self.config['minimax']['max_tokens'], 8192)


class TestMiniMaxConfigService(unittest.TestCase):
"""Test ConfigService handles MiniMax provider correctly."""

def test_config_service_includes_minimax(self):
from services.config_service import config_service
config = config_service.get_config()
self.assertIn('minimax', config)

def test_minimax_not_marked_as_custom(self):
from services.config_service import DEFAULT_PROVIDERS_CONFIG
minimax_config = DEFAULT_PROVIDERS_CONFIG['minimax']
self.assertNotIn('is_custom', minimax_config)


class TestMiniMaxProviderRouting(unittest.TestCase):
"""Test that MiniMax provider routes via OpenAI-compatible path (not Ollama).

This tests the routing logic from _create_text_model() without importing
the full agent_service module (which has heavy dependencies).
"""

def test_minimax_provider_is_not_ollama(self):
"""MiniMax should not match the 'ollama' provider check."""
provider = 'minimax'
self.assertNotEqual(provider, 'ollama')

def test_minimax_openai_compatible_routing(self):
"""Simulate the _create_text_model routing logic."""
provider = 'minimax'
model = 'MiniMax-M2.7'
url = 'https://api.minimax.io/v1/'

# This mirrors the logic in agent_service._create_text_model
if provider == 'ollama':
path = 'ollama'
else:
path = 'openai_compat'

self.assertEqual(path, 'openai_compat')

def test_all_minimax_models_route_correctly(self):
"""All MiniMax models should use OpenAI-compatible path."""
from services.config_service import DEFAULT_PROVIDERS_CONFIG
models = DEFAULT_PROVIDERS_CONFIG['minimax']['models']
for model_name in models:
provider = 'minimax'
self.assertNotEqual(provider, 'ollama',
f"Model {model_name} should not route via Ollama")


class TestMiniMaxProviderConfig(unittest.TestCase):
"""Test MiniMax provider configuration structure."""

def test_minimax_config_has_required_fields(self):
from services.config_service import DEFAULT_PROVIDERS_CONFIG
minimax = DEFAULT_PROVIDERS_CONFIG['minimax']
self.assertIn('models', minimax)
self.assertIn('url', minimax)
self.assertIn('api_key', minimax)
self.assertIn('max_tokens', minimax)

def test_minimax_model_count(self):
from services.config_service import DEFAULT_PROVIDERS_CONFIG
models = DEFAULT_PROVIDERS_CONFIG['minimax']['models']
self.assertEqual(len(models), 3)

def test_minimax_url_starts_with_https(self):
from services.config_service import DEFAULT_PROVIDERS_CONFIG
url = DEFAULT_PROVIDERS_CONFIG['minimax']['url']
self.assertTrue(url.startswith('https://'))

def test_minimax_url_ends_with_slash(self):
from services.config_service import DEFAULT_PROVIDERS_CONFIG
url = DEFAULT_PROVIDERS_CONFIG['minimax']['url']
self.assertTrue(url.endswith('/'))

def test_minimax_config_matches_other_providers(self):
"""MiniMax config should have the same structure as OpenAI config."""
from services.config_service import DEFAULT_PROVIDERS_CONFIG
minimax = DEFAULT_PROVIDERS_CONFIG['minimax']
openai = DEFAULT_PROVIDERS_CONFIG['openai']
self.assertEqual(set(minimax.keys()), set(openai.keys()))


if __name__ == '__main__':
unittest.main()