Merge pull request #549 from presenton/feature/vertex-openaiazure
Some checks failed
Test All Applications / Test Main FastAPI (push) Has been cancelled
Test All Applications / Test Electron FastAPI (push) Has been cancelled
Test All Applications / Test Main Next.js (push) Has been cancelled
Test All Applications / Test Electron Next.js (push) Has been cancelled
Some checks failed
Test All Applications / Test Main FastAPI (push) Has been cancelled
Test All Applications / Test Electron FastAPI (push) Has been cancelled
Test All Applications / Test Main Next.js (push) Has been cancelled
Test All Applications / Test Electron Next.js (push) Has been cancelled
Feature/vertex openaiazure
This commit is contained in:
commit
342679ec60
22 changed files with 706 additions and 19 deletions
21
README.md
21
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
|
||||
<pre><code class="language-bash">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</code></pre>
|
||||
|
||||
- Using Vertex AI (API key mode)
|
||||
<pre><code class="language-bash">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</code></pre>
|
||||
|
||||
- Using Azure OpenAI
|
||||
<pre><code class="language-bash">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</code></pre>
|
||||
|
||||
- Using Ollama
|
||||
<pre><code class="language-bash">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</code></pre>
|
||||
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ class LLMProvider(Enum):
|
|||
OLLAMA = "ollama"
|
||||
OPENAI = "openai"
|
||||
GOOGLE = "google"
|
||||
VERTEX = "vertex"
|
||||
AZURE = "azure"
|
||||
ANTHROPIC = "anthropic"
|
||||
CUSTOM = "custom"
|
||||
CODEX = "codex"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
),
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 = ({
|
|||
: (
|
||||
<>
|
||||
<label className="block text-sm font-medium capitalize text-gray-700 mb-2">
|
||||
{selectedProvider === 'custom' ? 'Custom LLM API Key' : `${llmConfig.LLM} API Key`}
|
||||
{providerApiKeyLabel}
|
||||
</label>
|
||||
<div className="relative">
|
||||
<input
|
||||
|
|
@ -413,7 +437,7 @@ const TextProvider = ({
|
|||
value={currentApiKey}
|
||||
onChange={(e) => onApiKeyChange(selectedProvider, e.target.value)}
|
||||
className="w-full px-2 py-3 outline-none border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition-colors"
|
||||
placeholder={`Enter your ${llmConfig.LLM} API key`}
|
||||
placeholder={`Enter your ${providerApiKeyLabel}`}
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
|
|
@ -434,10 +458,67 @@ const TextProvider = ({
|
|||
placeholder="OpenAI-compatible URL"
|
||||
/>
|
||||
)}
|
||||
{selectedProvider === 'vertex' && (
|
||||
<div className="mt-2 space-y-2">
|
||||
<input
|
||||
type="text"
|
||||
value={llmConfig.VERTEX_PROJECT || ''}
|
||||
onChange={(e) => onInputChange(e.target.value, 'VERTEX_PROJECT')}
|
||||
className="w-full px-2 py-3 outline-none border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition-colors"
|
||||
placeholder="GCP project (optional if API key used)"
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
value={llmConfig.VERTEX_LOCATION || ''}
|
||||
onChange={(e) => onInputChange(e.target.value, 'VERTEX_LOCATION')}
|
||||
className="w-full px-2 py-3 outline-none border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition-colors"
|
||||
placeholder="GCP location (optional)"
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
value={llmConfig.VERTEX_BASE_URL || ''}
|
||||
onChange={(e) => onInputChange(e.target.value, 'VERTEX_BASE_URL')}
|
||||
className="w-full px-2 py-3 outline-none border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition-colors"
|
||||
placeholder="Vertex base URL (optional)"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{selectedProvider === 'azure' && (
|
||||
<div className="mt-2 space-y-2">
|
||||
<input
|
||||
type="text"
|
||||
value={llmConfig.AZURE_OPENAI_ENDPOINT || ''}
|
||||
onChange={(e) => onInputChange(e.target.value, 'AZURE_OPENAI_ENDPOINT')}
|
||||
className="w-full px-2 py-3 outline-none border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition-colors"
|
||||
placeholder="Azure endpoint (https://...openai.azure.com)"
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
value={llmConfig.AZURE_OPENAI_BASE_URL || ''}
|
||||
onChange={(e) => onInputChange(e.target.value, 'AZURE_OPENAI_BASE_URL')}
|
||||
className="w-full px-2 py-3 outline-none border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition-colors"
|
||||
placeholder="Azure base URL (optional alternative)"
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
value={llmConfig.AZURE_OPENAI_API_VERSION || ''}
|
||||
onChange={(e) => onInputChange(e.target.value, 'AZURE_OPENAI_API_VERSION')}
|
||||
className="w-full px-2 py-3 outline-none border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition-colors"
|
||||
placeholder="API version (e.g. 2024-10-21)"
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
value={llmConfig.AZURE_OPENAI_DEPLOYMENT || ''}
|
||||
onChange={(e) => onInputChange(e.target.value, 'AZURE_OPENAI_DEPLOYMENT')}
|
||||
className="w-full px-2 py-3 outline-none border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition-colors"
|
||||
placeholder="Deployment name (optional)"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
</div>
|
||||
{selectedProvider !== 'ollama' && selectedProvider !== 'codex' && (!modelsChecked || (modelsChecked && availableModels.length === 0)) && (
|
||||
{!isManualModelProvider && selectedProvider !== 'ollama' && selectedProvider !== 'codex' && (!modelsChecked || (modelsChecked && availableModels.length === 0)) && (
|
||||
|
||||
<button
|
||||
onClick={fetchAvailableModels}
|
||||
|
|
@ -466,7 +547,7 @@ const TextProvider = ({
|
|||
</div>
|
||||
</div>
|
||||
{/* Model Selection - only show if models are available */}
|
||||
{selectedProvider !== 'codex' && modelsChecked && availableModels.length > 0 ? (
|
||||
{!isManualModelProvider && selectedProvider !== 'codex' && modelsChecked && availableModels.length > 0 ? (
|
||||
<div className="w-[222px]">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-3">
|
||||
|
|
@ -553,6 +634,28 @@ const TextProvider = ({
|
|||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
{isManualModelProvider ? (
|
||||
<div className="w-[222px]">
|
||||
<label className="block text-sm font-medium text-gray-700 mb-3">
|
||||
{`Enter ${modelLabel} Model`}
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
value={currentModel}
|
||||
onChange={(e) => {
|
||||
if (currentModelField) {
|
||||
onInputChange(e.target.value, currentModelField);
|
||||
}
|
||||
}}
|
||||
className="w-full h-12 px-4 py-3 outline-none border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition-colors"
|
||||
placeholder={
|
||||
selectedProvider === 'vertex'
|
||||
? 'e.g. gemini-2.5-flash'
|
||||
: 'e.g. gpt-4.1'
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
{/* Show message if no models found */}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,10 @@ const CurrentConfig = () => {
|
|||
? 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"
|
||||
|
|
|
|||
|
|
@ -72,6 +72,10 @@ const getSelectedTextModel = (config?: LLMConfig): string => {
|
|||
return config.OPENAI_MODEL || "";
|
||||
case "google":
|
||||
return config.GOOGLE_MODEL || "";
|
||||
case "vertex":
|
||||
return config.VERTEX_MODEL || "";
|
||||
case "azure":
|
||||
return config.AZURE_OPENAI_MODEL || "";
|
||||
case "anthropic":
|
||||
return config.ANTHROPIC_MODEL || "";
|
||||
case "ollama":
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@ import { checkIfSelectedOllamaModelIsPulled, pullOllamaModel } from '@/utils/pro
|
|||
import { getApiUrl } from '@/utils/api';
|
||||
import CodexConfig, { CHATGPT_MODELS } from '../CodexConfig';
|
||||
|
||||
const MANUAL_MODEL_PROVIDERS = new Set(["vertex", "azure"]);
|
||||
|
||||
const PresentonMode = ({ currentStep, setStep }: { currentStep: number, setStep: (step: number) => void }) => {
|
||||
const pathname = usePathname();
|
||||
const [openProviderSelect, setOpenProviderSelect] = useState(false);
|
||||
|
|
@ -42,6 +44,7 @@ const PresentonMode = ({ currentStep, setStep }: { currentStep: number, setStep:
|
|||
status: string;
|
||||
done: boolean;
|
||||
} | null>(null);
|
||||
const isManualModelProvider = MANUAL_MODEL_PROVIDERS.has(llmConfig.LLM || "");
|
||||
|
||||
const handleProviderChange = (provider: string) => {
|
||||
setLlmConfig(prev => ({
|
||||
|
|
@ -65,6 +68,10 @@ const PresentonMode = ({ currentStep, setStep }: { currentStep: number, setStep:
|
|||
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':
|
||||
|
|
@ -81,6 +88,10 @@ const PresentonMode = ({ currentStep, setStep }: { currentStep: number, setStep:
|
|||
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':
|
||||
|
|
@ -101,6 +112,14 @@ const PresentonMode = ({ currentStep, setStep }: { currentStep: number, setStep:
|
|||
const currentModel = currentModelField ? ((llmConfig as Record<string, unknown>)[currentModelField] as string || '') : '';
|
||||
const currentOllamaUrl = llmConfig.OLLAMA_URL || '';
|
||||
const useCustomOllamaUrl = !!llmConfig.USE_CUSTOM_URL;
|
||||
const providerApiKeyLabel =
|
||||
llmConfig.LLM === 'custom'
|
||||
? 'Custom LLM API Key'
|
||||
: llmConfig.LLM === 'vertex'
|
||||
? 'Vertex API Key'
|
||||
: llmConfig.LLM === 'azure'
|
||||
? 'Azure OpenAI API Key'
|
||||
: `${llmConfig.LLM} API Key`;
|
||||
|
||||
const getSelectedTextModel = (config: LLMConfig): string => {
|
||||
switch (config.LLM) {
|
||||
|
|
@ -108,6 +127,10 @@ const PresentonMode = ({ currentStep, setStep }: { currentStep: number, setStep:
|
|||
return config.OPENAI_MODEL || '';
|
||||
case 'google':
|
||||
return config.GOOGLE_MODEL || '';
|
||||
case 'vertex':
|
||||
return config.VERTEX_MODEL || '';
|
||||
case 'azure':
|
||||
return config.AZURE_OPENAI_MODEL || '';
|
||||
case 'anthropic':
|
||||
return config.ANTHROPIC_MODEL || '';
|
||||
case 'ollama':
|
||||
|
|
@ -128,6 +151,7 @@ const PresentonMode = ({ currentStep, setStep }: { currentStep: number, setStep:
|
|||
};
|
||||
|
||||
const fetchAvailableModels = async () => {
|
||||
if (isManualModelProvider) return;
|
||||
if (llmConfig.LLM === 'openai' && !currentApiKey) return;
|
||||
if (llmConfig.LLM === 'google' && !currentApiKey) return;
|
||||
if (llmConfig.LLM === 'anthropic' && !currentApiKey) return;
|
||||
|
|
@ -607,7 +631,7 @@ const PresentonMode = ({ currentStep, setStep }: { currentStep: number, setStep:
|
|||
<div className='flex items-center justify-between mb-2'>
|
||||
|
||||
<label className="block text-sm font-medium capitalize text-gray-700 ">
|
||||
{llmConfig.LLM === 'custom' ? 'Custom LLM API Key' : `${llmConfig.LLM} API Key`}
|
||||
{providerApiKeyLabel}
|
||||
</label>
|
||||
{llmConfig.LLM && LLM_PROVIDERS[llmConfig.LLM!]?.getApiKeyUrl && <a href={LLM_PROVIDERS[llmConfig.LLM!]?.getApiKeyUrl || ""} target='_blank' className='text-[#666666] text-xs font-normal flex items-center gap-1'>Get API Key <ArrowUpRight className='w-3.5 h-3.5' /></a>}
|
||||
</div>
|
||||
|
|
@ -621,7 +645,7 @@ const PresentonMode = ({ currentStep, setStep }: { currentStep: number, setStep:
|
|||
[currentApiKeyField]: e.target.value
|
||||
}))}
|
||||
className="w-full px-2 py-3 outline-none border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition-colors"
|
||||
placeholder={`Enter your ${llmConfig.LLM} API key`}
|
||||
placeholder={`Enter your ${providerApiKeyLabel}`}
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
|
|
@ -645,12 +669,90 @@ const PresentonMode = ({ currentStep, setStep }: { currentStep: number, setStep:
|
|||
placeholder="OpenAI-compatible URL"
|
||||
/>
|
||||
)}
|
||||
{llmConfig.LLM === 'vertex' && (
|
||||
<div className="mt-2 space-y-2">
|
||||
<input
|
||||
type="text"
|
||||
value={llmConfig.VERTEX_PROJECT || ''}
|
||||
onChange={(e) => setLlmConfig(prev => ({
|
||||
...prev,
|
||||
VERTEX_PROJECT: e.target.value
|
||||
}))}
|
||||
className="w-full px-2 py-3 outline-none border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition-colors"
|
||||
placeholder="GCP project (optional if API key used)"
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
value={llmConfig.VERTEX_LOCATION || ''}
|
||||
onChange={(e) => setLlmConfig(prev => ({
|
||||
...prev,
|
||||
VERTEX_LOCATION: e.target.value
|
||||
}))}
|
||||
className="w-full px-2 py-3 outline-none border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition-colors"
|
||||
placeholder="GCP location (optional)"
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
value={llmConfig.VERTEX_BASE_URL || ''}
|
||||
onChange={(e) => setLlmConfig(prev => ({
|
||||
...prev,
|
||||
VERTEX_BASE_URL: e.target.value
|
||||
}))}
|
||||
className="w-full px-2 py-3 outline-none border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition-colors"
|
||||
placeholder="Vertex base URL (optional)"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{llmConfig.LLM === 'azure' && (
|
||||
<div className="mt-2 space-y-2">
|
||||
<input
|
||||
type="text"
|
||||
value={llmConfig.AZURE_OPENAI_ENDPOINT || ''}
|
||||
onChange={(e) => setLlmConfig(prev => ({
|
||||
...prev,
|
||||
AZURE_OPENAI_ENDPOINT: e.target.value
|
||||
}))}
|
||||
className="w-full px-2 py-3 outline-none border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition-colors"
|
||||
placeholder="Azure endpoint (https://...openai.azure.com)"
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
value={llmConfig.AZURE_OPENAI_BASE_URL || ''}
|
||||
onChange={(e) => setLlmConfig(prev => ({
|
||||
...prev,
|
||||
AZURE_OPENAI_BASE_URL: e.target.value
|
||||
}))}
|
||||
className="w-full px-2 py-3 outline-none border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition-colors"
|
||||
placeholder="Azure base URL (optional alternative)"
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
value={llmConfig.AZURE_OPENAI_API_VERSION || ''}
|
||||
onChange={(e) => setLlmConfig(prev => ({
|
||||
...prev,
|
||||
AZURE_OPENAI_API_VERSION: e.target.value
|
||||
}))}
|
||||
className="w-full px-2 py-3 outline-none border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition-colors"
|
||||
placeholder="API version (e.g. 2024-10-21)"
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
value={llmConfig.AZURE_OPENAI_DEPLOYMENT || ''}
|
||||
onChange={(e) => setLlmConfig(prev => ({
|
||||
...prev,
|
||||
AZURE_OPENAI_DEPLOYMENT: e.target.value
|
||||
}))}
|
||||
className="w-full px-2 py-3 outline-none border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition-colors"
|
||||
placeholder="Deployment name (optional)"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
{llmConfig.LLM !== 'ollama' && llmConfig.LLM !== 'chatgpt' && llmConfig.LLM !== 'codex' && (!modelsChecked || (modelsChecked && availableModels.length === 0)) && (
|
||||
{!isManualModelProvider && llmConfig.LLM !== 'ollama' && llmConfig.LLM !== 'chatgpt' && llmConfig.LLM !== 'codex' && (!modelsChecked || (modelsChecked && availableModels.length === 0)) && (
|
||||
|
||||
<button
|
||||
onClick={fetchAvailableModels}
|
||||
|
|
@ -683,7 +785,7 @@ const PresentonMode = ({ currentStep, setStep }: { currentStep: number, setStep:
|
|||
|
||||
|
||||
{/* Model Selection - only show if models are available */}
|
||||
{llmConfig.LLM !== 'chatgpt' && llmConfig.LLM !== 'codex' && modelsChecked && availableModels.length > 0 && (
|
||||
{!isManualModelProvider && llmConfig.LLM !== 'chatgpt' && llmConfig.LLM !== 'codex' && modelsChecked && availableModels.length > 0 && (
|
||||
<div className="w-full">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-2">
|
||||
|
|
@ -765,6 +867,27 @@ const PresentonMode = ({ currentStep, setStep }: { currentStep: number, setStep:
|
|||
</div>
|
||||
</div>
|
||||
)}
|
||||
{isManualModelProvider && (
|
||||
<div className="w-full">
|
||||
<label className="block text-sm font-medium text-gray-700 mb-2">
|
||||
Enter {LLM_PROVIDERS[llmConfig.LLM!]?.label} Model
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
value={currentModel}
|
||||
onChange={(e) => {
|
||||
if (currentModelField) {
|
||||
setLlmConfig(prev => ({
|
||||
...prev,
|
||||
[currentModelField]: e.target.value
|
||||
}));
|
||||
}
|
||||
}}
|
||||
className="w-full h-12 px-4 py-3 outline-none border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition-colors"
|
||||
placeholder={llmConfig.LLM === 'vertex' ? 'e.g. gemini-2.5-flash' : 'e.g. gpt-4.1'}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{/* Image Provider */}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,21 @@ export interface LLMConfig {
|
|||
GOOGLE_API_KEY?: string;
|
||||
GOOGLE_MODEL?: string;
|
||||
|
||||
// Vertex AI
|
||||
VERTEX_API_KEY?: string;
|
||||
VERTEX_MODEL?: string;
|
||||
VERTEX_PROJECT?: string;
|
||||
VERTEX_LOCATION?: string;
|
||||
VERTEX_BASE_URL?: string;
|
||||
|
||||
// Azure OpenAI
|
||||
AZURE_OPENAI_API_KEY?: string;
|
||||
AZURE_OPENAI_MODEL?: string;
|
||||
AZURE_OPENAI_ENDPOINT?: string;
|
||||
AZURE_OPENAI_BASE_URL?: string;
|
||||
AZURE_OPENAI_API_VERSION?: string;
|
||||
AZURE_OPENAI_DEPLOYMENT?: string;
|
||||
|
||||
// Anthropic
|
||||
ANTHROPIC_API_KEY?: string;
|
||||
ANTHROPIC_MODEL?: string;
|
||||
|
|
|
|||
|
|
@ -132,6 +132,20 @@ export const LLM_PROVIDERS: Record<string, LLMProviderOption> = {
|
|||
icon: "/providers/gemini-color.svg",
|
||||
getApiKeyUrl: "https://www.google.com/search?q=how+to+get+google+AI+studio+api+key&sxsrf=ANbL-n5_hUGaEiG9v6k9VxZWyv0mqO0Jew%3A1776339625724",
|
||||
},
|
||||
vertex: {
|
||||
value: "vertex",
|
||||
label: "Vertex AI",
|
||||
description: "Google Vertex AI models",
|
||||
icon: "/providers/gemini-color.svg",
|
||||
getApiKeyUrl: "https://www.google.com/search?q=how+to+get+vertex+ai+api+key",
|
||||
},
|
||||
azure: {
|
||||
value: "azure",
|
||||
label: "Azure OpenAI",
|
||||
description: "Azure-hosted OpenAI deployments",
|
||||
icon: "/providers/openai.png",
|
||||
getApiKeyUrl: "https://www.google.com/search?q=azure+openai+api+key",
|
||||
},
|
||||
anthropic: {
|
||||
value: "anthropic",
|
||||
label: "Anthropic",
|
||||
|
|
|
|||
|
|
@ -34,6 +34,17 @@ export const updateLLMConfig = (
|
|||
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",
|
||||
|
|
@ -81,7 +92,7 @@ export const changeProvider = (
|
|||
} else if (provider === "google") {
|
||||
newConfig.IMAGE_PROVIDER = "gemini_flash";
|
||||
} else {
|
||||
newConfig.IMAGE_PROVIDER = "pexels"; // default for ollama, custom, codex
|
||||
newConfig.IMAGE_PROVIDER = "pexels"; // default for vertex, azure, ollama, custom, codex
|
||||
}
|
||||
|
||||
return newConfig;
|
||||
|
|
|
|||
|
|
@ -36,6 +36,35 @@ export const getLLMConfigValidationError = (
|
|||
if (!isProvided(llmConfig.GOOGLE_MODEL)) {
|
||||
return 'No Google model selected. Use "Check models" after entering your API key, then choose a model.';
|
||||
}
|
||||
} else if (llm === "vertex") {
|
||||
const hasApiKey = isProvided(llmConfig.VERTEX_API_KEY);
|
||||
const hasProject = isProvided(llmConfig.VERTEX_PROJECT);
|
||||
const hasLocation = isProvided(llmConfig.VERTEX_LOCATION);
|
||||
if (!hasApiKey && !hasProject) {
|
||||
return "Vertex AI requires either a Vertex API key or a GCP project.";
|
||||
}
|
||||
if (hasApiKey && (hasProject || hasLocation)) {
|
||||
return "Use either Vertex API key mode or project/location mode, not both.";
|
||||
}
|
||||
if (!isProvided(llmConfig.VERTEX_MODEL)) {
|
||||
return "Vertex model is required.";
|
||||
}
|
||||
} else if (llm === "azure") {
|
||||
if (!isProvided(llmConfig.AZURE_OPENAI_API_KEY)) {
|
||||
return "Azure OpenAI API key is required.";
|
||||
}
|
||||
if (!isProvided(llmConfig.AZURE_OPENAI_API_VERSION)) {
|
||||
return "Azure OpenAI API version is required.";
|
||||
}
|
||||
if (
|
||||
!isProvided(llmConfig.AZURE_OPENAI_ENDPOINT) &&
|
||||
!isProvided(llmConfig.AZURE_OPENAI_BASE_URL)
|
||||
) {
|
||||
return "Azure OpenAI endpoint or base URL is required.";
|
||||
}
|
||||
if (!isProvided(llmConfig.AZURE_OPENAI_MODEL)) {
|
||||
return "Azure OpenAI model/deployment name is required.";
|
||||
}
|
||||
} else if (llm === "anthropic") {
|
||||
if (!isProvided(llmConfig.ANTHROPIC_API_KEY)) {
|
||||
return "Anthropic API key is required.";
|
||||
|
|
|
|||
19
start.js
19
start.js
|
|
@ -151,7 +151,7 @@ const setupUserConfigFromEnv = () => {
|
|||
existingConfig = JSON.parse(readFileSync(userConfigPath, "utf8"));
|
||||
}
|
||||
|
||||
if (!["ollama", "openai", "google", "anthropic", "custom", "codex"].includes(existingConfig.LLM)) {
|
||||
if (!["ollama", "openai", "google", "vertex", "azure", "anthropic", "custom", "codex"].includes(existingConfig.LLM)) {
|
||||
existingConfig.LLM = undefined;
|
||||
}
|
||||
|
||||
|
|
@ -161,6 +161,23 @@ const setupUserConfigFromEnv = () => {
|
|||
OPENAI_MODEL: process.env.OPENAI_MODEL || existingConfig.OPENAI_MODEL,
|
||||
GOOGLE_API_KEY: process.env.GOOGLE_API_KEY || existingConfig.GOOGLE_API_KEY,
|
||||
GOOGLE_MODEL: process.env.GOOGLE_MODEL || existingConfig.GOOGLE_MODEL,
|
||||
VERTEX_API_KEY: process.env.VERTEX_API_KEY || existingConfig.VERTEX_API_KEY,
|
||||
VERTEX_MODEL: process.env.VERTEX_MODEL || existingConfig.VERTEX_MODEL,
|
||||
VERTEX_PROJECT: process.env.VERTEX_PROJECT || existingConfig.VERTEX_PROJECT,
|
||||
VERTEX_LOCATION: process.env.VERTEX_LOCATION || existingConfig.VERTEX_LOCATION,
|
||||
VERTEX_BASE_URL: process.env.VERTEX_BASE_URL || existingConfig.VERTEX_BASE_URL,
|
||||
AZURE_OPENAI_API_KEY:
|
||||
process.env.AZURE_OPENAI_API_KEY || existingConfig.AZURE_OPENAI_API_KEY,
|
||||
AZURE_OPENAI_MODEL:
|
||||
process.env.AZURE_OPENAI_MODEL || existingConfig.AZURE_OPENAI_MODEL,
|
||||
AZURE_OPENAI_ENDPOINT:
|
||||
process.env.AZURE_OPENAI_ENDPOINT || existingConfig.AZURE_OPENAI_ENDPOINT,
|
||||
AZURE_OPENAI_BASE_URL:
|
||||
process.env.AZURE_OPENAI_BASE_URL || existingConfig.AZURE_OPENAI_BASE_URL,
|
||||
AZURE_OPENAI_API_VERSION:
|
||||
process.env.AZURE_OPENAI_API_VERSION || existingConfig.AZURE_OPENAI_API_VERSION,
|
||||
AZURE_OPENAI_DEPLOYMENT:
|
||||
process.env.AZURE_OPENAI_DEPLOYMENT || existingConfig.AZURE_OPENAI_DEPLOYMENT,
|
||||
OLLAMA_URL: process.env.OLLAMA_URL || existingConfig.OLLAMA_URL,
|
||||
OLLAMA_MODEL: process.env.OLLAMA_MODEL || existingConfig.OLLAMA_MODEL,
|
||||
ANTHROPIC_API_KEY:
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue