Skip to content

Commit

Permalink
Merge pull request #271 from cabcookie:add-ai-tools
Browse files Browse the repository at this point in the history
fix: allow levels for heading (was just h1 right now)
  • Loading branch information
cabcookie authored Dec 15, 2024
2 parents 547149b + db8d33d commit 7f83a89
Show file tree
Hide file tree
Showing 14 changed files with 917 additions and 356 deletions.
23 changes: 23 additions & 0 deletions components/chat/ChatInput.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { JSONContent } from "@tiptap/core";
import { Dispatch, FC, SetStateAction } from "react";
import InboxEditor from "../ui-elements/editors/inbox-editor/InboxEditor";

interface ChatInputProps {
prompt: JSONContent;
setPrompt: Dispatch<SetStateAction<JSONContent>>;
handleSend: () => void;
}

const ChatInput: FC<ChatInputProps> = ({ prompt, setPrompt, handleSend }) => (
<InboxEditor
notes={prompt}
saveNotes={(editor) => setPrompt(editor.getJSON())}
autoFocus
placeholder="Send a message"
saveAtCmdEnter={handleSend}
showSaveStatus={false}
className="pb-12 max-h-60 md:max-h-80 overflow-y-auto"
/>
);

export default ChatInput;
30 changes: 30 additions & 0 deletions components/chat/ChatMetadata.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { MentionedPerson } from "@/helpers/chat/set-mentioned-people";
import { PersonJob } from "@/pages/chat";
import { FC } from "react";

interface ChatMetadataProps {
currentJob?: PersonJob;
mentionedPeople?: MentionedPerson[];
}

const ChatMetadata: FC<ChatMetadataProps> = ({ currentJob, mentionedPeople }) =>
currentJob?.user && (
<div className="text-xs text-muted-foreground p-2 pt-1 space-y-1 bg-white/95">
<div>We will integrate the following information in the request:</div>
<ul className="list-disc list-inside">
<li>
Your name: {currentJob.user} (
{currentJob.jobRole && `${currentJob.jobRole} `}at{" "}
{currentJob.employer})
</li>
{mentionedPeople && mentionedPeople.length > 0 && (
<li>
Information about these people:{" "}
{mentionedPeople.map((person) => person.name).join(", ")}
</li>
)}
</ul>
</div>
);

export default ChatMetadata;
22 changes: 22 additions & 0 deletions components/chat/ChatSendBtn.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { ArrowUp, Loader2 } from "lucide-react";
import { FC } from "react";
import { Button } from "../ui/button";

interface ChatSendBtnProps {
isSending: boolean;
handleSend: () => void;
}

const ChatSendBtn: FC<ChatSendBtnProps> = ({ isSending, handleSend }) => {
return (
<Button
className="rounded-full w-10 h-10 absolute bottom-1 right-1"
onClick={handleSend}
disabled={isSending}
>
{!isSending ? <ArrowUp /> : <Loader2 className="animate-spin" />}
</Button>
);
};

export default ChatSendBtn;
5 changes: 5 additions & 0 deletions components/chat/ChatUiGradient.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const ChatUiGradient = () => (
<div className="h-8 bg-gradient-to-t from-background/95 via-background/80 to-background/0" />
);

export default ChatUiGradient;
99 changes: 33 additions & 66 deletions components/chat/MessageInput.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
import usePerson from "@/api/usePerson";
import useCurrentUser from "@/api/useUser";
import { PersonAccount } from "@/helpers/person/accounts";
import { setCurrentJobByUser } from "@/helpers/chat/current-job";
import { handlePromptSend } from "@/helpers/chat/handle-send";
import {
MentionedPerson,
setMentionedPeopleByPrompt,
} from "@/helpers/chat/set-mentioned-people";
import { cn } from "@/lib/utils";
import { PersonJob } from "@/pages/chat";
import { SendMessage } from "@aws-amplify/ui-react-ai";
import { JSONContent } from "@tiptap/core";
import { find, flow, get, identity } from "lodash/fp";
import { ArrowUp, Loader2 } from "lucide-react";
import { FC, useEffect, useState } from "react";
import { emptyDocument } from "../ui-elements/editors/helpers/document";
import { getTextFromJsonContent } from "../ui-elements/editors/helpers/text-generation";
import InboxEditor from "../ui-elements/editors/inbox-editor/InboxEditor";
import { Button } from "../ui/button";
import ChatInput from "./ChatInput";
import ChatMetadata from "./ChatMetadata";
import ChatSendBtn from "./ChatSendBtn";
import ChatUiGradient from "./ChatUiGradient";

