mirror of
https://github.com/dograh-hq/dograh.git
synced 2026-06-16 08:25:18 +02:00
feat: add AWS Bedrock support
This commit is contained in:
parent
1604e306ec
commit
fe84f086ba
30 changed files with 546 additions and 195 deletions
|
|
@ -125,6 +125,7 @@ export default function CampaignsPage() {
|
|||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>ID</TableHead>
|
||||
<TableHead>Name</TableHead>
|
||||
<TableHead>Workflow</TableHead>
|
||||
<TableHead>State</TableHead>
|
||||
|
|
@ -139,6 +140,7 @@ export default function CampaignsPage() {
|
|||
className="cursor-pointer hover:bg-muted/50"
|
||||
onClick={() => handleRowClick(campaign.id)}
|
||||
>
|
||||
<TableCell>{campaign.id}</TableCell>
|
||||
<TableCell className="font-medium">{campaign.name}</TableCell>
|
||||
<TableCell>{campaign.workflow_name}</TableCell>
|
||||
<TableCell>
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import {
|
|||
Panel,
|
||||
ReactFlow,
|
||||
} from "@xyflow/react";
|
||||
import { BookA, BrushCleaning, Maximize2, Mic, Minus, Plus, Rocket, Settings, Variable } from 'lucide-react';
|
||||
import { BookA, BrushCleaning, Maximize2, Mic, Minus, PhoneOff, Plus, Rocket, Settings, Variable } from 'lucide-react';
|
||||
import React, { useEffect, useMemo, useState } from 'react';
|
||||
|
||||
import { listDocumentsApiV1KnowledgeBaseDocumentsGet, listRecordingsApiV1WorkflowRecordingsGet, listToolsApiV1ToolsGet } from '@/client';
|
||||
|
|
@ -25,6 +25,7 @@ import { EmbedDialog } from './components/EmbedDialog';
|
|||
import { PhoneCallDialog } from './components/PhoneCallDialog';
|
||||
import { RecordingsDialog } from './components/RecordingsDialog';
|
||||
import { TemplateContextVariablesDialog } from './components/TemplateContextVariablesDialog';
|
||||
import { VoicemailDetectionDialog } from './components/VoicemailDetectionDialog';
|
||||
import { WorkflowEditorHeader } from "./components/WorkflowEditorHeader";
|
||||
import { WorkflowProvider } from "./contexts/WorkflowContext";
|
||||
import { useWorkflowState } from "./hooks/useWorkflowState";
|
||||
|
|
@ -69,6 +70,7 @@ function RenderWorkflow({ initialWorkflowName, workflowId, initialFlow, initialT
|
|||
const [isEmbedDialogOpen, setIsEmbedDialogOpen] = useState(false);
|
||||
const [isPhoneCallDialogOpen, setIsPhoneCallDialogOpen] = useState(false);
|
||||
const [isRecordingsDialogOpen, setIsRecordingsDialogOpen] = useState(false);
|
||||
const [isVoicemailDialogOpen, setIsVoicemailDialogOpen] = useState(false);
|
||||
const [documents, setDocuments] = useState<DocumentResponseSchema[] | undefined>(undefined);
|
||||
const [tools, setTools] = useState<ToolResponse[] | undefined>(undefined);
|
||||
const [recordings, setRecordings] = useState<RecordingResponseSchema[]>([]);
|
||||
|
|
@ -283,6 +285,22 @@ function RenderWorkflow({ initialWorkflowName, workflowId, initialFlow, initialT
|
|||
</TooltipContent>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="icon"
|
||||
onClick={() => setIsVoicemailDialogOpen(true)}
|
||||
className="bg-white shadow-sm hover:shadow-md"
|
||||
>
|
||||
<PhoneOff className="h-4 w-4" />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="left">
|
||||
<p>Voicemail Detection</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
|
|
@ -428,6 +446,13 @@ function RenderWorkflow({ initialWorkflowName, workflowId, initialFlow, initialT
|
|||
workflowId={workflowId}
|
||||
onRecordingsChange={setRecordings}
|
||||
/>
|
||||
|
||||
<VoicemailDetectionDialog
|
||||
open={isVoicemailDialogOpen}
|
||||
onOpenChange={setIsVoicemailDialogOpen}
|
||||
workflowConfigurations={workflowConfigurations}
|
||||
onSave={saveWorkflowConfigurations}
|
||||
/>
|
||||
</div>
|
||||
</WorkflowProvider>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,205 @@
|
|||
import { useEffect, useState } from "react";
|
||||
|
||||
import { LLMConfigSelector } from "@/components/LLMConfigSelector";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from "@/components/ui/dialog";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
import { Textarea } from "@/components/ui/textarea";
|
||||
import {
|
||||
DEFAULT_VOICEMAIL_DETECTION_CONFIGURATION,
|
||||
type VoicemailDetectionConfiguration,
|
||||
type WorkflowConfigurations,
|
||||
} from "@/types/workflow-configurations";
|
||||
|
||||
// Must match VoicemailDetector.DEFAULT_SYSTEM_PROMPT in pipecat
|
||||
const DEFAULT_VOICEMAIL_SYSTEM_PROMPT = `You are a voicemail detection classifier for an OUTBOUND calling system. A bot has called a phone number and you need to determine if a human answered or if the call went to voicemail based on the provided text.
|
||||
|
||||
HUMAN ANSWERED - LIVE CONVERSATION (respond "CONVERSATION"):
|
||||
- Personal greetings: "Hello?", "Hi", "Yeah?", "John speaking"
|
||||
- Interactive responses: "Who is this?", "What do you want?", "Can I help you?"
|
||||
- Conversational tone expecting back-and-forth dialogue
|
||||
- Questions directed at the caller: "Hello? Anyone there?"
|
||||
- Informal responses: "Yep", "What's up?", "Speaking"
|
||||
- Natural, spontaneous speech patterns
|
||||
- Immediate acknowledgment of the call
|
||||
|
||||
VOICEMAIL SYSTEM (respond "VOICEMAIL"):
|
||||
- Automated voicemail greetings: "Hi, you've reached [name], please leave a message"
|
||||
- Phone carrier messages: "The number you have dialed is not in service", "Please leave a message", "All circuits are busy"
|
||||
- Professional voicemail: "This is [name], I'm not available right now"
|
||||
- Instructions about leaving messages: "leave a message", "leave your name and number"
|
||||
- References to callback or messaging: "call me back", "I'll get back to you"
|
||||
- Carrier system messages: "mailbox is full", "has not been set up"
|
||||
- Business hours messages: "our office is currently closed"
|
||||
|
||||
Respond with ONLY "CONVERSATION" if a person answered, or "VOICEMAIL" if it's voicemail/recording.`;
|
||||
|
||||
interface VoicemailDetectionDialogProps {
|
||||
open: boolean;
|
||||
onOpenChange: (open: boolean) => void;
|
||||
workflowConfigurations: WorkflowConfigurations;
|
||||
onSave: (configurations: WorkflowConfigurations) => void;
|
||||
}
|
||||
|
||||
export const VoicemailDetectionDialog = ({
|
||||
open,
|
||||
onOpenChange,
|
||||
workflowConfigurations,
|
||||
onSave,
|
||||
}: VoicemailDetectionDialogProps) => {
|
||||
const getConfig = (): VoicemailDetectionConfiguration => ({
|
||||
...DEFAULT_VOICEMAIL_DETECTION_CONFIGURATION,
|
||||
...workflowConfigurations.voicemail_detection,
|
||||
});
|
||||
|
||||
const [enabled, setEnabled] = useState(getConfig().enabled);
|
||||
const [useWorkflowLlm, setUseWorkflowLlm] = useState(getConfig().use_workflow_llm);
|
||||
const [provider, setProvider] = useState(getConfig().provider || "openai");
|
||||
const [model, setModel] = useState(getConfig().model || "gpt-4.1");
|
||||
const [apiKey, setApiKey] = useState(getConfig().api_key || "");
|
||||
const [systemPrompt, setSystemPrompt] = useState(getConfig().system_prompt || DEFAULT_VOICEMAIL_SYSTEM_PROMPT);
|
||||
const [longSpeechTimeout, setLongSpeechTimeout] = useState(getConfig().long_speech_timeout);
|
||||
|
||||
// Sync state from props whenever the dialog opens
|
||||
useEffect(() => {
|
||||
if (open) {
|
||||
const config = {
|
||||
...DEFAULT_VOICEMAIL_DETECTION_CONFIGURATION,
|
||||
...workflowConfigurations.voicemail_detection,
|
||||
};
|
||||
setEnabled(config.enabled);
|
||||
setUseWorkflowLlm(config.use_workflow_llm);
|
||||
setProvider(config.provider || "openai");
|
||||
setModel(config.model || "gpt-4.1");
|
||||
setApiKey(config.api_key || "");
|
||||
setSystemPrompt(config.system_prompt || DEFAULT_VOICEMAIL_SYSTEM_PROMPT);
|
||||
setLongSpeechTimeout(config.long_speech_timeout);
|
||||
}
|
||||
}, [open, workflowConfigurations]);
|
||||
|
||||
const handleOpenChange = (newOpen: boolean) => {
|
||||
onOpenChange(newOpen);
|
||||
};
|
||||
|
||||
const handleSave = () => {
|
||||
const voicemailConfig: VoicemailDetectionConfiguration = {
|
||||
enabled,
|
||||
use_workflow_llm: useWorkflowLlm,
|
||||
provider: useWorkflowLlm ? undefined : provider,
|
||||
model: useWorkflowLlm ? undefined : model,
|
||||
api_key: useWorkflowLlm ? undefined : apiKey,
|
||||
system_prompt: systemPrompt && systemPrompt !== DEFAULT_VOICEMAIL_SYSTEM_PROMPT ? systemPrompt : undefined,
|
||||
long_speech_timeout: longSpeechTimeout,
|
||||
};
|
||||
|
||||
onSave({
|
||||
...workflowConfigurations,
|
||||
voicemail_detection: voicemailConfig,
|
||||
});
|
||||
onOpenChange(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={handleOpenChange}>
|
||||
<DialogContent className="max-w-lg max-h-[80vh] overflow-y-auto">
|
||||
<DialogHeader>
|
||||
<DialogTitle>Voicemail Detection</DialogTitle>
|
||||
<DialogDescription>
|
||||
Configure voicemail detection to automatically detect and end calls
|
||||
when a voicemail system is reached.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center space-x-2 p-2 border rounded-md bg-muted/20">
|
||||
<Switch
|
||||
id="voicemail-enabled"
|
||||
checked={enabled}
|
||||
onCheckedChange={setEnabled}
|
||||
/>
|
||||
<Label htmlFor="voicemail-enabled">Enable Voicemail Detection</Label>
|
||||
</div>
|
||||
|
||||
{enabled && (
|
||||
<>
|
||||
{/* LLM Configuration */}
|
||||
<div className="space-y-3">
|
||||
<div className="flex items-center space-x-2 p-2 border rounded-md bg-muted/20">
|
||||
<Switch
|
||||
id="voicemail-use-workflow-llm"
|
||||
checked={useWorkflowLlm}
|
||||
onCheckedChange={setUseWorkflowLlm}
|
||||
/>
|
||||
<Label htmlFor="voicemail-use-workflow-llm">Use Workflow LLM</Label>
|
||||
<Label className="text-xs text-muted-foreground ml-2">
|
||||
Use the LLM configured in your account settings.
|
||||
</Label>
|
||||
</div>
|
||||
|
||||
{!useWorkflowLlm && (
|
||||
<LLMConfigSelector
|
||||
provider={provider}
|
||||
onProviderChange={setProvider}
|
||||
model={model}
|
||||
onModelChange={setModel}
|
||||
apiKey={apiKey}
|
||||
onApiKeyChange={setApiKey}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* System Prompt */}
|
||||
<div className="grid gap-2">
|
||||
<Label>System Prompt</Label>
|
||||
<Label className="text-xs text-muted-foreground">
|
||||
Prompt for voicemail classification.
|
||||
The LLM must respond with either "CONVERSATION" or "VOICEMAIL".
|
||||
</Label>
|
||||
<Textarea
|
||||
value={systemPrompt}
|
||||
onChange={(e) => setSystemPrompt(e.target.value)}
|
||||
className="min-h-[200px] font-mono text-xs"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Timing Configuration */}
|
||||
<div className="grid gap-4 p-3 border rounded-md bg-muted/10">
|
||||
<Label className="font-medium">Timing</Label>
|
||||
<div className="space-y-2">
|
||||
<Label className="text-sm">Speech Cutoff (seconds)</Label>
|
||||
<Label className="text-xs text-muted-foreground">
|
||||
Trigger classification early if first turn speech exceeds this duration.
|
||||
</Label>
|
||||
<Input
|
||||
type="number"
|
||||
step="0.5"
|
||||
min="1"
|
||||
max="30"
|
||||
value={longSpeechTimeout}
|
||||
onChange={(e) => setLongSpeechTimeout(parseFloat(e.target.value) || 8.0)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<DialogFooter>
|
||||
<Button variant="outline" onClick={() => onOpenChange(false)}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button onClick={handleSave}>Save</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
|
@ -1242,7 +1242,10 @@ export const getCurrentPeriodUsageApiV1OrganizationsUsageCurrentPeriodGet = <Thr
|
|||
|
||||
/**
|
||||
* Get Mps Credits
|
||||
* Get usage and quota from MPS for the user's configured Dograh service keys.
|
||||
* Get aggregated usage and quota from MPS.
|
||||
*
|
||||
* OSS users: queries by provider_id (created_by).
|
||||
* Hosted users: queries by organization_id.
|
||||
*/
|
||||
export const getMpsCreditsApiV1OrganizationsUsageMpsCreditsGet = <ThrowOnError extends boolean = false>(options?: Options<GetMpsCreditsApiV1OrganizationsUsageMpsCreditsGetData, ThrowOnError>) => {
|
||||
return (options?.client ?? _heyApiClient).get<GetMpsCreditsApiV1OrganizationsUsageMpsCreditsGetResponse, GetMpsCreditsApiV1OrganizationsUsageMpsCreditsGetError, ThrowOnError>({
|
||||
|
|
|
|||
|
|
@ -1238,7 +1238,7 @@ export type UpdateToolRequest = {
|
|||
};
|
||||
|
||||
export type UpdateWorkflowRequest = {
|
||||
name: string;
|
||||
name?: string | null;
|
||||
workflow_definition?: {
|
||||
[key: string]: unknown;
|
||||
} | null;
|
||||
|
|
@ -1266,16 +1266,16 @@ export type UsageHistoryResponse = {
|
|||
|
||||
export type UserConfigurationRequestResponseSchema = {
|
||||
llm?: {
|
||||
[key: string]: string | number | Array<string>;
|
||||
[key: string]: string | number | Array<string> | null;
|
||||
} | null;
|
||||
tts?: {
|
||||
[key: string]: string | number | Array<string>;
|
||||
[key: string]: string | number | Array<string> | null;
|
||||
} | null;
|
||||
stt?: {
|
||||
[key: string]: string | number | Array<string>;
|
||||
[key: string]: string | number | Array<string> | null;
|
||||
} | null;
|
||||
embeddings?: {
|
||||
[key: string]: string | number | Array<string>;
|
||||
[key: string]: string | number | Array<string> | null;
|
||||
} | null;
|
||||
test_phone_number?: string | null;
|
||||
timezone?: string | null;
|
||||
|
|
|
|||
|
|
@ -24,6 +24,8 @@ import { useNodeHandlers } from "./common/useNodeHandlers";
|
|||
|
||||
interface StartCallEditFormProps {
|
||||
nodeData: FlowNodeData;
|
||||
greeting: string;
|
||||
setGreeting: (value: string) => void;
|
||||
prompt: string;
|
||||
setPrompt: (value: string) => void;
|
||||
name: string;
|
||||
|
|
@ -32,8 +34,6 @@ interface StartCallEditFormProps {
|
|||
setAllowInterrupt: (value: boolean) => void;
|
||||
addGlobalPrompt: boolean;
|
||||
setAddGlobalPrompt: (value: boolean) => void;
|
||||
detectVoicemail: boolean;
|
||||
setDetectVoicemail: (value: boolean) => void;
|
||||
delayedStart: boolean;
|
||||
setDelayedStart: (value: boolean) => void;
|
||||
delayedStartDuration: number;
|
||||
|
|
@ -65,11 +65,11 @@ export const StartCall = memo(({ data, selected, id }: StartCallNodeProps) => {
|
|||
const { saveWorkflow, tools, documents, recordings } = useWorkflow();
|
||||
|
||||
// Form state
|
||||
const [greeting, setGreeting] = useState(data.greeting ?? "");
|
||||
const [prompt, setPrompt] = useState(data.prompt ?? "");
|
||||
const [name, setName] = useState(data.name);
|
||||
const [allowInterrupt, setAllowInterrupt] = useState(data.allow_interrupt ?? true);
|
||||
const [addGlobalPrompt, setAddGlobalPrompt] = useState(data.add_global_prompt ?? true);
|
||||
const [detectVoicemail, setDetectVoicemail] = useState(data.detect_voicemail ?? false);
|
||||
const [delayedStart, setDelayedStart] = useState(data.delayed_start ?? false);
|
||||
const [delayedStartDuration, setDelayedStartDuration] = useState(data.delayed_start_duration ?? 2);
|
||||
const [extractionEnabled, setExtractionEnabled] = useState(data.extraction_enabled ?? false);
|
||||
|
|
@ -78,22 +78,23 @@ export const StartCall = memo(({ data, selected, id }: StartCallNodeProps) => {
|
|||
const [toolUuids, setToolUuids] = useState<string[]>(data.tool_uuids ?? []);
|
||||
const [documentUuids, setDocumentUuids] = useState<string[]>(data.document_uuids ?? []);
|
||||
|
||||
// Compute if form has unsaved changes (only check prompt, name)
|
||||
// Compute if form has unsaved changes (only check prompt, name, greeting)
|
||||
const isDirty = useMemo(() => {
|
||||
return (
|
||||
greeting !== (data.greeting ?? "") ||
|
||||
prompt !== (data.prompt ?? "") ||
|
||||
name !== (data.name ?? "")
|
||||
);
|
||||
}, [prompt, name, data]);
|
||||
}, [greeting, prompt, name, data]);
|
||||
|
||||
const handleSave = async () => {
|
||||
handleSaveNodeData({
|
||||
...data,
|
||||
greeting: greeting || undefined,
|
||||
prompt,
|
||||
name,
|
||||
allow_interrupt: allowInterrupt,
|
||||
add_global_prompt: addGlobalPrompt,
|
||||
detect_voicemail: detectVoicemail,
|
||||
delayed_start: delayedStart,
|
||||
delayed_start_duration: delayedStart ? delayedStartDuration : undefined,
|
||||
extraction_enabled: extractionEnabled,
|
||||
|
|
@ -112,11 +113,11 @@ export const StartCall = memo(({ data, selected, id }: StartCallNodeProps) => {
|
|||
// Reset form state when dialog opens
|
||||
const handleOpenChange = (newOpen: boolean) => {
|
||||
if (newOpen) {
|
||||
setGreeting(data.greeting ?? "");
|
||||
setPrompt(data.prompt ?? "");
|
||||
setName(data.name);
|
||||
setAllowInterrupt(data.allow_interrupt ?? true);
|
||||
setAddGlobalPrompt(data.add_global_prompt ?? true);
|
||||
setDetectVoicemail(data.detect_voicemail ?? false);
|
||||
setDelayedStart(data.delayed_start ?? false);
|
||||
setDelayedStartDuration(data.delayed_start_duration ?? 3);
|
||||
setExtractionEnabled(data.extraction_enabled ?? false);
|
||||
|
|
@ -131,11 +132,11 @@ export const StartCall = memo(({ data, selected, id }: StartCallNodeProps) => {
|
|||
// Update form state when data changes (e.g., from undo/redo)
|
||||
useEffect(() => {
|
||||
if (open) {
|
||||
setGreeting(data.greeting ?? "");
|
||||
setPrompt(data.prompt ?? "");
|
||||
setName(data.name);
|
||||
setAllowInterrupt(data.allow_interrupt ?? true);
|
||||
setAddGlobalPrompt(data.add_global_prompt ?? true);
|
||||
setDetectVoicemail(data.detect_voicemail ?? false);
|
||||
setDelayedStart(data.delayed_start ?? false);
|
||||
setDelayedStartDuration(data.delayed_start_duration ?? 3);
|
||||
setExtractionEnabled(data.extraction_enabled ?? false);
|
||||
|
|
@ -225,6 +226,8 @@ export const StartCall = memo(({ data, selected, id }: StartCallNodeProps) => {
|
|||
{open && (
|
||||
<StartCallEditForm
|
||||
nodeData={data}
|
||||
greeting={greeting}
|
||||
setGreeting={setGreeting}
|
||||
prompt={prompt}
|
||||
setPrompt={setPrompt}
|
||||
name={name}
|
||||
|
|
@ -233,8 +236,6 @@ export const StartCall = memo(({ data, selected, id }: StartCallNodeProps) => {
|
|||
setAllowInterrupt={setAllowInterrupt}
|
||||
addGlobalPrompt={addGlobalPrompt}
|
||||
setAddGlobalPrompt={setAddGlobalPrompt}
|
||||
detectVoicemail={detectVoicemail}
|
||||
setDetectVoicemail={setDetectVoicemail}
|
||||
delayedStart={delayedStart}
|
||||
setDelayedStart={setDelayedStart}
|
||||
delayedStartDuration={delayedStartDuration}
|
||||
|
|
@ -260,6 +261,8 @@ export const StartCall = memo(({ data, selected, id }: StartCallNodeProps) => {
|
|||
});
|
||||
|
||||
const StartCallEditForm = ({
|
||||
greeting,
|
||||
setGreeting,
|
||||
prompt,
|
||||
setPrompt,
|
||||
name,
|
||||
|
|
@ -268,8 +271,6 @@ const StartCallEditForm = ({
|
|||
setAllowInterrupt,
|
||||
addGlobalPrompt,
|
||||
setAddGlobalPrompt,
|
||||
detectVoicemail,
|
||||
setDetectVoicemail,
|
||||
delayedStart,
|
||||
setDelayedStart,
|
||||
delayedStartDuration,
|
||||
|
|
@ -326,6 +327,18 @@ const StartCallEditForm = ({
|
|||
onChange={(e) => setName(e.target.value)}
|
||||
/>
|
||||
|
||||
<Label>Greeting</Label>
|
||||
<Label className="text-xs text-muted-foreground">
|
||||
Optional greeting message played via TTS when the call starts. If set, this will be spoken directly instead of generating a response from the LLM. Supports template variables like {"{{variable_name}}"}.
|
||||
</Label>
|
||||
<MentionTextarea
|
||||
value={greeting}
|
||||
onChange={setGreeting}
|
||||
className="min-h-[60px] max-h-[200px] resize-none overflow-y-auto"
|
||||
placeholder="e.g. Hello {{first_name}}, this is Sarah calling from Acme Corp."
|
||||
recordings={recordings}
|
||||
/>
|
||||
|
||||
<Label>Prompt</Label>
|
||||
<Label className="text-xs text-muted-foreground">
|
||||
Enter the prompt for the agent. This will be used to generate the agent's response. Prompt engineering's best practices apply.
|
||||
|
|
@ -354,19 +367,6 @@ const StartCallEditForm = ({
|
|||
Add Global Prompt
|
||||
</Label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<Switch
|
||||
id="detect-voicemail"
|
||||
checked={detectVoicemail}
|
||||
onCheckedChange={setDetectVoicemail}
|
||||
/>
|
||||
<Label htmlFor="detect-voicemail">
|
||||
Detect Voicemail
|
||||
</Label>
|
||||
<Label className="text-xs text-muted-foreground">
|
||||
Automatically detect and end call if voicemail is reached.
|
||||
</Label>
|
||||
</div>
|
||||
<div className="flex flex-col space-y-2">
|
||||
<div className="flex items-center space-x-2">
|
||||
<Switch
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ export type FlowNodeData = {
|
|||
extraction_prompt?: string;
|
||||
extraction_variables?: ExtractionVariable[];
|
||||
add_global_prompt?: boolean;
|
||||
greeting?: string;
|
||||
wait_for_user_greeting?: boolean;
|
||||
detect_voicemail?: boolean;
|
||||
delayed_start?: boolean;
|
||||
|
|
|
|||
|
|
@ -12,6 +12,22 @@ export interface AmbientNoiseConfiguration {
|
|||
|
||||
export type TurnStopStrategy = 'transcription' | 'turn_analyzer';
|
||||
|
||||
export interface VoicemailDetectionConfiguration {
|
||||
enabled: boolean;
|
||||
use_workflow_llm: boolean;
|
||||
provider?: string;
|
||||
model?: string;
|
||||
api_key?: string;
|
||||
system_prompt?: string;
|
||||
long_speech_timeout: number; // seconds cutoff for long speech detection
|
||||
}
|
||||
|
||||
export const DEFAULT_VOICEMAIL_DETECTION_CONFIGURATION: VoicemailDetectionConfiguration = {
|
||||
enabled: false,
|
||||
use_workflow_llm: true,
|
||||
long_speech_timeout: 8.0,
|
||||
};
|
||||
|
||||
export interface WorkflowConfigurations {
|
||||
vad_configuration?: VADConfiguration;
|
||||
ambient_noise_configuration: AmbientNoiseConfiguration;
|
||||
|
|
@ -20,6 +36,7 @@ export interface WorkflowConfigurations {
|
|||
smart_turn_stop_secs: number; // Timeout in seconds for incomplete turn detection
|
||||
turn_stop_strategy: TurnStopStrategy; // Strategy for detecting end of user turn
|
||||
dictionary?: string; // Comma-separated words for voice agent to listen for
|
||||
voicemail_detection?: VoicemailDetectionConfiguration;
|
||||
[key: string]: unknown; // Allow additional properties for future configurations
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue