Skip to content

Commit daa3083

Browse files
Add functionality to edit the character details manually as well.
1 parent aacbb8c commit daa3083

File tree

4 files changed

+110
-42
lines changed

4 files changed

+110
-42
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,5 @@ dist-ssr
2626
.env
2727
*.env
2828
.env.*
29-
!example.env
29+
!example.env
30+
.vercel
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
import { Message, MessageTypeEnum } from "@/lib/types/conversation.type";
2+
import { Check, Pencil, X } from "lucide-react";
3+
import React, { useEffect } from "react";
4+
import { vapi } from "../Assistant";
5+
6+
function CharacterDetails() {
7+
const [characterDetails, setCharacterDetails] = React.useState<
8+
Record<string, string>
9+
>({
10+
name: "John Doe",
11+
"personality traits":
12+
"Mysterious, Intelligent, Smart, Ruthless, Cunning, Manipulative.",
13+
});
14+
15+
const [editKey, setEditKey] = React.useState<string | null>(null);
16+
const [editValue, setEditValue] = React.useState<string>("");
17+
18+
useEffect(() => {
19+
const onMessageUpdate = (message: Message) => {
20+
if (message.type !== MessageTypeEnum.FUNCTION_CALL) return;
21+
if (message.functionCall.name === "finalizeDetail") {
22+
const params = message.functionCall.parameters;
23+
setCharacterDetails((details) => ({
24+
...details,
25+
[params.key.toLowerCase()]: [params.value],
26+
}));
27+
}
28+
};
29+
30+
vapi.on("message", onMessageUpdate);
31+
return () => {
32+
vapi.off("message", onMessageUpdate);
33+
};
34+
}, []);
35+
36+
const handleEdit = (key: string) => {
37+
setEditKey(key);
38+
setEditValue(characterDetails[key]);
39+
};
40+
41+
const handleEditChange = (event: React.ChangeEvent<HTMLTextAreaElement>) => {
42+
setEditValue(event.target.value);
43+
};
44+
45+
const handleCancel = () => {
46+
setEditKey(null);
47+
setEditValue("");
48+
};
49+
50+
const handleSave = () => {
51+
if (editKey) {
52+
vapi.send({
53+
type: MessageTypeEnum.ADD_MESSAGE,
54+
message: {
55+
role: "system",
56+
content: `The user has updated the final value for ${editKey} to ${editValue}.`,
57+
},
58+
});
59+
}
60+
setEditKey(null);
61+
setEditValue("");
62+
};
63+
return (
64+
<>
65+
{Object.keys(characterDetails).map((key: string) => (
66+
<div className="flex flex-row gap-2 justify-between w-full" key={key}>
67+
<h1 className="font-bold capitalize">{key}</h1>
68+
<div className="flex">
69+
{editKey === key ? (
70+
<textarea
71+
value={editValue}
72+
className="border-0 h-auto focus-visible:ring-0 focus-visible:outline-none"
73+
onChange={handleEditChange}
74+
/>
75+
) : (
76+
<div className="transition text-right ">
77+
{characterDetails[key]}
78+
</div>
79+
)}
80+
{editKey === key ? (
81+
<div className="right-0 top-0 flex">
82+
<button onClick={handleCancel} className="py-1">
83+
<X size={16} className="font-bold text-red-500" />
84+
</button>
85+
<button className="py-1">
86+
<Check
87+
size={16}
88+
onClick={handleSave}
89+
className="font-bold text-green-500"
90+
/>
91+
</button>
92+
</div>
93+
) : (
94+
<button className="p-1" onClick={() => handleEdit(key)}>
95+
<Pencil size={16} className="font-bold text-blue-500" />
96+
</button>
97+
)}
98+
</div>
99+
</div>
100+
))}
101+
</>
102+
);
103+
}
104+
105+
export { CharacterDetails };

src/features/Character/CharacterPreview.tsx

Lines changed: 2 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,11 @@
1-
import React, { useEffect } from "react";
2-
import { vapi } from "../Assistant";
3-
import { Message, MessageTypeEnum } from "../../lib/types/conversation.type";
1+
import { CharacterDetails } from "./CharacterDetails";
42

53
function CharacterPreview() {
6-
const [characterDetails, setCharacterDetails] = React.useState<
7-
Record<string, string>
8-
>({});
9-
10-
useEffect(() => {
11-
const onMessageUpdate = (message: Message) => {
12-
if (message.type !== MessageTypeEnum.FUNCTION_CALL) return;
13-
console.log("messaged", message);
14-
if (message.functionCall.name === "finalizeDetail") {
15-
console.log(
16-
"message.functionCall.parameters",
17-
message.functionCall.parameters
18-
);
19-
const params = message.functionCall.parameters;
20-
// Add the topping to the pizza
21-
setCharacterDetails((details) => ({
22-
...details,
23-
[params.key]: [params.value],
24-
}));
25-
}
26-
};
27-
28-
vapi.on("message", onMessageUpdate);
29-
30-
return () => {
31-
vapi.off("message", onMessageUpdate);
32-
};
33-
}, []);
34-
354
return (
365
<div>
376
<div className="border rounded-lg p-4 flex flex-col gap-2 w-96 m-3 h-auto">
387
<h1 className="text-2xl text-center w-full">Preview</h1>
39-
{Object.keys(characterDetails).length === 0 ? (
40-
<p className="text-slate-500 w-full text-center">No details yet.</p>
41-
) : null}
42-
{Object.keys(characterDetails).map((key: string) => (
43-
<div className="flex flex-row gap-2 justify-between w-full" key={key}>
44-
<h1 className="font-bold capitalize">{key}</h1>
45-
<p className="text-right">{characterDetails[key]}</p>
46-
</div>
47-
))}
8+
<CharacterDetails />
489
</div>
4910
</div>
5011
);

src/lib/types/conversation.type.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ export enum MessageTypeEnum {
22
TRANSCRIPT = "transcript",
33
FUNCTION_CALL = "function-call",
44
FUNCTION_CALL_RESULT = "function-call-result",
5+
ADD_MESSAGE = "add-message",
56
}
67

78
export enum MessageRoleEnum {

0 commit comments

Comments
 (0)