mirror of
https://github.com/dograh-hq/dograh.git
synced 2026-06-13 08:15:21 +02:00
fix: fix review comments
This commit is contained in:
parent
dfee942f9a
commit
c7e0d06a2b
13 changed files with 477 additions and 253 deletions
|
|
@ -78,6 +78,8 @@ export function useTextChatSession({
|
|||
setSession(toTextChatSession(response.data));
|
||||
setDraft("");
|
||||
} catch (error) {
|
||||
setSession(null);
|
||||
setStarted(false);
|
||||
toast.error(getErrorMessage(error));
|
||||
} finally {
|
||||
setCreatingSession(false);
|
||||
|
|
|
|||
|
|
@ -1,186 +0,0 @@
|
|||
import { Loader2 } from "lucide-react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
import { getWorkflowRunApiV1WorkflowWorkflowIdRunsRunIdGet } from "@/client/sdk.gen";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { ConversationRailFrame, RealtimeFeedback } from "@/components/workflow/conversation";
|
||||
import { useAuth } from "@/lib/auth";
|
||||
|
||||
import {
|
||||
ApiKeyErrorDialog,
|
||||
AudioControls,
|
||||
ConnectionStatus,
|
||||
WorkflowConfigErrorDialog
|
||||
} from "./components";
|
||||
import { useWebSocketRTC } from "./hooks";
|
||||
|
||||
const RUN_SHELL_HEIGHT_CLASS = "h-[calc(100svh-49px)] min-h-[calc(100svh-49px)] max-h-[calc(100svh-49px)]";
|
||||
|
||||
const BrowserCall = ({ workflowId, workflowRunId, initialContextVariables }: {
|
||||
workflowId: number,
|
||||
workflowRunId: number,
|
||||
initialContextVariables?: Record<string, string> | null
|
||||
}) => {
|
||||
const router = useRouter();
|
||||
const auth = useAuth();
|
||||
const [accessToken, setAccessToken] = useState<string | null>(null);
|
||||
const [checkingForRecording, setCheckingForRecording] = useState(false);
|
||||
|
||||
// Get access token for WebSocket connection (non-SDK usage)
|
||||
useEffect(() => {
|
||||
if (auth.isAuthenticated && !auth.loading) {
|
||||
auth.getAccessToken().then(setAccessToken);
|
||||
}
|
||||
}, [auth]);
|
||||
|
||||
const {
|
||||
audioRef,
|
||||
audioInputs,
|
||||
selectedAudioInput,
|
||||
setSelectedAudioInput,
|
||||
connectionActive,
|
||||
permissionError,
|
||||
isCompleted,
|
||||
apiKeyModalOpen,
|
||||
setApiKeyModalOpen,
|
||||
apiKeyError,
|
||||
apiKeyErrorCode,
|
||||
workflowConfigError,
|
||||
workflowConfigModalOpen,
|
||||
setWorkflowConfigModalOpen,
|
||||
connectionStatus,
|
||||
start,
|
||||
stop,
|
||||
isStarting,
|
||||
getAudioInputDevices,
|
||||
feedbackMessages,
|
||||
} = useWebSocketRTC({ workflowId, workflowRunId, accessToken, initialContextVariables });
|
||||
|
||||
// Poll for recording availability after call ends
|
||||
useEffect(() => {
|
||||
if (!isCompleted || !auth.isAuthenticated) return;
|
||||
|
||||
setCheckingForRecording(true);
|
||||
const intervalId = setInterval(async () => {
|
||||
try {
|
||||
const response = await getWorkflowRunApiV1WorkflowWorkflowIdRunsRunIdGet({
|
||||
path: {
|
||||
workflow_id: workflowId,
|
||||
run_id: workflowRunId,
|
||||
},
|
||||
});
|
||||
|
||||
if (response.data?.transcript_url || response.data?.recording_url) {
|
||||
setCheckingForRecording(false);
|
||||
clearInterval(intervalId);
|
||||
// Refresh the page to show the recording
|
||||
window.location.reload();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error checking for recording:', error);
|
||||
}
|
||||
}, 5000); // Check every 5 seconds
|
||||
|
||||
// Clean up after 2 minutes
|
||||
const timeoutId = setTimeout(() => {
|
||||
clearInterval(intervalId);
|
||||
setCheckingForRecording(false);
|
||||
}, 120000);
|
||||
|
||||
return () => {
|
||||
clearInterval(intervalId);
|
||||
clearTimeout(timeoutId);
|
||||
};
|
||||
}, [isCompleted, auth.isAuthenticated, workflowId, workflowRunId]);
|
||||
|
||||
const navigateToCredits = () => {
|
||||
router.push('/api-keys');
|
||||
};
|
||||
|
||||
const navigateToModelConfig = () => {
|
||||
router.push('/model-configurations');
|
||||
};
|
||||
|
||||
const navigateToWorkflow = () => {
|
||||
router.push(`/workflow/${workflowId}`)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={`flex ${RUN_SHELL_HEIGHT_CLASS} min-h-0 w-full overflow-hidden bg-background`}>
|
||||
<div className="min-w-0 flex-1 overflow-y-auto">
|
||||
<div className="flex min-h-full items-center justify-center px-8 py-8">
|
||||
<Card className="w-full max-w-xl">
|
||||
<CardHeader>
|
||||
<CardTitle>Call Voice Agent</CardTitle>
|
||||
</CardHeader>
|
||||
|
||||
<CardContent>
|
||||
{isCompleted && checkingForRecording ? (
|
||||
<div className="flex flex-col items-center justify-center space-y-4 p-8">
|
||||
<Loader2 className="h-8 w-8 animate-spin text-primary" />
|
||||
<div className="text-center space-y-2">
|
||||
<p className="text-foreground font-medium">Processing your call</p>
|
||||
<p className="text-sm text-muted-foreground">Fetching transcript and recording...</p>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<AudioControls
|
||||
audioInputs={audioInputs}
|
||||
selectedAudioInput={selectedAudioInput}
|
||||
setSelectedAudioInput={setSelectedAudioInput}
|
||||
isCompleted={isCompleted}
|
||||
connectionActive={connectionActive}
|
||||
permissionError={permissionError}
|
||||
start={start}
|
||||
stop={stop}
|
||||
isStarting={isStarting}
|
||||
getAudioInputDevices={getAudioInputDevices}
|
||||
/>
|
||||
|
||||
<ConnectionStatus
|
||||
connectionStatus={connectionStatus}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</CardContent>
|
||||
|
||||
<audio ref={audioRef} autoPlay playsInline className="hidden" />
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="h-full min-h-0 w-[420px] shrink-0 border-l border-border bg-background p-5">
|
||||
<ConversationRailFrame className="h-full">
|
||||
<RealtimeFeedback
|
||||
mode="live"
|
||||
messages={feedbackMessages}
|
||||
isCallActive={connectionActive}
|
||||
isCallCompleted={isCompleted}
|
||||
/>
|
||||
</ConversationRailFrame>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ApiKeyErrorDialog
|
||||
open={apiKeyModalOpen}
|
||||
onOpenChange={setApiKeyModalOpen}
|
||||
error={apiKeyError}
|
||||
errorCode={apiKeyErrorCode}
|
||||
onNavigateToCredits={navigateToCredits}
|
||||
onNavigateToModelConfig={navigateToModelConfig}
|
||||
/>
|
||||
|
||||
<WorkflowConfigErrorDialog
|
||||
open={workflowConfigModalOpen}
|
||||
onOpenChange={setWorkflowConfigModalOpen}
|
||||
error={workflowConfigError}
|
||||
onNavigateToWorkflow={navigateToWorkflow}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default BrowserCall;
|
||||
|
|
@ -6,7 +6,6 @@ import { useParams } from 'next/navigation';
|
|||
import posthog from 'posthog-js';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
|
||||
import BrowserCall from '@/app/workflow/[workflowId]/run/[runId]/BrowserCall';
|
||||
import WorkflowLayout from '@/app/workflow/WorkflowLayout';
|
||||
import { getWorkflowRunApiV1WorkflowWorkflowIdRunsRunIdGet } from '@/client/sdk.gen';
|
||||
import { MediaPreviewButton, MediaPreviewDialog } from '@/components/MediaPreviewDialog';
|
||||
|
|
@ -201,7 +200,7 @@ export default function WorkflowRunPage() {
|
|||
|
||||
let returnValue = null;
|
||||
const isTextChatRun = workflowRun?.mode === WORKFLOW_RUN_MODES.TEXTCHAT;
|
||||
const showHistoricalRunView = Boolean(workflowRun?.is_completed || isTextChatRun);
|
||||
const showRunDetailsView = Boolean(workflowRun?.is_completed || isTextChatRun);
|
||||
|
||||
if (isLoading) {
|
||||
returnValue = (
|
||||
|
|
@ -225,7 +224,7 @@ export default function WorkflowRunPage() {
|
|||
</div>
|
||||
);
|
||||
}
|
||||
else if (showHistoricalRunView) {
|
||||
else if (showRunDetailsView) {
|
||||
returnValue = (
|
||||
<div className={`flex ${RUN_SHELL_HEIGHT_CLASS} min-h-0 w-full overflow-hidden bg-background`}>
|
||||
<div className="min-w-0 flex-1 overflow-y-auto">
|
||||
|
|
@ -366,23 +365,25 @@ export default function WorkflowRunPage() {
|
|||
);
|
||||
}
|
||||
else {
|
||||
returnValue =
|
||||
<BrowserCall
|
||||
workflowId={Number(params.workflowId)}
|
||||
workflowRunId={Number(params.runId)}
|
||||
initialContextVariables={
|
||||
workflowRun?.initial_context
|
||||
? Object.fromEntries(
|
||||
Object.entries(workflowRun.initial_context).map(([key, value]) => [
|
||||
key,
|
||||
typeof value === 'object' && value !== null
|
||||
? JSON.stringify(value)
|
||||
: String(value)
|
||||
])
|
||||
)
|
||||
: null
|
||||
}
|
||||
/>
|
||||
returnValue = (
|
||||
<div className="flex h-full items-center justify-center p-6">
|
||||
<Card className="w-full max-w-xl border-border">
|
||||
<CardHeader className="space-y-2">
|
||||
<CardTitle className="text-2xl">Run Details Unavailable</CardTitle>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
This run does not have a details view yet. Go back to the workflow to continue testing or make changes.
|
||||
</p>
|
||||
</CardHeader>
|
||||
<CardFooter>
|
||||
<Button asChild className="gap-2">
|
||||
<Link href={`/workflow/${params.workflowId}`}>
|
||||
Customize Agent
|
||||
</Link>
|
||||
</Button>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
@ -391,7 +392,7 @@ export default function WorkflowRunPage() {
|
|||
{dialog}
|
||||
|
||||
{/* Onboarding Tooltip for Customize Workflow */}
|
||||
{showHistoricalRunView && (
|
||||
{showRunDetailsView && (
|
||||
<OnboardingTooltip
|
||||
title='Customize Your Workflow'
|
||||
targetRef={customizeButtonRef}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue