diff --git a/README.md b/README.md index 4bfb2c89..ce338385 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ What makes Presenton different? - Use Fully **self-hosted** in Web through [Docker Package](https://docs.presenton.ai/v3/get-started/quickstart) - Or Download [Desktop App](https://presenton.ai/download) (Mac, Windows & Linux) -- Works with OpenAI, Gemini, Anthropic, Ollama, or custom models +- Works with OpenAI, Gemini, Vertex AI, Azure OpenAI, Anthropic, Ollama, or custom models - Comes with AI Presentation Generation API - Fully open-source (Apache 2.0) - Works with your own design/templates @@ -97,7 +97,7 @@ Presenton gives you complete control over your AI presentation workflow. Choose - Flexible Generation — Build presentations from prompts or uploaded documents - Export Ready — Save as PowerPoint (PPTX) and PDF with professional formatting - Built-In MCP Server — Generate presentations over Model Context Protocol -- Bring Your Own Key — Use your own API keys for OpenAI, Google Gemini, Anthropic Claude, or any compatible provider. Only pay for what you use, no hidden fees or subscriptions. +- Bring Your Own Key — Use your own API keys for OpenAI, Google Gemini, Vertex AI, Azure OpenAI, Anthropic Claude, or any compatible provider. Only pay for what you use, no hidden fees or subscriptions. - Ollama Integration — Run open-source models locally with full privacy - OpenAI API Compatible — Connect to any OpenAI-compatible endpoint with your own models - Multi-Provider Support — Mix and match text and image generation providers @@ -204,11 +204,20 @@ Other optional variables exist in code (for example advanced Mem0 paths, LitePar #### LLM and API keys - **CAN_CHANGE_KEYS**=[true/false]: Set to **false** if you want to keep API keys hidden and make them unmodifiable. -- **LLM**=[openai/google/anthropic/ollama/custom/codex]: Select the text **LLM**. +- **LLM**=[openai/google/vertex/azure/anthropic/ollama/custom/codex]: Select the text **LLM**. - **OPENAI_API_KEY**: Required if **LLM** is **openai**. - **OPENAI_MODEL**: Required if **LLM** is **openai** (default: `gpt-4.1`). - **GOOGLE_API_KEY**: Required if **LLM** is **google**. - **GOOGLE_MODEL**: Required if **LLM** is **google** (default: `models/gemini-2.0-flash`). +- **VERTEX_MODEL**: Required if **LLM** is **vertex** (default: `gemini-2.5-flash`). +- **VERTEX_API_KEY**: Optional auth path for **LLM=vertex** (Vertex Express). +- **VERTEX_PROJECT** / **VERTEX_LOCATION**: Optional auth path for **LLM=vertex** when using GCP project credentials (do not combine with `VERTEX_API_KEY`). +- **VERTEX_BASE_URL**: Optional Vertex gateway/base URL override. +- **AZURE_OPENAI_MODEL**: Required if **LLM** is **azure** (deployment/model name). +- **AZURE_OPENAI_API_KEY**: Required if **LLM** is **azure**. +- **AZURE_OPENAI_API_VERSION**: Required if **LLM** is **azure** (for example `2024-10-21`). +- **AZURE_OPENAI_ENDPOINT** / **AZURE_OPENAI_BASE_URL**: At least one is required if **LLM** is **azure**. +- **AZURE_OPENAI_DEPLOYMENT**: Optional deployment override for **LLM** is **azure**. - **ANTHROPIC_API_KEY**: Required if **LLM** is **anthropic**. - **ANTHROPIC_MODEL**: Required if **LLM** is **anthropic** (default: `claude-3-5-sonnet-20241022`). - **CODEX_MODEL**: Required if **LLM** is **codex** (Codex OAuth flow; compose maps host port **1455** for the callback). @@ -321,6 +330,12 @@ Same variables as compose; use `-e` instead of `.env` when running `docker run` - Using Google
docker run -it --name presenton -p 5000:80 -e LLM="google" -e GOOGLE_API_KEY="******" -e IMAGE_PROVIDER="gemini_flash" -e CAN_CHANGE_KEYS="false" -v "./app_data:/app_data" ghcr.io/presenton/presenton:latest
+- Using Vertex AI (API key mode)
+ docker run -it --name presenton -p 5000:80 -e LLM="vertex" -e VERTEX_API_KEY="******" -e VERTEX_MODEL="gemini-2.5-flash" -e IMAGE_PROVIDER="gemini_flash" -e CAN_CHANGE_KEYS="false" -v "./app_data:/app_data" ghcr.io/presenton/presenton:latest
+
+- Using Azure OpenAI
+ docker run -it --name presenton -p 5000:80 -e LLM="azure" -e AZURE_OPENAI_API_KEY="******" -e AZURE_OPENAI_MODEL="gpt-4.1" -e AZURE_OPENAI_API_VERSION="2024-10-21" -e AZURE_OPENAI_ENDPOINT="https://YOUR-RESOURCE.openai.azure.com" -e IMAGE_PROVIDER="pexels" -e PEXELS_API_KEY="******" -e CAN_CHANGE_KEYS="false" -v "./app_data:/app_data" ghcr.io/presenton/presenton:latest
+
- Using Ollama
docker run -it --name presenton -p 5000:80 -e LLM="ollama" -e OLLAMA_MODEL="llama3.2:3b" -e IMAGE_PROVIDER="pexels" -e PEXELS_API_KEY="*******" -e CAN_CHANGE_KEYS="false" -v "./app_data:/app_data" ghcr.io/presenton/presenton:latest
diff --git a/docker-compose.yml b/docker-compose.yml
index 386cdde7..768278a6 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -19,6 +19,17 @@ services:
- OPENAI_MODEL=${OPENAI_MODEL}
- GOOGLE_API_KEY=${GOOGLE_API_KEY}
- GOOGLE_MODEL=${GOOGLE_MODEL}
+ - VERTEX_API_KEY=${VERTEX_API_KEY}
+ - VERTEX_MODEL=${VERTEX_MODEL}
+ - VERTEX_PROJECT=${VERTEX_PROJECT}
+ - VERTEX_LOCATION=${VERTEX_LOCATION}
+ - VERTEX_BASE_URL=${VERTEX_BASE_URL}
+ - AZURE_OPENAI_API_KEY=${AZURE_OPENAI_API_KEY}
+ - AZURE_OPENAI_MODEL=${AZURE_OPENAI_MODEL}
+ - AZURE_OPENAI_ENDPOINT=${AZURE_OPENAI_ENDPOINT}
+ - AZURE_OPENAI_BASE_URL=${AZURE_OPENAI_BASE_URL}
+ - AZURE_OPENAI_API_VERSION=${AZURE_OPENAI_API_VERSION}
+ - AZURE_OPENAI_DEPLOYMENT=${AZURE_OPENAI_DEPLOYMENT}
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
- ANTHROPIC_MODEL=${ANTHROPIC_MODEL}
- OLLAMA_URL=${OLLAMA_URL}
@@ -82,6 +93,17 @@ services:
- OPENAI_MODEL=${OPENAI_MODEL}
- GOOGLE_API_KEY=${GOOGLE_API_KEY}
- GOOGLE_MODEL=${GOOGLE_MODEL}
+ - VERTEX_API_KEY=${VERTEX_API_KEY}
+ - VERTEX_MODEL=${VERTEX_MODEL}
+ - VERTEX_PROJECT=${VERTEX_PROJECT}
+ - VERTEX_LOCATION=${VERTEX_LOCATION}
+ - VERTEX_BASE_URL=${VERTEX_BASE_URL}
+ - AZURE_OPENAI_API_KEY=${AZURE_OPENAI_API_KEY}
+ - AZURE_OPENAI_MODEL=${AZURE_OPENAI_MODEL}
+ - AZURE_OPENAI_ENDPOINT=${AZURE_OPENAI_ENDPOINT}
+ - AZURE_OPENAI_BASE_URL=${AZURE_OPENAI_BASE_URL}
+ - AZURE_OPENAI_API_VERSION=${AZURE_OPENAI_API_VERSION}
+ - AZURE_OPENAI_DEPLOYMENT=${AZURE_OPENAI_DEPLOYMENT}
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
- ANTHROPIC_MODEL=${ANTHROPIC_MODEL}
- OLLAMA_URL=${OLLAMA_URL}
@@ -141,6 +163,17 @@ services:
- OPENAI_MODEL=${OPENAI_MODEL}
- GOOGLE_API_KEY=${GOOGLE_API_KEY}
- GOOGLE_MODEL=${GOOGLE_MODEL}
+ - VERTEX_API_KEY=${VERTEX_API_KEY}
+ - VERTEX_MODEL=${VERTEX_MODEL}
+ - VERTEX_PROJECT=${VERTEX_PROJECT}
+ - VERTEX_LOCATION=${VERTEX_LOCATION}
+ - VERTEX_BASE_URL=${VERTEX_BASE_URL}
+ - AZURE_OPENAI_API_KEY=${AZURE_OPENAI_API_KEY}
+ - AZURE_OPENAI_MODEL=${AZURE_OPENAI_MODEL}
+ - AZURE_OPENAI_ENDPOINT=${AZURE_OPENAI_ENDPOINT}
+ - AZURE_OPENAI_BASE_URL=${AZURE_OPENAI_BASE_URL}
+ - AZURE_OPENAI_API_VERSION=${AZURE_OPENAI_API_VERSION}
+ - AZURE_OPENAI_DEPLOYMENT=${AZURE_OPENAI_DEPLOYMENT}
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
- ANTHROPIC_MODEL=${ANTHROPIC_MODEL}
- OLLAMA_URL=${OLLAMA_URL}
@@ -205,6 +238,17 @@ services:
- OPENAI_MODEL=${OPENAI_MODEL}
- GOOGLE_API_KEY=${GOOGLE_API_KEY}
- GOOGLE_MODEL=${GOOGLE_MODEL}
+ - VERTEX_API_KEY=${VERTEX_API_KEY}
+ - VERTEX_MODEL=${VERTEX_MODEL}
+ - VERTEX_PROJECT=${VERTEX_PROJECT}
+ - VERTEX_LOCATION=${VERTEX_LOCATION}
+ - VERTEX_BASE_URL=${VERTEX_BASE_URL}
+ - AZURE_OPENAI_API_KEY=${AZURE_OPENAI_API_KEY}
+ - AZURE_OPENAI_MODEL=${AZURE_OPENAI_MODEL}
+ - AZURE_OPENAI_ENDPOINT=${AZURE_OPENAI_ENDPOINT}
+ - AZURE_OPENAI_BASE_URL=${AZURE_OPENAI_BASE_URL}
+ - AZURE_OPENAI_API_VERSION=${AZURE_OPENAI_API_VERSION}
+ - AZURE_OPENAI_DEPLOYMENT=${AZURE_OPENAI_DEPLOYMENT}
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
- ANTHROPIC_MODEL=${ANTHROPIC_MODEL}
- OLLAMA_URL=${OLLAMA_URL}
diff --git a/servers/fastapi/constants/llm.py b/servers/fastapi/constants/llm.py
index 1172de4f..cf96920a 100644
--- a/servers/fastapi/constants/llm.py
+++ b/servers/fastapi/constants/llm.py
@@ -3,5 +3,7 @@ OPENAI_URL = "https://api.openai.com/v1"
# Default models
DEFAULT_OPENAI_MODEL = "gpt-4.1"
DEFAULT_GOOGLE_MODEL = "models/gemini-2.5-flash"
+DEFAULT_VERTEX_MODEL = "gemini-2.5-flash"
+DEFAULT_AZURE_MODEL = "gpt-4.1"
DEFAULT_ANTHROPIC_MODEL = "claude-sonnet-4-20250514"
DEFAULT_CODEX_MODEL = "gpt-5.2"
diff --git a/servers/fastapi/enums/llm_provider.py b/servers/fastapi/enums/llm_provider.py
index 3bf23f09..c5a98b80 100644
--- a/servers/fastapi/enums/llm_provider.py
+++ b/servers/fastapi/enums/llm_provider.py
@@ -5,6 +5,8 @@ class LLMProvider(Enum):
OLLAMA = "ollama"
OPENAI = "openai"
GOOGLE = "google"
+ VERTEX = "vertex"
+ AZURE = "azure"
ANTHROPIC = "anthropic"
CUSTOM = "custom"
CODEX = "codex"
diff --git a/servers/fastapi/models/user_config.py b/servers/fastapi/models/user_config.py
index db41401b..c40c1d85 100644
--- a/servers/fastapi/models/user_config.py
+++ b/servers/fastapi/models/user_config.py
@@ -13,6 +13,21 @@ class UserConfig(BaseModel):
GOOGLE_API_KEY: Optional[str] = None
GOOGLE_MODEL: Optional[str] = None
+ # Vertex AI
+ VERTEX_API_KEY: Optional[str] = None
+ VERTEX_MODEL: Optional[str] = None
+ VERTEX_PROJECT: Optional[str] = None
+ VERTEX_LOCATION: Optional[str] = None
+ VERTEX_BASE_URL: Optional[str] = None
+
+ # Azure OpenAI
+ AZURE_OPENAI_API_KEY: Optional[str] = None
+ AZURE_OPENAI_MODEL: Optional[str] = None
+ AZURE_OPENAI_ENDPOINT: Optional[str] = None
+ AZURE_OPENAI_BASE_URL: Optional[str] = None
+ AZURE_OPENAI_API_VERSION: Optional[str] = None
+ AZURE_OPENAI_DEPLOYMENT: Optional[str] = None
+
# Anthropic
ANTHROPIC_API_KEY: Optional[str] = None
ANTHROPIC_MODEL: Optional[str] = None
diff --git a/servers/fastapi/utils/get_env.py b/servers/fastapi/utils/get_env.py
index ea111630..cfabbc41 100644
--- a/servers/fastapi/utils/get_env.py
+++ b/servers/fastapi/utils/get_env.py
@@ -57,6 +57,50 @@ def get_google_model_env():
return os.getenv("GOOGLE_MODEL")
+def get_vertex_api_key_env():
+ return os.getenv("VERTEX_API_KEY")
+
+
+def get_vertex_model_env():
+ return os.getenv("VERTEX_MODEL")
+
+
+def get_vertex_project_env():
+ return os.getenv("VERTEX_PROJECT")
+
+
+def get_vertex_location_env():
+ return os.getenv("VERTEX_LOCATION")
+
+
+def get_vertex_base_url_env():
+ return os.getenv("VERTEX_BASE_URL")
+
+
+def get_azure_openai_api_key_env():
+ return os.getenv("AZURE_OPENAI_API_KEY")
+
+
+def get_azure_openai_model_env():
+ return os.getenv("AZURE_OPENAI_MODEL")
+
+
+def get_azure_openai_endpoint_env():
+ return os.getenv("AZURE_OPENAI_ENDPOINT")
+
+
+def get_azure_openai_base_url_env():
+ return os.getenv("AZURE_OPENAI_BASE_URL")
+
+
+def get_azure_openai_api_version_env():
+ return os.getenv("AZURE_OPENAI_API_VERSION")
+
+
+def get_azure_openai_deployment_env():
+ return os.getenv("AZURE_OPENAI_DEPLOYMENT")
+
+
def get_custom_llm_api_key_env():
return os.getenv("CUSTOM_LLM_API_KEY")
diff --git a/servers/fastapi/utils/llm_config.py b/servers/fastapi/utils/llm_config.py
index f5340bef..959272f7 100644
--- a/servers/fastapi/utils/llm_config.py
+++ b/servers/fastapi/utils/llm_config.py
@@ -4,15 +4,22 @@ from typing import Optional
from fastapi import HTTPException
from llmai.shared import (
AnthropicClientConfig,
+ AzureOpenAIClientConfig,
ChatGPTClientConfig,
ClientConfig,
GoogleClientConfig,
OpenAIApiType,
OpenAIClientConfig,
+ VertexAIClientConfig,
)
from enums.llm_provider import LLMProvider
from utils.get_env import (
+ get_azure_openai_api_key_env,
+ get_azure_openai_api_version_env,
+ get_azure_openai_base_url_env,
+ get_azure_openai_deployment_env,
+ get_azure_openai_endpoint_env,
get_anthropic_api_key_env,
get_codex_access_token_env,
get_codex_account_id_env,
@@ -24,6 +31,10 @@ from utils.get_env import (
get_google_api_key_env,
get_ollama_url_env,
get_openai_api_key_env,
+ get_vertex_api_key_env,
+ get_vertex_base_url_env,
+ get_vertex_location_env,
+ get_vertex_project_env,
get_web_grounding_env,
)
from utils.llm_provider import get_llm_provider
@@ -101,6 +112,74 @@ def get_llm_config() -> ClientConfig:
if not api_key:
raise HTTPException(status_code=400, detail="Google API Key is not set")
return GoogleClientConfig(api_key=api_key)
+ case LLMProvider.VERTEX:
+ api_key = get_vertex_api_key_env()
+ project = get_vertex_project_env()
+ location = get_vertex_location_env()
+ base_url = get_vertex_base_url_env()
+
+ if api_key and (project or location):
+ raise HTTPException(
+ status_code=400,
+ detail=(
+ "Vertex configuration is ambiguous. Configure either "
+ "VERTEX_API_KEY or VERTEX_PROJECT/VERTEX_LOCATION, not both."
+ ),
+ )
+
+ if api_key:
+ return VertexAIClientConfig(
+ api_key=api_key,
+ base_url=base_url or None,
+ )
+
+ if not project:
+ raise HTTPException(
+ status_code=400,
+ detail=(
+ "Vertex configuration is incomplete. Set VERTEX_API_KEY "
+ "or VERTEX_PROJECT (optionally with VERTEX_LOCATION)."
+ ),
+ )
+
+ return VertexAIClientConfig(
+ project=project,
+ location=location or None,
+ base_url=base_url or None,
+ )
+ case LLMProvider.AZURE:
+ api_key = get_azure_openai_api_key_env()
+ api_version = get_azure_openai_api_version_env()
+ endpoint = get_azure_openai_endpoint_env()
+ base_url = get_azure_openai_base_url_env()
+ deployment = get_azure_openai_deployment_env()
+
+ if not api_key:
+ raise HTTPException(
+ status_code=400,
+ detail="Azure OpenAI API Key is not set",
+ )
+ if not api_version:
+ raise HTTPException(
+ status_code=400,
+ detail="Azure OpenAI API Version is not set",
+ )
+ if not endpoint and not base_url:
+ raise HTTPException(
+ status_code=400,
+ detail=(
+ "Azure OpenAI endpoint is not set. "
+ "Configure AZURE_OPENAI_ENDPOINT or AZURE_OPENAI_BASE_URL."
+ ),
+ )
+
+ return AzureOpenAIClientConfig(
+ api_key=api_key,
+ api_version=api_version,
+ endpoint=endpoint or None,
+ base_url=base_url or None,
+ deployment=deployment or None,
+ )
case LLMProvider.ANTHROPIC:
api_key = get_anthropic_api_key_env()
if not api_key:
@@ -134,8 +213,8 @@ def get_llm_config() -> ClientConfig:
raise HTTPException(
status_code=400,
detail=(
- "LLM Provider must be either openai, google, anthropic, "
- "ollama, custom, or codex"
+ "LLM Provider must be either openai, google, vertex, azure, "
+ "anthropic, ollama, custom, or codex"
),
)
diff --git a/servers/fastapi/utils/llm_provider.py b/servers/fastapi/utils/llm_provider.py
index f355d9cc..56e120fd 100644
--- a/servers/fastapi/utils/llm_provider.py
+++ b/servers/fastapi/utils/llm_provider.py
@@ -4,12 +4,15 @@ from openai import OpenAI
from constants.llm import (
DEFAULT_ANTHROPIC_MODEL,
+ DEFAULT_AZURE_MODEL,
DEFAULT_CODEX_MODEL,
DEFAULT_GOOGLE_MODEL,
DEFAULT_OPENAI_MODEL,
+ DEFAULT_VERTEX_MODEL,
)
from enums.llm_provider import LLMProvider
from utils.get_env import (
+ get_azure_openai_model_env,
get_anthropic_model_env,
get_codex_model_env,
get_custom_model_env,
@@ -19,6 +22,7 @@ from utils.get_env import (
get_ollama_model_env,
get_openai_api_key_env,
get_openai_model_env,
+ get_vertex_model_env,
)
@@ -28,7 +32,10 @@ def get_llm_provider():
except:
raise HTTPException(
status_code=500,
- detail=f"Invalid LLM provider. Please select one of: openai, google, anthropic, ollama, custom, codex",
+ detail=(
+ "Invalid LLM provider. Please select one of: "
+ "openai, google, vertex, azure, anthropic, ollama, custom, codex"
+ ),
)
@@ -44,6 +51,14 @@ def is_anthropic_selected():
return get_llm_provider() == LLMProvider.ANTHROPIC
+def is_vertex_selected():
+ return get_llm_provider() == LLMProvider.VERTEX
+
+
+def is_azure_selected():
+ return get_llm_provider() == LLMProvider.AZURE
+
+
def is_ollama_selected():
return get_llm_provider() == LLMProvider.OLLAMA
@@ -62,6 +77,10 @@ def get_model():
return get_openai_model_env() or DEFAULT_OPENAI_MODEL
elif selected_llm == LLMProvider.GOOGLE:
return get_google_model_env() or DEFAULT_GOOGLE_MODEL
+ elif selected_llm == LLMProvider.VERTEX:
+ return get_vertex_model_env() or DEFAULT_VERTEX_MODEL
+ elif selected_llm == LLMProvider.AZURE:
+ return get_azure_openai_model_env() or DEFAULT_AZURE_MODEL
elif selected_llm == LLMProvider.ANTHROPIC:
return get_anthropic_model_env() or DEFAULT_ANTHROPIC_MODEL
elif selected_llm == LLMProvider.OLLAMA:
@@ -73,7 +92,10 @@ def get_model():
else:
raise HTTPException(
status_code=500,
- detail=f"Invalid LLM provider. Please select one of: openai, google, anthropic, ollama, custom, codex",
+ detail=(
+ "Invalid LLM provider. Please select one of: "
+ "openai, google, vertex, azure, anthropic, ollama, custom, codex"
+ ),
)
diff --git a/servers/fastapi/utils/llm_utils.py b/servers/fastapi/utils/llm_utils.py
index 027decc9..7de18ef5 100644
--- a/servers/fastapi/utils/llm_utils.py
+++ b/servers/fastapi/utils/llm_utils.py
@@ -64,7 +64,7 @@ def get_generate_kwargs(
if max_tokens is not None:
kwargs["max_tokens"] = max_tokens
if tools:
- if get_llm_provider() == LLMProvider.GOOGLE:
+ if get_llm_provider() in (LLMProvider.GOOGLE, LLMProvider.VERTEX):
kwargs["tools"] = _tools_for_google_gemini(tools)
else:
kwargs["tools"] = tools
diff --git a/servers/fastapi/utils/model_availability.py b/servers/fastapi/utils/model_availability.py
index 1c40070d..e17e0bf9 100644
--- a/servers/fastapi/utils/model_availability.py
+++ b/servers/fastapi/utils/model_availability.py
@@ -8,6 +8,10 @@ from utils.available_models import (
list_available_openai_compatible_models,
)
from utils.get_env import (
+ get_azure_openai_api_key_env,
+ get_azure_openai_api_version_env,
+ get_azure_openai_base_url_env,
+ get_azure_openai_endpoint_env,
get_anthropic_api_key_env,
get_anthropic_model_env,
get_can_change_keys_env,
@@ -16,6 +20,9 @@ from utils.get_env import (
get_openai_model_env,
get_pixabay_api_key_env,
get_pexels_api_key_env,
+ get_vertex_api_key_env,
+ get_vertex_location_env,
+ get_vertex_project_env,
get_comfyui_url_env,
get_comfyui_workflow_env,
)
@@ -65,6 +72,34 @@ async def check_llm_and_image_provider_api_or_model_availability():
print("Available models: ", available_models)
raise Exception(f"Model {google_model} is not available")
+ elif get_llm_provider() == LLMProvider.VERTEX:
+ vertex_api_key = get_vertex_api_key_env()
+ vertex_project = get_vertex_project_env()
+ vertex_location = get_vertex_location_env()
+ if not vertex_api_key and not vertex_project:
+ raise Exception(
+ "Configure VERTEX_API_KEY or VERTEX_PROJECT for Vertex AI"
+ )
+ if vertex_api_key and (vertex_project or vertex_location):
+ raise Exception(
+ "Vertex config is ambiguous. Use either VERTEX_API_KEY or "
+ "VERTEX_PROJECT/VERTEX_LOCATION, not both."
+ )
+
+ elif get_llm_provider() == LLMProvider.AZURE:
+ azure_api_key = get_azure_openai_api_key_env()
+ azure_endpoint = get_azure_openai_endpoint_env()
+ azure_base_url = get_azure_openai_base_url_env()
+ azure_api_version = get_azure_openai_api_version_env()
+ if not azure_api_key:
+ raise Exception("AZURE_OPENAI_API_KEY must be provided")
+ if not azure_api_version:
+ raise Exception("AZURE_OPENAI_API_VERSION must be provided")
+ if not azure_endpoint and not azure_base_url:
+ raise Exception(
+ "AZURE_OPENAI_ENDPOINT or AZURE_OPENAI_BASE_URL must be provided"
+ )
+
elif get_llm_provider() == LLMProvider.ANTHROPIC:
anthropic_api_key = get_anthropic_api_key_env()
if not anthropic_api_key:
diff --git a/servers/fastapi/utils/set_env.py b/servers/fastapi/utils/set_env.py
index 18456d8e..93ca0e1e 100644
--- a/servers/fastapi/utils/set_env.py
+++ b/servers/fastapi/utils/set_env.py
@@ -37,6 +37,50 @@ def set_google_model_env(value):
os.environ["GOOGLE_MODEL"] = value
+def set_vertex_api_key_env(value):
+ os.environ["VERTEX_API_KEY"] = value
+
+
+def set_vertex_model_env(value):
+ os.environ["VERTEX_MODEL"] = value
+
+
+def set_vertex_project_env(value):
+ os.environ["VERTEX_PROJECT"] = value
+
+
+def set_vertex_location_env(value):
+ os.environ["VERTEX_LOCATION"] = value
+
+
+def set_vertex_base_url_env(value):
+ os.environ["VERTEX_BASE_URL"] = value
+
+
+def set_azure_openai_api_key_env(value):
+ os.environ["AZURE_OPENAI_API_KEY"] = value
+
+
+def set_azure_openai_model_env(value):
+ os.environ["AZURE_OPENAI_MODEL"] = value
+
+
+def set_azure_openai_endpoint_env(value):
+ os.environ["AZURE_OPENAI_ENDPOINT"] = value
+
+
+def set_azure_openai_base_url_env(value):
+ os.environ["AZURE_OPENAI_BASE_URL"] = value
+
+
+def set_azure_openai_api_version_env(value):
+ os.environ["AZURE_OPENAI_API_VERSION"] = value
+
+
+def set_azure_openai_deployment_env(value):
+ os.environ["AZURE_OPENAI_DEPLOYMENT"] = value
+
+
def set_anthropic_api_key_env(value):
os.environ["ANTHROPIC_API_KEY"] = value
diff --git a/servers/fastapi/utils/user_config.py b/servers/fastapi/utils/user_config.py
index bc499075..876a7362 100644
--- a/servers/fastapi/utils/user_config.py
+++ b/servers/fastapi/utils/user_config.py
@@ -15,6 +15,17 @@ from utils.get_env import (
get_disable_thinking_env,
get_google_api_key_env,
get_google_model_env,
+ get_vertex_api_key_env,
+ get_vertex_model_env,
+ get_vertex_project_env,
+ get_vertex_location_env,
+ get_vertex_base_url_env,
+ get_azure_openai_api_key_env,
+ get_azure_openai_model_env,
+ get_azure_openai_endpoint_env,
+ get_azure_openai_base_url_env,
+ get_azure_openai_api_version_env,
+ get_azure_openai_deployment_env,
get_gpt_image_1_5_quality_env,
get_llm_provider_env,
get_ollama_model_env,
@@ -53,6 +64,17 @@ from utils.set_env import (
set_extended_reasoning_env,
set_google_api_key_env,
set_google_model_env,
+ set_vertex_api_key_env,
+ set_vertex_model_env,
+ set_vertex_project_env,
+ set_vertex_location_env,
+ set_vertex_base_url_env,
+ set_azure_openai_api_key_env,
+ set_azure_openai_model_env,
+ set_azure_openai_endpoint_env,
+ set_azure_openai_base_url_env,
+ set_azure_openai_api_version_env,
+ set_azure_openai_deployment_env,
set_gpt_image_1_5_quality_env,
set_llm_provider_env,
set_ollama_model_env,
@@ -94,6 +116,23 @@ def get_user_config():
OPENAI_MODEL=existing_config.OPENAI_MODEL or get_openai_model_env(),
GOOGLE_API_KEY=existing_config.GOOGLE_API_KEY or get_google_api_key_env(),
GOOGLE_MODEL=existing_config.GOOGLE_MODEL or get_google_model_env(),
+ VERTEX_API_KEY=existing_config.VERTEX_API_KEY or get_vertex_api_key_env(),
+ VERTEX_MODEL=existing_config.VERTEX_MODEL or get_vertex_model_env(),
+ VERTEX_PROJECT=existing_config.VERTEX_PROJECT or get_vertex_project_env(),
+ VERTEX_LOCATION=existing_config.VERTEX_LOCATION or get_vertex_location_env(),
+ VERTEX_BASE_URL=existing_config.VERTEX_BASE_URL or get_vertex_base_url_env(),
+ AZURE_OPENAI_API_KEY=existing_config.AZURE_OPENAI_API_KEY
+ or get_azure_openai_api_key_env(),
+ AZURE_OPENAI_MODEL=existing_config.AZURE_OPENAI_MODEL
+ or get_azure_openai_model_env(),
+ AZURE_OPENAI_ENDPOINT=existing_config.AZURE_OPENAI_ENDPOINT
+ or get_azure_openai_endpoint_env(),
+ AZURE_OPENAI_BASE_URL=existing_config.AZURE_OPENAI_BASE_URL
+ or get_azure_openai_base_url_env(),
+ AZURE_OPENAI_API_VERSION=existing_config.AZURE_OPENAI_API_VERSION
+ or get_azure_openai_api_version_env(),
+ AZURE_OPENAI_DEPLOYMENT=existing_config.AZURE_OPENAI_DEPLOYMENT
+ or get_azure_openai_deployment_env(),
ANTHROPIC_API_KEY=existing_config.ANTHROPIC_API_KEY
or get_anthropic_api_key_env(),
ANTHROPIC_MODEL=existing_config.ANTHROPIC_MODEL or get_anthropic_model_env(),
@@ -160,6 +199,28 @@ def update_env_with_user_config():
set_google_api_key_env(user_config.GOOGLE_API_KEY)
if user_config.GOOGLE_MODEL:
set_google_model_env(user_config.GOOGLE_MODEL)
+ if user_config.VERTEX_API_KEY:
+ set_vertex_api_key_env(user_config.VERTEX_API_KEY)
+ if user_config.VERTEX_MODEL:
+ set_vertex_model_env(user_config.VERTEX_MODEL)
+ if user_config.VERTEX_PROJECT:
+ set_vertex_project_env(user_config.VERTEX_PROJECT)
+ if user_config.VERTEX_LOCATION:
+ set_vertex_location_env(user_config.VERTEX_LOCATION)
+ if user_config.VERTEX_BASE_URL:
+ set_vertex_base_url_env(user_config.VERTEX_BASE_URL)
+ if user_config.AZURE_OPENAI_API_KEY:
+ set_azure_openai_api_key_env(user_config.AZURE_OPENAI_API_KEY)
+ if user_config.AZURE_OPENAI_MODEL:
+ set_azure_openai_model_env(user_config.AZURE_OPENAI_MODEL)
+ if user_config.AZURE_OPENAI_ENDPOINT:
+ set_azure_openai_endpoint_env(user_config.AZURE_OPENAI_ENDPOINT)
+ if user_config.AZURE_OPENAI_BASE_URL:
+ set_azure_openai_base_url_env(user_config.AZURE_OPENAI_BASE_URL)
+ if user_config.AZURE_OPENAI_API_VERSION:
+ set_azure_openai_api_version_env(user_config.AZURE_OPENAI_API_VERSION)
+ if user_config.AZURE_OPENAI_DEPLOYMENT:
+ set_azure_openai_deployment_env(user_config.AZURE_OPENAI_DEPLOYMENT)
if user_config.ANTHROPIC_API_KEY:
set_anthropic_api_key_env(user_config.ANTHROPIC_API_KEY)
if user_config.ANTHROPIC_MODEL:
diff --git a/servers/nextjs/app/(presentation-generator)/(dashboard)/settings/SettingPage.tsx b/servers/nextjs/app/(presentation-generator)/(dashboard)/settings/SettingPage.tsx
index 1c027d7a..e25dda74 100644
--- a/servers/nextjs/app/(presentation-generator)/(dashboard)/settings/SettingPage.tsx
+++ b/servers/nextjs/app/(presentation-generator)/(dashboard)/settings/SettingPage.tsx
@@ -289,6 +289,10 @@ const SettingsPage = () => {
? llmConfig.OPENAI_MODEL
: textProviderKey === "google"
? llmConfig.GOOGLE_MODEL
+ : textProviderKey === "vertex"
+ ? llmConfig.VERTEX_MODEL
+ : textProviderKey === "azure"
+ ? llmConfig.AZURE_OPENAI_MODEL
: textProviderKey === "anthropic"
? llmConfig.ANTHROPIC_MODEL
: textProviderKey === "ollama"
@@ -312,7 +316,7 @@ const SettingsPage = () => {
useEffect(() => {
- if (llmConfig.LLM === "codex" && !llmConfig.CODEX_MODEL || llmConfig.LLM === "openai" && !llmConfig.OPENAI_MODEL || llmConfig.LLM === "google" && !llmConfig.GOOGLE_MODEL || llmConfig.LLM === "anthropic" && !llmConfig.ANTHROPIC_MODEL || llmConfig.LLM === "ollama" && !llmConfig.OLLAMA_MODEL || llmConfig.LLM === "custom" && !llmConfig.CUSTOM_MODEL) {
+ if (llmConfig.LLM === "codex" && !llmConfig.CODEX_MODEL || llmConfig.LLM === "openai" && !llmConfig.OPENAI_MODEL || llmConfig.LLM === "google" && !llmConfig.GOOGLE_MODEL || llmConfig.LLM === "vertex" && !llmConfig.VERTEX_MODEL || llmConfig.LLM === "azure" && !llmConfig.AZURE_OPENAI_MODEL || llmConfig.LLM === "anthropic" && !llmConfig.ANTHROPIC_MODEL || llmConfig.LLM === "ollama" && !llmConfig.OLLAMA_MODEL || llmConfig.LLM === "custom" && !llmConfig.CUSTOM_MODEL) {
notify.error("Cannot save settings", "Please select a model for the selected provider");
const currentUrl = window.location.href;
diff --git a/servers/nextjs/app/(presentation-generator)/(dashboard)/settings/TextProvider.tsx b/servers/nextjs/app/(presentation-generator)/(dashboard)/settings/TextProvider.tsx
index 09e93533..59d82932 100644
--- a/servers/nextjs/app/(presentation-generator)/(dashboard)/settings/TextProvider.tsx
+++ b/servers/nextjs/app/(presentation-generator)/(dashboard)/settings/TextProvider.tsx
@@ -23,6 +23,8 @@ interface ModelOption {
size?: string;
}
+const MANUAL_MODEL_PROVIDERS = new Set(['vertex', 'azure']);
+
const TextProvider = ({
onInputChange,
@@ -40,12 +42,17 @@ const TextProvider = ({
const selectedProvider = (llmConfig.LLM || 'openai') as keyof typeof LLM_PROVIDERS;
const selectedProviderMeta = LLM_PROVIDERS[selectedProvider];
+ const isManualModelProvider = MANUAL_MODEL_PROVIDERS.has(selectedProvider);
const currentModelField = useMemo(() => {
switch (selectedProvider) {
case 'openai':
return 'OPENAI_MODEL';
case 'google':
return 'GOOGLE_MODEL';
+ case 'vertex':
+ return 'VERTEX_MODEL';
+ case 'azure':
+ return 'AZURE_OPENAI_MODEL';
case 'anthropic':
return 'ANTHROPIC_MODEL';
case 'ollama':
@@ -65,6 +72,10 @@ const TextProvider = ({
return 'OPENAI_API_KEY';
case 'google':
return 'GOOGLE_API_KEY';
+ case 'vertex':
+ return 'VERTEX_API_KEY';
+ case 'azure':
+ return 'AZURE_OPENAI_API_KEY';
case 'anthropic':
return 'ANTHROPIC_API_KEY';
case 'custom':
@@ -80,6 +91,14 @@ const TextProvider = ({
const currentOllamaUrl = llmConfig.OLLAMA_URL || '';
const useCustomOllamaUrl = !!llmConfig.USE_CUSTOM_URL;
const modelLabel = selectedProviderMeta?.label || selectedProvider;
+ const providerApiKeyLabel =
+ selectedProvider === 'custom'
+ ? 'Custom LLM API Key'
+ : selectedProvider === 'vertex'
+ ? 'Vertex API Key'
+ : selectedProvider === 'azure'
+ ? 'Azure OpenAI API Key'
+ : `${selectedProvider} API Key`;
useEffect(() => {
if (isFirstRender.current) {
@@ -107,6 +126,10 @@ const TextProvider = ({
? 'OPENAI_API_KEY'
: llm === 'google'
? 'GOOGLE_API_KEY'
+ : llm === 'vertex'
+ ? 'VERTEX_API_KEY'
+ : llm === 'azure'
+ ? 'AZURE_OPENAI_API_KEY'
: llm === 'anthropic'
? 'ANTHROPIC_API_KEY'
: llm === 'custom'
@@ -118,6 +141,7 @@ const TextProvider = ({
};
const fetchAvailableModels = async () => {
+ if (isManualModelProvider) return;
if (selectedProvider === 'openai' && !currentApiKey) return;
if (selectedProvider === 'google' && !currentApiKey) return;
if (selectedProvider === 'anthropic' && !currentApiKey) return;
@@ -405,7 +429,7 @@ const TextProvider = ({
: (
<>