From 97448262cb4e6ebab151bbdcfd26e569ce5120b5 Mon Sep 17 00:00:00 2001 From: ogzhanolguncu Date: Wed, 15 Jan 2025 18:52:57 +0300 Subject: [PATCH] fix: duplicate filter when querying openai --- .../controls/components/logs-search/index.tsx | 21 ++++++-- .../app/(app)/logs-v2/filters.schema.ts | 49 +++++++++++++++++++ .../lib/trpc/routers/logs/llm-search.ts | 40 +-------------- 3 files changed, 68 insertions(+), 42 deletions(-) diff --git a/apps/dashboard/app/(app)/logs-v2/components/controls/components/logs-search/index.tsx b/apps/dashboard/app/(app)/logs-v2/components/controls/components/logs-search/index.tsx index bb571d3d7..0c7d4b52b 100644 --- a/apps/dashboard/app/(app)/logs-v2/components/controls/components/logs-search/index.tsx +++ b/apps/dashboard/app/(app)/logs-v2/components/controls/components/logs-search/index.tsx @@ -1,15 +1,30 @@ +import { transformStructuredOutputToFilters } from "@/app/(app)/logs-v2/filters.schema"; +import { useFilters } from "@/app/(app)/logs-v2/hooks/use-filters"; import { useKeyboardShortcut } from "@/app/(app)/logs-v2/hooks/use-keyboard-shortcut"; import { toast } from "@/components/ui/toaster"; import { trpc } from "@/lib/trpc/client"; +import { cn } from "@/lib/utils"; import { CaretRightOutline, CircleInfoSparkle, Magnifier, Refresh3 } from "@unkey/icons"; -import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@unkey/ui"; -import { cn } from "@unkey/ui/src/lib/utils"; +import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "components/ui/tooltip"; import { useRef, useState } from "react"; export const LogsSearch = () => { + const { filters, updateFilters } = useFilters(); const queryLLMForStructuredOutput = trpc.logs.llmSearch.useMutation({ onSuccess(data) { - console.info("OUTPUT", data); + if (data) { + const transformedFilters = transformStructuredOutputToFilters(data, filters); + updateFilters(transformedFilters); + } else { + toast.error("Try to be more descriptive about your query", { + duration: 8000, + important: true, + position: "top-right", + style: { + whiteSpace: "pre-line", + }, + }); + } }, onError(error) { toast.error(error.message, { diff --git a/apps/dashboard/app/(app)/logs-v2/filters.schema.ts b/apps/dashboard/app/(app)/logs-v2/filters.schema.ts index 845f04527..eea5633f1 100644 --- a/apps/dashboard/app/(app)/logs-v2/filters.schema.ts +++ b/apps/dashboard/app/(app)/logs-v2/filters.schema.ts @@ -4,6 +4,7 @@ import type { FieldConfig, FilterField, FilterFieldConfigs, + FilterValue, HttpMethod, NumberConfig, StatusConfig, @@ -52,6 +53,54 @@ export const filterOutputSchema = z.object({ ), }); +// Required for transforming OpenAI structured outputs into our own Filter types +export const transformStructuredOutputToFilters = ( + data: z.infer, + existingFilters: FilterValue[] = [], +): FilterValue[] => { + const uniqueFilters = [...existingFilters]; + const seenFilters = new Set(existingFilters.map((f) => `${f.field}-${f.operator}-${f.value}`)); + + for (const filterGroup of data.filters) { + filterGroup.filters.forEach((filter) => { + const baseFilter = { + field: filterGroup.field, + operator: filter.operator, + value: filter.value, + }; + + const filterKey = `${baseFilter.field}-${baseFilter.operator}-${baseFilter.value}`; + + if (seenFilters.has(filterKey)) { + return; + } + + if (filterGroup.field === "status") { + const numericValue = + typeof filter.value === "string" ? Number.parseInt(filter.value) : filter.value; + + uniqueFilters.push({ + id: crypto.randomUUID(), + ...baseFilter, + value: numericValue, + metadata: { + colorClass: filterFieldConfig.status.getColorClass?.(numericValue), + }, + }); + } else { + uniqueFilters.push({ + id: crypto.randomUUID(), + ...baseFilter, + }); + } + + seenFilters.add(filterKey); + }); + } + + return uniqueFilters; +}; + // Type guard for config types function isStatusConfig(config: FieldConfig): config is StatusConfig { return "validate" in config && config.type === "number"; diff --git a/apps/dashboard/lib/trpc/routers/logs/llm-search.ts b/apps/dashboard/lib/trpc/routers/logs/llm-search.ts index 1207b6641..cdc5168d7 100644 --- a/apps/dashboard/lib/trpc/routers/logs/llm-search.ts +++ b/apps/dashboard/lib/trpc/routers/logs/llm-search.ts @@ -1,6 +1,5 @@ import { METHODS } from "@/app/(app)/logs-v2/constants"; import { filterFieldConfig, filterOutputSchema } from "@/app/(app)/logs-v2/filters.schema"; -import type { QuerySearchParams } from "@/app/(app)/logs-v2/filters.type"; import { db } from "@/lib/db"; import { env } from "@/lib/env"; import { rateLimitedProcedure, ratelimit } from "@/lib/trpc/ratelimitProcedure"; @@ -55,7 +54,7 @@ async function getStructuredSearchFromLLM(userSearchMsg: string) { }); } - return transformFiltersToQuerySearchParams(completion.choices[0].message.parsed); + return completion.choices[0].message.parsed; } catch (error) { console.error( `Something went wrong when querying OpenAI. Input: ${JSON.stringify( @@ -108,43 +107,6 @@ export const llmSearch = rateLimitedProcedure(ratelimit.update) }); // HELPERS -function transformFiltersToQuerySearchParams( - result: z.infer, -): QuerySearchParams { - const output: QuerySearchParams = { - host: null, - requestId: null, - methods: null, - paths: null, - status: null, - }; - - for (const filter of result.filters) { - const filterValues = filter.filters.map((f) => ({ - operator: f.operator, - value: f.value, - })); - - switch (filter.field) { - case "host": - case "requestId": - if (filter.filters.length > 0) { - output[filter.field] = filterValues[0]; - } - break; - - case "methods": - case "paths": - case "status": - if (filter.filters.length > 0) { - output[filter.field] = filterValues; - } - break; - } - } - - return output; -} const getSystemPrompt = () => { const operatorsByField = Object.entries(filterFieldConfig)