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
30 changes: 30 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,36 @@ The model may then be used in OntoGPT by prefixing its name with `ollama/`, e.g.

Some ollama models may not be listed in `ontogpt list-models` but the full list of downloaded LLMs can be seen with `ollama list` command.

## MiniMax

[MiniMax](https://www.minimaxi.com/) models may be used through their OpenAI-compatible API.

1. Set your MiniMax API key:

```bash
export MINIMAX_API_KEY="your-minimax-api-key"
```

Or use the `runoak` key manager:

```bash
runoak set-apikey -e minimax-key <your minimax api key>
```

2. Use a MiniMax model with the `minimax/` prefix or the `--model-provider` option:

```bash
ontogpt extract -t drug -i example.txt -m minimax/MiniMax-M2.7
```

Or equivalently:

```bash
ontogpt extract -t drug -i example.txt -m MiniMax-M2.7 --model-provider minimax
```

Available MiniMax models include `MiniMax-M2.7` (latest, 204K context) and `MiniMax-M2.7-highspeed` (204K context, optimized for speed).

## Evaluations

OntoGPT's functions have been evaluated on test data. Please see the full documentation for details on these evaluations and how to reproduce them.
Expand Down
22 changes: 22 additions & 0 deletions src/ontogpt/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,28 @@
# This is provided by the litellm package
MODELS = get_model_cost_map("")

# Add MiniMax models (OpenAI-compatible API at https://api.minimax.io/v1)
# These may not be in litellm's default cost map yet
MINIMAX_MODELS = {
"minimax/MiniMax-M2.7": {
"max_tokens": 204800,
"max_input_tokens": 204800,
"max_output_tokens": 16384,
"litellm_provider": "minimax",
"mode": "chat",
},
"minimax/MiniMax-M2.7-highspeed": {
"max_tokens": 204800,
"max_input_tokens": 204800,
"max_output_tokens": 16384,
"litellm_provider": "minimax",
"mode": "chat",
},
}
for model_name, model_info in MINIMAX_MODELS.items():
if model_name not in MODELS:
MODELS[model_name] = model_info

try:
__version__ = metadata.version(__name__)
except metadata.PackageNotFoundError:
Expand Down
3 changes: 2 additions & 1 deletion src/ontogpt/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,8 @@ def parse_tabular_input(inputpath: str, selectcols: List[str]) -> str:
model_provider_option = click.option(
"--model-provider",
help="Specify a provider if model is not specified in the model name."
" If using a proxy using the OpenAI API format, this should be set to 'openai'.",
" If using a proxy using the OpenAI API format, this should be set to 'openai'."
" For MiniMax models, set this to 'minimax'.",
)
temperature_option = click.option(
"-p",
Expand Down
28 changes: 28 additions & 0 deletions src/ontogpt/clients/llm_client.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""Client for running LLM completion requests through LiteLLM."""

import logging
import os
import sys
from dataclasses import dataclass, field

Expand All @@ -18,6 +19,9 @@
# Just get the part before the slash in each model name
SERVICES = {model.split("/")[0] for model in MODELS.keys() if len(model.split("/")) > 1}

# MiniMax API base URL (OpenAI-compatible endpoint)
MINIMAX_API_BASE = "https://api.minimax.io/v1"

# Necessary to avoid repeated debug messages
litellm.suppress_debug_info = True

Expand Down Expand Up @@ -57,12 +61,36 @@ def __post_init__(self):
else:
raise ValueError(f"Model name must be a string, got {type(self.model)}")

# Detect MiniMax provider from model name prefix or explicit provider
is_minimax = (
self.custom_llm_provider == "minimax"
or self.model.startswith("minimax/")
)

if self.model.startswith("ollama"):
self.api_key = "" # Don't need an API key
elif self.model.startswith("fake"):
# Just used for testing
self.api_key = "" # Don't need an API key
logger.info(f"Using mock model: {self.model}")
elif is_minimax:
# MiniMax uses an OpenAI-compatible API
if not self.api_key:
self.api_key = os.environ.get("MINIMAX_API_KEY", "") or get_apikey_value(
"minimax-key"
)
if self.api_base is None:
self.api_base = MINIMAX_API_BASE
# Strip the minimax/ prefix so litellm sends just the model name
if self.model.startswith("minimax/"):
self.model = self.model[len("minimax/"):]
# Route through litellm's OpenAI-compatible path
self.custom_llm_provider = "openai"
# Clamp temperature: MiniMax requires (0.0, 1.0]
if self.temperature <= 0.0:
self.temperature = 0.01
elif self.temperature > 1.0:
self.temperature = 1.0
elif not self.api_key and not self.custom_llm_provider:
self.api_key = get_apikey_value("openai")
elif self.custom_llm_provider == "anthropic":
Expand Down
44 changes: 44 additions & 0 deletions tests/integration/test_clients/test_minimax_integration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
"""Integration tests for MiniMax provider support.

These tests require a valid MINIMAX_API_KEY environment variable.
They are skipped if the key is not set.
"""

import os
import unittest

import pytest

from ontogpt.clients.llm_client import LLMClient

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


@pytest.mark.skipif(not MINIMAX_API_KEY, reason="MINIMAX_API_KEY not set")
class TestMiniMaxIntegration(unittest.TestCase):
"""Integration tests for MiniMax LLM provider."""

def test_minimax_completion_with_prefix(self):
"""Test basic completion using minimax/ model prefix."""
client = LLMClient(model="minimax/MiniMax-M2.7", temperature=0.7)
result = client.complete("Respond with exactly one word: hello")
self.assertIsInstance(result, str)
self.assertGreater(len(result.strip()), 0)

def test_minimax_completion_with_provider(self):
"""Test basic completion using --model-provider minimax."""
client = LLMClient(
model="MiniMax-M2.7",
custom_llm_provider="minimax",
temperature=0.5,
)
result = client.complete("What is 2 + 2? Answer with just the number.")
self.assertIsInstance(result, str)
self.assertIn("4", result)

def test_minimax_highspeed_model(self):
"""Test completion with the highspeed variant."""
client = LLMClient(model="minimax/MiniMax-M2.7-highspeed", temperature=0.7)
result = client.complete("Say the word 'test'.")
self.assertIsInstance(result, str)
self.assertGreater(len(result.strip()), 0)
Loading