From aa893400c0a71236865682757afca78fd9d119ed Mon Sep 17 00:00:00 2001 From: rootflo-hardik Date: Sun, 14 Dec 2025 12:43:18 +0530 Subject: [PATCH 1/3] llm_provider default base url fix --- wavefront/client/eslint.config.js | 2 + .../client/src/components/DashboardLayout.tsx | 2 +- wavefront/client/src/config/llm-providers.ts | 13 +++++++ .../src/pages/apps/[appId]/agents/[id].tsx | 2 +- .../[appId]/datasources/[datasourceId].tsx | 4 +- .../CreateLLMInferenceDialog.tsx | 39 +++++++++++++------ .../apps/[appId]/llm-inference/[configId].tsx | 18 +++++++-- 7 files changed, 61 insertions(+), 19 deletions(-) diff --git a/wavefront/client/eslint.config.js b/wavefront/client/eslint.config.js index fa9de8ac..14fa1db1 100644 --- a/wavefront/client/eslint.config.js +++ b/wavefront/client/eslint.config.js @@ -23,6 +23,8 @@ export default tseslint.config( ...reactHooks.configs.recommended.rules, 'react-refresh/only-export-components': ['warn', { allowConstantExport: true }], 'prettier/prettier': 'error', + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/no-unused-vars': 'off', }, } ); diff --git a/wavefront/client/src/components/DashboardLayout.tsx b/wavefront/client/src/components/DashboardLayout.tsx index ba89056b..40d1700f 100644 --- a/wavefront/client/src/components/DashboardLayout.tsx +++ b/wavefront/client/src/components/DashboardLayout.tsx @@ -27,7 +27,7 @@ const DashboardLayout = ({ user, apps = [] }: { user: IUser; apps: App[] }) => { if (timeoutRef.current) { clearTimeout(timeoutRef.current); } - // @ts-ignore + // @ts-expect-error ts-expect error timeoutRef.current = setTimeout( () => { navigate('/logout'); diff --git a/wavefront/client/src/config/llm-providers.ts b/wavefront/client/src/config/llm-providers.ts index 028d4793..b670fad1 100644 --- a/wavefront/client/src/config/llm-providers.ts +++ b/wavefront/client/src/config/llm-providers.ts @@ -20,6 +20,7 @@ export interface ParameterConfig { export interface ProviderConfig { name: string; + baseUrl?: string; badge: { bg: string; text: string; @@ -36,6 +37,7 @@ export type InferenceEngineType = 'gemini' | 'openai' | 'ollama' | 'vllm' | 'ant export const LLM_PROVIDERS_CONFIG: Record = { openai: { name: 'OpenAI GPT', + baseUrl: 'https://api.openai.com/v1', badge: { bg: 'bg-green-100', text: 'text-green-800', @@ -117,6 +119,7 @@ export const LLM_PROVIDERS_CONFIG: Record = }, anthropic: { name: 'Anthropic Claude', + baseUrl: 'https://api.anthropic.com', badge: { bg: 'bg-orange-100', text: 'text-orange-800', @@ -162,6 +165,7 @@ export const LLM_PROVIDERS_CONFIG: Record = }, gemini: { name: 'Google Gemini', + baseUrl: 'https://generativelanguage.googleapis.com', badge: { bg: 'bg-blue-100', text: 'text-blue-800', @@ -279,6 +283,7 @@ export const LLM_PROVIDERS_CONFIG: Record = }, groq: { name: 'Groq', + baseUrl: 'https://api.groq.com/openai/v1', badge: { bg: 'bg-purple-100', text: 'text-purple-800', @@ -536,3 +541,11 @@ export function cleanParameters(params: Record): Record { // Prepare inputs based on what's provided // eslint-disable-next-line @typescript-eslint/no-explicit-any let inputs: string | any[]; - let finalTextInput = inferenceInput.trim(); + const finalTextInput = inferenceInput.trim(); // Handle different input combinations // eslint-disable-next-line @typescript-eslint/no-explicit-any const conversationInputs: any[] = []; diff --git a/wavefront/client/src/pages/apps/[appId]/datasources/[datasourceId].tsx b/wavefront/client/src/pages/apps/[appId]/datasources/[datasourceId].tsx index 5c75689c..25028938 100644 --- a/wavefront/client/src/pages/apps/[appId]/datasources/[datasourceId].tsx +++ b/wavefront/client/src/pages/apps/[appId]/datasources/[datasourceId].tsx @@ -117,8 +117,7 @@ const DatasourceDetail: React.FC = () => { if (!datasourceId) return; if (yamlContent) { const yamlResponse = validateDynamicQueryYaml(yamlContent); - if (yamlResponse.valid) { - } else { + if (!yamlResponse.valid) { notifyError(yamlResponse.error); return; } @@ -190,6 +189,7 @@ const DatasourceDetail: React.FC = () => { notifySuccess('Datasource deleted successfully'); navigate(`/apps/${appId}/datasources`); } catch (error) { + console.error('Error deleting datasource'); } finally { setDeleting(false); setShowDeleteConfirm(false); diff --git a/wavefront/client/src/pages/apps/[appId]/llm-inference/CreateLLMInferenceDialog.tsx b/wavefront/client/src/pages/apps/[appId]/llm-inference/CreateLLMInferenceDialog.tsx index 06d2404e..6d718ebb 100644 --- a/wavefront/client/src/pages/apps/[appId]/llm-inference/CreateLLMInferenceDialog.tsx +++ b/wavefront/client/src/pages/apps/[appId]/llm-inference/CreateLLMInferenceDialog.tsx @@ -22,7 +22,13 @@ import { import { Input } from '@app/components/ui/input'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@app/components/ui/select'; import { Slider } from '@app/components/ui/slider'; -import { cleanParameters, getProviderConfig, initializeParameters, ParameterConfig } from '@app/config/llm-providers'; +import { + cleanParameters, + getDefaultBaseUrl, + getProviderConfig, + initializeParameters, + ParameterConfig, +} from '@app/config/llm-providers'; import { useDashboardStore, useNotifyStore } from '@app/store'; import { InferenceEngineType } from '@app/types/llm-inference-config'; import { zodResolver } from '@hookform/resolvers/zod'; @@ -55,10 +61,10 @@ const BASE_URL_PLACEHOLDERS: Record = { ollama: 'http://localhost:11434', vllm: 'http://localhost:8000', azure_openai: 'https://your-resource.openai.azure.com', - openai: 'Base URL', - anthropic: 'Base URL', - gemini: 'Base URL', - groq: 'Base URL', + openai: 'https://api.openai.com/v1', + anthropic: 'https://api.anthropic.com', + gemini: 'https://generativelanguage.googleapis.com', + groq: 'https://api.groq.com/openai/v1', }; const createLLMInferenceSchema = z.object({ @@ -98,7 +104,7 @@ const CreateLLMInferenceDialog: React.FC = ({ llmModel: '', type: 'openai', apiKey: '', - baseUrl: '', + baseUrl: getDefaultBaseUrl('openai'), }, }); @@ -110,21 +116,26 @@ const CreateLLMInferenceDialog: React.FC = ({ setType(newType); const defaultParams = initializeParameters(newType); setParameters(defaultParams); + + // Set default base URL for the provider + const defaultBaseUrl = getDefaultBaseUrl(newType); + form.setValue('baseUrl', defaultBaseUrl); } - }, [watchedType, isOpen]); + }, [watchedType, isOpen, form]); // Reset form when dialog closes useEffect(() => { if (!isOpen) { + const defaultType = 'openai'; form.reset({ displayName: '', llmModel: '', - type: 'openai', + type: defaultType, apiKey: '', - baseUrl: '', + baseUrl: getDefaultBaseUrl(defaultType), }); - setType('openai'); - setParameters(initializeParameters('openai')); + setType(defaultType); + setParameters(initializeParameters(defaultType)); } }, [isOpen, form]); @@ -133,7 +144,7 @@ const CreateLLMInferenceDialog: React.FC = ({ }; const supportsBaseUrl = (engineType: InferenceEngineType) => { - return ['ollama', 'vllm', 'azure_openai'].includes(engineType); + return ['ollama', 'vllm', 'azure_openai', 'openai', 'anthropic', 'gemini', 'groq'].includes(engineType); }; const setParameter = (key: string, value: any) => { @@ -330,6 +341,10 @@ const CreateLLMInferenceDialog: React.FC = ({ const newType = value as InferenceEngineType; setType(newType); setParameters(initializeParameters(newType)); + + // Set default base URL for the provider + const defaultBaseUrl = getDefaultBaseUrl(newType); + form.setValue('baseUrl', defaultBaseUrl); }} value={field.value} > diff --git a/wavefront/client/src/pages/apps/[appId]/llm-inference/[configId].tsx b/wavefront/client/src/pages/apps/[appId]/llm-inference/[configId].tsx index 918a3245..f58a6628 100644 --- a/wavefront/client/src/pages/apps/[appId]/llm-inference/[configId].tsx +++ b/wavefront/client/src/pages/apps/[appId]/llm-inference/[configId].tsx @@ -14,7 +14,13 @@ import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from ' import { Input } from '@app/components/ui/input'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@app/components/ui/select'; import { Slider } from '@app/components/ui/slider'; -import { cleanParameters, getProviderConfig, mergeParameters, ParameterConfig } from '@app/config/llm-providers'; +import { + cleanParameters, + getDefaultBaseUrl, + getProviderConfig, + mergeParameters, + ParameterConfig, +} from '@app/config/llm-providers'; import { useGetLLMConfig } from '@app/hooks'; import { getLLMConfigKey, getLLMConfigsKey } from '@app/hooks/data/query-keys'; import { useNotifyStore } from '@app/store'; @@ -92,13 +98,19 @@ const LLMInferenceConfigDetail: React.FC = () => { } }, [config, form]); - // Update parameters when provider type changes in edit mode + // Update parameters and base URL when provider type changes in edit mode const watchedType = form.watch('type'); useEffect(() => { if (editing && config) { const mergedParams = mergeParameters(watchedType, watchedType === config.type ? config.parameters : null); setParameters(mergedParams); form.setValue('parameters', mergedParams); + + // Update base URL to the new provider's default when type changes + if (watchedType !== config.type) { + const defaultBaseUrl = getDefaultBaseUrl(watchedType); + form.setValue('base_url', defaultBaseUrl); + } } }, [watchedType, editing, config, form]); @@ -179,7 +191,7 @@ const LLMInferenceConfigDetail: React.FC = () => { }; const supportsBaseUrl = (engineType: InferenceEngineType) => { - return ['ollama', 'vllm', 'azure_openai'].includes(engineType); + return ['ollama', 'vllm', 'azure_openai', 'openai', 'anthropic', 'gemini', 'groq'].includes(engineType); }; return ( From 7e89835fe3298579e18df2bef3d1bcdda4e599dc Mon Sep 17 00:00:00 2001 From: rootflo-hardik Date: Sun, 14 Dec 2025 12:50:50 +0530 Subject: [PATCH 2/3] rag openai embeddings --- .../rag_ingestion/embeddings/embed.py | 11 +++++++--- .../controllers/knowledge_base_controller.py | 21 +++++++++---------- .../knowledge_base_module/embeddings/embed.py | 11 +++++++--- 3 files changed, 26 insertions(+), 17 deletions(-) diff --git a/wavefront/server/background_jobs/rag_ingestion/rag_ingestion/embeddings/embed.py b/wavefront/server/background_jobs/rag_ingestion/rag_ingestion/embeddings/embed.py index d6f43103..04909ac2 100644 --- a/wavefront/server/background_jobs/rag_ingestion/rag_ingestion/embeddings/embed.py +++ b/wavefront/server/background_jobs/rag_ingestion/rag_ingestion/embeddings/embed.py @@ -1,3 +1,4 @@ +import os from rag_ingestion.models.knowledge_base_embeddings import KnowledgeBaseEmbeddingObject import requests from rag_ingestion.env import EMBEDDING_SERVICE_URL @@ -7,7 +8,7 @@ class EmbeddingFunc: def __init__(self): self.max_batch_size = 32 - self.bgm_url = f'{EMBEDDING_SERVICE_URL}/v1/embeddings' + self.bgm_url = f'{EMBEDDING_SERVICE_URL}' logger.info(f'The embedding url is {EMBEDDING_SERVICE_URL}') def generate_document_embeddings(self, chunks): @@ -33,12 +34,16 @@ def generate_chunk_embeddings(self, chunks): return embeddings def bgm_embedding(self, texts): + openai_api_key = os.getenv('OPENAI_API_KEY') or '' response = requests.post( self.bgm_url, + headers={'Authorization': 'Bearer ' + openai_api_key}, json={ - 'model': 'BAAI/bge-m3', + # 'model': 'BAAI/bge-m3', + 'model': 'text-embedding-3-small', 'input': texts, 'encoding_format': 'float', }, ) - return response.json()['data'][0]['embedding'] + res = response.json() + return res['data'][0]['embedding'] diff --git a/wavefront/server/modules/knowledge_base_module/knowledge_base_module/controllers/knowledge_base_controller.py b/wavefront/server/modules/knowledge_base_module/knowledge_base_module/controllers/knowledge_base_controller.py index 276b1f12..e1facbe3 100644 --- a/wavefront/server/modules/knowledge_base_module/knowledge_base_module/controllers/knowledge_base_controller.py +++ b/wavefront/server/modules/knowledge_base_module/knowledge_base_module/controllers/knowledge_base_controller.py @@ -82,16 +82,17 @@ async def create_knowledge_base( ) -@knowledge_base_router.get( - '/v1/knowledge-bases/{kb_id}', response_model=KnowledgeBaseResponse -) +@knowledge_base_router.get('/v1/knowledge-bases/{kb_id}') @inject async def get_knowledge_bases_id( kb_id: uuid.UUID, + response_formatter: ResponseFormatter = Depends( + Provide[CommonContainer.response_formatter] + ), knowledge_base_repository: SQLAlchemyRepository[KnowledgeBase] = Depends( Provide[KnowledgeBaseContainer.knowledge_base_repository] ), -) -> KnowledgeBaseResponse: +) -> JSONResponse: """Get knowledge base by ID.""" fetch_knowledge_base_id = await knowledge_base_repository.find_one(id=kb_id) if not fetch_knowledge_base_id: @@ -100,13 +101,11 @@ async def get_knowledge_bases_id( detail="Knowledge Base with the mentioned id doesn't exist", ) - return KnowledgeBaseResponse( - id=fetch_knowledge_base_id.id, - name=fetch_knowledge_base_id.name, - description=fetch_knowledge_base_id.description, - type=fetch_knowledge_base_id.type, - created_at=fetch_knowledge_base_id.created_at, - updated_at=fetch_knowledge_base_id.updated_at, + return JSONResponse( + status_code=status.HTTP_200_OK, + content=response_formatter.buildSuccessResponse( + data=fetch_knowledge_base_id.to_dict() + ), ) diff --git a/wavefront/server/modules/knowledge_base_module/knowledge_base_module/embeddings/embed.py b/wavefront/server/modules/knowledge_base_module/knowledge_base_module/embeddings/embed.py index 13d4674d..8cefc352 100644 --- a/wavefront/server/modules/knowledge_base_module/knowledge_base_module/embeddings/embed.py +++ b/wavefront/server/modules/knowledge_base_module/knowledge_base_module/embeddings/embed.py @@ -1,3 +1,4 @@ +import os import requests from typing import List from dataclasses import dataclass @@ -13,7 +14,7 @@ class KnowledgeBaseEmbeddingObject: class EmbeddingFunc: def __init__(self, embedding_url): self.max_batch_size = 32 - self.bgm_url = f'{embedding_url}/v1/embeddings' + self.bgm_url = f'{embedding_url}' def generate_document_embeddings(self, chunks): contents = [v['content'] for v in chunks.values()] @@ -42,12 +43,16 @@ def generate_chunk_embeddings(self, chunks): return embeddings def bgm_embedding(self, texts): + openai_api_key = os.getenv('OPENAI_API_KEY') or '' response = requests.post( self.bgm_url, + headers={'Authorization': 'Bearer ' + openai_api_key}, json={ - 'model': 'BAAI/bge-m3', + # 'model': 'BAAI/bge-m3', + 'model': 'text-embedding-3-small', 'input': texts, 'encoding_format': 'float', }, ) - return response.json()['data'][0]['embedding'] + res = response.json() + return res['data'][0]['embedding'] From 3d676d92d447946cf7696aa3bc5ef252f7d6a125 Mon Sep 17 00:00:00 2001 From: vishnu r kumar Date: Mon, 15 Dec 2025 00:13:42 +0530 Subject: [PATCH 3/3] refactor: fix review comments --- wavefront/client/eslint.config.js | 2 -- .../client/src/components/DashboardLayout.tsx | 4 ++-- .../rag_ingestion/embeddings/embed.py | 14 +++++++++----- .../rag_ingestion/rag_ingestion/env.py | 2 ++ 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/wavefront/client/eslint.config.js b/wavefront/client/eslint.config.js index 14fa1db1..fa9de8ac 100644 --- a/wavefront/client/eslint.config.js +++ b/wavefront/client/eslint.config.js @@ -23,8 +23,6 @@ export default tseslint.config( ...reactHooks.configs.recommended.rules, 'react-refresh/only-export-components': ['warn', { allowConstantExport: true }], 'prettier/prettier': 'error', - '@typescript-eslint/no-explicit-any': 'off', - '@typescript-eslint/no-unused-vars': 'off', }, } ); diff --git a/wavefront/client/src/components/DashboardLayout.tsx b/wavefront/client/src/components/DashboardLayout.tsx index 40d1700f..e2c29921 100644 --- a/wavefront/client/src/components/DashboardLayout.tsx +++ b/wavefront/client/src/components/DashboardLayout.tsx @@ -14,7 +14,7 @@ interface IUser { const DashboardLayout = ({ user, apps = [] }: { user: IUser; apps: App[] }) => { const currentPath = useLocation(); const navigate = useNavigate(); - const timeoutRef = useRef(null); + const timeoutRef = useRef | null>(null); /* The Broadcast Channel API enables communication between different browser windows, tabs, iframes, and web workers. creating a channel with name 'timeout' @@ -27,7 +27,7 @@ const DashboardLayout = ({ user, apps = [] }: { user: IUser; apps: App[] }) => { if (timeoutRef.current) { clearTimeout(timeoutRef.current); } - // @ts-expect-error ts-expect error + timeoutRef.current = setTimeout( () => { navigate('/logout'); diff --git a/wavefront/server/background_jobs/rag_ingestion/rag_ingestion/embeddings/embed.py b/wavefront/server/background_jobs/rag_ingestion/rag_ingestion/embeddings/embed.py index 04909ac2..4ec90e0a 100644 --- a/wavefront/server/background_jobs/rag_ingestion/rag_ingestion/embeddings/embed.py +++ b/wavefront/server/background_jobs/rag_ingestion/rag_ingestion/embeddings/embed.py @@ -1,8 +1,8 @@ -import os from rag_ingestion.models.knowledge_base_embeddings import KnowledgeBaseEmbeddingObject import requests from rag_ingestion.env import EMBEDDING_SERVICE_URL from flo_utils.utils.log import logger +from rag_ingestion.env import OPENAI_API_KEY, EMBEDDING_MODEL class EmbeddingFunc: @@ -34,16 +34,20 @@ def generate_chunk_embeddings(self, chunks): return embeddings def bgm_embedding(self, texts): - openai_api_key = os.getenv('OPENAI_API_KEY') or '' + headers = { + 'Authorization': f'Bearer {OPENAI_API_KEY}', + } + response = requests.post( self.bgm_url, - headers={'Authorization': 'Bearer ' + openai_api_key}, + headers=headers if EMBEDDING_MODEL == 'text-embedding-3-small' else None, json={ - # 'model': 'BAAI/bge-m3', - 'model': 'text-embedding-3-small', + 'model': EMBEDDING_MODEL, 'input': texts, 'encoding_format': 'float', }, + timeout=60, ) + response.raise_for_status() res = response.json() return res['data'][0]['embedding'] diff --git a/wavefront/server/background_jobs/rag_ingestion/rag_ingestion/env.py b/wavefront/server/background_jobs/rag_ingestion/rag_ingestion/env.py index 415327f4..6de4001d 100644 --- a/wavefront/server/background_jobs/rag_ingestion/rag_ingestion/env.py +++ b/wavefront/server/background_jobs/rag_ingestion/rag_ingestion/env.py @@ -5,7 +5,9 @@ CLOUD_PROVIDER = os.getenv('CLOUD_PROVIDER', 'gcp') RETRY_COUNT = os.getenv('RETRY_COUNT', 3) +OPENAI_API_KEY = os.getenv('OPENAI_API_KEY') EMBEDDING_SERVICE_URL = os.getenv('EMBEDDING_SERVICE_URL') FLOWARE_SERVICE_URL = os.getenv('FLOWARE_SERVICE_URL') APP_ENV = os.getenv('APP_ENV', 'dev') PASSTHROUGH_SECRET = os.getenv('PASSTHROUGH_SECRET') +EMBEDDING_MODEL = os.getenv('EMBEDDING_MODEL', 'text-embedding-3-small')