diff --git a/docker-compose.yml b/docker-compose.yml index 49cf6c49..da81c479 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,5 +1,25 @@ services: production: + # image: ghcr.io/presenton/presenton:latest + build: + context: . + dockerfile: Dockerfile + ports: + # You can replace 5000 with any other port number of your choice to run Presenton on a different port number. + - "5000:80" + volumes: + - ./user_data:/app/user_data + environment: + - CAN_CHANGE_KEYS=${CAN_CHANGE_KEYS} + - LLM=${LLM} + - LLM_PROVIDER_URL=${LLM_PROVIDER_URL} + - LLM_API_KEY=${LLM_API_KEY} + - OPENAI_API_KEY=${OPENAI_API_KEY} + - GOOGLE_API_KEY=${GOOGLE_API_KEY} + - OLLAMA_MODEL=${OLLAMA_MODEL} + - PEXELS_API_KEY=${PEXELS_API_KEY} + + production-gpu: # image: ghcr.io/presenton/presenton:latest build: context: . @@ -19,12 +39,35 @@ services: environment: - CAN_CHANGE_KEYS=${CAN_CHANGE_KEYS} - LLM=${LLM} + - LLM_PROVIDER_URL=${LLM_PROVIDER_URL} + - LLM_API_KEY=${LLM_API_KEY} - OPENAI_API_KEY=${OPENAI_API_KEY} - GOOGLE_API_KEY=${GOOGLE_API_KEY} - OLLAMA_MODEL=${OLLAMA_MODEL} - PEXELS_API_KEY=${PEXELS_API_KEY} development: + build: + context: . + dockerfile: Dockerfile.dev + ports: + - "5000:80" + - "3000:3000" + - "8000:8000" + volumes: + - .:/app + environment: + - NODE_ENV=development + - CAN_CHANGE_KEYS=${CAN_CHANGE_KEYS} + - LLM=${LLM} + - LLM_PROVIDER_URL=${LLM_PROVIDER_URL} + - LLM_API_KEY=${LLM_API_KEY} + - OPENAI_API_KEY=${OPENAI_API_KEY} + - GOOGLE_API_KEY=${GOOGLE_API_KEY} + - OLLAMA_MODEL=${OLLAMA_MODEL} + - PEXELS_API_KEY=${PEXELS_API_KEY} + + development-gpu: build: context: . dockerfile: Dockerfile.dev @@ -45,6 +88,8 @@ services: - NODE_ENV=development - CAN_CHANGE_KEYS=${CAN_CHANGE_KEYS} - LLM=${LLM} + - LLM_PROVIDER_URL=${LLM_PROVIDER_URL} + - LLM_API_KEY=${LLM_API_KEY} - OPENAI_API_KEY=${OPENAI_API_KEY} - GOOGLE_API_KEY=${GOOGLE_API_KEY} - OLLAMA_MODEL=${OLLAMA_MODEL} diff --git a/servers/fastapi/api/routers/presentation/handlers/edit.py b/servers/fastapi/api/routers/presentation/handlers/edit.py index 6cc1d514..938f19b7 100644 --- a/servers/fastapi/api/routers/presentation/handlers/edit.py +++ b/servers/fastapi/api/routers/presentation/handlers/edit.py @@ -93,7 +93,7 @@ class PresentationEditHandler: icons=None, presentation=slide_to_edit.presentation, properties=slide_to_edit.properties, - content=edited_content, + content=edited_content.to_content(), ) new_slide_images_count = new_slide_model.images_count diff --git a/servers/fastapi/api/routers/presentation/handlers/list_ollama_pulled_models.py b/servers/fastapi/api/routers/presentation/handlers/list_ollama_pulled_models.py index c96db431..29177aed 100644 --- a/servers/fastapi/api/routers/presentation/handlers/list_ollama_pulled_models.py +++ b/servers/fastapi/api/routers/presentation/handlers/list_ollama_pulled_models.py @@ -1,9 +1,12 @@ -import os import aiohttp +from fastapi import HTTPException from api.models import LogMetadata from api.routers.presentation.models import OllamaModelStatusResponse from api.services.logging import LoggingService -from api.utils.model_utils import get_llm_api_key_or, get_llm_provider_url_or +from api.utils.model_utils import ( + get_llm_provider_url_or, + get_ollama_request_headers, +) class ListPulledOllamaModelsHandler: @@ -13,13 +16,23 @@ class ListPulledOllamaModelsHandler: logging_service.message("Listing Ollama models"), extra=log_metadata.model_dump(), ) - async with aiohttp.ClientSession() as session: async with session.get( f"{get_llm_provider_url_or()}/api/tags", - headers={"Authorization": f"Bearer {get_llm_api_key_or()}"}, + headers=get_ollama_request_headers(), ) as response: - response_data = await response.json() + if response.status == 200: + response_data = await response.json() + elif response.status == 403: + raise HTTPException( + status_code=403, + detail="Forbidden: Please check your Ollama Configuration", + ) + else: + raise HTTPException( + status_code=response.status, + detail=f"Failed to list Ollama models: {response.status}", + ) logging_service.logger.info( logging_service.message(response_data), diff --git a/servers/fastapi/api/routers/presentation/handlers/pull_ollama_model.py b/servers/fastapi/api/routers/presentation/handlers/pull_ollama_model.py index f14dd239..29dc6394 100644 --- a/servers/fastapi/api/routers/presentation/handlers/pull_ollama_model.py +++ b/servers/fastapi/api/routers/presentation/handlers/pull_ollama_model.py @@ -1,4 +1,5 @@ import json +import traceback import aiohttp from fastapi import BackgroundTasks, HTTPException from api.models import LogMetadata @@ -8,7 +9,10 @@ from api.routers.presentation.handlers.list_supported_ollama_models import ( from api.routers.presentation.models import OllamaModelStatusResponse from api.services.instances import REDIS_SERVICE from api.services.logging import LoggingService -from api.utils.model_utils import get_llm_api_key_or, get_llm_provider_url_or +from api.utils.model_utils import ( + get_llm_provider_url_or, + get_ollama_request_headers, +) class PullOllamaModelHandler: @@ -38,7 +42,7 @@ class PullOllamaModelHandler: async with aiohttp.ClientSession() as session: async with session.get( f"{get_llm_provider_url_or()}/api/tags", - headers={"Authorization": f"Bearer {get_llm_api_key_or()}"}, + headers=get_ollama_request_headers(), ) as response: if response.status == 200: pulled_models = await response.json() @@ -57,17 +61,49 @@ class PullOllamaModelHandler: downloaded=filtered_models[0]["size"], done=True, ) + elif response.status == 403: + print(response) + raise HTTPException( + status_code=403, + detail="Forbidden: Please check your Ollama Configuration", + ) + else: + raise HTTPException( + status_code=response.status, + detail=f"Failed to list Ollama models: {response.status}", + ) + except HTTPException as e: + logging_service.logger.warning( + logging_service.message(e.detail), + extra=log_metadata.model_dump(), + ) + raise e except Exception as e: + traceback.print_exc() logging_service.logger.warning( f"Failed to check pulled models: {e}", extra=log_metadata.model_dump(), ) + raise HTTPException( + status_code=500, + detail=f"Failed to check pulled models: {e}", + ) saved_model_status = REDIS_SERVICE.get(f"ollama_models/{self.name}") # If the model is being pulled, return the model if saved_model_status: - return json.loads(saved_model_status) + saved_model_status_json = json.loads(saved_model_status) + # If the model is being pulled, return the model + # ? If the model status is pulled in redis but was not found while listing pulled models, + # ? it means the model was deleted and we need to pull it again + if ( + saved_model_status_json["status"] == "error" + or saved_model_status_json["status"] == "pulled" + ): + REDIS_SERVICE.delete(f"ollama_models/{self.name}") + else: + return saved_model_status_json # If the model is not being pulled, pull the model background_tasks.add_task(self.pull_model_in_background) @@ -93,8 +129,8 @@ class PullOllamaModelHandler: async with aiohttp.ClientSession() as session: async with session.post( f"{get_llm_provider_url_or()}/api/pull", + headers=get_ollama_request_headers(), json={"model": self.name}, - headers={"Authorization": f"Bearer {get_llm_api_key_or()}"}, ) as response: if response.status != 200: raise HTTPException( @@ -136,7 +172,10 @@ class PullOllamaModelHandler: f"ollama_models/{self.name}", json.dumps(saved_model_status.model_dump(mode="json")), ) - raise e + raise HTTPException( + status_code=500, + detail=f"Failed to pull model: {e}", + ) saved_model_status.done = True saved_model_status.status = "pulled" diff --git a/servers/fastapi/api/utils/model_utils.py b/servers/fastapi/api/utils/model_utils.py index b2ee037a..2e4b3b7d 100644 --- a/servers/fastapi/api/utils/model_utils.py +++ b/servers/fastapi/api/utils/model_utils.py @@ -10,11 +10,18 @@ def is_ollama_selected() -> bool: def get_llm_provider_url_or(): - return os.getenv("LLM_PROVIDER_URL") or "http://localhost:11434" + llm_provider_url = os.getenv("LLM_PROVIDER_URL") or "http://localhost:11434" + if llm_provider_url.endswith("/"): + return llm_provider_url[:-1] + return llm_provider_url -def get_llm_api_key_or(): - return os.getenv("LLM_API_KEY") or "ollama" +def get_ollama_request_headers(): + if os.getenv("LLM_API_KEY"): + return { + "Authorization": f"Bearer {os.getenv('LLM_API_KEY')}", + } + return {} def get_selected_llm_provider() -> SelectedLLMProvider: @@ -41,7 +48,7 @@ def get_llm_api_key(): elif selected_llm == SelectedLLMProvider.GOOGLE: return os.getenv("GOOGLE_API_KEY") elif selected_llm == SelectedLLMProvider.OLLAMA: - return get_llm_api_key_or() + return os.getenv("LLM_API_KEY") or "ollama" else: raise ValueError(f"Invalid LLM API key") diff --git a/servers/fastapi/api/utils/utils.py b/servers/fastapi/api/utils/utils.py index e297cc96..96174bde 100644 --- a/servers/fastapi/api/utils/utils.py +++ b/servers/fastapi/api/utils/utils.py @@ -42,13 +42,13 @@ def get_user_config(): return UserConfig( LLM=existing_config.LLM or os.getenv("LLM"), + LLM_PROVIDER_URL=existing_config.LLM_PROVIDER_URL + or os.getenv("LLM_PROVIDER_URL"), + LLM_API_KEY=existing_config.LLM_API_KEY or os.getenv("LLM_API_KEY"), OPENAI_API_KEY=existing_config.OPENAI_API_KEY or os.getenv("OPENAI_API_KEY"), GOOGLE_API_KEY=existing_config.GOOGLE_API_KEY or os.getenv("GOOGLE_API_KEY"), MODEL=existing_config.MODEL or os.getenv("MODEL"), PEXELS_API_KEY=existing_config.PEXELS_API_KEY or os.getenv("PEXELS_API_KEY"), - LLM_PROVIDER_URL=existing_config.LLM_PROVIDER_URL - or os.getenv("LLM_PROVIDER_URL"), - LLM_API_KEY=existing_config.LLM_API_KEY or os.getenv("LLM_API_KEY"), ) @@ -56,6 +56,10 @@ def update_env_with_user_config(): user_config = get_user_config() if user_config.LLM: os.environ["LLM"] = user_config.LLM + if user_config.LLM_PROVIDER_URL: + os.environ["LLM_PROVIDER_URL"] = user_config.LLM_PROVIDER_URL + if user_config.LLM_API_KEY: + os.environ["LLM_API_KEY"] = user_config.LLM_API_KEY if user_config.OPENAI_API_KEY: os.environ["OPENAI_API_KEY"] = user_config.OPENAI_API_KEY if user_config.GOOGLE_API_KEY: @@ -64,10 +68,6 @@ def update_env_with_user_config(): os.environ["MODEL"] = user_config.MODEL if user_config.PEXELS_API_KEY: os.environ["PEXELS_API_KEY"] = user_config.PEXELS_API_KEY - if user_config.LLM_PROVIDER_URL: - os.environ["LLM_PROVIDER_URL"] = user_config.LLM_PROVIDER_URL - if user_config.LLM_API_KEY: - os.environ["LLM_API_KEY"] = user_config.LLM_API_KEY def get_resource(relative_path): diff --git a/servers/fastapi/server.py b/servers/fastapi/server.py index aba13788..19b8773b 100644 --- a/servers/fastapi/server.py +++ b/servers/fastapi/server.py @@ -2,11 +2,6 @@ import os import uvicorn import argparse -from api.main import app - - -# ? Helps pyinstaller for dependencies resolution -app if __name__ == "__main__": os.makedirs("debug", exist_ok=True) diff --git a/servers/nextjs/app/api/user-config/route.ts b/servers/nextjs/app/api/user-config/route.ts index 1fc257b4..87549b91 100644 --- a/servers/nextjs/app/api/user-config/route.ts +++ b/servers/nextjs/app/api/user-config/route.ts @@ -34,12 +34,13 @@ export async function POST(request: Request) { } const mergedConfig: LLMConfig = { LLM: userConfig.LLM || existingConfig.LLM, + LLM_PROVIDER_URL: userConfig.LLM_PROVIDER_URL || existingConfig.LLM_PROVIDER_URL, + LLM_API_KEY: userConfig.LLM_API_KEY, OPENAI_API_KEY: userConfig.OPENAI_API_KEY || existingConfig.OPENAI_API_KEY, GOOGLE_API_KEY: userConfig.GOOGLE_API_KEY || existingConfig.GOOGLE_API_KEY, MODEL: userConfig.MODEL || existingConfig.MODEL, - LLM_PROVIDER_URL: userConfig.LLM_PROVIDER_URL || existingConfig.LLM_PROVIDER_URL, - LLM_API_KEY: userConfig.LLM_API_KEY || existingConfig.LLM_API_KEY, PEXELS_API_KEY: userConfig.PEXELS_API_KEY || existingConfig.PEXELS_API_KEY, + USE_CUSTOM_URL: userConfig.USE_CUSTOM_URL === undefined ? existingConfig.USE_CUSTOM_URL : userConfig.USE_CUSTOM_URL, } fs.writeFileSync(userConfigPath, JSON.stringify(mergedConfig)) return NextResponse.json(mergedConfig) diff --git a/servers/nextjs/app/settings/SettingPage.tsx b/servers/nextjs/app/settings/SettingPage.tsx index 703d4ac4..d7a54425 100644 --- a/servers/nextjs/app/settings/SettingPage.tsx +++ b/servers/nextjs/app/settings/SettingPage.tsx @@ -72,7 +72,7 @@ const SettingsPage = () => { }); const [isLoading, setIsLoading] = useState(false); const [openModelSelect, setOpenModelSelect] = useState(false); - const [useCustomOllamaUrl, setUseCustomOllamaUrl] = useState(false); + const [useCustomOllamaUrl, setUseCustomOllamaUrl] = useState(userConfigState.llm_config.USE_CUSTOM_URL || false); const api_key_changed = (apiKey: string, field?: string) => { if (llmConfig.LLM === 'openai') { @@ -91,27 +91,12 @@ const SettingsPage = () => { } const handleSaveConfig = async () => { - if (llmConfig.LLM === 'ollama') { - try { + try { + await handleSaveLLMConfig(llmConfig); + if (llmConfig.LLM === 'ollama') { setIsLoading(true); await pullOllamaModels(); - toast({ - title: 'Success', - description: 'Model downloaded successfully', - }); - } catch (error) { - console.error('Error pulling model:', error); - toast({ - title: 'Error', - description: 'Failed to download model. Please try again.', - variant: 'destructive', - }); - setIsLoading(false); - return; } - } - try { - await handleSaveLLMConfig(llmConfig, useCustomOllamaUrl); toast({ title: 'Success', description: 'Configuration saved successfully', @@ -122,7 +107,7 @@ const SettingsPage = () => { console.error('Error:', error); toast({ title: 'Error', - description: 'Failed to save configuration', + description: error instanceof Error ? error.message : 'Failed to save configuration', variant: 'destructive', }); setIsLoading(false); @@ -136,34 +121,48 @@ const SettingsPage = () => { } } + const resetDownloadingModel = () => { + setDownloadingModel({ + name: '', + size: null, + downloaded: null, + status: '', + done: false, + }); + } + const pullOllamaModels = async (): Promise => { return new Promise((resolve, reject) => { const interval = setInterval(async () => { try { const response = await fetch(`/api/v1/ppt/ollama/pull-model?name=${llmConfig.MODEL}`); if (response.status === 200) { - const data = await response.json(); - - if (data.done) { + if (data.done && data.status !== 'error') { clearInterval(interval); setDownloadingModel(data); resolve(); + } else if (data.status === 'error') { + clearInterval(interval); + resetDownloadingModel(); + reject(new Error('Error occurred while pulling model')); } else { setDownloadingModel(data); } } else { clearInterval(interval); - reject(new Error('Model pulling failed')); + resetDownloadingModel(); + if (response.status === 403) { + reject(new Error('Request to Ollama Not Authorized')); + } + reject(new Error('Error occurred while pulling model')); } } catch (error) { - - console.log('Error fetching ollama models:', error); clearInterval(interval); + resetDownloadingModel(); reject(error); } }, 1000); - }); } @@ -177,6 +176,14 @@ const SettingsPage = () => { } } + const setOllamaConfig = () => { + if (!useCustomOllamaUrl) { + setLlmConfig({ ...llmConfig, LLM_PROVIDER_URL: 'http://localhost:11434', LLM_API_KEY: undefined, USE_CUSTOM_URL: false }); + } else { + setLlmConfig({ ...llmConfig, USE_CUSTOM_URL: true }); + } + } + useEffect(() => { if (!canChangeKeys) { @@ -188,11 +195,7 @@ const SettingsPage = () => { }, [userConfigState.llm_config.LLM]); useEffect(() => { - if (!useCustomOllamaUrl) { - setLlmConfig({ ...llmConfig, LLM_PROVIDER_URL: undefined, LLM_API_KEY: undefined }); - } else { - setLlmConfig({ ...llmConfig, LLM_PROVIDER_URL: 'http://localhost:11434', LLM_API_KEY: '' }); - } + setOllamaConfig(); }, [useCustomOllamaUrl]); if (!canChangeKeys) { diff --git a/servers/nextjs/app/storeInitializer.tsx b/servers/nextjs/app/storeInitializer.tsx index edbb856d..8e0e1436 100644 --- a/servers/nextjs/app/storeInitializer.tsx +++ b/servers/nextjs/app/storeInitializer.tsx @@ -41,7 +41,7 @@ export function StoreInitializer({ children }: { children: React.ReactNode }) { llmConfig.LLM = 'openai'; } dispatch(setLLMConfig(llmConfig)); - const isValid = hasValidLLMConfig(llmConfig, false); + const isValid = hasValidLLMConfig(llmConfig); if (isValid) { // Check if the selected Ollama model is pulled if (llmConfig.LLM === 'ollama') { @@ -75,10 +75,15 @@ export function StoreInitializer({ children }: { children: React.ReactNode }) { } const checkIfSelectedOllamaModelIsPulled = async (ollamaModel: string) => { - const response = await fetch('/api/v1/ppt/ollama/list-pulled-models'); - const data = await response.json(); - const pulledModels = data.map((model: any) => model.name); - return pulledModels.includes(ollamaModel); + try { + const response = await fetch('/api/v1/ppt/ollama/list-pulled-models'); + const data = await response.json(); + const pulledModels = data.map((model: any) => model.name); + return pulledModels.includes(ollamaModel); + } catch (error) { + console.error('Error checking if selected Ollama model is pulled:', error); + return false; + } } diff --git a/servers/nextjs/components/Home.tsx b/servers/nextjs/components/Home.tsx index b76ecbbb..c8d41b5b 100644 --- a/servers/nextjs/components/Home.tsx +++ b/servers/nextjs/components/Home.tsx @@ -159,7 +159,7 @@ export default function Home() { }); const [isLoading, setIsLoading] = useState(false); const [openModelSelect, setOpenModelSelect] = useState(false); - const [useCustomOllamaUrl, setUseCustomOllamaUrl] = useState(false); + const [useCustomOllamaUrl, setUseCustomOllamaUrl] = useState(llmConfig.USE_CUSTOM_URL || false); const canChangeKeys = config.can_change_keys; @@ -180,27 +180,12 @@ export default function Home() { } const handleSaveConfig = async () => { - if (llmConfig.LLM === 'ollama') { - try { + try { + await handleSaveLLMConfig(llmConfig); + if (llmConfig.LLM === 'ollama') { setIsLoading(true); await pullOllamaModels(); - toast({ - title: 'Success', - description: 'Model downloaded successfully', - }); - } catch (error) { - console.error('Error pulling model:', error); - toast({ - title: 'Error', - description: 'Failed to download model. Please try again.', - variant: 'destructive', - }); - setIsLoading(false); - return; } - } - try { - await handleSaveLLMConfig(llmConfig, useCustomOllamaUrl); toast({ title: 'Success', description: 'Configuration saved successfully', @@ -211,7 +196,7 @@ export default function Home() { console.error('Error:', error); toast({ title: 'Error', - description: 'Failed to save configuration', + description: error instanceof Error ? error.message : 'Failed to save configuration', variant: 'destructive', }); setIsLoading(false); @@ -225,6 +210,16 @@ export default function Home() { } } + const resetDownloadingModel = () => { + setDownloadingModel({ + name: '', + size: null, + downloaded: null, + status: '', + done: false, + }); + } + const pullOllamaModels = async (): Promise => { return new Promise((resolve, reject) => { const interval = setInterval(async () => { @@ -232,21 +227,28 @@ export default function Home() { const response = await fetch(`/api/v1/ppt/ollama/pull-model?name=${llmConfig.MODEL}`); if (response.status === 200) { const data = await response.json(); - - if (data.done) { + if (data.done && data.status !== 'error') { clearInterval(interval); setDownloadingModel(data); resolve(); + } else if (data.status === 'error') { + clearInterval(interval); + resetDownloadingModel(); + reject(new Error('Error occurred while pulling model')); } else { setDownloadingModel(data); } } else { clearInterval(interval); - reject(new Error('Model pulling failed')); + resetDownloadingModel(); + if (response.status === 403) { + reject(new Error('Request to Ollama Not Authorized')); + } + reject(new Error('Error occurred while pulling model')); } } catch (error) { - console.log('Error fetching ollama models:', error); clearInterval(interval); + resetDownloadingModel(); reject(error); } }, 1000); @@ -263,6 +265,14 @@ export default function Home() { } } + const setOllamaConfig = () => { + if (!useCustomOllamaUrl) { + setLlmConfig({ ...llmConfig, LLM_PROVIDER_URL: 'http://localhost:11434', LLM_API_KEY: undefined, USE_CUSTOM_URL: false }); + } else { + setLlmConfig({ ...llmConfig, USE_CUSTOM_URL: true }); + } + } + useEffect(() => { if (!canChangeKeys) { router.push("/upload"); @@ -273,11 +283,7 @@ export default function Home() { }, []); useEffect(() => { - if (!useCustomOllamaUrl) { - setLlmConfig({ ...llmConfig, LLM_PROVIDER_URL: undefined, LLM_API_KEY: undefined }); - } else { - setLlmConfig({ ...llmConfig, LLM_PROVIDER_URL: 'http://localhost:11434', LLM_API_KEY: '' }); - } + setOllamaConfig(); }, [useCustomOllamaUrl]); diff --git a/servers/nextjs/types/global.d.ts b/servers/nextjs/types/global.d.ts index d3269c53..965ebe08 100644 --- a/servers/nextjs/types/global.d.ts +++ b/servers/nextjs/types/global.d.ts @@ -15,10 +15,13 @@ interface TextFrameProps { interface LLMConfig { LLM?: string; + LLM_PROVIDER_URL?: string; + LLM_API_KEY?: string; OPENAI_API_KEY?: string; GOOGLE_API_KEY?: string; PEXELS_API_KEY?: string; - LLM_PROVIDER_URL?: string; - LLM_API_KEY?: string; MODEL?: string; + + // Only used in UI settings + USE_CUSTOM_URL?: boolean; } \ No newline at end of file diff --git a/servers/nextjs/utils/storeHelpers.ts b/servers/nextjs/utils/storeHelpers.ts index dbb13274..cea2205b 100644 --- a/servers/nextjs/utils/storeHelpers.ts +++ b/servers/nextjs/utils/storeHelpers.ts @@ -1,8 +1,8 @@ import { setLLMConfig } from "@/store/slices/userConfig"; import { store } from "@/store/store"; -export const handleSaveLLMConfig = async (llmConfig: LLMConfig, useCustomOllamaUrl: boolean) => { - if (!hasValidLLMConfig(llmConfig, useCustomOllamaUrl)) { +export const handleSaveLLMConfig = async (llmConfig: LLMConfig) => { + if (!hasValidLLMConfig(llmConfig)) { throw new Error('API key cannot be empty'); } @@ -14,21 +14,18 @@ export const handleSaveLLMConfig = async (llmConfig: LLMConfig, useCustomOllamaU store.dispatch(setLLMConfig(llmConfig)); } -export const hasValidLLMConfig = (llmConfig: LLMConfig, useCustomOllamaUrl: boolean) => { +export const hasValidLLMConfig = (llmConfig: LLMConfig) => { if (!llmConfig.LLM) return false; const OPENAI_API_KEY = llmConfig.OPENAI_API_KEY; const GOOGLE_API_KEY = llmConfig.GOOGLE_API_KEY; const MODEL = llmConfig.MODEL; const PEXELS_API_KEY = llmConfig.PEXELS_API_KEY; - const isOllamaBaseConfigValid = PEXELS_API_KEY !== '' && PEXELS_API_KEY !== null && PEXELS_API_KEY !== undefined && MODEL !== '' && MODEL !== null && MODEL !== undefined; + const isOllamaConfigValid = PEXELS_API_KEY !== '' && PEXELS_API_KEY !== null && PEXELS_API_KEY !== undefined && MODEL !== '' && MODEL !== null && MODEL !== undefined && llmConfig.LLM_PROVIDER_URL !== '' && llmConfig.LLM_PROVIDER_URL !== null && llmConfig.LLM_PROVIDER_URL !== undefined; return llmConfig.LLM === 'openai' ? OPENAI_API_KEY !== '' && OPENAI_API_KEY !== null && OPENAI_API_KEY !== undefined : llmConfig.LLM === 'google' ? GOOGLE_API_KEY !== '' && GOOGLE_API_KEY !== null && GOOGLE_API_KEY !== undefined : - llmConfig.LLM === 'ollama' ? - useCustomOllamaUrl ? - isOllamaBaseConfigValid && llmConfig.LLM_PROVIDER_URL !== '' && llmConfig.LLM_PROVIDER_URL !== null && llmConfig.LLM_PROVIDER_URL !== undefined && llmConfig.LLM_API_KEY !== '' && llmConfig.LLM_API_KEY !== null && llmConfig.LLM_API_KEY !== undefined : - isOllamaBaseConfigValid : false; + llmConfig.LLM === 'ollama' ? isOllamaConfigValid : false; } \ No newline at end of file diff --git a/start.js b/start.js index 728665dc..13bcb030 100644 --- a/start.js +++ b/start.js @@ -35,10 +35,13 @@ const setupUserConfigFromEnv = () => { const userConfig = { LLM: process.env.LLM || existingConfig.LLM, + LLM_PROVIDER_URL: process.env.LLM_PROVIDER_URL || existingConfig.LLM_PROVIDER_URL, + LLM_API_KEY: process.env.LLM_API_KEY || existingConfig.LLM_API_KEY, OPENAI_API_KEY: process.env.OPENAI_API_KEY || existingConfig.OPENAI_API_KEY, GOOGLE_API_KEY: process.env.GOOGLE_API_KEY || existingConfig.GOOGLE_API_KEY, - OLLAMA_MODEL: process.env.OLLAMA_MODEL || existingConfig.OLLAMA_MODEL, + MODEL: process.env.MODEL || existingConfig.MODEL, PEXELS_API_KEY: process.env.PEXELS_API_KEY || existingConfig.PEXELS_API_KEY, + USE_CUSTOM_URL: process.env.USE_CUSTOM_URL || existingConfig.USE_CUSTOM_URL, }; fs.writeFileSync(userConfigPath, JSON.stringify(userConfig));