Skip to content

Commit

Permalink
Feat: supports OSS Chat with Orama Switch
Browse files Browse the repository at this point in the history
  • Loading branch information
raiindev committed Nov 25, 2024
1 parent 65357d8 commit 90dff7b
Show file tree
Hide file tree
Showing 14 changed files with 97 additions and 151 deletions.
3 changes: 2 additions & 1 deletion apps/demo-react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
"dependencies": {
"react": "^18.3.1",
"react-dom": "^18.3.1",
"@orama/react-components": "workspace:*"
"@orama/react-components": "workspace:*",
"@oramacloud/client": "^2.1.4"
},
"devDependencies": {
"@types/react": "^18.3.3",
Expand Down
1 change: 1 addition & 0 deletions apps/demo-react/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { OramaChatBox, OramaSearchBox, OramaSearchButton } from '@orama/react-components'
import './App.css'
import { OramaClient } from "@oramacloud/client"

function App() {
return (
Expand Down
2 changes: 1 addition & 1 deletion apps/storybook/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
},
"dependencies": {
"@orama/wc-components": "workspace:*",
"@oramacloud/client": "1.3.15",
"@oramacloud/client": "^2.1.0",
"@storybook/preview-api": "^8.2.9",
"@storybook/web-components": "^8.2.3"
},
Expand Down
19 changes: 7 additions & 12 deletions apps/storybook/stories/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ export type DemoIndexConfig = Record<string, Components.OramaSearchBox>
const demoIndexes: DemoIndexConfig = {
orama: {
open: true,
index: {
api_key: 'LerNlbp6379jVKaPs4wt2nZT4MJZbU1J',
endpoint: 'https://cloud.orama.run/v1/indexes/docs-orama-b3f5xd',
},
// Uncomment this line to use the OramaClient instance and comment the index prop
// clientInstance: new OramaClient({
// index: {
// api_key: 'LerNlbp6379jVKaPs4wt2nZT4MJZbU1J',
// endpoint: 'https://cloud.orama.run/v1/indexes/docs-orama-b3f5xd',
// }),
// },
// Uncomment this line to use the OramaClient instance and comment the index prop
clientInstance: new OramaClient({
api_key: 'LerNlbp6379jVKaPs4wt2nZT4MJZbU1J',
endpoint: 'https://cloud.orama.run/v1/indexes/docs-orama-b3f5xd',
}),
placeholder: 'What do you want to learn about Orama?',
sourceBaseUrl: 'https://docs.orama.com',
sourcesMap: {
Expand All @@ -28,11 +28,6 @@ const demoIndexes: DemoIndexConfig = {
description: 'content',
section: 'category',
},
highlight: {
caseSensitive: false,
HTMLTag: 'b',
CSSClass: 'font-bold',
},
},
recipes: {
open: true,
Expand Down
5 changes: 4 additions & 1 deletion apps/storybook/stories/public/orama-search-box.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,9 @@ const Template = ({
facetProperty,
themeConfig,
index,
clientInstance,
sourceBaseUrl,
sourcesMap,
highlight,
resultMap,
}) => {
return html`<div>
Expand All @@ -93,6 +93,7 @@ const Template = ({
.colorScheme=${colorScheme}
.themeConfig=${themeConfig || preset.themeConfig}
.index=${index || preset.index}
.clientInstance=${clientInstance || preset.clientInstance}
.instance=${preset.instance}
.suggestions=${suggestions || preset?.suggestions}
.sourceBaseUrl=${sourceBaseUrl || preset?.sourceBaseUrl}
Expand All @@ -119,6 +120,7 @@ const TemplateAsEmbed = ({
resultMap,
themeConfig,
index,
clientInstance,
sourceBaseURL,
suggestions,
sourcesMap,
Expand All @@ -132,6 +134,7 @@ const TemplateAsEmbed = ({
.colorScheme=${colorScheme}
.themeConfig=${themeConfig || preset.themeConfig}
.index=${index || preset.index}
.clientInstance=${clientInstance || preset.clientInstance}
.instance=${preset.instance}
.suggestions=${suggestions || preset?.suggestions}
.sourceBaseUrl=${sourceBaseURL || preset?.sourceBaseUrl}
Expand Down
3 changes: 2 additions & 1 deletion packages/ui-stencil/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@
"types": "dist/types/index.d.ts",
"dependencies": {
"@orama/highlight": "^0.1.6",
"@orama/orama": "^2.0.23",
"@orama/orama": "^3.0.0",
"@orama/switch": "^3.0.0",
"@oramacloud/client": "^2.1.0",
"@phosphor-icons/webcomponents": "^2.1.5",
"@stencil/core": "^4.19.0",
Expand Down
14 changes: 8 additions & 6 deletions packages/ui-stencil/src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,25 @@ import { ButtonProps } from "./components/internal/orama-button/orama-button";
import { ChatMarkdownLinkHref, ChatMarkdownLinkTarget, ChatMarkdownLinkTitle, CloudIndexConfig, ColorScheme, Facet, OnAnswerGeneratedCallbackProps, OnAnswerSourceClickCallbackProps, OnChatMarkdownLinkClickedCallbackProps, OnSearchCompletedCallbackProps, OnSearchResultClickCallbackProps, ResultMap, SearchResult, SearchResultBySection, SourcesMap } from "./types/index";
import { TChatInteraction } from "./context/chatContext";
import { OramaClient } from "@oramacloud/client";
import { AnyOrama, Orama, SearchParams } from "@orama/orama";
import { Facet } from "./components/internal/orama-facets/orama-facets";
import { InputProps } from "./components/internal/orama-input/orama-input";
import { ModalStatus } from "./components/internal/orama-modal/orama-modal";
import { HighlightOptions } from "@orama/highlight";
import { TThemeOverrides } from "./config/theme";
import { AnyOrama, Orama, SearchParams } from "@orama/orama";
import { TThemeOverrides as TThemeOverrides1 } from "./components.d";
import { SearchResultsProps } from "./components/internal/orama-search-results/orama-search-results";
import { TextProps } from "./components/internal/orama-text/orama-text";
export { ButtonProps } from "./components/internal/orama-button/orama-button";
export { ChatMarkdownLinkHref, ChatMarkdownLinkTarget, ChatMarkdownLinkTitle, CloudIndexConfig, ColorScheme, Facet, OnAnswerGeneratedCallbackProps, OnAnswerSourceClickCallbackProps, OnChatMarkdownLinkClickedCallbackProps, OnSearchCompletedCallbackProps, OnSearchResultClickCallbackProps, ResultMap, SearchResult, SearchResultBySection, SourcesMap } from "./types/index";
export { TChatInteraction } from "./context/chatContext";
export { OramaClient } from "@oramacloud/client";
export { AnyOrama, Orama, SearchParams } from "@orama/orama";
export { Facet } from "./components/internal/orama-facets/orama-facets";
export { InputProps } from "./components/internal/orama-input/orama-input";
export { ModalStatus } from "./components/internal/orama-modal/orama-modal";
export { HighlightOptions } from "@orama/highlight";
export { TThemeOverrides } from "./config/theme";
export { AnyOrama, Orama, SearchParams } from "@orama/orama";
export { TThemeOverrides as TThemeOverrides1 } from "./components.d";
export { SearchResultsProps } from "./components/internal/orama-search-results/orama-search-results";
export { TextProps } from "./components/internal/orama-text/orama-text";
Expand Down Expand Up @@ -65,7 +67,7 @@ export namespace Components {
"chatMarkdownLinkHref"?: ChatMarkdownLinkHref;
"chatMarkdownLinkTarget"?: ChatMarkdownLinkTarget;
"chatMarkdownLinkTitle"?: ChatMarkdownLinkTitle;
"clientInstance"?: OramaClient;
"clientInstance"?: OramaClient | Orama<unknown>;
"index"?: CloudIndexConfig;
"linksRel"?: string;
"linksTarget"?: string;
Expand Down Expand Up @@ -149,7 +151,7 @@ export namespace Components {
"chatMarkdownLinkTarget"?: ChatMarkdownLinkTarget;
"chatMarkdownLinkTitle"?: ChatMarkdownLinkTitle;
"chatPlaceholder"?: string;
"clientInstance"?: OramaClient;
"clientInstance"?: OramaClient | AnyOrama;
"colorScheme"?: ColorScheme;
"disableChat"?: boolean;
"facetProperty"?: string;
Expand Down Expand Up @@ -623,7 +625,7 @@ declare namespace LocalJSX {
"chatMarkdownLinkHref"?: ChatMarkdownLinkHref;
"chatMarkdownLinkTarget"?: ChatMarkdownLinkTarget;
"chatMarkdownLinkTitle"?: ChatMarkdownLinkTitle;
"clientInstance"?: OramaClient;
"clientInstance"?: OramaClient | Orama<unknown>;
"index"?: CloudIndexConfig;
"linksRel"?: string;
"linksTarget"?: string;
Expand Down Expand Up @@ -725,7 +727,7 @@ declare namespace LocalJSX {
"chatMarkdownLinkTarget"?: ChatMarkdownLinkTarget;
"chatMarkdownLinkTitle"?: ChatMarkdownLinkTitle;
"chatPlaceholder"?: string;
"clientInstance"?: OramaClient;
"clientInstance"?: OramaClient | AnyOrama;
"colorScheme"?: ColorScheme;
"disableChat"?: boolean;
"facetProperty"?: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import type {
} from '@/types'
import type { OramaClient } from '@oramacloud/client'
import '@phosphor-icons/webcomponents/dist/icons/PhArrowClockwise.mjs'
import type { Orama } from '@orama/orama'

@Component({
tag: 'orama-chat-box',
Expand All @@ -23,7 +24,7 @@ import '@phosphor-icons/webcomponents/dist/icons/PhArrowClockwise.mjs'
export class ChatBox {
@Element() el: HTMLElement
@Prop() index?: CloudIndexConfig
@Prop() clientInstance?: OramaClient
@Prop() clientInstance?: OramaClient | Orama<unknown>
@Prop() sourceBaseUrl?: string
@Prop() linksTarget?: string
@Prop() linksRel?: string
Expand All @@ -36,7 +37,6 @@ export class ChatBox {
@Prop() chatMarkdownLinkHref?: ChatMarkdownLinkHref
@Prop() chatMarkdownLinkTarget?: ChatMarkdownLinkTarget

@State() oramaClient: OramaClient
@State() componentID = generateRandomID('chat-box')

/**
Expand Down Expand Up @@ -66,9 +66,9 @@ export class ChatBox {

startChatService() {
validateCloudIndexConfig(this.el, this.index, this.clientInstance)
this.oramaClient = this.clientInstance || initOramaClient(this.index)
const oramaClient = this.clientInstance || initOramaClient(this.index)

chatContext.chatService = new ChatService(this.oramaClient)
chatContext.chatService = new ChatService(oramaClient)
}

render() {
Expand Down
2 changes: 0 additions & 2 deletions packages/ui-stencil/src/components/orama-chat-box/readme.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
# orama-chat-box



<!-- Auto Generated Below -->


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ import type {
} from '@/types'
import type { TThemeOverrides } from '@/config/theme'

// TODO: AI components should be lazyly loaded. In case of Disable AI flag, it should not be loaded at all
// https://linear.app/oramasearch/issue/ORM-1824/ai-components-should-be-lazyly-loaded-in-case-of-disable-ai-flag-they

@Component({
tag: 'orama-search-box',
styleUrl: 'orama-search-box.scss',
Expand All @@ -36,7 +39,7 @@ export class SearchBox {
@Prop() themeConfig?: Partial<TThemeOverrides>
@Prop() colorScheme?: ColorScheme = 'light'
@Prop() index?: CloudIndexConfig
@Prop() clientInstance?: OramaClient
@Prop() clientInstance?: OramaClient | AnyOrama
@Prop({ mutable: true }) open = false
@Prop() facetProperty?: string
@Prop() resultMap?: Partial<ResultMap> = {}
Expand All @@ -59,7 +62,6 @@ export class SearchBox {
@Prop() chatMarkdownLinkHref?: ChatMarkdownLinkHref
@Prop() chatMarkdownLinkTarget?: ChatMarkdownLinkTarget

@State() oramaClient: OramaClient
@State() componentID = generateRandomID('search-box')
@State() systemScheme: Omit<ColorScheme, 'system'> = 'light'
@State() windowWidth: number
Expand Down Expand Up @@ -93,6 +95,7 @@ export class SearchBox {
schemaQuery: MediaQueryList

@Watch('index')
@Watch('clientInstance')
indexChanged() {
this.startServices()
}
Expand Down Expand Up @@ -171,10 +174,10 @@ export class SearchBox {

startServices() {
validateCloudIndexConfig(this.htmlElement, this.index, this.clientInstance)
this.oramaClient = this.clientInstance ? this.clientInstance : initOramaClient(this.index)
const oramaClient = this.clientInstance ? this.clientInstance : initOramaClient(this.index)

searchState.searchService = new SearchService(this.oramaClient)
chatContext.chatService = new ChatService(this.oramaClient)
searchState.searchService = new SearchService(oramaClient)
chatContext.chatService = new ChatService(oramaClient)
}

componentWillLoad() {
Expand Down
27 changes: 18 additions & 9 deletions packages/ui-stencil/src/services/ChatService.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
import type { OramaClient, AnswerSession, AskParams } from '@oramacloud/client'
import type { AnswerSession as OSSAnswerSession } from '@orama/orama'
import type { AnswerSession as CloudAnswerSession } from '@oramacloud/client'
import type { OramaSwitchClient } from '@orama/switch'
import { Switch } from '@orama/switch'
import { OramaClientNotInitializedError } from '@/erros/OramaClientNotInitialized'
import { chatContext, TAnswerStatus } from '@/context/chatContext'
import type { OnAnswerGeneratedCallbackProps } from '@/types'

export class ChatService {
oramaClient: OramaClient
answerSession: AnswerSession<true>
oramaClient: Switch<OramaSwitchClient>
answerSession: CloudAnswerSession<true> | OSSAnswerSession

constructor(oramaClient: OramaClient) {
this.oramaClient = oramaClient
constructor(oramaClient: OramaSwitchClient) {
this.oramaClient = new Switch(oramaClient)
}

sendQuestion = (
Expand Down Expand Up @@ -45,6 +49,7 @@ export class ChatService {
chatContext.interactions = normalizedState.map((interaction, index) => {
const isLatest = state.length - 1 === index
let answerStatus = TAnswerStatus.loading
let sources = []

if (interaction.aborted) {
answerStatus = TAnswerStatus.aborted
Expand All @@ -57,7 +62,15 @@ export class ChatService {
}

// biome-ignore lint/suspicious/noExplicitAny: Client should expose this type
const sources = (interaction.sources as any)?.map((source) => source.document)
/**
* we usually expected to receive interaction.sources as an array, but sometimes it comes as an object.
* need to check OSS Orama and fix it if it's a bug.
**/
if (interaction.sources) {
sources = Array.isArray(interaction.sources) ?
(interaction.sources as any)?.map((source) => source.document) :
(interaction.sources.hits as any)?.map((source) => source.document)
}

if (isLatest && answerStatus === TAnswerStatus.done) {
callbacks?.onAnswerGeneratedCallback?.({
Expand All @@ -83,10 +96,6 @@ export class ChatService {
},
},
})

if (systemPrompts) {
this.answerSession.setSystemPromptConfiguration({ systemPrompts })
}
}

// TODO: ABORT/ERROR/STOP should emmit onStateChange event. Keeping the lines below as a reference
Expand Down
12 changes: 7 additions & 5 deletions packages/ui-stencil/src/services/SearchService.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { OramaClient, ClientSearchParams } from '@oramacloud/client'
import type { ClientSearchParams } from '@oramacloud/client'
import { OramaClientNotInitializedError } from '@/erros/OramaClientNotInitialized'
import { searchState } from '@/context/searchContext'
import { Switch, type OramaSwitchClient } from '@orama/switch'
import type {
OnSearchCompletedCallbackProps,
ResultMap,
Expand All @@ -13,14 +14,15 @@ import type {
const LIMIT_RESULTS = 10

// TODO: Orama Client should expose Result type
type OramaHit = { id: string; score: number; document: { title: string; description: string; path: string } }
// biome-ignore lint/suspicious/noExplicitAny: There is not way to type document as we only know what it is in runtime
type OramaHit = { id: string; score: number; document: any }

export class SearchService {
private abortController: AbortController
private oramaClient: OramaClient
private oramaClient: Switch<OramaSwitchClient>

constructor(oramaClient: OramaClient) {
this.oramaClient = oramaClient
constructor(oramaClient: OramaSwitchClient) {
this.oramaClient = new Switch(oramaClient)
this.abortController = new AbortController()
}

Expand Down
12 changes: 10 additions & 2 deletions packages/ui-stencil/src/utils/utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import type { CloudIndexConfig } from '@/types'
import type { AnyOrama, Orama } from '@orama/orama'
import { Switch } from '@orama/switch'
import { OramaClient } from '@oramacloud/client'

/**
Expand Down Expand Up @@ -72,7 +74,11 @@ export function getNonExplicitAttributes(element: HTMLElement, explicitProps: st
}, {})
}

export function validateCloudIndexConfig(el: HTMLElement, index?: CloudIndexConfig, instance?: OramaClient): void {
export function validateCloudIndexConfig(
el: HTMLElement,
index?: CloudIndexConfig,
instance?: OramaClient | AnyOrama,
): void {
const componentDetails = `
Component: ${el.tagName.toLowerCase()}
Id: ${el.id}
Expand All @@ -85,8 +91,10 @@ export function validateCloudIndexConfig(el: HTMLElement, index?: CloudIndexConf
}

if (instance && !index) {
const oramaInstance = new Switch(instance)

// TODO: maybe add a validate method to the client?
instance
oramaInstance
.search({
term: 'test',
})
Expand Down
Loading

0 comments on commit 90dff7b

Please sign in to comment.