diff --git a/surfsense_backend/alembic/versions/fd3f2e543873_add_litellm_params_to_searchspaces.py b/surfsense_backend/alembic/versions/fd3f2e543873_add_litellm_params_to_searchspaces.py new file mode 100644 index 000000000..1758f7602 --- /dev/null +++ b/surfsense_backend/alembic/versions/fd3f2e543873_add_litellm_params_to_searchspaces.py @@ -0,0 +1,40 @@ +"""add litellm_params to searchspaces + +Revision ID: fd3f2e543873 +Revises: eb0c978da8fd +Create Date: 2025-10-07 04:11:50.392338 + +""" +from typing import Sequence, Union + +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects import postgresql + +# revision identifiers, used by Alembic. +revision: str = 'fd3f2e543873' +down_revision: Union[str, None] = 'eb0c978da8fd' +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + """Upgrade schema.""" + # ### commands auto generated by Alembic - please adjust! ### + op.drop_index(op.f('chucks_search_index'), table_name='chunks', postgresql_using='gin') + op.drop_index(op.f('chucks_vector_index'), table_name='chunks', postgresql_using='hnsw') + op.drop_index(op.f('document_search_index'), table_name='documents', postgresql_using='gin') + op.drop_index(op.f('document_vector_index'), table_name='documents', postgresql_using='hnsw') + op.drop_column('searchspaces', 'inference_params') + # ### end Alembic commands ### + + +def downgrade() -> None: + """Downgrade schema.""" + # ### commands auto generated by Alembic - please adjust! ### + op.add_column('searchspaces', sa.Column('inference_params', postgresql.JSON(astext_type=sa.Text()), autoincrement=False, nullable=True)) + op.create_index(op.f('document_vector_index'), 'documents', ['embedding'], unique=False, postgresql_using='hnsw') + op.create_index(op.f('document_search_index'), 'documents', [sa.literal_column("to_tsvector('english'::regconfig, content)")], unique=False, postgresql_using='gin') + op.create_index(op.f('chucks_vector_index'), 'chunks', ['embedding'], unique=False, postgresql_using='hnsw') + op.create_index(op.f('chucks_search_index'), 'chunks', [sa.literal_column("to_tsvector('english'::regconfig, content)")], unique=False, postgresql_using='gin') + # ### end Alembic commands ### diff --git a/surfsense_web/components/inference-params-editor.tsx b/surfsense_web/components/inference-params-editor.tsx new file mode 100644 index 000000000..df198cfa0 --- /dev/null +++ b/surfsense_web/components/inference-params-editor.tsx @@ -0,0 +1,138 @@ +"use client"; + +import { useState } from "react"; +import { Plus, Trash2 } from "lucide-react"; +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; + +interface InferenceParamsEditorProps { + params: Record; + setParams: (newParams: Record) => void; +} + +const PARAM_KEYS = ["temperature", "max_tokens", "top_k", "top_p"] as const; + +export default function InferenceParamsEditor({ + params, + setParams, +}: InferenceParamsEditorProps) { + const [selectedKey, setSelectedKey] = useState(""); + const [value, setValue] = useState(""); + + const handleAdd = () => { + if (!selectedKey || value === "") return; + + if (params[selectedKey]) { + alert(`${selectedKey} already exists`); + return; + } + + const numericValue = Number(value); + + if ((selectedKey === "temperature" || selectedKey === "top_p") && (isNaN(numericValue) || numericValue < 0 || numericValue > 1)) { + alert("Value must be a number between 0 and 1"); + return; + } + + if ((selectedKey === "max_tokens" || selectedKey === "top_k") && (!Number.isInteger(numericValue) || numericValue < 0)) { + alert("Value must be a non-negative integer"); + return; + } + + setParams({ + ...params, + [selectedKey]: isNaN(numericValue) ? value : numericValue, + }); + + setSelectedKey(""); + setValue(""); + }; + + const handleDelete = (key: string) => { + const newParams = { ...params }; + delete newParams[key]; + setParams(newParams); + }; + + return ( +
+
+
+ + +
+ +
+ + setValue(e.target.value)} + className="w-full" + /> +
+ + +
+ +
+ + {Object.keys(params).length > 0 && ( +
+ + + + + + + + + + {Object.entries(params).map(([key, val]) => ( + + + + + + ))} + +
KeyValueActions
{key}{val.toString()} + +
+
+ )} +
+ ); +} diff --git a/surfsense_web/components/onboard/add-provider-step.tsx b/surfsense_web/components/onboard/add-provider-step.tsx index 62f5bc3b1..f582000a3 100644 --- a/surfsense_web/components/onboard/add-provider-step.tsx +++ b/surfsense_web/components/onboard/add-provider-step.tsx @@ -20,6 +20,8 @@ import { import { LLM_PROVIDERS } from "@/contracts/enums/llm-providers"; import { type CreateLLMConfig, useLLMConfigs } from "@/hooks/use-llm-configs"; +import InferenceParamsEditor from "../inference-params-editor"; + interface AddProviderStepProps { onConfigCreated?: () => void; onConfigDeleted?: () => void; @@ -72,6 +74,10 @@ export function AddProviderStep({ onConfigCreated, onConfigDeleted }: AddProvide const selectedProvider = LLM_PROVIDERS.find((p) => p.value === formData.provider); + const handleParamsChange = (newParams: Record) => { + setFormData((prev) => ({ ...prev, litellm_params: newParams })); + }; + return (
{/* Info Alert */} @@ -239,6 +245,15 @@ export function AddProviderStep({ onConfigCreated, onConfigDeleted }: AddProvide />
+ {/* Optional Inference Parameters */} +
+ +
+ +
+ {/* Optional Inference Parameters */} +
+ + setFormData((prev) => ({ ...prev, litellm_params: newParams })) + } + /> +
+