Merge pull request #725 from lfnovo/feat/dashscope-minimax-providers

feat: add DashScope (Qwen) and MiniMax provider support
This commit is contained in:
Luis Novo 2026-04-06 13:42:45 -03:00 committed by GitHub
commit 6274358b21
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 227 additions and 16 deletions

View file

@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
## [1.8.2] - 2026-04-06
### Added
- DashScope (Qwen) provider support — Alibaba Cloud's Qwen models (qwen-turbo, qwen-plus, qwen-max)
- MiniMax provider support — MiniMax models with 204K context (MiniMax-M2.5, MiniMax-M2.5-highspeed)
- Model discovery, connection testing, and credential management for both new providers
- Documentation for DashScope and MiniMax in AI providers guide, environment reference, and provider comparison
### Dependencies
- Bump esperanto to >= 2.20.0
## [1.8.1] - 2026-03-10
### Added

View file

@ -58,7 +58,7 @@ In a world dominated by Artificial Intelligence, having the ability to think
**Open Notebook empowers you to:**
- 🔒 **Control your data** - Keep your research private and secure
- 🤖 **Choose your AI models** - Support for 16+ providers including OpenAI, Anthropic, Ollama, LM Studio, and more
- 🤖 **Choose your AI models** - Support for 18+ providers including OpenAI, Anthropic, Ollama, LM Studio, and more
- 📚 **Organize multi-modal content** - PDFs, videos, audio, web pages, and more
- 🎙️ **Generate professional podcasts** - Advanced multi-speaker podcast generation
- 🔍 **Search intelligently** - Full-text and vector search across all your content
@ -74,7 +74,7 @@ Learn more about our project at [https://www.open-notebook.ai](https://www.open-
| Feature | Open Notebook | Google Notebook LM | Advantage |
|---------|---------------|--------------------|-----------|
| **Privacy & Control** | Self-hosted, your data | Google cloud only | Complete data sovereignty |
| **AI Provider Choice** | 16+ providers (OpenAI, Anthropic, Ollama, LM Studio, etc.) | Google models only | Flexibility and cost optimization |
| **AI Provider Choice** | 18+ providers (OpenAI, Anthropic, Ollama, LM Studio, etc.) | Google models only | Flexibility and cost optimization |
| **Podcast Speakers** | 1-4 speakers with custom profiles | 2 speakers only | Extreme flexibility |
| **Content Transformations** | Custom and built-in | Limited options | Unlimited processing power |
| **API Access** | Full REST API | No API | Complete automation |
@ -213,6 +213,8 @@ Thanks to the [Esperanto](https://github.com/lfnovo/esperanto) library, we suppo
| Voyage | ❌ | ✅ | ❌ | ❌ |
| xAI | ✅ | ❌ | ❌ | ❌ |
| OpenRouter | ✅ | ❌ | ❌ | ❌ |
| DashScope (Qwen) | ✅ | ❌ | ❌ | ❌ |
| MiniMax | ✅ | ❌ | ❌ | ❌ |
| OpenAI Compatible* | ✅ | ❌ | ❌ | ❌ |
*Supports LM Studio and any OpenAI-compatible endpoint
@ -223,7 +225,7 @@ Thanks to the [Esperanto](https://github.com/lfnovo/esperanto) library, we suppo
- **🔒 Privacy-First**: Your data stays under your control - no cloud dependencies
- **🎯 Multi-Notebook Organization**: Manage multiple research projects seamlessly
- **📚 Universal Content Support**: PDFs, videos, audio, web pages, Office docs, and more
- **🤖 Multi-Model AI Support**: 16+ providers including OpenAI, Anthropic, Ollama, Google, LM Studio, and more
- **🤖 Multi-Model AI Support**: 18+ providers including OpenAI, Anthropic, Ollama, Google, LM Studio, and more
- **🎙️ Professional Podcast Generation**: Advanced multi-speaker podcasts with Episode Profiles
- **🔍 Intelligent Search**: Full-text and vector search across all your content
- **💬 Context-Aware Chat**: AI conversations powered by your research materials
@ -280,7 +282,7 @@ Thanks to the [Esperanto](https://github.com/lfnovo/esperanto) library, we suppo
### Recently Completed ✅
- **Next.js Frontend**: Modern React-based frontend with improved performance
- **Comprehensive REST API**: Full programmatic access to all functionality
- **Multi-Model Support**: 16+ AI providers including OpenAI, Anthropic, Ollama, LM Studio
- **Multi-Model Support**: 18+ AI providers including OpenAI, Anthropic, Ollama, LM Studio
- **Advanced Podcast Generator**: Professional multi-speaker podcasts with Episode Profiles
- **Content Transformations**: Powerful customizable actions for content processing
- **Enhanced Citations**: Improved layout and finer control for source citations

View file

@ -57,6 +57,8 @@ PROVIDER_ENV_CONFIG: Dict[str, dict] = {
"openai_compatible": {
"required_any": ["OPENAI_COMPATIBLE_BASE_URL", "OPENAI_COMPATIBLE_API_KEY"],
},
"dashscope": {"required": ["DASHSCOPE_API_KEY"]},
"minimax": {"required": ["MINIMAX_API_KEY"]},
}
PROVIDER_MODALITIES: Dict[str, List[str]] = {
@ -74,6 +76,8 @@ PROVIDER_MODALITIES: Dict[str, List[str]] = {
"vertex": ["language", "embedding"],
"azure": ["language", "embedding", "speech_to_text", "text_to_speech"],
"openai_compatible": ["language", "embedding", "speech_to_text", "text_to_speech"],
"dashscope": ["language"],
"minimax": ["language"],
}
@ -512,6 +516,8 @@ async def discover_with_config(provider: str, config: dict) -> List[dict]:
"deepseek": "https://api.deepseek.com/models",
"xai": "https://api.x.ai/v1/models",
"openrouter": "https://openrouter.ai/api/v1/models",
"dashscope": "https://dashscope.aliyuncs.com/compatible-mode/v1/models",
"minimax": "https://api.minimax.io/v1/models",
}
if provider == "ollama":

View file

@ -96,6 +96,8 @@ PROVIDER_PRIORITY = [
"ollama",
"azure",
"openai_compatible",
"dashscope",
"minimax",
]
# Model preference patterns (preferred models within each provider)
@ -105,6 +107,8 @@ MODEL_PREFERENCES = {
"google": ["gemini-2.0", "gemini-1.5-pro", "gemini-pro"],
"mistral": ["mistral-large", "mixtral"],
"groq": ["llama-3.3", "llama-3.1", "mixtral"],
"dashscope": ["qwen-max", "qwen-plus", "qwen-turbo"],
"minimax": ["MiniMax-M2.5", "MiniMax-M2.5-highspeed"],
}
@ -378,6 +382,8 @@ async def get_provider_availability():
"voyage": "VOYAGE_API_KEY",
"elevenlabs": "ELEVENLABS_API_KEY",
"ollama": "OLLAMA_API_BASE",
"dashscope": "DASHSCOPE_API_KEY",
"minimax": "MINIMAX_API_KEY",
}
provider_status = {}

View file

@ -12,7 +12,7 @@
---
### ☁️ I want to use other cloud AI (Anthropic, Google, OpenRouter, etc.)
**5 minutes to running.** Choose from 15+ AI providers.
**5 minutes to running.** Choose from 17+ AI providers.
→ [Cloud Providers Quick Start](quick-start-cloud.md)
@ -39,7 +39,7 @@
| Feature | Open Notebook | Notebook LM |
|---------|---|---|
| **Privacy** | Self-hosted, your control | Cloud, Google's servers |
| **AI Choice** | 15+ providers | Google's models only |
| **AI Choice** | 17+ providers | Google's models only |
| **Podcast Speakers** | 1-4 customizable | 2 only |
| **Cost** | Completely free | Free (but your data) |
| **Offline** | Yes | No |

View file

@ -1,6 +1,6 @@
# AI Providers - Comparison & Selection Guide
Open Notebook supports 15+ AI providers. This guide helps you **choose the right provider** for your needs.
Open Notebook supports 17+ AI providers. This guide helps you **choose the right provider** for your needs.
> 💡 **Just want to set up a provider?** Skip to the [Configuration Guide](../5-CONFIGURATION/ai-providers.md) for detailed setup instructions.
@ -54,6 +54,24 @@ Open Notebook supports 15+ AI providers. This guide helps you **choose the right
→ [Setup Guide](../5-CONFIGURATION/ai-providers.md#openrouter)
**DashScope (Qwen)**
- Cost: ~$0.01-0.06 per 1K tokens
- Speed: Fast
- Quality: Good
- Best for: Users in Asia, Alibaba Cloud ecosystem
- Advantage: Competitive pricing, strong multilingual support
→ [Setup Guide](../5-CONFIGURATION/ai-providers.md#dashscope-qwen)
**MiniMax**
- Cost: Varies by model
- Speed: Fast
- Quality: Good
- Best for: Long context tasks (204K tokens)
- Advantage: Very long context window
→ [Setup Guide](../5-CONFIGURATION/ai-providers.md#minimax)
### Local / Self-Hosted (Free)
**Ollama (Recommended for Local)**
@ -98,6 +116,8 @@ Open Notebook supports 15+ AI providers. This guide helps you **choose the right
| **Google** | Very Fast | $$ | Good-Excellent | Low | 5 min | 2M |
| **Groq** | Ultra Fast | $ | Good | Low | 5 min | 32K |
| **OpenRouter** | Varies | Varies | Varies | Low | 5 min | Varies |
| **DashScope** | Fast | $ | Good | Low | 5 min | Varies |
| **MiniMax** | Fast | $$ | Good | Low | 5 min | 204K |
| **Ollama** | Slow-Medium | Free | Good | Max | 10 min | Varies |
| **LM Studio** | Slow-Medium | Free | Good | Max | 15 min | Varies |
| **Azure** | Very Fast | $$ | Excellent | High | 10 min | 128K |

View file

@ -249,6 +249,76 @@ Heavy use: Depends on models chosen
---
### DashScope (Qwen)
**Cost:** ~$0.01-0.06 per 1K tokens (varies by model)
**Get Your API Key:**
1. Go to https://dashscope.console.aliyun.com/
2. Create an Alibaba Cloud account (if needed)
3. Navigate to API Keys section
4. Create a new API key
**Configure in Open Notebook:**
1. Go to **Settings** → **API Keys**
2. Click **Add Credential**
3. Select provider: **DashScope (Qwen)**
4. Give it a name, paste your API key
5. Click **Save**, then **Test Connection**
6. Click **Discover Models** → **Register Models**
**Available Models:**
- `qwen-max` — Most capable Qwen model
- `qwen-plus` — Good balance of quality and speed
- `qwen-turbo` — Fastest, cheapest
**Recommended:**
- For quality: `qwen-max` (best overall)
- For general use: `qwen-plus` (good balance)
- For speed/cost: `qwen-turbo` (cheapest)
**Troubleshooting:**
- "Invalid API key" → Check the key in the DashScope console
- "Model not available" → Re-discover models from the credential
---
### MiniMax
**Cost:** Varies by model
**Get Your API Key:**
1. Go to https://platform.minimaxi.com/
2. Create an account (if needed)
3. Navigate to API Keys section
4. Create a new API key
**Configure in Open Notebook:**
1. Go to **Settings** → **API Keys**
2. Click **Add Credential**
3. Select provider: **MiniMax**
4. Give it a name, paste your API key
5. Click **Save**, then **Test Connection**
6. Click **Discover Models** → **Register Models**
**Available Models:**
- `MiniMax-M2.5` — Most capable, 204K context
- `MiniMax-M2.5-highspeed` — Faster variant, 204K context
**Recommended:**
- For quality: `MiniMax-M2.5` (best overall)
- For speed: `MiniMax-M2.5-highspeed` (faster responses)
**Advantages:**
- Very long context (204K tokens)
- Competitive pricing
**Troubleshooting:**
- "Invalid API key" → Check the key in the MiniMax platform
- "Model not available" → Re-discover models from the credential
---
## Self-Hosted / Local
### Ollama (Recommended for Local)

View file

@ -263,6 +263,8 @@ If you have these variables configured from a previous installation, click the *
| `OPENAI_COMPATIBLE_API_KEY_STT` | OpenAI-Compatible | Configure per-service key in credential |
| `OPENAI_COMPATIBLE_BASE_URL_TTS` | OpenAI-Compatible | Configure per-service URL in credential |
| `OPENAI_COMPATIBLE_API_KEY_TTS` | OpenAI-Compatible | Configure per-service key in credential |
| `DASHSCOPE_API_KEY` | DashScope (Qwen) | Settings → API Keys → Add DashScope Credential |
| `MINIMAX_API_KEY` | MiniMax | Settings → API Keys → Add MiniMax Credential |
| `AZURE_OPENAI_API_KEY` | Azure OpenAI | Settings → API Keys → Add Azure OpenAI Credential |
| `AZURE_OPENAI_ENDPOINT` | Azure OpenAI | Configure in Azure OpenAI credential |
| `AZURE_OPENAI_API_VERSION` | Azure OpenAI | Configure in Azure OpenAI credential |

View file

@ -18,7 +18,7 @@ Open Notebook is an open-source, privacy-focused alternative to Google's Noteboo
### How is it different from Google Notebook LM?
**Privacy**: Your data stays local by default. Only your chosen AI providers receive queries.
**Flexibility**: Support for 15+ AI providers (OpenAI, Anthropic, Google, local models, etc.)
**Flexibility**: Support for 17+ AI providers (OpenAI, Anthropic, Google, local models, etc.)
**Customization**: Open source, so you can modify and extend functionality
**Control**: You control your data, models, and processing

View file

@ -86,7 +86,7 @@ Open Notebook aims to be a **privacy-focused, self-hosted alternative to Google'
- Graceful degradation when providers are unavailable
**Example Decisions**:
- ✅ Support for 16+ AI providers
- ✅ Support for 18+ AI providers
- ✅ Per-feature model selection (chat, embeddings, TTS)
- ❌ Features that only work with OpenAI
- ❌ Hard-coded API endpoints for specific providers

View file

@ -75,12 +75,14 @@ const PROVIDER_DISPLAY_NAMES: Record<string, string> = {
azure: 'Azure OpenAI',
vertex: 'Google Vertex AI',
openai_compatible: 'OpenAI Compatible',
dashscope: 'DashScope (Qwen)',
minimax: 'MiniMax',
}
// All providers in display order
const ALL_PROVIDERS = [
'openai', 'anthropic', 'google', 'groq', 'mistral', 'deepseek',
'xai', 'openrouter', 'voyage', 'elevenlabs', 'ollama',
'xai', 'openrouter', 'dashscope', 'minimax', 'voyage', 'elevenlabs', 'ollama',
'azure', 'vertex', 'openai_compatible',
]
@ -100,6 +102,8 @@ const PROVIDER_MODALITIES: Record<string, ModelType[]> = {
azure: ['language', 'embedding', 'text_to_speech', 'speech_to_text'],
vertex: ['language', 'embedding', 'text_to_speech'],
openai_compatible: ['language', 'embedding', 'text_to_speech', 'speech_to_text'],
dashscope: ['language'],
minimax: ['language'],
}
// Documentation links
@ -117,6 +121,8 @@ const PROVIDER_DOCS: Record<string, string> = {
azure: 'https://portal.azure.com/#view/Microsoft_Azure_ProjectOxford/CognitiveServicesHub/~/OpenAI',
vertex: 'https://cloud.google.com/vertex-ai/docs/start/cloud-environment',
openai_compatible: 'https://github.com/lfnovo/open-notebook/blob/main/docs/5-CONFIGURATION/openai-compatible.md',
dashscope: 'https://help.aliyun.com/zh/model-studio/getting-started/',
minimax: 'https://platform.minimaxi.com/document/Guides',
}
const TYPE_ICONS: Record<ModelType, React.ReactNode> = {

View file

@ -34,6 +34,8 @@ TEST_MODELS = {
"vertex": ("gemini-2.0-flash", "language"), # Uses Google Vertex AI
"azure": ("gpt-35-turbo", "language"), # Azure OpenAI deployment name
"openai_compatible": (None, "language"), # Dynamic - will use first available model
"dashscope": ("qwen-plus", "language"),
"minimax": ("MiniMax-M2.5", "language"),
}

View file

@ -62,6 +62,12 @@ PROVIDER_CONFIG = {
"ollama": {
"env_var": "OLLAMA_API_BASE",
},
"dashscope": {
"env_var": "DASHSCOPE_API_KEY",
},
"minimax": {
"env_var": "MINIMAX_API_KEY",
},
}

View file

@ -131,6 +131,14 @@ ELEVENLABS_MODEL_TYPES = {
"text_to_speech": ["eleven"],
}
DASHSCOPE_MODEL_TYPES = {
"language": ["qwen"],
}
MINIMAX_MODEL_TYPES = {
"language": ["minimax", "abab"],
}
def classify_model_type(model_name: str, provider: str) -> str:
"""
@ -150,6 +158,8 @@ def classify_model_type(model_name: str, provider: str) -> str:
"xai": XAI_MODEL_TYPES,
"voyage": VOYAGE_MODEL_TYPES,
"elevenlabs": ELEVENLABS_MODEL_TYPES,
"dashscope": DASHSCOPE_MODEL_TYPES,
"minimax": MINIMAX_MODEL_TYPES,
}
mapping = type_mappings.get(provider, {})
@ -518,6 +528,74 @@ async def discover_elevenlabs_models() -> List[DiscoveredModel]:
]
async def discover_dashscope_models() -> List[DiscoveredModel]:
"""Fetch available models from DashScope (Qwen) API."""
api_key = os.environ.get("DASHSCOPE_API_KEY")
if not api_key:
return []
models = []
try:
async with httpx.AsyncClient() as client:
response = await client.get(
"https://dashscope.aliyuncs.com/compatible-mode/v1/models",
headers={"Authorization": f"Bearer {api_key}"},
timeout=30.0,
)
response.raise_for_status()
data = response.json()
for model in data.get("data", []):
model_id = model.get("id", "")
if model_id:
model_type = classify_model_type(model_id, "dashscope")
models.append(
DiscoveredModel(
name=model_id,
provider="dashscope",
model_type=model_type,
)
)
except Exception as e:
logger.warning(f"Failed to discover DashScope models: {e}")
return models
async def discover_minimax_models() -> List[DiscoveredModel]:
"""Fetch available models from MiniMax API."""
api_key = os.environ.get("MINIMAX_API_KEY")
if not api_key:
return []
models = []
try:
async with httpx.AsyncClient() as client:
response = await client.get(
"https://api.minimax.io/v1/models",
headers={"Authorization": f"Bearer {api_key}"},
timeout=30.0,
)
response.raise_for_status()
data = response.json()
for model in data.get("data", []):
model_id = model.get("id", "")
if model_id:
model_type = classify_model_type(model_id, "minimax")
models.append(
DiscoveredModel(
name=model_id,
provider="minimax",
model_type=model_type,
)
)
except Exception as e:
logger.warning(f"Failed to discover MiniMax models: {e}")
return models
async def discover_openai_compatible_models() -> List[DiscoveredModel]:
"""
Fetch available models from an OpenAI-compatible API endpoint.
@ -600,6 +678,8 @@ PROVIDER_DISCOVERY_FUNCTIONS = {
"voyage": discover_voyage_models,
"elevenlabs": discover_elevenlabs_models,
"openai_compatible": discover_openai_compatible_models,
"dashscope": discover_dashscope_models,
"minimax": discover_minimax_models,
"azure": None, # Azure requires credential-based discovery (different auth)
"vertex": None, # Vertex requires credential-based discovery (service account)
}

View file

@ -1,6 +1,6 @@
[project]
name = "open-notebook"
version = "1.8.1"
version = "1.8.2"
description = "An open source implementation of a research assistant, inspired by Google Notebook LM"
authors = [
{name = "Luis Novo", email = "lfnovo@gmail.com"}
@ -34,7 +34,7 @@ dependencies = [
"httpx[socks]>=0.27.0",
"content-core>=1.14.1,<2",
"ai-prompter>=0.3,<1",
"esperanto>=2.19.7,<3",
"esperanto>=2.20.0,<3",
"surrealdb>=1.0.4",
"podcast-creator>=0.12.0,<1",
"surreal-commands>=1.3.1,<2",

View file

@ -648,15 +648,15 @@ wheels = [
[[package]]
name = "esperanto"
version = "2.19.7"
version = "2.20.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "httpx" },
{ name = "pydantic" },
]
sdist = { url = "https://files.pythonhosted.org/packages/da/e0/d7c7f91a7b86744ce040385a4c81f8eaa147a140f299995c1fb8a59c4238/esperanto-2.19.7.tar.gz", hash = "sha256:83b2b1683361fc019444305a34ae398da71724f76b9563c0cf5a7c4d54fb08eb", size = 833887, upload-time = "2026-03-11T20:25:41.47Z" }
sdist = { url = "https://files.pythonhosted.org/packages/bb/8c/eba93a2b7b1a4fc6812bcf0a83a69a3376fcaf5831fae04a0ad539baeff6/esperanto-2.20.0.tar.gz", hash = "sha256:53a16c539ed2f83e3400b4e56d5a20b7873df6cb926c1e6696a9611b3be928fb", size = 845084, upload-time = "2026-03-21T14:32:04.589Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/fb/ab/6d81682bfd3b2f5db283c302c4695623f282ae08c99c667609467c10bc22/esperanto-2.19.7-py3-none-any.whl", hash = "sha256:9a853a51f59495ac2487c3d7a12942c931e4daf6185e45247b715938a4597685", size = 202436, upload-time = "2026-03-11T20:25:40.089Z" },
{ url = "https://files.pythonhosted.org/packages/13/83/476dd4d7ee9f1b013ccd66e2518d150e66d3537736aed735b27230af0eb4/esperanto-2.20.0-py3-none-any.whl", hash = "sha256:767f95d08dd29e7d1950f4cc2ec908084e93ec61e945ce9446f001c54b86bb63", size = 203977, upload-time = "2026-03-21T14:32:05.676Z" },
]
[[package]]
@ -2129,7 +2129,7 @@ requires-dist = [
{ name = "ai-prompter", specifier = ">=0.3,<1" },
{ name = "babel", specifier = ">=2.18.0" },
{ name = "content-core", specifier = ">=1.14.1,<2" },
{ name = "esperanto", specifier = ">=2.19.7,<3" },
{ name = "esperanto", specifier = ">=2.20.0,<3" },
{ name = "fastapi", specifier = ">=0.104.0" },
{ name = "httpx", extras = ["socks"], specifier = ">=0.27.0" },
{ name = "ipykernel", marker = "extra == 'dev'", specifier = ">=6.29.5" },