Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add kapa widget #1661

Merged
merged 14 commits into from
Oct 21, 2024
Merged

feat: add kapa widget #1661

merged 14 commits into from
Oct 21, 2024

Conversation

danielroe
Copy link
Member

@danielroe danielroe commented Sep 19, 2024

πŸ”— Linked issue

❓ Type of change

  • πŸ“– Documentation (updates to the documentation or readme)
  • 🐞 Bug fix (a non-breaking change that fixes an issue)
  • πŸ‘Œ Enhancement (improving an existing functionality)
  • ✨ New feature (a non-breaking change that adds functionality)
  • 🧹 Chore (updates to the build process or auxiliary tools and libraries)
  • ⚠️ Breaking change (fix or feature that would cause existing functionality to change)

πŸ“š Description

https://docs.kapa.ai/integrations/website-widget/configuration

This adds configuration for the kapa widget (though note that it may not display as it's possible it has to be allow-listed for each preview domain - but you can check locally).

Here's what it looks like - note that the advice isn't exactly correct (it references nitro.config rather than nuxt.config but this is something we can fine-tune).

cursorful-video.mp4

It would be nice in future to integrate it into the search box if possible πŸ™

Note I couldn't use @nuxt/scripts as it caused a CORS issue when loaded that way - any ideas @harlan-zw?

@harlan-zw
Copy link
Contributor

harlan-zw commented Oct 20, 2024

Nuxt Scripts will set crossorigin to anonymous for better default privacy, most scripts support this however for the that don't you'll need to eject out of it by doing crossorigin: false.

Below is a full implementation using Nuxt Scripts with the following benefits:

  • Low-priority preloading while page is changing for faster script load
  • Fully typed events API (if you ever want to do something with it) with example for onModalOpen
const kapa = {
  'key': 'kapa',
  'src': 'https://widget.kapa.ai/kapa-widget.bundle.js',
  'data-website-id': 'fb3af718-9db2-440d-9da9-14e6c5fca2aa',
  'data-project-name': 'Nuxt',
  'data-project-color': '#00DC82',
  'data-button-text-color': '#000000',
  'data-project-logo': 'https://nuxt.com/assets/design-kit/icon-black.svg',
  'data-modal-image': 'https://nuxt.com/assets/design-kit/icon-green.svg',
  'data-button-padding': '0.5rem',
  'data-button-width': '5.5rem',
  'data-modal-disclaimer': 'This is a custom LLM for answering questions about Nuxt. Answers are based on the contents of the documentation, GitHub information and Stack Overflow articles. Please note that answers are generated by AI and may not be fully accurate, so please use your best judgement.',
  'data-user-analytics-fingerprint-enabled': 'true',
  // fix for CORS error
  'crossorigin': false,
} as const

interface OnModalOpenArgs {
  mode: 'search' | 'ai'
}

interface OnModalCloseArgs {
  mode: 'search' | 'ai'
}

interface OnAskAIQuerySubmitArgs {
  threadId: string | null
  questionAnswerId: string
  question: string
}

interface OnAskAIExampleQuerySubmitArgs {
  threadId: string | null
  questionAnswerId: string
  question: string
}

interface OnAskAIAnswerCompletedArgs {
  threadId: string
  questionAnswerId: string
  question: string
  answer: string
  conversation: { questionAnswerId: string, question: string, answer: string }[]
}

interface OnAskAIFeedbackSubmitArgs {
  reaction: string
  comment: {
    issue: string
    irrelevant: boolean
    incorrect: boolean
    unaddressed: boolean
  }
  threadId: string
  questionAnswerId: string
  question: string
  answer: string
  conversation: { questionAnswerId: string, question: string, answer: string }[]
}

interface OnAskAILinkClickArgs {
  href: string
  threadId: string
  questionAnswerId: string
  question: string
  answer: string
}

interface OnAskAISourceClickArgs {
  source: {
    title: string
    subtitle: string
    url: string
  }
  threadId: string
  questionAnswerId: string
  question: string
  answer: string
}

interface OnAskAIAnswerCopyArgs {
  threadId: string
  questionAnswerId: string
  question: string
  answer: string
}

interface OnAskAIGenerationStopArgs {
  threadId: string | null
  question: string
  conversation: { questionAnswerId: string, question: string, answer: string }[]
}

interface OnAskAIConversationResetArgs {
  threadId: string
  conversation: { questionAnswerId: string, question: string, answer: string }[]
}

interface OnModeSwitchArgs {
  mode: 'search' | 'ai'
}

interface OnSearchResultsCompletedArgs {
  query: string
  searchResults: { title: string, subtitle: string, url: string, sourceName: string }[]
}

interface OnSearchResultsShowMoreClickArgs {
  query: string
  searchResults: { title: string, subtitle: string, url: string, sourceName: string }[]
}

interface OnSearchResultClickArgs {
  query: string
  searchResult: { title: string, subtitle: string, url: string, sourceName: string }
  rank: number
}

interface Kapa {
  (event: 'onModalOpen', handler: (args: OnModalOpenArgs) => void): void
  (event: 'onModalClose', handler: (args: OnModalCloseArgs) => void): void
  (event: 'onAskAIQuerySubmit', handler: (args: OnAskAIQuerySubmitArgs) => void): void
  (event: 'onAskAIExampleQuerySubmit', handler: (args: OnAskAIExampleQuerySubmitArgs) => void): void
  (event: 'onAskAIAnswerCompleted', handler: (args: OnAskAIAnswerCompletedArgs) => void): void
  (event: 'onAskAIFeedbackSubmit', handler: (args: OnAskAIFeedbackSubmitArgs) => void): void
  (event: 'onAskAILinkClick', handler: (args: OnAskAILinkClickArgs) => void): void
  (event: 'onAskAISourceClick', handler: (args: OnAskAISourceClickArgs) => void): void
  (event: 'onAskAIAnswerCopy', handler: (args: OnAskAIAnswerCopyArgs) => void): void
  (event: 'onAskAIGenerationStop', handler: (args: OnAskAIGenerationStopArgs) => void): void
  (event: 'onAskAIConversationReset', handler: (args: OnAskAIConversationResetArgs) => void): void
  (event: 'onModeSwitch', handler: (args: OnModeSwitchArgs) => void): void
  (event: 'onSearchResultsCompleted', handler: (args: OnSearchResultsCompletedArgs) => void): void
  (event: 'onSearchResultsShowMoreClick', handler: (args: OnSearchResultsShowMoreClickArgs) => void): void
  (event: 'onSearchResultClick', handler: (args: OnSearchResultClickArgs) => void): void
}

declare global {
  interface Window {
    Kapa: Kapa
  }
}

export default defineNuxtPlugin(() => {
  const script = useScript<{ Kapa: Kapa }>(kapa, {
    trigger: 'manual',
    use() {
      return { Kapa: window.Kapa }
    },
  })
  addRouteMiddleware((to) => {
    if (to.path.startsWith('/docs')) {
      script.warmup('preload')
      onNuxtReady(() => {
        script.load()
      })
    }
  })
  script.proxy.Kapa('onModalOpen', ({ mode }) => {
    console.log('Kapa modal opened in', mode, 'mode')
  })
})

app/app.vue Outdated Show resolved Hide resolved
@atinux atinux merged commit 1bb6ca9 into main Oct 21, 2024
2 of 3 checks passed
@atinux atinux deleted the feat/kapa branch October 21, 2024 21:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants