Skip to content

Commit

Permalink
feat: add chat input and tool suggestion framework
Browse files Browse the repository at this point in the history
  • Loading branch information
EiffelFly committed Nov 26, 2024
1 parent 2e44504 commit 55df210
Show file tree
Hide file tree
Showing 15 changed files with 1,557 additions and 252 deletions.
22 changes: 22 additions & 0 deletions apps/console/src/app/[entity]/chat/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Metadata } from "next";

import { generateNextMetaBase } from "@instill-ai/toolkit/server";

import { ChatPageRender } from "./render";

export async function generateMetadata(): Promise<Metadata> {
const metadata: Metadata = {
title: `Instill Core | Chat`,
metadataBase: generateNextMetaBase({
defaultBase: "http://localhost:3000",
}),
openGraph: {
images: ["/instill-open-graph.png"],
},
};
return Promise.resolve(metadata);
}

export default async function Page() {
return <ChatPageRender />;
}
27 changes: 27 additions & 0 deletions apps/console/src/app/[entity]/chat/render.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
"use client";

import {
AppTopbar,
ChatView,
NamespaceSwitch,
PageBase,
} from "@instill-ai/toolkit";

import { useAppAccessToken } from "~/lib/use-app-access-token";
import { useAppTrackToken } from "~/lib/useAppTrackToken";

export function ChatPageRender() {
useAppAccessToken();
useAppTrackToken({ enabled: true });

return (
<PageBase>
<AppTopbar namespaceSwitch={<NamespaceSwitch />} />
<PageBase.Container>
<PageBase.Content contentPadding="p-8">
<ChatView />
</PageBase.Content>
</PageBase.Container>
</PageBase>
);
}
2 changes: 2 additions & 0 deletions packages/toolkit/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -123,13 +123,15 @@
"@tiptap/extension-italic": "^2.1.13",
"@tiptap/extension-link": "^2.1.13",
"@tiptap/extension-list-item": "^2.1.12",
"@tiptap/extension-mention": "^2.10.2",
"@tiptap/extension-ordered-list": "^2.1.12",
"@tiptap/extension-paragraph": "^2.1.12",
"@tiptap/extension-placeholder": "^2.1.16",
"@tiptap/extension-strike": "^2.1.13",
"@tiptap/extension-text": "^2.1.12",
"@tiptap/pm": "^2.1.13",
"@tiptap/react": "^2.1.12",
"@tiptap/suggestion": "^2.10.2",
"@types/lodash.debounce": "^4.0.9",
"@types/lodash.isequal": "^4.5.8",
"@uiw/codemirror-extensions-langs": "^4.22.2",
Expand Down
2 changes: 2 additions & 0 deletions packages/toolkit/src/components/top-bar/AppTopbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
import { useGuardPipelineBuilderUnsavedChangesNavigation } from "../../lib/hook";
import { env } from "../../server";
import { CETopbarDropdown } from "./CETopbarDropdown";
import { ChatLink } from "./ChatLink";
import { CloudTopbarDropdown } from "./CloudTopbarDropdown";
import { ExploreLink } from "./ExploreLink";
import { NamespaceSwitch } from "./NamespaceSwitch";
Expand Down Expand Up @@ -110,6 +111,7 @@ export const AppTopbar = ({
</div>
</div>
<div className="flex flex-1 flex-row justify-end">
<ChatLink />
{topbarControllerChildren ? (
topbarControllerChildren
) : isCloud ? (
Expand Down
32 changes: 32 additions & 0 deletions packages/toolkit/src/components/top-bar/ChatLink.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
"use client";

import Link from "next/link";
import { usePathname } from "next/navigation";
import cn from "clsx";

import { useRouteInfo } from "../../lib";

export const ChatLink = () => {
const routeInfo = useRouteInfo();

const pathname = usePathname();
const chatPath = `/${routeInfo.data.namespaceId}/chat`;

const isActive = pathname.startsWith(chatPath);

return (
<div className="my-auto flex flex-row gap-x-1">
<Link
href={chatPath}
className={cn(
"-mb-2 flex h-8 flex-row gap-x-2 border-b-2 text-base font-semibold text-semantic-fg-disabled hover:text-semantic-accent-default",
isActive
? "text-semantic-fg-primary border-semantic-accent-default"
: "border-transparent",
)}
>
Chat
</Link>
</div>
);
};
27 changes: 27 additions & 0 deletions packages/toolkit/src/lib/use-instill-store/chatSlice.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { StateCreator } from "zustand";

import { ChatSlice, InstillStore, InstillStoreMutators } from "./types";

export const createChatSlice: StateCreator<
InstillStore,
InstillStoreMutators,
[],
ChatSlice
> = (set) => ({
enabledTools: [],
updateEnabledTools: (fn: (prev: string[]) => string[]) =>
set((state) => {
return {
...state,
enabledTools: fn(state.enabledTools),
};
}),
enableToolSuggestion: false,
updateEnableToolSuggestion: (fn: (prev: boolean) => boolean) =>
set((state) => {
return {
...state,
enableToolSuggestion: fn(state.enableToolSuggestion),
};
}),
});
10 changes: 9 additions & 1 deletion packages/toolkit/src/lib/use-instill-store/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -303,12 +303,20 @@ export type RecentlyUsedSlice = {
) => void;
};

export type ChatSlice = {
enabledTools: string[];
updateEnabledTools: (fn: (prev: string[]) => string[]) => void;
enableToolSuggestion: boolean;
updateEnableToolSuggestion: (fn: (prev: boolean) => boolean) => void;
};

export type InstillStore = SmartHintSlice &
PipelineBuilderSlice &
GeneralSlice &
RecentlyUsedSlice &
EditorSlice &
FeatureFlagSlice;
FeatureFlagSlice &
ChatSlice;

export type InstillStoreMutators = [
["zustand/devtools", never],
Expand Down
2 changes: 2 additions & 0 deletions packages/toolkit/src/lib/use-instill-store/useInstillStore.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { create } from "zustand";
import { devtools, subscribeWithSelector } from "zustand/middleware";

import { createChatSlice } from "./chatSlice";
import { createEditorSlice } from "./editorSlice";
import { createFeatureFlagSlice } from "./featureFlagSlice";
import { createGeneralSlice } from "./generalSlice";
Expand All @@ -18,6 +19,7 @@ export const useInstillStore = create<InstillStore>()(
...createRecentlyUsedSlice(...a),
...createEditorSlice(...a),
...createFeatureFlagSlice(...a),
...createChatSlice(...a),
})),
),
);
71 changes: 58 additions & 13 deletions packages/toolkit/src/view/chat/ChatInput.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,74 @@
import * as React from "react";
import BulletList from "@tiptap/extension-bullet-list";
import Document from "@tiptap/extension-document";
import ListItem from "@tiptap/extension-list-item";
import Mention from "@tiptap/extension-mention";
import Paragraph from "@tiptap/extension-paragraph";
import Placeholder from "@tiptap/extension-placeholder";
import Text from "@tiptap/extension-text";
import { EditorContent, useEditor } from "@tiptap/react";

import { Button, Icons } from "@instill-ai/design-system";

import { useToolSuggestionConfig } from "./useToolSuggestionConfig";

export const ChatInput = () => {
const toolSuggestionConfig = useToolSuggestionConfig();

const editor = useEditor({
extensions: [Document, BulletList, Paragraph, Text],
extensions: [
Document,
BulletList.configure({
HTMLAttributes: {
class: "!mb-0",
},
}),
ListItem,
Paragraph,
Text,
Mention.configure({
HTMLAttributes: {
class: "mention",
},
suggestion: toolSuggestionConfig,
}),
Placeholder.configure({
placeholder: "Ask something or @mention an action",
}),
],
editorProps: {
attributes: {
class: "w-full h-full markdown-body rounded-[12px] p-6",
class: "w-full h-full markdown-body pl-4 py-4 focus:outline-none",
},
},
content: "<h2>Your Pipeline Readme</h2>",
// onUpdate: ({ editor }) => {},
});

<div
className="flex flex-col px-2 border rounded"
style={{
borderColor: "#E1E6EF",
}}
>
<div className="flex p-4">
<EditorContent editor={editor} />
</div>
</div>;
return (
<React.Fragment>
<style jsx={true} global={true}>
{`
.mention {
background-color: #f0f0f0;
padding: 0.1rem 0.3rem;
border-radius: 0.4rem;
box-decoration-break: clone;
}
`}
</style>
<div
className="flex flex-col px-2 border rounded"
style={{
borderColor: "#E1E6EF",
}}
>
<div className="flex flex-row w-full pr-4">
<EditorContent className="w-full" editor={editor} />
<Button variant="primary" size="sm" className="!p-2 my-auto">
<Icons.ArrowNarrowRight className="w-4 h-4 stroke-semantic-bg-primary" />
</Button>
</div>
</div>
</React.Fragment>
);
};
11 changes: 11 additions & 0 deletions packages/toolkit/src/view/chat/ChatView.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { ChatInput } from "./ChatInput";

export const ChatView = () => {
return (
<div className="flex flex-col">
<div id="tool-suggestion" />
<div className="h-[1000px]"></div>
<ChatInput />
</div>
);
};
Loading

0 comments on commit 55df210

Please sign in to comment.