瀏覽代碼

feat: valves full integration

Timothy J. Baek 11 月之前
父節點
當前提交
2d596d7307

+ 44 - 9
backend/main.py

@@ -477,6 +477,7 @@ async def get_pipeline_valves(pipeline_id: str, user=Depends(get_admin_user)):
     if pipeline_id in app.state.MODELS and "pipeline" in app.state.MODELS[pipeline_id]:
         pipeline = app.state.MODELS[pipeline_id]
 
+        r = None
         try:
             urlIdx = pipeline["urlIdx"]
 
@@ -495,12 +496,23 @@ async def get_pipeline_valves(pipeline_id: str, user=Depends(get_admin_user)):
             # Handle connection error here
             print(f"Connection error: {e}")
 
+            detail = "Pipeline not found"
+
+            if r is not None:
+                try:
+                    res = r.json()
+                    if "detail" in res:
+                        detail = res["detail"]
+                except:
+                    pass
+
             raise HTTPException(
-                status_code=status.HTTP_404_NOT_FOUND,
-                detail="Pipeline not found",
+                status_code=(
+                    r.status_code if r is not None else status.HTTP_404_NOT_FOUND
+                ),
+                detail=detail,
             )
 
-        return {"data": pipeline["pipeline"]["valves"]}
     else:
         raise HTTPException(
             status_code=status.HTTP_404_NOT_FOUND,
@@ -514,6 +526,7 @@ async def get_pipeline_valves_spec(pipeline_id: str, user=Depends(get_admin_user
     if pipeline_id in app.state.MODELS and "pipeline" in app.state.MODELS[pipeline_id]:
         pipeline = app.state.MODELS[pipeline_id]
 
+        r = None
         try:
             urlIdx = pipeline["urlIdx"]
 
@@ -532,12 +545,21 @@ async def get_pipeline_valves_spec(pipeline_id: str, user=Depends(get_admin_user
             # Handle connection error here
             print(f"Connection error: {e}")
 
+            detail = "Pipeline not found"
+            if r is not None:
+                try:
+                    res = r.json()
+                    if "detail" in res:
+                        detail = res["detail"]
+                except:
+                    pass
+
             raise HTTPException(
-                status_code=status.HTTP_404_NOT_FOUND,
-                detail="Pipeline not found",
+                status_code=(
+                    r.status_code if r is not None else status.HTTP_404_NOT_FOUND
+                ),
+                detail=detail,
             )
-
-        return {"data": pipeline["pipeline"]["valves"]}
     else:
         raise HTTPException(
             status_code=status.HTTP_404_NOT_FOUND,
@@ -554,6 +576,7 @@ async def update_pipeline_valves(
     if pipeline_id in app.state.MODELS and "pipeline" in app.state.MODELS[pipeline_id]:
         pipeline = app.state.MODELS[pipeline_id]
 
+        r = None
         try:
             urlIdx = pipeline["urlIdx"]
 
@@ -576,9 +599,21 @@ async def update_pipeline_valves(
             # Handle connection error here
             print(f"Connection error: {e}")
 
+            detail = "Pipeline not found"
+
+            if r is not None:
+                try:
+                    res = r.json()
+                    if "detail" in res:
+                        detail = res["detail"]
+                except:
+                    pass
+
             raise HTTPException(
-                status_code=status.HTTP_404_NOT_FOUND,
-                detail="Pipeline not found",
+                status_code=(
+                    r.status_code if r is not None else status.HTTP_404_NOT_FOUND
+                ),
+                detail=detail,
             )
     else:
         raise HTTPException(

+ 6 - 1
src/lib/apis/index.ts

@@ -156,7 +156,12 @@ export const updatePipelineValves = async (
 		})
 		.catch((err) => {
 			console.log(err);
-			error = err;
+
+			if ('detail' in err) {
+				error = err.detail;
+			} else {
+				error = err;
+			}
 			return null;
 		});
 

+ 87 - 20
src/lib/components/admin/Settings/Pipelines.svelte

@@ -1,43 +1,63 @@
 <script lang="ts">
 	import { v4 as uuidv4 } from 'uuid';
 
-	import { getContext, onMount } from 'svelte';
+	import { getContext, onMount, tick } from 'svelte';
 
 	import type { Writable } from 'svelte/store';
 	import type { i18n as i18nType } from 'i18next';
 	import { stringify } from 'postcss';
-	import { getPipelineValves, getPipelines } from '$lib/apis';
+	import {
+		getPipelineValves,
+		getPipelineValvesSpec,
+		updatePipelineValves,
+		getPipelines
+	} from '$lib/apis';
 	import Spinner from '$lib/components/common/Spinner.svelte';
+	import { toast } from 'svelte-sonner';
 
 	const i18n: Writable<i18nType> = getContext('i18n');
 
 	export let saveHandler: Function;
 
 	let pipelines = null;
+
 	let valves = null;
+	let valves_spec = null;
+
+	let selectedPipelineIdx = null;
+
+	const updateHandler = async () => {
+		const pipeline = pipelines[selectedPipelineIdx];
 
-	let selectedPipelineIdx = 0;
+		if (pipeline && (pipeline?.pipeline?.valves ?? false)) {
+			const res = await updatePipelineValves(localStorage.token, pipeline.id, valves).catch(
+				(error) => {
+					toast.error(error);
+				}
+			);
 
-	$: if (
-		pipelines !== null &&
-		pipelines.length > 0 &&
-		pipelines[selectedPipelineIdx] !== undefined &&
-		pipelines[selectedPipelineIdx].pipeline.valves
-	) {
-		(async () => {
-			valves = await getPipelineValves(localStorage.token, pipelines[selectedPipelineIdx].id);
-		})();
-	}
+			if (res) {
+				toast.success('Valves updated successfully');
+				saveHandler();
+			}
+		} else {
+			toast.error('No valves to update');
+		}
+	};
 
 	onMount(async () => {
 		pipelines = await getPipelines(localStorage.token);
+
+		if (pipelines.length > 0) {
+			selectedPipelineIdx = 0;
+		}
 	});
 </script>
 
 <form
 	class="flex flex-col h-full justify-between space-y-3 text-sm"
 	on:submit|preventDefault={async () => {
-		saveHandler();
+		updateHandler();
 	}}
 >
 	<div class=" space-y-2 pr-1.5 overflow-y-scroll max-h-80 h-full">
@@ -47,17 +67,30 @@
 					{$i18n.t('Pipelines')}
 				</div>
 			</div>
-			<div class="space-y-2">
+			<div class="space-y-1">
 				{#if pipelines.length > 0}
 					<div class="flex gap-2">
 						<div class="flex-1 pb-1">
 							<select
 								class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
 								bind:value={selectedPipelineIdx}
-								placeholder={$i18n.t('Select an Ollama instance')}
+								placeholder={$i18n.t('Select a pipeline')}
+								on:change={async () => {
+									await tick();
+									valves_spec = await getPipelineValvesSpec(
+										localStorage.token,
+										pipelines[selectedPipelineIdx].id
+									);
+									valves = await getPipelineValves(
+										localStorage.token,
+										pipelines[selectedPipelineIdx].id
+									);
+								}}
 							>
 								{#each pipelines as pipeline, idx}
-									<option value={idx} class="bg-gray-100 dark:bg-gray-700">{pipeline.name}</option>
+									<option value={idx} class="bg-gray-100 dark:bg-gray-700"
+										>{pipeline.name} ({pipeline.pipeline.type ?? 'pipe'})</option
+									>
 								{/each}
 							</select>
 						</div>
@@ -66,11 +99,45 @@
 
 				<div class="text-sm font-medium">{$i18n.t('Valves')}</div>
 
-				<div class="space-y-2">
+				<div class="space-y-1">
 					{#if pipelines[selectedPipelineIdx].pipeline.valves}
 						{#if valves}
-							{#each Object.keys(valves) as valve, idx}
-								<div>{valve}</div>
+							{#each Object.keys(valves_spec.properties) as property, idx}
+								<div class=" py-0.5 w-full justify-between">
+									<div class="flex w-full justify-between">
+										<div class=" self-center text-xs font-medium">
+											{valves_spec.properties[property].title}
+										</div>
+
+										<button
+											class="p-1 px-3 text-xs flex rounded transition"
+											type="button"
+											on:click={() => {
+												valves[property] = (valves[property] ?? null) === null ? '' : null;
+											}}
+										>
+											{#if (valves[property] ?? null) === null}
+												<span class="ml-2 self-center"> {$i18n.t('None')} </span>
+											{:else}
+												<span class="ml-2 self-center"> {$i18n.t('Custom')} </span>
+											{/if}
+										</button>
+									</div>
+
+									{#if (valves[property] ?? null) !== null}
+										<div class="flex mt-0.5 space-x-2">
+											<div class=" flex-1">
+												<input
+													class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
+													type="text"
+													placeholder={valves_spec.properties[property].title}
+													bind:value={valves[property]}
+													autocomplete="off"
+												/>
+											</div>
+										</div>
+									{/if}
+								</div>
 							{/each}
 						{:else}
 							<Spinner className="size-5" />

+ 0 - 5
src/lib/components/admin/SettingsModal.svelte

@@ -185,35 +185,30 @@
 				{#if selectedTab === 'general'}
 					<General
 						saveHandler={() => {
-							show = false;
 							toast.success($i18n.t('Settings saved successfully!'));
 						}}
 					/>
 				{:else if selectedTab === 'users'}
 					<Users
 						saveHandler={() => {
-							show = false;
 							toast.success($i18n.t('Settings saved successfully!'));
 						}}
 					/>
 				{:else if selectedTab === 'db'}
 					<Database
 						saveHandler={() => {
-							show = false;
 							toast.success($i18n.t('Settings saved successfully!'));
 						}}
 					/>
 				{:else if selectedTab === 'banners'}
 					<Banners
 						saveHandler={() => {
-							show = false;
 							toast.success($i18n.t('Settings saved successfully!'));
 						}}
 					/>
 				{:else if selectedTab === 'pipelines'}
 					<Pipelines
 						saveHandler={() => {
-							show = false;
 							toast.success($i18n.t('Settings saved successfully!'));
 						}}
 					/>