Skip to content

Commit

Permalink
chatbot
Browse files Browse the repository at this point in the history
  • Loading branch information
abvthecity committed Aug 2, 2024
1 parent 69714a2 commit 32f51ce
Show file tree
Hide file tree
Showing 21 changed files with 501 additions and 350 deletions.
1 change: 1 addition & 0 deletions packages/commons/search-utils/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"@types/node": "^18.7.18",
"depcheck": "^1.4.3",
"eslint": "^8.56.0",
"instantsearch.js": "^4.63.0",
"organize-imports-cli": "^0.10.0",
"prettier": "^3.3.2",
"stylelint": "^16.1.0",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import { Algolia, FernNavigation } from "@fern-api/fdr-sdk";
import { SidebarVersionInfo } from "@fern-ui/fdr-utils";
import { UnreachableCaseError } from "ts-essentials";
import type { SearchRecord } from "./types";

export function getSlugForSearchRecord(record: SearchRecord, basePath: string | undefined): string {
export function getSlugForSearchRecord(record: Algolia.AlgoliaRecord, basePath: string | undefined): string {
return visitSearchRecord<string>(record)._visit({
v3: (record) => record.slug,
v2: (record) =>
Expand All @@ -21,6 +19,25 @@ export function getSlugForSearchRecord(record: SearchRecord, basePath: string |
});
}

export function getTitleForSearchRecord(record: Algolia.AlgoliaRecord): string {
return visitSearchRecord<string>(record)._visit({
v3: (record) => record.title,
v2: (record) =>
record.type === "endpoint-v2"
? record.endpoint.path.parts.map((p) => (p.type === "pathParameter" ? `:${p.value}` : p.value)).join("")
: record.title,
v1: (record) => record.title,
});
}

export function getContentForSearchRecord(record: Algolia.AlgoliaRecord): string | undefined {
return visitSearchRecord<string | undefined>(record)._visit({
v3: (record) => record.content ?? undefined,
v2: (record) => (record.type === "page-v2" ? record.content : undefined),
v1: () => undefined,
});
}

function getLeadingPathForSearchRecord(record: Algolia.AlgoliaRecord): string[] {
switch (record.type) {
case "page":
Expand All @@ -35,10 +52,10 @@ function getLeadingPathForSearchRecord(record: Algolia.AlgoliaRecord): string[]
}

export function createSearchPlaceholderWithVersion(
activeVersion: SidebarVersionInfo | undefined,
version: string | undefined,
sidebar: FernNavigation.SidebarRootNode | undefined,
): string {
return `Search ${activeVersion != null ? `across ${activeVersion.id} ` : ""}for ${createSearchPlaceholder(sidebar)}...`;
return `Search ${version != null ? `across ${version} ` : ""}for ${createSearchPlaceholder(sidebar)}...`;
}

function createSearchPlaceholder(sidebar: FernNavigation.SidebarRootNode | undefined): string {
Expand Down
2 changes: 2 additions & 0 deletions packages/commons/search-utils/src/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
export * from "./SearchConfig";
export * from "./getSlugForSearchRecord";
export * from "./types";
File renamed without changes.
2 changes: 1 addition & 1 deletion packages/ui/app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@
"@shikijs/transformers": "^1.2.2",
"@types/nprogress": "^0.2.3",
"@vercel/edge-config": "^1.1.0",
"algoliasearch": "^4.22.1",
"algoliasearch": "^4.24.0",
"bezier-easing": "^2.1.0",
"clsx": "^2.1.0",
"colorjs.io": "^0.5.0",
Expand Down
4 changes: 2 additions & 2 deletions packages/ui/app/src/search/SearchDialog.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { createSearchPlaceholderWithVersion } from "@fern-ui/search-utils";
import { useAtomValue, useSetAtom } from "jotai";
import dynamic from "next/dynamic";
import { PropsWithChildren, ReactElement, useMemo, useRef } from "react";
Expand All @@ -18,7 +19,6 @@ import { useAlgoliaSearchClient } from "./algolia/useAlgoliaSearchClient";
import { InkeepChatButton } from "./inkeep/InkeepChatButton";
import { InkeepCustomTrigger } from "./inkeep/InkeepCustomTrigger";
import { useSearchTrigger } from "./useSearchTrigger";
import { createSearchPlaceholderWithVersion } from "./util";

const CohereChatButton = dynamic(
() => import("./cohere/CohereChatButton").then(({ CohereChatButton }) => CohereChatButton),
Expand Down Expand Up @@ -61,7 +61,7 @@ export const SearchSidebar: React.FC<PropsWithChildren<SearchSidebar.Props>> = (
const sidebar = useSidebarNodes();
const activeVersion = useAtomValue(CURRENT_VERSION_ATOM);
const placeholder = useMemo(
() => createSearchPlaceholderWithVersion(activeVersion, sidebar),
() => createSearchPlaceholderWithVersion(activeVersion?.id, sidebar),
[activeVersion, sidebar],
);

Expand Down
3 changes: 1 addition & 2 deletions packages/ui/app/src/search/SearchHit.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { visitDiscriminatedUnion } from "@fern-ui/core-utils";
import { getSlugForSearchRecord, type SearchRecord } from "@fern-ui/search-utils";
import cn from "clsx";
import Link from "next/link";
import { ReactElement, useMemo } from "react";
Expand All @@ -9,8 +10,6 @@ import { EndpointRecordV3 } from "./content/EndpointRecordV3";
import { PageRecord } from "./content/PageRecord";
import { PageRecordV2 } from "./content/PageRecordV2";
import { PageRecordV3 } from "./content/PageRecordV3";
import type { SearchRecord } from "./types";
import { getSlugForSearchRecord } from "./util";

export declare namespace SearchHit {
export interface Props {
Expand Down
3 changes: 1 addition & 2 deletions packages/ui/app/src/search/SearchHits.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import { FernScrollArea } from "@fern-ui/components";
import { useKeyboardPress } from "@fern-ui/react-commons";
import { getSlugForSearchRecord, type SearchRecord } from "@fern-ui/search-utils";
import { useRouter } from "next/router";
import React, { PropsWithChildren, useEffect, useMemo, useRef, useState } from "react";
import { useInfiniteHits, useInstantSearch } from "react-instantsearch";
import { useBasePath, useCloseSearchDialog } from "../atoms";
import { SearchHit } from "./SearchHit";
import type { SearchRecord } from "./types";
import { getSlugForSearchRecord } from "./util";

export const EmptyStateView: React.FC<PropsWithChildren> = ({ children }) => {
return <div className="justify t-muted flex h-24 w-full flex-col items-center py-3">{children}</div>;
Expand Down
15 changes: 10 additions & 5 deletions packages/ui/app/src/search/algolia/AlgoliaSearchDialog.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
import { createSearchPlaceholderWithVersion } from "@fern-ui/search-utils";
import * as Dialog from "@radix-ui/react-dialog";
import { SearchClient } from "algoliasearch";
import clsx from "clsx";
import { useAtomValue, useSetAtom } from "jotai";
import { ReactElement, useMemo, useRef } from "react";
import { InstantSearch } from "react-instantsearch";
import { CURRENT_VERSION_ATOM, POSITION_SEARCH_DIALOG_OVER_HEADER_ATOM, useSidebarNodes } from "../../atoms";

import { IS_MOBILE_SCREEN_ATOM, SEARCH_DIALOG_OPEN_ATOM, useIsSearchDialogOpen } from "../../atoms";
import {
CURRENT_VERSION_ATOM,
IS_MOBILE_SCREEN_ATOM,
POSITION_SEARCH_DIALOG_OVER_HEADER_ATOM,
SEARCH_DIALOG_OPEN_ATOM,
useIsSearchDialogOpen,
useSidebarNodes,
} from "../../atoms";
import { SearchHits } from "../SearchHits";
import { createSearchPlaceholderWithVersion } from "../util";
import { SearchBox } from "./SearchBox";
import { useAlgoliaSearchClient } from "./useAlgoliaSearchClient";

Expand Down Expand Up @@ -51,7 +56,7 @@ function FernInstantSearch({ searchClient, indexName, inputRef }: FernInstantSea
const sidebar = useSidebarNodes();
const activeVersion = useAtomValue(CURRENT_VERSION_ATOM);
const placeholder = useMemo(
() => createSearchPlaceholderWithVersion(activeVersion, sidebar),
() => createSearchPlaceholderWithVersion(activeVersion?.id, sidebar),
[activeVersion, sidebar],
);
return (
Expand Down
37 changes: 33 additions & 4 deletions packages/ui/app/src/search/cohere/CohereChatButton.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ChatbotMessage, ChatbotModal, CohereIcon } from "@fern-ui/chatbot";
import { ChatbotMessage, ChatbotModal, Citation, CohereIcon } from "@fern-ui/chatbot";
import * as Dialog from "@radix-ui/react-dialog";
import type { Cohere } from "cohere-ai";
import { useAtom } from "jotai";
Expand All @@ -7,8 +7,10 @@ import { createPortal } from "react-dom";
import urlJoin from "url-join";
import { Stream } from "../../api-playground/Stream";
import { COHERE_ASK_AI, useBasePath } from "../../atoms";
import { FernLink } from "../../components/FernLink";
import { CodeBlock } from "../../mdx/components/code";
import { useSearchConfig } from "../../services/useSearchService";
import { BuiltWithFern } from "../../sidebar/BuiltWithFern";

export function CohereChatButton(): ReactElement | null {
const [config] = useSearchConfig();
Expand All @@ -31,6 +33,7 @@ export function CohereChatButton(): ReactElement | null {
}

let text = "";
const citations: Citation[] = [];

const stream = new Stream<ChatbotMessage>({
stream: body,
Expand All @@ -39,7 +42,19 @@ export function CohereChatButton(): ReactElement | null {
if (event.eventType === "text-generation") {
text += event.text;
}
return { message: text, role: "AI", citations: [] };

if (event.eventType === "citation-generation") {
event.citations.forEach((citation) => {
citations.push({
text: citation.text,
start: citation.start,
end: citation.end,
slugs: citation.documentIds,
});
});
}

return { message: text, role: "AI", citations };
},
terminator: "\n",
});
Expand All @@ -63,8 +78,8 @@ export function CohereChatButton(): ReactElement | null {
document.body,
)}
<Dialog.Portal>
<Dialog.Overlay className="fixed inset-0 z-0 bg-background/50 backdrop-blur-sm max-sm:hidden" />
<Dialog.Content className="fixed md:max-w-content-width my-[10vh] top-0 inset-x-0 z-10 mx-6 max-h-[80vh] md:mx-auto flex flex-col">
<Dialog.Overlay className="fixed inset-0 z-0 bg-background/50 backdrop-blur-sm" />
<Dialog.Content className="fixed md:max-w-content-width my-[10vh] top-0 inset-x-0 mx-6 max-h-[80vh] md:mx-auto flex flex-col">
<ChatbotModal
chatStream={chatStream}
className="bg-search-dialog border-default flex h-auto min-h-0 shrink flex-col overflow-hidden rounded-xl border text-left align-middle shadow-2xl backdrop-blur-lg"
Expand All @@ -79,7 +94,21 @@ export function CohereChatButton(): ReactElement | null {
}
return <pre {...props} />;
},
a({ href, ...props }) {
if (href == null) {
return <a {...props} />;
}
return <FernLink href={href} {...props} />;
},
}}
belowInput={
<div className="mt-4 px-5 text-grayscale-a10 flex justify-between items-center gap-2">
<FernLink href="https://cohere.com/" className="text-xs font-medium">
Powered by Cohere (command-r-plus)
</FernLink>
<BuiltWithFern />
</div>
}
/>
</Dialog.Content>
</Dialog.Portal>
Expand Down
2 changes: 1 addition & 1 deletion packages/ui/app/src/search/content/EndpointRecord.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { SearchRecord } from "@fern-ui/search-utils";
import { CodeIcon } from "@radix-ui/react-icons";
import cn from "clsx";
import { Snippet } from "react-instantsearch";
import type { SearchRecord } from "../types";

export declare namespace EndpointRecord {
export interface Props {
Expand Down
2 changes: 1 addition & 1 deletion packages/ui/app/src/search/content/EndpointRecordV2.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { visitDiscriminatedUnion } from "@fern-ui/core-utils";
import type { EndpointSearchRecordV2 } from "@fern-ui/search-utils";
import cn from "clsx";
import { CornerDownLeft } from "react-feather";
import type { EndpointSearchRecordV2 } from "../types";
import { SearchHitBreadCrumbs } from "./SearchHitBreadCrumbs";

export declare namespace EndpointRecordV2 {
Expand Down
2 changes: 1 addition & 1 deletion packages/ui/app/src/search/content/PageRecord.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { SearchRecord } from "@fern-ui/search-utils";
import { ActivityLogIcon } from "@radix-ui/react-icons";
import cn from "clsx";
import { Snippet } from "react-instantsearch";
import type { SearchRecord } from "../types";

export declare namespace PageRecord {
export interface Props {
Expand Down
2 changes: 1 addition & 1 deletion packages/ui/app/src/search/content/PageRecordV2.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { PageSearchRecordV2 } from "@fern-ui/search-utils";
import cn from "clsx";
import { CornerDownLeft } from "react-feather";
import type { PageSearchRecordV2 } from "../types";
import { SearchHitBreadCrumbs } from "./SearchHitBreadCrumbs";

export declare namespace PageRecordV2 {
Expand Down
Loading

0 comments on commit 32f51ce

Please sign in to comment.