fix more issues with output cell mutation
This commit is contained in:
@@ -5,7 +5,7 @@ import { useExperiment, useHandledAsyncCallback } from "~/utils/hooks";
|
|||||||
import SyntaxHighlighter from "react-syntax-highlighter";
|
import SyntaxHighlighter from "react-syntax-highlighter";
|
||||||
import { docco } from "react-syntax-highlighter/dist/cjs/styles/hljs";
|
import { docco } from "react-syntax-highlighter/dist/cjs/styles/hljs";
|
||||||
import stringify from "json-stringify-pretty-compact";
|
import stringify from "json-stringify-pretty-compact";
|
||||||
import { useMemo, type ReactElement, useState, useEffect } from "react";
|
import { type ReactElement, useState, useEffect, useRef } from "react";
|
||||||
import { BsCheck, BsClock, BsX, BsCurrencyDollar } from "react-icons/bs";
|
import { BsCheck, BsClock, BsX, BsCurrencyDollar } from "react-icons/bs";
|
||||||
import { type ModelOutput } from "@prisma/client";
|
import { type ModelOutput } from "@prisma/client";
|
||||||
import { type ChatCompletion } from "openai/resources/chat";
|
import { type ChatCompletion } from "openai/resources/chat";
|
||||||
@@ -43,23 +43,26 @@ export default function OutputCell({
|
|||||||
|
|
||||||
const model = getModelName(variant.config as JSONSerializable);
|
const model = getModelName(variant.config as JSONSerializable);
|
||||||
|
|
||||||
const shouldStream =
|
|
||||||
isObject(variant) &&
|
|
||||||
"config" in variant &&
|
|
||||||
isObject(variant.config) &&
|
|
||||||
"stream" in variant.config &&
|
|
||||||
variant.config.stream === true;
|
|
||||||
const channel = useMemo(() => {
|
|
||||||
if (!shouldStream) return;
|
|
||||||
return generateChannel();
|
|
||||||
}, [shouldStream]);
|
|
||||||
|
|
||||||
const outputMutation = api.outputs.get.useMutation();
|
const outputMutation = api.outputs.get.useMutation();
|
||||||
|
|
||||||
const [output, setOutput] = useState<RouterOutputs["outputs"]["get"]>(null);
|
const [output, setOutput] = useState<RouterOutputs["outputs"]["get"]>(null);
|
||||||
|
const [channel, setChannel] = useState<string | undefined>(undefined);
|
||||||
|
const fetchMutex = useRef(false);
|
||||||
const [fetchOutput, fetchingOutput] = useHandledAsyncCallback(async () => {
|
const [fetchOutput, fetchingOutput] = useHandledAsyncCallback(async () => {
|
||||||
|
if (fetchMutex.current) return;
|
||||||
|
fetchMutex.current = true;
|
||||||
setOutput(null);
|
setOutput(null);
|
||||||
|
|
||||||
|
const shouldStream =
|
||||||
|
isObject(variant) &&
|
||||||
|
"config" in variant &&
|
||||||
|
isObject(variant.config) &&
|
||||||
|
"stream" in variant.config &&
|
||||||
|
variant.config.stream === true;
|
||||||
|
|
||||||
|
const channel = shouldStream ? generateChannel() : undefined;
|
||||||
|
setChannel(channel);
|
||||||
|
|
||||||
const output = await outputMutation.mutateAsync({
|
const output = await outputMutation.mutateAsync({
|
||||||
scenarioId: scenario.id,
|
scenarioId: scenario.id,
|
||||||
variantId: variant.id,
|
variantId: variant.id,
|
||||||
@@ -67,9 +70,10 @@ export default function OutputCell({
|
|||||||
});
|
});
|
||||||
setOutput(output);
|
setOutput(output);
|
||||||
await utils.promptVariants.stats.invalidate();
|
await utils.promptVariants.stats.invalidate();
|
||||||
}, [outputMutation, scenario.id, variant.id, channel]);
|
fetchMutex.current = false;
|
||||||
|
}, [outputMutation, scenario.id, variant.id]);
|
||||||
|
|
||||||
useEffect(fetchOutput, [scenario.id, variant.id, channel]);
|
useEffect(fetchOutput, [scenario.id, variant.id]);
|
||||||
|
|
||||||
// Disconnect from socket if we're not streaming anymore
|
// Disconnect from socket if we're not streaming anymore
|
||||||
const streamedMessage = useSocket(fetchingOutput ? channel : undefined);
|
const streamedMessage = useSocket(fetchingOutput ? channel : undefined);
|
||||||
|
|||||||
@@ -18,11 +18,11 @@ export function useHandledAsyncCallback<T extends unknown[], U>(
|
|||||||
callback: AsyncFunction<T, U>,
|
callback: AsyncFunction<T, U>,
|
||||||
deps: React.DependencyList
|
deps: React.DependencyList
|
||||||
) {
|
) {
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(0);
|
||||||
const [error, setError] = useState<Error | null>(null);
|
const [error, setError] = useState<Error | null>(null);
|
||||||
|
|
||||||
const wrappedCallback = useCallback((...args: T) => {
|
const wrappedCallback = useCallback((...args: T) => {
|
||||||
setLoading(true);
|
setLoading((loading) => loading + 1);
|
||||||
setError(null);
|
setError(null);
|
||||||
|
|
||||||
callback(...args)
|
callback(...args)
|
||||||
@@ -31,13 +31,13 @@ export function useHandledAsyncCallback<T extends unknown[], U>(
|
|||||||
console.error(error);
|
console.error(error);
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
setLoading(false);
|
setLoading((loading) => loading - 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, deps);
|
}, deps);
|
||||||
|
|
||||||
return [wrappedCallback, loading, error] as const;
|
return [wrappedCallback, loading > 0, error] as const;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Have to do this ugly thing to convince Next not to try to access `navigator`
|
// Have to do this ugly thing to convince Next not to try to access `navigator`
|
||||||
|
|||||||
Reference in New Issue
Block a user