export type PromptWithContext = Parameters<SendMessage>[0];

Expand All @@ -26,75 +30,38 @@ const MessageInput: FC<MessageInputProps> = ({ id, onSend, className }) => {
const [prompt, setPrompt] = useState<JSONContent>(emptyDocument);
const [isSending, setIsSending] = useState(false);
const { user } = useCurrentUser();
const { person } = usePerson(user?.personId);
const { person: chatUser } = usePerson(user?.personId);
const [currentJob, setCurrentJob] = useState<PersonJob | undefined>();
const [mentionedPeople, setMentionedPeople] = useState<
MentionedPerson[] | undefined
>();

useEffect(() => {
flow(
identity<typeof person>,
get("accounts"),
find<PersonAccount>(["isCurrent", true]),
(account) =>
!account
? undefined
: {
user: user?.userName,
employer: account.accountName,
jobRole: account.position,
},
setCurrentJob
)(person);
}, [person, user?.userName]);
setCurrentJobByUser(user, chatUser, setCurrentJob);
}, [chatUser, user?.userName]);

const handleSend = () => {
setIsSending(true);
const message = {
content: [{ text: getTextFromJsonContent(prompt) }],
aiContext: {
user: currentJob,
},
} as PromptWithContext;
onSend(message);
setPrompt(emptyDocument);
};
useEffect(() => {
setMentionedPeopleByPrompt(prompt, setMentionedPeople);
}, [prompt]);

const handleSend = () =>
handlePromptSend(
setIsSending,
currentJob,
mentionedPeople,
onSend,
prompt,
setPrompt
);

