From 5ab93767ddf2063f5a2e339cf995b93e775dd132 Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Thu, 2 Oct 2025 12:17:13 +0530 Subject: [PATCH 1/2] UX improvements for onboarding --- .gitignore | 1 + api/requirements.dev.txt | 1 + api/services/configuration/registry.py | 4 ++ ui/src/app/create-workflow/page.tsx | 42 +++++++++--- .../workflow/[workflowId]/RenderWorkflow.tsx | 14 +--- .../[workflowId]/run/[runId]/BrowserCall.tsx | 2 +- .../run/[runId]/components/AudioControls.tsx | 1 - .../[workflowId]/run/[runId]/page.tsx | 68 ++++++++++++------- ui/src/context/OnboardingContext.tsx | 2 +- 9 files changed, 85 insertions(+), 50 deletions(-) diff --git a/.gitignore b/.gitignore index 7663dd6..6661ba9 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ __pycache__ /run/ infrastructure/ nginx/ +prd/ \ No newline at end of file diff --git a/api/requirements.dev.txt b/api/requirements.dev.txt index a102a54..d9fbbf8 100644 --- a/api/requirements.dev.txt +++ b/api/requirements.dev.txt @@ -3,3 +3,4 @@ ruff==0.11.3 pytest==8.3.5 pytest-asyncio==0.26.0 pre-commit==4.2.0 +watchfiles==1.1.0 \ No newline at end of file diff --git a/api/services/configuration/registry.py b/api/services/configuration/registry.py index 2eb468a..780a0db 100644 --- a/api/services/configuration/registry.py +++ b/api/services/configuration/registry.py @@ -157,6 +157,8 @@ class AzureLLMService(BaseLLMConfiguration): # Dograh LLM Service class DograhLLMModel(str, Enum): DEFAULT = "default" + FAST = "fast" + ACCURATE = "accurate" @register_llm @@ -279,6 +281,8 @@ class OpenAITTSService(BaseTTSConfiguration): # Dograh TTS Service class DograhVoice(str, Enum): DEFAULT = "default" + JOEY = "joey" + RACHEL = "rachel" class DograhTTSModel(str, Enum): diff --git a/ui/src/app/create-workflow/page.tsx b/ui/src/app/create-workflow/page.tsx index 570c441..58fe5d1 100644 --- a/ui/src/app/create-workflow/page.tsx +++ b/ui/src/app/create-workflow/page.tsx @@ -3,7 +3,7 @@ import { useRouter } from 'next/navigation'; import { useState } from 'react'; -import { createWorkflowFromTemplateApiV1WorkflowCreateTemplatePost } from '@/client/sdk.gen'; +import { createWorkflowFromTemplateApiV1WorkflowCreateTemplatePost, createWorkflowRunApiV1WorkflowWorkflowIdRunsPost } from '@/client/sdk.gen'; import { Button } from '@/components/ui/button'; import { Card, CardContent, CardDescription, CardHeader } from '@/components/ui/card'; import { @@ -18,6 +18,7 @@ import { Input } from '@/components/ui/input'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { useAuth } from '@/lib/auth'; import logger from '@/lib/logger'; +import { getRandomId } from '@/lib/utils'; export default function CreateWorkflowPage() { const router = useRouter(); @@ -72,8 +73,34 @@ export default function CreateWorkflowPage() { } }; - const handleModalContinue = () => { - if (workflowId) { + const handleModalContinue = async () => { + if (!workflowId || !user) return; + + try { + const accessToken = await getAccessToken(); + const workflowRunName = `WR-${getRandomId()}`; + + // Create a workflow run + const response = await createWorkflowRunApiV1WorkflowWorkflowIdRunsPost({ + path: { + workflow_id: Number(workflowId), + }, + body: { + mode: 'smallwebrtc', // Same mode as "Web Call" button + name: workflowRunName + }, + headers: { + 'Authorization': `Bearer ${accessToken}`, + }, + }); + + // Navigate to the workflow run page + if (response.data?.id) { + router.push(`/workflow/${workflowId}/run/${response.data.id}`); + } + } catch (err) { + logger.error(`Error creating workflow run: ${err}`); + // Fallback to workflow page if run creation fails router.push(`/workflow/${workflowId}`); } }; @@ -222,16 +249,13 @@ export default function CreateWorkflowPage() {

- A starter template has been generated for your use case, with some randomised data and sample actions. + A voice agent workflow has been generated for your use case, with some artificial data and sample actions.

The voice bot is pre-set to communicate in English with an American accent.

- You're encouraged to first test the bot and then modify it to your specific requirements and location (currency/accent etc). -

-

- Feel free to join our Slack channel for any queries and star us on GitHub. + Next steps would be to test the voice bot using web call, and then modify it to suit your use case.