return (
<div className={cn(className)}>
<div className="h-8 bg-gradient-to-t from-background/95 via-background/80 to-background/0" />

<ChatUiGradient />
<div className="relative bg-white/95">
<InboxEditor
key={id}
notes={prompt}
saveNotes={(editor) => setPrompt(editor.getJSON())}
autoFocus
placeholder="Send a message"
saveAtCmdEnter={handleSend}
showSaveStatus={false}
className="pb-12 max-h-60 md:max-h-80 overflow-y-auto"
/>

<Button
className="rounded-full w-10 h-10 absolute bottom-3 right-1"
onClick={handleSend}
disabled={isSending}
>
{!isSending ? <ArrowUp /> : <Loader2 className="animate-spin" />}
</Button>
<ChatInput key={id} {...{ prompt, setPrompt, handleSend }} />
<ChatSendBtn {...{ isSending, handleSend }} />
</div>

{currentJob?.user && (
<div className="text-xs text-muted-foreground p-2 pt-1 space-y-1 bg-white/95">
<div>We will integrate the following information in the request:</div>
<ul className="list-disc list-inside">
<li>
Your name: {currentJob.user} (
{currentJob.jobRole && `${currentJob.jobRole} `}at{" "}
{currentJob.employer})
</li>
</ul>
</div>
)}
<ChatMetadata {...{ currentJob, mentionedPeople }} />
</div>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { TaskItem } from "../extensions/tasks/task-item";
const extendedConfig: Partial<NodeConfig<any, any>> = {
addAttributes() {
return {
...this.parent?.(),
blockId: {
default: null,
parseHTML: (element) => element.getAttribute("data-block-id"),
Expand Down
16 changes: 7 additions & 9 deletions docs/releases/next.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,20 @@
# Implementiere einen einfachen Chatbot ohne Spezialwissen (Version :VERSION)
# Kontext zu Personen im Chatbot berücksichtigen (Version :VERSION)

- [Allgemeines AI Chat Backend eingerichtet](https://docs.amplify.aws/react/ai/set-up-ai/)
- Eine eigene Oberfläche für einen Chatbot eingerichtet.
- Eine Seitenleiste zeigt die vergangenen Conversationen an.
- Informationen zu Personen werden dem Kontext im Chatbot vermerkt, wenn eine Person erwähnt wird.

## Fehlerbehebungen

- Im Editor für Projektnotizen wird die Ebene der Überschriften nun wieder berücksichtigt.

## Bekannte Fehler

- Bei längeren Antworten, die der Bot generiert, überschreibt er seine Antwort irgendwann selbst.

## In Arbeit

- Chat stabilisieren
- Chat einrichten, der Daten nutzt und in die Antworten mit einfließen lässt.

## Geplant

- Ich möchte ein Projekt in der täglichen Aufgabenliste abschließen können; es taucht nur dann wieder auf, wenn neue Aufgaben nach dem Abhaken hinzu kommen.
- Ich möchte `ContextProject.tsx` so wie es ist komplett auflösen. Ich sehe das nicht als effizient an, immer so viele Daten zu laden, selbst wenn ich nur die Projektnamen haben möchte.
- Chat stabilisieren

### Meetings

Expand Down
19 changes: 19 additions & 0 deletions helpers/chat/create-ai-context.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { PromptWithContext } from "@/components/chat/MessageInput";
import { PersonJob } from "@/pages/chat";
import { MentionedPerson } from "./set-mentioned-people";

export const createAiContext = (
currentJob: PersonJob | undefined,
mentionedPeople: MentionedPerson[] | undefined
): PromptWithContext["aiContext"] => ({
...(!currentJob && (!mentionedPeople || mentionedPeople.length === 0)
? {}
: {
description:
"Use the information from context as valid information to leverage for your response. Do not mention you are referring these information.",
}),
...(!currentJob ? {} : { user: currentJob }),
...(!mentionedPeople || mentionedPeople.length === 0
? {}
: { mentionedPeople }),
});
26 changes: 26 additions & 0 deletions helpers/chat/current-job.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { Person } from "@/api/usePerson";
import { User } from "@/api/useUser";
import { PersonAccount } from "@/helpers/person/accounts";
import { PersonJob } from "@/pages/chat";
import { find, flow, get, identity } from "lodash/fp";
import { Dispatch, SetStateAction } from "react";

export const setCurrentJobByUser = (
user: User | undefined,
person: Person | undefined,
setCurrentJob: Dispatch<SetStateAction<PersonJob | undefined>>
) =>
flow(
identity<typeof person>,
get("accounts"),
find<PersonAccount>(["isCurrent", true]),
(account) =>
!account
? undefined
: {
user: user?.userName,
employer: account.accountName,
jobRole: account.position,
},
setCurrentJob
)(person);
27 changes: 27 additions & 0 deletions helpers/chat/handle-send.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { PromptWithContext } from "@/components/chat/MessageInput";
import { emptyDocument } from "@/components/ui-elements/editors/helpers/document";
import { getTextFromJsonContent } from "@/components/ui-elements/editors/helpers/text-generation";
import { createAiContext } from "@/helpers/chat/create-ai-context";
import { PersonJob } from "@/pages/chat";
import { SendMessage } from "@aws-amplify/ui-react-ai";
import { JSONContent } from "@tiptap/core";
import { Dispatch, SetStateAction } from "react";
import { MentionedPerson } from "./set-mentioned-people";

export const handlePromptSend = (
setIsSending: Dispatch<SetStateAction<boolean>>,
currentJob: PersonJob | undefined,
mentionedPeople: MentionedPerson[] | undefined,
onSend: SendMessage,
prompt: JSONContent,
setPrompt: Dispatch<SetStateAction<JSONContent>>
) => {
setIsSending(true);
const message = {
content: [{ text: getTextFromJsonContent(prompt) }],
aiContext: createAiContext(currentJob, mentionedPeople),
} as PromptWithContext;
console.log({ message });
onSend(message);
setPrompt(emptyDocument);
};
Loading

0 comments on commit 7f83a89

Please sign in to comment.