@@ -241,7 +265,7 @@ export default function CreateWorkflowPage() { onClick={handleModalContinue} className="w-full bg-gradient-to-r from-blue-600 to-purple-600 hover:from-blue-700 hover:to-purple-700 font-semibold" > - Continue to Workflow + Start Web Call diff --git a/ui/src/app/workflow/[workflowId]/RenderWorkflow.tsx b/ui/src/app/workflow/[workflowId]/RenderWorkflow.tsx index d892cab..ca00f3c 100644 --- a/ui/src/app/workflow/[workflowId]/RenderWorkflow.tsx +++ b/ui/src/app/workflow/[workflowId]/RenderWorkflow.tsx @@ -5,12 +5,9 @@ import { Panel, ReactFlow, } from "@xyflow/react"; -import { ArrowLeft } from 'lucide-react'; -import Link from 'next/link'; import WorkflowLayout from '@/app/workflow/WorkflowLayout'; import { FlowEdge, FlowNode, NodeType } from "@/components/flow/types"; -import { Button } from '@/components/ui/button'; import { WorkflowConfigurations } from '@/types/workflow-configurations'; import AddNodePanel from "../../../components/flow/AddNodePanel"; @@ -75,15 +72,6 @@ function RenderWorkflow({ initialWorkflowName, workflowId, initialFlow, initialT saveWorkflowConfigurations } = useWorkflowState({ initialWorkflowName, workflowId, initialFlow, initialTemplateContextVariables, initialWorkflowConfigurations }); - const backButton = ( - - - - ); - const headerActions = ( - +
- Agent Run + Call Voice Agent diff --git a/ui/src/app/workflow/[workflowId]/run/[runId]/components/AudioControls.tsx b/ui/src/app/workflow/[workflowId]/run/[runId]/components/AudioControls.tsx index dde64ec..188412c 100644 --- a/ui/src/app/workflow/[workflowId]/run/[runId]/components/AudioControls.tsx +++ b/ui/src/app/workflow/[workflowId]/run/[runId]/components/AudioControls.tsx @@ -73,7 +73,6 @@ export const AudioControls = ({
{!connectionActive ? ( <> -

Ready to start your call

- - - - -
- ); - let returnValue = null; if (isLoading) { @@ -123,12 +110,31 @@ export default function WorkflowRunPage() {
- Agent Run Completed -
- - - +
+ Agent Run Completed +
+ + + +
+ + +

Your voice agent run has been completed successfully. You can preview or download the transcript and recording.

@@ -207,9 +213,21 @@ export default function WorkflowRunPage() { } return ( - + {returnValue} {dialog} + + {/* Onboarding Tooltip for Customize Workflow */} + {workflowRun?.is_completed && ( + markTooltipSeen('customize_workflow')} + showNext={false} + isVisible={!hasSeenTooltip('customize_workflow')} + /> + )} ); } diff --git a/ui/src/context/OnboardingContext.tsx b/ui/src/context/OnboardingContext.tsx index d9e469c..639143d 100644 --- a/ui/src/context/OnboardingContext.tsx +++ b/ui/src/context/OnboardingContext.tsx @@ -2,7 +2,7 @@ import { createContext, useContext, useEffect, useState } from 'react'; -export type TooltipKey = 'web_call'; // Add more tooltip keys as needed +export type TooltipKey = 'web_call' | 'customize_workflow'; // Add more tooltip keys as needed interface OnboardingState { seenTooltips: TooltipKey[]; From b86a460062fe4c3cdc9dc26bfd61dc25ce97822d Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Sat, 4 Oct 2025 11:05:47 +0530 Subject: [PATCH 2/2] Move smallwebrtc to constants --- ui/src/app/create-workflow/page.tsx | 3 ++- .../workflow/[workflowId]/components/WorkflowHeader.tsx | 3 ++- ui/src/constants/workflowRunModes.ts | 9 +++++++++ 3 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 ui/src/constants/workflowRunModes.ts diff --git a/ui/src/app/create-workflow/page.tsx b/ui/src/app/create-workflow/page.tsx index 58fe5d1..8ee02bf 100644 --- a/ui/src/app/create-workflow/page.tsx +++ b/ui/src/app/create-workflow/page.tsx @@ -16,6 +16,7 @@ import { } from '@/components/ui/dialog'; import { Input } from '@/components/ui/input'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; +import { WORKFLOW_RUN_MODES } from '@/constants/workflowRunModes'; import { useAuth } from '@/lib/auth'; import logger from '@/lib/logger'; import { getRandomId } from '@/lib/utils'; @@ -86,7 +87,7 @@ export default function CreateWorkflowPage() { workflow_id: Number(workflowId), }, body: { - mode: 'smallwebrtc', // Same mode as "Web Call" button + mode: WORKFLOW_RUN_MODES.SMALL_WEBRTC, // Same mode as "Web Call" button name: workflowRunName }, headers: { diff --git a/ui/src/app/workflow/[workflowId]/components/WorkflowHeader.tsx b/ui/src/app/workflow/[workflowId]/components/WorkflowHeader.tsx index 035081e..1a15dd5 100644 --- a/ui/src/app/workflow/[workflowId]/components/WorkflowHeader.tsx +++ b/ui/src/app/workflow/[workflowId]/components/WorkflowHeader.tsx @@ -12,6 +12,7 @@ import { OnboardingTooltip } from '@/components/onboarding/OnboardingTooltip'; import { Button } from "@/components/ui/button"; import { Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog"; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip"; +import { WORKFLOW_RUN_MODES } from '@/constants/workflowRunModes'; import { useOnboarding } from '@/context/OnboardingContext'; import { useUserConfig } from "@/context/UserConfigContext"; import { useAuth } from '@/lib/auth'; @@ -203,7 +204,7 @@ const WorkflowHeader = ({ isDirty, workflowName, rfInstance, onRun, workflowId, if (!hasSeenTooltip('web_call')) { markTooltipSeen('web_call'); } - onRun("smallwebrtc"); // Don't change the mode since its defined in the database enum + onRun(WORKFLOW_RUN_MODES.SMALL_WEBRTC); }} disabled={hasValidationErrors} > diff --git a/ui/src/constants/workflowRunModes.ts b/ui/src/constants/workflowRunModes.ts new file mode 100644 index 0000000..2b4da41 --- /dev/null +++ b/ui/src/constants/workflowRunModes.ts @@ -0,0 +1,9 @@ +/** + * Workflow run mode constants + * These modes determine how a workflow run is executed + */ +export const WORKFLOW_RUN_MODES = { + SMALL_WEBRTC: 'smallwebrtc', +} as const; + +export type WorkflowRunMode = typeof WORKFLOW_RUN_MODES[keyof typeof WORKFLOW_RUN_MODES];