├── .changeset ├── README.md └── config.json ├── .eslintrc.js ├── .github ├── ISSUE_TEMPLATE │ ├── 1.bug_report.yml │ ├── 2.feature_request.yml │ └── config.yml ├── SECURITY.md ├── dependabot.yml ├── scripts │ └── cleanup-examples-changesets.mjs └── workflows │ ├── ci.yml │ ├── quality.yml │ ├── release-snapshot.yml │ └── release.yml ├── .gitignore ├── .kodiak.toml ├── .npmrc ├── .prettierignore ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── assets ├── hero.gif └── logo.png ├── examples ├── next-website │ ├── .env.local.example │ ├── .eslintrc.js │ ├── .gitignore │ ├── README.md │ ├── app │ │ ├── api │ │ │ └── chat │ │ │ │ └── [[...openassistantgpt]] │ │ │ │ └── route.ts │ │ ├── components │ │ │ └── ui │ │ │ │ └── button.tsx │ │ ├── favicon.ico │ │ ├── global.css │ │ ├── layout.tsx │ │ └── page.tsx │ ├── lib │ │ └── utils.ts │ ├── next.config.js │ ├── package.json │ ├── postcss.config.js │ ├── tailwind.config.js │ └── tsconfig.json ├── website-chatbot-window │ ├── .env.local.example │ ├── .eslintrc.js │ ├── .gitignore │ ├── README.md │ ├── app │ │ ├── api │ │ │ └── chat │ │ │ │ └── [[...openassistantgpt]] │ │ │ │ └── route.ts │ │ ├── favicon.ico │ │ ├── global.css │ │ ├── layout.tsx │ │ ├── page.tsx │ │ └── window │ │ │ ├── button-extension.tsx │ │ │ ├── button.tsx │ │ │ └── page.tsx │ ├── lib │ │ └── utils.ts │ ├── next.config.js │ ├── package.json │ ├── postcss.config.js │ ├── tailwind.config.js │ └── tsconfig.json └── website-custom-api │ ├── .env.local.example │ ├── .eslintrc.js │ ├── .gitignore │ ├── README.md │ ├── app │ ├── api │ │ └── [assistantId] │ │ │ └── assistant │ │ │ ├── file │ │ │ └── [fileId] │ │ │ │ └── route.ts │ │ │ └── route.ts │ ├── favicon.ico │ ├── global.css │ ├── layout.tsx │ ├── page.tsx │ └── window │ │ └── page.tsx │ ├── next.config.js │ ├── package.json │ ├── postcss.config.js │ ├── tailwind.config.js │ └── tsconfig.json ├── package.json ├── packages ├── assistant │ ├── .eslintrc.js │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── src │ │ ├── assistant-response.test.tsx │ │ ├── assistant-response.ts │ │ ├── assistant │ │ │ ├── file │ │ │ │ └── route.ts │ │ │ ├── route.ts │ │ │ └── upload │ │ │ │ └── route.ts │ │ ├── file-extensions-list.ts │ │ ├── index.ts │ │ └── route-handler.ts │ ├── tsconfig.json │ ├── tsup.config.ts │ ├── turbo.json │ └── vitest.config.js ├── core │ ├── .eslintrc.js │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── src │ │ ├── index.test.tsx │ │ └── index.ts │ ├── tsconfig.json │ ├── tsup.config.ts │ ├── turbo.json │ └── vitest.config.js ├── react │ ├── .eslintrc.js │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── src │ │ ├── index.ts │ │ ├── use-assistant.ts │ │ └── use-assistant.ui.test.tsx │ ├── tsconfig.json │ ├── tsup.config.ts │ ├── turbo.json │ └── vitest.config.js └── ui │ ├── .eslintrc.js │ ├── CHANGELOG.md │ ├── README.md │ ├── components │ ├── chat-footer-text.tsx │ ├── chat-header.tsx │ ├── chat-history.tsx │ ├── chat-message-actions.tsx │ ├── chat-message.tsx │ ├── chat.tsx │ ├── empty-placeholder.tsx │ ├── external-link.tsx │ ├── icons.tsx │ ├── markdown.tsx │ ├── preview-attachement.tsx │ └── ui │ │ ├── button.tsx │ │ ├── card.tsx │ │ ├── codeblock.tsx │ │ ├── dialog.tsx │ │ ├── dropdown-menu.tsx │ │ ├── input.tsx │ │ ├── label.tsx │ │ ├── textarea.tsx │ │ ├── toast.tsx │ │ ├── tooltip.tsx │ │ └── use-toast.tsx │ ├── hooks │ ├── use-copy-to-clipboard.ts │ ├── use-enter-submit.ts │ └── use-scroll-to-buttom.ts │ ├── lib │ └── utils.ts │ ├── package.json │ ├── postcss.config.js │ ├── src │ ├── chatbot.test.tsx │ ├── chatbot.ts │ ├── global.css │ └── index.ts │ ├── tailwind.config.js │ ├── tsconfig.json │ ├── tsup.config.ts │ ├── turbo.json │ ├── types │ └── attachements.ts │ └── vitest.config.js ├── pnpm-lock.yaml ├── pnpm-workspace.yaml ├── tools ├── eslint-config │ ├── CHANGELOG.md │ ├── index.js │ └── package.json └── tsconfig │ ├── CHANGELOG.md │ ├── base.json │ ├── nextjs.json │ ├── node14.json │ ├── package.json │ └── react-library.json ├── turbo.json └── website └── sdk ├── .eslintrc.js ├── .gitignore ├── README.md ├── app ├── favicon.ico ├── globals.css ├── layout.tsx └── page.tsx ├── components.json ├── components ├── features.tsx ├── hero.tsx ├── icons.tsx ├── landing-page.tsx ├── main-nav.tsx ├── mobile-nav.tsx ├── site-footer.tsx ├── tech-carousel.tsx └── ui │ ├── button.tsx │ ├── card.tsx │ └── carousel.tsx ├── config ├── marketing.ts └── site.ts ├── hooks └── use-lock-body.ts ├── lib ├── metadata.ts └── utils.ts ├── next.config.mjs ├── package.json ├── postcss.config.mjs ├── public ├── hero.png ├── logo-32-32.png ├── next.svg ├── shadcn.png ├── tailwindcss.png ├── turbo.png └── vercel.svg ├── tailwind.config.ts ├── tsconfig.json └── types └── index.d.ts /.changeset/README.md: -------------------------------------------------------------------------------- 1 | # Changesets 2 | 3 | Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works 4 | with multi-package repos, or single-package repos to help you version and publish your code. You can 5 | find the full documentation for it [in our repository](https://github.com/changesets/changesets) 6 | 7 | We have a quick list of common questions to get you started engaging with this project in 8 | [our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md) 9 | -------------------------------------------------------------------------------- /.changeset/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://unpkg.com/@changesets/config@2.2.0/schema.json", 3 | "changelog": "@changesets/cli/changelog", 4 | "commit": false, 5 | "fixed": [], 6 | "linked": [], 7 | "access": "public", 8 | "baseBranch": "main", 9 | "updateInternalDependencies": "patch" 10 | } -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | // This tells ESLint to load the config from the package `eslint-config-openassistantgpt` 4 | extends: ['openassistantgpt'], 5 | settings: { 6 | next: { 7 | rootDir: ['apps/*/'], 8 | }, 9 | }, 10 | rules: { 11 | '@next/next/no-html-link-for-pages': ['error', 'website/sdk', 'examples'], 12 | '@next/next/no-html-link-for-pages': [ 13 | 'error', 14 | '@openassistantgpt/assistant', 15 | ], 16 | }, 17 | }; 18 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/1.bug_report.yml: -------------------------------------------------------------------------------- 1 | name: Bug report 2 | description: Create a bug report for the OpenAssistantGPT SDK. 3 | labels: [] 4 | body: 5 | - type: markdown 6 | attributes: 7 | value: | 8 | This template is to report bugs for the OpenAsistantGPT SDK. If you need help with your own project, feel free to [start a new thread in our discussions](https://github.com/OpenAssistantGPT/OpenAssistantGPT-SDK/discussions). 9 | - type: textarea 10 | attributes: 11 | label: Description 12 | description: A detailed description of the bug you are encountering with the SDK, and how other people can reproduce it. This includes helpful information such as the API you are using, the framework and AI provider. 13 | placeholder: | 14 | Reproduction steps... 15 | validations: 16 | required: true 17 | - type: textarea 18 | attributes: 19 | label: Code example 20 | description: Provide an example code snippet that has the problem 21 | placeholder: | 22 | import OpenAI from 'openai'; 23 | import { Chatbot } from '@openassistantgpt/ui'; 24 | ... 25 | - type: textarea 26 | attributes: 27 | label: Additional context 28 | description: | 29 | Any extra information that might help us investigate. 30 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/2.feature_request.yml: -------------------------------------------------------------------------------- 1 | name: Feature Request 2 | description: Propose a new feature for the OpenAssistantGPT SDK. 3 | labels: [] 4 | body: 5 | - type: markdown 6 | attributes: 7 | value: | 8 | This template is to propose new features for the OpenAssistantGPT SDK. If you need help with your own project, feel free to [start a new thread in our discussions](https://github.com/OpenAssistantGPT/OpenAssistantGPT-SDK/discussions). 9 | - type: textarea 10 | attributes: 11 | label: Feature Description 12 | description: A detailed description of the feature you are proposing for the SDK. This includes helpful information such as the API you are using, the framework, and AI provider. 13 | placeholder: | 14 | Feature description... 15 | validations: 16 | required: true 17 | - type: textarea 18 | attributes: 19 | label: Use Case 20 | description: Provide a use case where this feature would be beneficial 21 | placeholder: | 22 | Use case... 23 | - type: textarea 24 | attributes: 25 | label: Additional context 26 | description: | 27 | Any extra information that might help us understand your feature request. 28 | placeholder: | 29 | Additional context... 30 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Ask a question 4 | url: https://github.com/OpenAssistantGPT/OpenAssistantGPT-SDK/discussions 5 | about: Please ask questions in our discussions forum. 6 | -------------------------------------------------------------------------------- /.github/SECURITY.md: -------------------------------------------------------------------------------- 1 | # Reporting Security Issues 2 | 3 | If you believe you have found a security vulnerability in the OpenAssistantGPT SDK, we encourage you to let us know right away. 4 | 5 | We will investigate all legitimate reports and do our best to quickly fix the problem. 6 | 7 | Email `openassistantgpt@gmail.com` to disclose any security vulnerabilities. 8 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: 'npm' 4 | directory: '/' 5 | schedule: 6 | interval: 'daily' 7 | -------------------------------------------------------------------------------- /.github/scripts/cleanup-examples-changesets.mjs: -------------------------------------------------------------------------------- 1 | /** 2 | * `changeset version` updates the version and adds a changelog file in 3 | * the example apps, but we don't want to do that. So this script reverts 4 | * any "version" field changes and deletes the `CHANGELOG.md` file. 5 | * 6 | * Source: https://github.com/TooTallNate/nx.js/blob/main/.github/scripts/cleanup-examples.mjs 7 | */ 8 | 9 | import { 10 | readFileSync, 11 | writeFileSync, 12 | unlinkSync, 13 | readdirSync, 14 | statSync 15 | } from 'node:fs' 16 | import { fileURLToPath } from 'url' 17 | import { join } from 'path' 18 | 19 | const examplesUrl = new URL('../../examples', import.meta.url) 20 | const examplesDir = fileURLToPath(examplesUrl) 21 | 22 | console.log('Cleaning up examples...', examplesDir) 23 | 24 | for (const app of readdirSync(examplesDir)) { 25 | const appPath = join(examplesDir, app) 26 | if (statSync(appPath).isDirectory()) { 27 | const packageJsonPath = join(appPath, 'package.json') 28 | const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8')) 29 | packageJson.version = '0.0.0' 30 | writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2) + '\n') 31 | 32 | try { 33 | const changelogUrl = new URL(`examples/${app}/CHANGELOG.md`, examplesUrl) 34 | console.log('Deleting', changelogUrl) 35 | unlinkSync(changelogUrl) 36 | } catch (err) { 37 | if (err.code !== 'ENOENT') throw err 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | branches: [main] 8 | 9 | jobs: 10 | test: 11 | name: 'Test' 12 | runs-on: ubuntu-latest 13 | env: 14 | TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} 15 | TURBO_TEAM: ${{ vars.TURBO_TEAM }} 16 | strategy: 17 | matrix: 18 | node-version: [20.x] 19 | steps: 20 | - name: Checkout 21 | uses: actions/checkout@v3 22 | 23 | - name: Setup pnpm 24 | uses: pnpm/action-setup@v4 25 | with: 26 | version: 8.6.9 27 | 28 | - name: Use Node.js ${{ matrix.node-version }} 29 | uses: actions/setup-node@v2 30 | with: 31 | node-version: ${{ matrix.node-version }} 32 | cache: 'pnpm' 33 | 34 | - name: Install dependencies 35 | run: pnpm install --frozen-lockfile 36 | 37 | - name: Install Playwright Browsers 38 | run: pnpm exec playwright install --with-deps 39 | 40 | - name: Run tests 41 | run: pnpm test 42 | -------------------------------------------------------------------------------- /.github/workflows/quality.yml: -------------------------------------------------------------------------------- 1 | name: Quality 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | branches: [main] 8 | 9 | jobs: 10 | prettier: 11 | name: 'Prettier' 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: Checkout 15 | uses: actions/checkout@v3 16 | 17 | - name: Setup pnpm 18 | uses: pnpm/action-setup@v4 19 | with: 20 | version: 8.6.9 21 | 22 | - name: Use Node.js 20 23 | uses: actions/setup-node@v3 24 | with: 25 | node-version: '20' 26 | cache: 'pnpm' 27 | 28 | - name: Install dependencies 29 | run: pnpm install --frozen-lockfile 30 | 31 | - name: Run Prettier check 32 | run: pnpm run prettier-check 33 | 34 | eslint: 35 | name: 'ESLint' 36 | runs-on: ubuntu-latest 37 | steps: 38 | - name: Checkout 39 | uses: actions/checkout@v3 40 | 41 | - name: Setup pnpm 42 | uses: pnpm/action-setup@v4 43 | with: 44 | version: 8.6.9 45 | 46 | - name: Use Node.js 18 47 | uses: actions/setup-node@v3 48 | with: 49 | node-version: '18' 50 | cache: 'pnpm' 51 | 52 | - name: Install dependencies 53 | run: pnpm install --frozen-lockfile 54 | 55 | - name: Run ESLint check 56 | run: pnpm run lint 57 | 58 | types: 59 | name: 'TypeScript' 60 | runs-on: ubuntu-latest 61 | steps: 62 | - name: Checkout 63 | uses: actions/checkout@v3 64 | 65 | - name: Setup pnpm 66 | uses: pnpm/action-setup@v4 67 | with: 68 | version: 8.6.9 69 | 70 | - name: Use Node.js 20 71 | uses: actions/setup-node@v3 72 | with: 73 | node-version: '20' 74 | cache: 'pnpm' 75 | 76 | - name: Install dependencies 77 | run: pnpm install --frozen-lockfile 78 | 79 | - name: Run TypeScript type check 80 | run: pnpm run type-check 81 | -------------------------------------------------------------------------------- /.github/workflows/release-snapshot.yml: -------------------------------------------------------------------------------- 1 | # This workflow lets you manually create snapshot releases 2 | # 3 | # A snapshot release is useful when you want to try out changes on a pull request 4 | # before making a full release and without making a pre release mode. 5 | # 6 | # Problem 7 | # 8 | # This is useful as changesets force pre release mode across all packages in our 9 | # mono repo. When using pre releases then stable releases of all packages are 10 | # blocked until pre release is exited. 11 | # 12 | # What are snapshot releases 13 | # 14 | # To work around this issue we have this workflow. It lets you create a 15 | # once-off release for a specific branch. We call those snapshot releases. 16 | # Snapshot releases are published under the `snapshot` dist-tag and have 17 | # versions like 0.4.0-579bd13f016c7de43a2830340634b3948db358b6-20230913164912, 18 | # which consist of the version that would be generated, the commit hash and 19 | # the timestamp. 20 | # 21 | # How to create a snapshot release 22 | # 23 | # Make sure you have a branch pushed to GitHub, and make sure that branch has 24 | # a changeset committed. You can generate a changeset with "pnpm changeset". 25 | # 26 | # Then open github.com/vercel/ai and click on Actions > Release Snapshot 27 | # Then click "Run workflow" on the right and select the branch you want to 28 | # create a snapshot release for and click the "Run workflow" button. 29 | 30 | name: Release Snapshot 31 | 32 | on: 33 | workflow_dispatch: 34 | 35 | jobs: 36 | release-snapshot: 37 | name: Release Snapshot 38 | runs-on: ubuntu-latest 39 | steps: 40 | - name: Checkout Repo 41 | uses: actions/checkout@v3 42 | with: 43 | fetch-depth: 0 44 | 45 | - name: Setup pnpm 8 46 | uses: pnpm/action-setup@v4 47 | with: 48 | version: 8.6.9 49 | 50 | - name: Setup Node.js 18.x 51 | uses: actions/setup-node@v2 52 | with: 53 | node-version: 18.x 54 | 55 | - name: Add npm auth token to pnpm 56 | run: pnpm config set '//registry.npmjs.org/:_authToken' "${NPM_TOKEN_ELEVATED}" 57 | env: 58 | NPM_TOKEN_ELEVATED: ${{secrets.NPM_TOKEN_ELEVATED}} 59 | 60 | - name: Install Dependencies 61 | run: pnpm i 62 | 63 | - name: Build 64 | run: pnpm clean && pnpm build 65 | 66 | - name: Add SHORT_SHA env property with commit short sha 67 | run: echo "SHORT_SHA=`echo ${{ github.sha }} | cut -c1-8`" >> $GITHUB_ENV 68 | 69 | - name: Create Snapshot Release 70 | run: | 71 | pnpm changeset version --snapshot ${SHORT_SHA} 72 | pnpm clean-examples 73 | pnpm changeset publish --no-git-tag --tag snapshot 74 | env: 75 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 76 | NPM_TOKEN: ${{ secrets.NPM_TOKEN_ELEVATED }} 77 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | paths: 8 | - '.changeset/**' 9 | - '.github/workflows/release.yml' 10 | workflow_dispatch: 11 | 12 | concurrency: ${{ github.workflow }}-${{ github.ref }} 13 | 14 | jobs: 15 | release: 16 | permissions: write-all 17 | name: Release 18 | runs-on: ubuntu-latest 19 | timeout-minutes: 10 20 | steps: 21 | - name: Checkout Repo 22 | uses: actions/checkout@v3 23 | with: 24 | fetch-depth: 0 25 | 26 | - name: Setup pnpm 8 27 | uses: pnpm/action-setup@v4 28 | with: 29 | version: 8.6.9 30 | 31 | - name: Setup Node.js 20.x 32 | uses: actions/setup-node@v2 33 | with: 34 | node-version: 20.x 35 | 36 | - name: Install Dependencies 37 | run: pnpm i 38 | 39 | - name: Create Release Pull Request or Publish to npm 40 | id: changesets 41 | uses: changesets/action@v1 42 | with: 43 | # This expects you to have a script called release which does a build for your packages and calls changeset publish 44 | version: pnpm ci:version 45 | publish: pnpm ci:release 46 | env: 47 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 48 | NPM_TOKEN: ${{ secrets.NPM_TOKEN_ELEVATED }} 49 | 50 | # - name: Get package version 51 | # id: package-version 52 | # run: echo "version=$(node -p "require('./packages/core/package.json').version")" >> "$GITHUB_OUTPUT" 53 | 54 | # - name: Create Git tag 55 | # run: git tag v${{ steps.package-version.outputs.version }} 56 | 57 | # - name: Push Git tag 58 | # run: git push origin v${{ steps.package-version.outputs.version }} 59 | 60 | # - name: Create GitHub Release 61 | # uses: actions/create-release@v1 62 | # env: 63 | # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 64 | # with: 65 | # tag_name: v${{ steps.package-version.outputs.version }} 66 | # release_name: Release v${{ steps.package-version.outputs.version }} 67 | # draft: false 68 | # prerelease: false 69 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | .turbo 4 | *.log 5 | .next 6 | dist 7 | dist-ssr 8 | *.local 9 | .env 10 | .cache 11 | server/dist 12 | public/dist 13 | .turbo 14 | test-results -------------------------------------------------------------------------------- /.kodiak.toml: -------------------------------------------------------------------------------- 1 | # .kodiak.toml 2 | version = 1 3 | 4 | [merge] 5 | automerge_label = "automerge" 6 | require_automerge_label = false 7 | method = "squash" 8 | delete_branch_on_merge = true 9 | optimistic_updates = false 10 | prioritize_ready_to_merge = true 11 | notify_on_conflict = false 12 | 13 | [merge.message] 14 | title = "pull_request_title" 15 | body = "pull_request_body" 16 | include_pr_number = true 17 | body_type = "markdown" 18 | strip_html_comments = true 19 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | auto-install-peers = true 2 | # necessary for a PNPM bug: https://github.com/pnpm/pnpm/issues/5152#issuecomment-1223449173 3 | strict-peer-dependencies = false 4 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | .next 2 | .nuxt 3 | node_modules 4 | dist 5 | .svelte-kit 6 | .solid 7 | _nuxt 8 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to the OpenAssistantGPT SDK 2 | 3 | We deeply appreciate your interest in contributing to our repository! Whether you're reporting bugs, suggesting enhancements, improving docs, or submitting pull requests, your contributions help improve the project for everyone. 4 | 5 | ## Reporting Bugs 6 | 7 | If you've encountered a bug in the project, we encourage you to report it to us. Please follow these steps: 8 | 9 | 1. **Check the Issue Tracker**: Before submitting a new bug report, please check our issue tracker to see if the bug has already been reported. If it has, you can add to the existing report. 10 | 2. **Create a New Issue**: If the bug hasn't been reported, create a new issue. Provide a clear title and a detailed description of the bug. Include any relevant logs, error messages, and steps to reproduce the issue. 11 | 3. **Label Your Issue**: If possible, label your issue as a `bug` so it's easier for maintainers to identify. 12 | 13 | ## Suggesting Enhancements 14 | 15 | We're always looking for suggestions to make our project better. If you have an idea for an enhancement, please: 16 | 17 | 1. **Check the Issue Tracker**: Similar to bug reports, please check if someone else has already suggested the enhancement. If so, feel free to add your thoughts to the existing issue. 18 | 2. **Create a New Issue**: If your enhancement hasn't been suggested yet, create a new issue. Provide a detailed description of your suggested enhancement and how it would benefit the project. 19 | 20 | ## Code Contributions 21 | 22 | We welcome your contributions to our code and documentation. Here's how you can contribute: 23 | 24 | ### Setting Up the Repository Locally 25 | 26 | To set up the repository on your local machine, follow these steps: 27 | 28 | 1. **Fork the Repository**: Make a copy of the repository to your GitHub account. 29 | 2. **Clone the Repository**: Clone the repository to your local machine, e.g. using `git clone`. 30 | 3. **Install pnpm**: If you haven't already, install `pnpm`. You can do this by running `npm install -g pnpm` if you're using npm. Alternatively, if you're using Homebrew (Mac), you can run `brew install pnpm`. 31 | 4. **Install Dependencies**: Navigate to the project directory and run `pnpm install` to install all necessary dependencies. 32 | 33 | ### Submitting Pull Requests 34 | 35 | We greatly appreciate your pull requests. Here are the steps to submit them: 36 | 37 | 1. **Create a New Branch**: Initiate your changes in a fresh branch. It's recommended to name the branch in a manner that signifies the changes you're implementing. 38 | 2. **Commit Your Changes**: Ensure your commits are succinct and clear, detailing what modifications have been made and the reasons behind them. 39 | 3. **Push the Changes to Your GitHub Repository**: After committing your changes, push them to your GitHub repository. 40 | 4. **Open a Pull Request**: Propose your changes for review. Furnish a lucid title and description of your contributions. Make sure to link any relevant issues your PR resolves. 41 | 5. **Respond to Feedback**: Stay receptive to and address any feedback or alteration requests from the project maintainers. 42 | 43 | ### Fixing Prettier Issues 44 | 45 | > [!TIP] 46 | > Run `pnpm prettier-fix` before opening a pull request. 47 | 48 | If you encounter any prettier issues, you can fix them by running `pnpm prettier-fix`. This command will automatically fix any formatting issues in your code. 49 | 50 | ### Running the Examples 51 | 52 | 1. run `pnpm install` in the root 53 | 1. run `pnpm build` in the root 54 | 1. `cd examples/next-website` (or another example folder) 55 | 1. Other examples: run `pnpm dev` and go to the browser url 56 | 57 | Thank you for contributing to the OpenAssistantGPT SDK! Your efforts make a significant difference. 58 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |  2 | 3 | # OpenAssistantGPT SDK 4 | 5 | This SDK is an extension of the vercel/ai SDK with more features, addapted to our use case and maintained by the OpenAssistantGPT team. 6 | If you want more information about OpenAssistantGPT you can find it [here](https://www.openassistantgpt.io/). 7 | 8 | We also provide our chatbot with our [hosted version](https://www.openassistantgpt.io/), with adavanced analytics, crawling for custom content and advanced security. 9 | 10 | # Deploy example 11 | 12 | Deploy our basic example using [Vercel](https://vercel.com): 13 | 14 | [](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2FOpenAssistantGPT%2FOpenAssistantGPT-SDK%2Ftree%2Fmain%2Fexamples%2Fnext-website&env=OPENAI_ASSISTANT_ID,OPENAI_API_KEY&envDescription=Find%20all%20informations%20in%20OpenAI%20Platform.&envLink=https%3A%2F%2Fplatform.openai.com%2F) 15 | 16 | For more information about the example give a look at this [README.md](https://github.com/OpenAssistantGPT/chatbot-sdk/tree/main/examples/next-website#openassistantgpt-sdk-nextjs-and-openai-chat-example). 17 | 18 | All examples 19 | 20 | - [Basic Website](./examples/next-website/README.md) 21 | - [Window Style Integration](./examples/website-chatbot-window/README.md) 22 | - [Custom API](./examples/website-custom-api//README.md) 23 | 24 | # Installation 25 | 26 | You will need Node.js 18+ and pnpm install on your local development machine. 27 | 28 | ```bash 29 | npm install openassistantgpt 30 | ``` 31 | 32 | # Usage 33 | 34 | ## Import Default CSS 35 | 36 | Import the default CSS files to ensure correct styling is applied. For NextJS apps - this should be added to your [layout file](https://github.com/OpenAssistantGPT/chatbot-sdk/blob/main/examples/next-website/app/layout.tsx#L1). 37 | 38 | ``` 39 | import "@openassistantgpt/ui/dist/index.css" 40 | ``` 41 | 42 | ## @openassistantgpt/assistant 43 | 44 | First you need to import our library and configure the POST and GET method. This will setup the backend correctly. 45 | 46 | ```bash 47 | npm install @openassistantgpt/assistant 48 | ``` 49 | 50 | Then you have to setup you environment variables by creating your `.env` file 51 | 52 | ``` 53 | OPENAI_API_KEY=xxxxxxx 54 | OPENAI_ASSISTANT_ID=xxxxxx 55 | ``` 56 | 57 | Once the package is installed and your environment variables are configured create the route file `/api/chat/[[...openassistantgpt]]/route.ts` 58 | 59 | ```js 60 | import { OpenAssistantGPT } from '@openassistantgpt/assistant'; 61 | 62 | // In OpenAssistantGPT handler you must enter your base path. 63 | // The base path is everything before the [[...openassistantgpt]] part of the route. 64 | const httpHandler = new OpenAssistantGPT('/api/chat/').handler; 65 | 66 | export { httpHandler as GET, httpHandler as POST }; 67 | ``` 68 | 69 | ## @openassistantgpt/ui 70 | 71 | First you need to import our library and configure your component to use it. 72 | 73 | ```bash 74 | npm install @openassistantgpt/ui 75 | ``` 76 | 77 | Once the UI package is installed create the `page.tsx` file and configure your chatbot like you want. 78 | 79 | ```js 80 | 'use client'; 81 | 82 | import { OpenAssistantGPTChat, ChatbotConfig } from '@openassistantgpt/ui'; 83 | 84 | export default function ChatPage() { 85 | const chatbot: ChatbotConfig = { 86 | id: '12345', 87 | name: 'OpenAssistantGPT', 88 | 89 | chatTitle: 'Chat with OpenAssistantGPT', 90 | welcomeMessage: 91 | "Welcome to OpenAssistantGPT! 🚀 I'm your AI assistant, crafted using this platform. How may I assist you today?", 92 | chatMessagePlaceHolder: 'Ask us any question...', 93 | 94 | rightToLeftLanguage: false, 95 | 96 | bubbleColor: 'linear-gradient(to top left, #003366, #336699)', 97 | bubbleTextColor: '#FFFFFF', 98 | 99 | chatHeaderBackgroundColor: '#FFFFFF', 100 | chatHeaderTextColor: '#52525b', 101 | 102 | chatbotReplyBackgroundColor: '#e4e4e7', 103 | chatbotReplyTextColor: '#000000', 104 | 105 | userReplyBackgroundColor: '#e4e4e7', 106 | userReplyTextColor: '#000000', 107 | 108 | chatbotLogoURL: 109 | 'https://gwetfkan2dovfoiz.public.blob.vercel-storage.com/search-8jZhOvOBPxuTmohrup5TPvSzrjsyog.png', 110 | chatInputStyle: 'default', 111 | 112 | chatHistoryEnabled: true, 113 | chatFileAttachementEnabled: true, 114 | 115 | displayFooterText: true, 116 | footerLink: 'https://www.openassistantgpt.io', 117 | footerTextName: 'OpenAssistantGPT', 118 | 119 | messageSourceText: '', 120 | withChatMessageIcon: true, 121 | }; 122 | 123 | return ( 124 | 129 | ); 130 | } 131 | ``` 132 | 133 | ## Community 134 | 135 | The OpenAssistantGPT SDK community can be found on [GitHub Discussions](https://github.com/OpenAssistantGPT/OpenAssistantGPT-SDK/discussions) where you can ask questions, voice ideas, and share your projects with other people. 136 | 137 | ## Contributing 138 | 139 | Contributions to the OpenAssistantGPT SDK are welcome and highly appreciated. However, before you jump right into it, we would like you to review our [Contribution Guidelines](https://github.com/OpenAssistantGPT/OpenAssistantGPT-SDK/blob/main/CONTRIBUTING.md) to make sure you have smooth experience contributing to OpenAssistantGPT SDK. 140 | 141 | ## Authors 142 | 143 | OpenAssistantGPT team members, with contributions from the [Open Source Community](https://github.com/OpenAssistantGPT/OpenAssistantGPT-SDK/graphs/contributors). 144 | -------------------------------------------------------------------------------- /assets/hero.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenAssistantGPT/chatbot-sdk/cb08d28e43d2e80d0d4d2e732855de02510da872/assets/hero.gif -------------------------------------------------------------------------------- /assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenAssistantGPT/chatbot-sdk/cb08d28e43d2e80d0d4d2e732855de02510da872/assets/logo.png -------------------------------------------------------------------------------- /examples/next-website/.env.local.example: -------------------------------------------------------------------------------- 1 | OPENAI_API_KEY=xxxxxxx 2 | OPENAI_ASSISTANT_ID="" 3 | BLOB_READ_WRITE_TOKEN="" -------------------------------------------------------------------------------- /examples/next-website/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: ['openassistantgpt'], 4 | }; 5 | -------------------------------------------------------------------------------- /examples/next-website/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | 27 | # local env files 28 | .env*.local 29 | 30 | # vercel 31 | .vercel 32 | 33 | # typescript 34 | *.tsbuildinfo 35 | next-env.d.ts 36 | -------------------------------------------------------------------------------- /examples/next-website/README.md: -------------------------------------------------------------------------------- 1 | # OpenAssistantGPT SDK, Next.js, and OpenAI Chat Example 2 | 3 | This example shows how to use the [OpenAssistantGPT SDK](https://openassistantgpt.io/), [Vercel AI SDK](https://sdk.vercel.ai/docs), [Next.js](https://nextjs.org/) and [OpenAI](https://openai.com) to create a ChatGPT-like AI-powered streaming chat bot. 4 | 5 | ## Deploy your own 6 | 7 | Deploy the example using [Vercel](https://vercel.com?utm_source=github): 8 | 9 | [](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2FOpenAssistantGPT%2FOpenAssistantGPT-SDK%2Ftree%2Fmain%2Fexamples%2Fnext-website&env=OPENAI_ASSISTANT_ID,OPENAI_API_KEY&envDescription=Find%20all%20informations%20in%20OpenAI%20Platform.&envLink=https%3A%2F%2Fplatform.openai.com%2F) 10 | 11 | ## How to use 12 | 13 | Execute [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app) with [npm](https://docs.npmjs.com/cli/init), [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/), or [pnpm](https://pnpm.io) to bootstrap the example: 14 | 15 | ```bash 16 | npx create-next-app --example https://github.com/OpenAssistantGPT/OpenAssistantGPT-SDK/tree/main/examples/next-website next-openassistantgpt-app 17 | ``` 18 | 19 | ```bash 20 | yarn create next-app --example https://github.com/OpenAssistantGPT/OpenAssistantGPT-SDK/tree/main/examples/next-website next-openassistantgpt-app 21 | ``` 22 | 23 | ```bash 24 | pnpm create next-app --example https://github.com/OpenAssistantGPT/OpenAssistantGPT-SDK/tree/main/examples/next-website next-openassistantgpt-app 25 | ``` 26 | 27 | To run the example locally you need to: 28 | 29 | 1. Sign up at [OpenAI's Developer Platform](https://platform.openai.com/signup). 30 | 2. Go to [OpenAI's dashboard](https://platform.openai.com/account/api-keys) and create an API KEY. 31 | 3. Set the required OpenAI environment variable as the token value as shown [the example env file](./.env.local.example) but in a new file called `.env.local` 32 | 4. `pnpm install` to install the required dependencies. 33 | 5. `pnpm dev` to launch the development server. 34 | 35 | ## Learn More 36 | 37 | To learn more about OpenAssistantGPT take a look at the following resources: 38 | 39 | - [OpenAssistantGPT](https://www.openassistantgpt.io/) 40 | -------------------------------------------------------------------------------- /examples/next-website/app/api/chat/[[...openassistantgpt]]/route.ts: -------------------------------------------------------------------------------- 1 | import { OpenAssistantGPT } from '@openassistantgpt/assistant'; 2 | 3 | // In OpenAssistantGPT handler you must enter your base path. 4 | // The base path is everything before the [[...openassistantgpt]] part of the route. 5 | const httpHandler = new OpenAssistantGPT('/api/chat/').handler; 6 | 7 | export { httpHandler as GET, httpHandler as POST }; 8 | -------------------------------------------------------------------------------- /examples/next-website/app/components/ui/button.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { Slot } from '@radix-ui/react-slot'; 3 | import { cva, type VariantProps } from 'class-variance-authority'; 4 | 5 | import { cn } from '@/lib/utils'; 6 | 7 | const buttonVariants = cva( 8 | 'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0', 9 | { 10 | variants: { 11 | variant: { 12 | default: 'bg-primary text-primary-foreground hover:bg-primary/90', 13 | destructive: 14 | 'bg-destructive text-destructive-foreground hover:bg-destructive/90', 15 | outline: 16 | 'border border-input bg-background hover:bg-accent hover:text-accent-foreground', 17 | secondary: 18 | 'bg-secondary text-secondary-foreground hover:bg-secondary/80', 19 | ghost: 'hover:bg-accent hover:text-accent-foreground', 20 | link: 'text-primary underline-offset-4 hover:underline', 21 | }, 22 | size: { 23 | default: 'h-10 px-4 py-2', 24 | sm: 'h-9 rounded-md px-3', 25 | lg: 'h-11 rounded-md px-8', 26 | icon: 'h-10 w-10', 27 | }, 28 | }, 29 | defaultVariants: { 30 | variant: 'default', 31 | size: 'default', 32 | }, 33 | }, 34 | ); 35 | 36 | export interface ButtonProps 37 | extends React.ButtonHTMLAttributes, 38 | VariantProps { 39 | asChild?: boolean; 40 | } 41 | 42 | const Button = React.forwardRef( 43 | ({ className, variant, size, asChild = false, ...props }, ref) => { 44 | const Comp = asChild ? Slot : 'button'; 45 | return ( 46 | 51 | ); 52 | }, 53 | ); 54 | Button.displayName = 'Button'; 55 | 56 | export { Button, buttonVariants }; 57 | -------------------------------------------------------------------------------- /examples/next-website/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenAssistantGPT/chatbot-sdk/cb08d28e43d2e80d0d4d2e732855de02510da872/examples/next-website/app/favicon.ico -------------------------------------------------------------------------------- /examples/next-website/app/global.css: -------------------------------------------------------------------------------- 1 | /* src/global.css */ 2 | @tailwind base; 3 | @tailwind components; 4 | @tailwind utilities; 5 | -------------------------------------------------------------------------------- /examples/next-website/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import '@openassistantgpt/ui/dist/index.css'; 2 | 3 | import { Inter } from 'next/font/google'; 4 | 5 | const inter = Inter({ subsets: ['latin'] }); 6 | 7 | export const metadata = { 8 | title: 'OpenAssistantGPT SDK Example', 9 | description: 'Example of using OpenAssistantGPT SDK in a Next.js website', 10 | }; 11 | 12 | export default function RootLayout({ 13 | children, 14 | }: { 15 | children: React.ReactNode; 16 | }) { 17 | return ( 18 | 19 | {children} 20 | 21 | ); 22 | } 23 | -------------------------------------------------------------------------------- /examples/next-website/app/page.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import { ChatbotConfig, Message, OpenAssistantGPTChat } from 'openassistantgpt'; 4 | import { useEffect, useState } from 'react'; 5 | import { Button } from './components/ui/button'; 6 | 7 | export default function ChatPage() { 8 | const [count, setMessagesCount] = useState(0); 9 | const [defaultMessage, setDefaultMessage] = useState(''); 10 | 11 | const chatbot: ChatbotConfig = { 12 | id: '12345', 13 | name: 'OpenAssistantGPT', 14 | 15 | chatTitle: 'Chat with OpenAssistantGPT', 16 | welcomeMessage: 17 | "Welcome to OpenAssistantGPT! 🚀 I'm your AI assistant, crafted using this platform. How may I assist you today?", 18 | chatMessagePlaceHolder: 'Ask us any question...', 19 | 20 | rightToLeftLanguage: false, 21 | 22 | bubbleColor: 'linear-gradient(to top left, #003366, #336699)', 23 | bubbleTextColor: '#FFFFFF', 24 | 25 | chatHeaderBackgroundColor: '#FFFFFF', 26 | chatHeaderTextColor: '#52525b', 27 | 28 | chatbotReplyBackgroundColor: '#e4e4e7', 29 | chatbotReplyTextColor: '#000000', 30 | 31 | userReplyBackgroundColor: '#e4e4e7', 32 | userReplyTextColor: '#000000', 33 | 34 | chatbotLogoURL: 35 | 'https://gwetfkan2dovfoiz.public.blob.vercel-storage.com/search-8jZhOvOBPxuTmohrup5TPvSzrjsyog.png', 36 | chatInputStyle: 'default', 37 | 38 | chatHistoryEnabled: true, 39 | chatFileAttachementEnabled: true, 40 | //fontSize: '14px', 41 | displayFooterText: true, 42 | footerLink: 'https://www.openassistantgpt.io', 43 | footerTextName: 'OpenAssistantGPT', 44 | 45 | fontSize: '14px', 46 | 47 | messageSourceText: '', 48 | withChatMessageIcon: true, 49 | }; 50 | 51 | useEffect(() => { 52 | console.log('Messages count:', count); 53 | }, [count]); 54 | 55 | function handleMessagesChange(messages: Message[]) { 56 | setMessagesCount(messages.length); 57 | } 58 | 59 | return ( 60 | 73 | setDefaultMessage('How many chatbot can I created on free plan?') 74 | } 75 | > 76 | How many chatbot can I created on free plan? 77 | 78 | ), 79 | count == 0 && ( 80 | setDefaultMessage('How to create a chatbot?')} 85 | > 86 | How to create a chatbot? 87 | 88 | ), 89 | count == 0 && ( 90 | 95 | setDefaultMessage('How to integrate chatbot in website?') 96 | } 97 | > 98 | How to integrate chatbot in website? 99 | 100 | ), 101 | count == 0 && ( 102 | setDefaultMessage('What is a SDK?')} 107 | > 108 | What is a SDK? 109 | 110 | ), 111 | ]} 112 | /> 113 | ); 114 | } 115 | -------------------------------------------------------------------------------- /examples/next-website/lib/utils.ts: -------------------------------------------------------------------------------- 1 | import { type ClassValue, clsx } from 'clsx'; 2 | import { twMerge } from 'tailwind-merge'; 3 | 4 | export function cn(...inputs: ClassValue[]) { 5 | return twMerge(clsx(inputs)); 6 | } 7 | -------------------------------------------------------------------------------- /examples/next-website/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = {}; 3 | 4 | module.exports = nextConfig; 5 | -------------------------------------------------------------------------------- /examples/next-website/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "next-website", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "@openassistantgpt/assistant": "^0.2.0", 13 | "@openassistantgpt/react": "^0.3.0", 14 | "@openassistantgpt/ui": "^0.3.0", 15 | "@radix-ui/react-dialog": "^1.1.1", 16 | "@radix-ui/react-icons": "^1.3.0", 17 | "@radix-ui/react-label": "^2.1.0", 18 | "@radix-ui/react-slot": "^1.1.0", 19 | "buffer": "^6.0.3", 20 | "class-variance-authority": "^0.7.0", 21 | "clsx": "^2.1.1", 22 | "lucide-react": "^0.408.0", 23 | "next": "14.2.15", 24 | "openai": "4.69.0", 25 | "openassistantgpt": "latest", 26 | "react": "^18.3.1", 27 | "react-dom": "^18.3.1", 28 | "tailwind-merge": "^2.5.4", 29 | "zod": "3.23.8", 30 | "zod-form-data": "^2.0.2" 31 | }, 32 | "devDependencies": { 33 | "@types/node": "^20.16.11", 34 | "@types/react": "^18.3.11", 35 | "@types/react-dom": "^18.3.1", 36 | "autoprefixer": "^10.4.20", 37 | "eslint": "^7.32.0", 38 | "eslint-config-next": "14.2.5", 39 | "postcss": "^8.4.47", 40 | "tailwindcss": "^3.4.14", 41 | "typescript": "5.1.3" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /examples/next-website/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /examples/next-website/tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | content: [ 4 | './pages/**/*.{js,ts,jsx,tsx,mdx}', 5 | './components/**/*.{js,ts,jsx,tsx,mdx}', 6 | './app/**/*.{js,ts,jsx,tsx,mdx}', 7 | ], 8 | theme: { 9 | extend: { 10 | backgroundImage: { 11 | 'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))', 12 | 'gradient-conic': 13 | 'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))', 14 | }, 15 | }, 16 | }, 17 | 18 | plugins: [], 19 | }; 20 | -------------------------------------------------------------------------------- /examples/next-website/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "forceConsistentCasingInFileNames": true, 9 | "noEmit": true, 10 | "esModuleInterop": true, 11 | "module": "esnext", 12 | "moduleResolution": "node", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "jsx": "preserve", 16 | "incremental": true, 17 | "plugins": [ 18 | { 19 | "name": "next" 20 | } 21 | ], 22 | "paths": { 23 | "@/*": ["./*"] 24 | } 25 | }, 26 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 27 | "exclude": ["node_modules"] 28 | } 29 | -------------------------------------------------------------------------------- /examples/website-chatbot-window/.env.local.example: -------------------------------------------------------------------------------- 1 | OPENAI_API_KEY=xxxxxxx 2 | OPENAI_ASSISTANT_ID="" -------------------------------------------------------------------------------- /examples/website-chatbot-window/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: ['openassistantgpt'], 4 | }; 5 | -------------------------------------------------------------------------------- /examples/website-chatbot-window/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | 27 | # local env files 28 | .env*.local 29 | 30 | # vercel 31 | .vercel 32 | 33 | # typescript 34 | *.tsbuildinfo 35 | next-env.d.ts 36 | -------------------------------------------------------------------------------- /examples/website-chatbot-window/README.md: -------------------------------------------------------------------------------- 1 | # OpenAssistantGPT SDK, Chatbot Window Integration 2 | 3 | This is example shows how to IFRAME our chatbot in a website and use it at different places. 4 | 5 | This example uses [OpenAssistantGPT SDK](https://openassistantgpt.io/), [Vercel AI SDK](https://sdk.vercel.ai/docs), [Next.js](https://nextjs.org/) and [OpenAI](https://openai.com) to create a ChatGPT-like AI-powered streaming chat bot. 6 | 7 | ## Deploy your own 8 | 9 | Deploy the example using [Vercel](https://vercel.com?utm_source=github): 10 | 11 | [](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2FOpenAssistantGPT%2FOpenAssistantGPT-SDK%2Ftree%2Fmain%2Fexamples%2Fwebsite-chatbot-window&env=OPENAI_ASSISTANT_ID,OPENAI_API_KEY&envDescription=Find%20all%20informations%20in%20OpenAI%20Platform.&envLink=https%3A%2F%2Fplatform.openai.com%2F) 12 | 13 | ## How to use 14 | 15 | Execute [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app) with [npm](https://docs.npmjs.com/cli/init), [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/), or [pnpm](https://pnpm.io) to bootstrap the example: 16 | 17 | ```bash 18 | npx create-next-app --example https://github.com/OpenAssistantGPT/OpenAssistantGPT-SDK/tree/main/examples/website-chatbot-window next-openassistantgpt-app 19 | ``` 20 | 21 | ```bash 22 | yarn create next-app --example https://github.com/OpenAssistantGPT/OpenAssistantGPT-SDK/tree/main/examples/website-chatbot-window next-openassistantgpt-app 23 | ``` 24 | 25 | ```bash 26 | pnpm create next-app --example https://github.com/OpenAssistantGPT/OpenAssistantGPT-SDK/tree/main/examples/website-chatbot-window next-openassistantgpt-app 27 | ``` 28 | 29 | To run the example locally you need to: 30 | 31 | 1. Sign up at [OpenAI's Developer Platform](https://platform.openai.com/signup). 32 | 2. Go to [OpenAI's dashboard](https://platform.openai.com/account/api-keys) and create an API KEY. 33 | 3. Set the required OpenAI environment variable as the token value as shown [the example env file](./.env.local.example) but in a new file called `.env.local` 34 | 4. `pnpm install` to install the required dependencies. 35 | 5. `pnpm dev` to launch the development server. 36 | 37 | ## Learn More 38 | 39 | To learn more about OpenAssistantGPT take a look at the following resources: 40 | 41 | - [OpenAssistantGPT](https://www.openassistantgpt.io/) 42 | -------------------------------------------------------------------------------- /examples/website-chatbot-window/app/api/chat/[[...openassistantgpt]]/route.ts: -------------------------------------------------------------------------------- 1 | import { OpenAssistantGPT } from '@openassistantgpt/assistant'; 2 | 3 | // In OpenAssistantGPT handler you must enter your base path. 4 | // The base path is everything before the [[...openassistantgpt]] part of the route. 5 | const httpHandler = new OpenAssistantGPT('/api/chat/').handler; 6 | 7 | export { httpHandler as GET, httpHandler as POST }; 8 | -------------------------------------------------------------------------------- /examples/website-chatbot-window/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenAssistantGPT/chatbot-sdk/cb08d28e43d2e80d0d4d2e732855de02510da872/examples/website-chatbot-window/app/favicon.ico -------------------------------------------------------------------------------- /examples/website-chatbot-window/app/global.css: -------------------------------------------------------------------------------- 1 | /* src/global.css */ 2 | @tailwind base; 3 | @tailwind components; 4 | @tailwind utilities; 5 | -------------------------------------------------------------------------------- /examples/website-chatbot-window/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import '@openassistantgpt/ui/dist/index.css'; 2 | 3 | import { Inter } from 'next/font/google'; 4 | 5 | const inter = Inter({ subsets: ['latin'] }); 6 | 7 | export const metadata = { 8 | title: 'OpenAssistantGPT SDK Example', 9 | description: 'Example of using OpenAssistantGPT SDK in a Next.js website', 10 | }; 11 | 12 | export default function RootLayout({ 13 | children, 14 | }: { 15 | children: React.ReactNode; 16 | }) { 17 | return ( 18 | 19 | {children} 20 | 21 | ); 22 | } 23 | -------------------------------------------------------------------------------- /examples/website-chatbot-window/app/page.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | export default function Home() { 4 | return ( 5 | <> 6 | THIS IS MY H1 7 | 15 | 29 | 30 | THIS IS THE FOOTER 31 | THIS IS THE FOOTER 32 | THIS IS THE FOOTER 33 | THIS IS THE FOOTER 34 | THIS IS THE FOOTER 35 | THIS IS THE FOOTER 36 | THIS IS THE FOOTER 37 | THIS IS THE FOOTER 38 | THIS IS THE FOOTER 39 | THIS IS THE FOOTER 40 | THIS IS THE FOOTER 41 | THIS IS THE FOOTER 42 | > 43 | ); 44 | } 45 | -------------------------------------------------------------------------------- /examples/website-chatbot-window/app/window/button-extension.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import React from 'react'; 4 | import { Button } from './button'; 5 | 6 | export function SupportInquiry() { 7 | return ( 8 | 9 | 10 | HELLO 11 | 12 | 13 | ); 14 | } 15 | -------------------------------------------------------------------------------- /examples/website-chatbot-window/app/window/button.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { VariantProps, cva } from 'class-variance-authority'; 3 | 4 | import { cn } from '@/lib/utils'; 5 | 6 | const buttonVariants = cva( 7 | 'inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none ring-offset-background', 8 | { 9 | variants: { 10 | variant: { 11 | default: 'bg-primary text-primary-foreground hover:bg-primary/90', 12 | destructive: 13 | 'bg-destructive text-destructive-foreground hover:bg-destructive/90', 14 | outline: 15 | 'border border-input hover:bg-accent hover:text-accent-foreground', 16 | secondary: 17 | 'bg-secondary text-secondary-foreground hover:bg-secondary/80', 18 | ghost: 'hover:bg-accent hover:text-accent-foreground', 19 | link: 'underline-offset-4 hover:underline text-primary', 20 | nothing: '', 21 | }, 22 | size: { 23 | default: 'h-10 py-2 px-4', 24 | sm: 'h-9 px-3 rounded-md', 25 | lg: 'h-11 px-8 rounded-md', 26 | icon: 'size-9', 27 | xs: 'size-3', 28 | }, 29 | }, 30 | defaultVariants: { 31 | variant: 'default', 32 | size: 'default', 33 | }, 34 | }, 35 | ); 36 | 37 | export interface ButtonProps 38 | extends React.ButtonHTMLAttributes, 39 | VariantProps {} 40 | 41 | const Button = React.forwardRef( 42 | ({ className, variant, size, ...props }, ref) => { 43 | return ( 44 | 49 | ); 50 | }, 51 | ); 52 | Button.displayName = 'Button'; 53 | 54 | export { Button, buttonVariants }; 55 | -------------------------------------------------------------------------------- /examples/website-chatbot-window/app/window/page.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import { OpenAssistantGPTChat, ChatbotConfig } from '@openassistantgpt/ui'; 4 | import { SupportInquiry } from './button-extension'; 5 | 6 | export default function ChatPage() { 7 | const chatbot: ChatbotConfig = { 8 | id: '12345', 9 | name: 'OpenAssistantGPT', 10 | 11 | chatTitle: 'Chat with OpenAssistantGPT', 12 | welcomeMessage: 13 | "Welcome to OpenAssistantGPT! 🚀 I'm your AI assistant, crafted using this platform. How may I assist you today?", 14 | chatMessagePlaceHolder: 'Ask us any question...', 15 | 16 | rightToLeftLanguage: false, 17 | 18 | bubbleColor: 'linear-gradient(to top left, #003366, #336699)', 19 | bubbleTextColor: '#FFFFFF', 20 | 21 | chatHeaderBackgroundColor: '#FFFFFF', 22 | chatHeaderTextColor: '#52525b', 23 | 24 | chatbotReplyBackgroundColor: '#e4e4e7', 25 | chatbotReplyTextColor: '#000000', 26 | 27 | userReplyBackgroundColor: '#e4e4e7', 28 | userReplyTextColor: '#000000', 29 | 30 | chatbotLogoURL: 31 | 'https://gwetfkan2dovfoiz.public.blob.vercel-storage.com/search-8jZhOvOBPxuTmohrup5TPvSzrjsyog.png', 32 | chatInputStyle: 'default', 33 | 34 | chatHistoryEnabled: true, 35 | chatFileAttachementEnabled: true, 36 | 37 | fontSize: '14px', 38 | 39 | displayFooterText: true, 40 | footerLink: 'https://www.openassistantgpt.io', 41 | footerTextName: 'OpenAssistantGPT', 42 | 43 | messageSourceText: 'Chatbot source:', 44 | withChatMessageIcon: false, 45 | }; 46 | 47 | return ( 48 | ]} 53 | handleAfterChat={() => console.log('after chat')} 54 | handleBeforeChat={() => console.log('before chat')} 55 | disableInput={false} 56 | annotationsFiles={[ 57 | { 58 | fileName: 'google', 59 | fileId: 'file-GMUsHaFBkyvlAHdpCvt3Hngf', 60 | downloadUrl: 'https://google.com', 61 | }, 62 | ]} 63 | /> 64 | ); 65 | } 66 | -------------------------------------------------------------------------------- /examples/website-chatbot-window/lib/utils.ts: -------------------------------------------------------------------------------- 1 | import { type ClassValue, clsx } from 'clsx'; 2 | import { twMerge } from 'tailwind-merge'; 3 | 4 | export function cn(...inputs: ClassValue[]) { 5 | return twMerge(clsx(inputs)); 6 | } 7 | -------------------------------------------------------------------------------- /examples/website-chatbot-window/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = {}; 3 | 4 | module.exports = nextConfig; 5 | -------------------------------------------------------------------------------- /examples/website-chatbot-window/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "website-chatbot-window", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "@openassistantgpt/assistant": "workspace:*", 13 | "@openassistantgpt/react": "latest", 14 | "@openassistantgpt/ui": "workspace:*", 15 | "ai": "3.2.32", 16 | "buffer": "^6.0.3", 17 | "class-variance-authority": "^0.7.0", 18 | "clsx": "^2.1.1", 19 | "next": "14.2.5", 20 | "openai": "4.69.0", 21 | "react": "^18.3.1", 22 | "react-dom": "^18.3.1", 23 | "tailwind-merge": "^2.5.4", 24 | "zod": "3.23.8", 25 | "zod-form-data": "^2.0.2" 26 | }, 27 | "devDependencies": { 28 | "@types/node": "^20.16.12", 29 | "@types/react": "^18.3.11", 30 | "@types/react-dom": "^18.3.1", 31 | "autoprefixer": "^10.4.20", 32 | "eslint": "^7.32.0", 33 | "eslint-config-next": "14.2.3", 34 | "postcss": "^8.4.47", 35 | "tailwindcss": "^3.4.14", 36 | "typescript": "5.1.3" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /examples/website-chatbot-window/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /examples/website-chatbot-window/tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | content: [ 4 | './pages/**/*.{js,ts,jsx,tsx,mdx}', 5 | './components/**/*.{js,ts,jsx,tsx,mdx}', 6 | './app/**/*.{js,ts,jsx,tsx,mdx}', 7 | ], 8 | theme: { 9 | extend: { 10 | backgroundImage: { 11 | 'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))', 12 | 'gradient-conic': 13 | 'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))', 14 | }, 15 | }, 16 | }, 17 | 18 | plugins: [], 19 | }; 20 | -------------------------------------------------------------------------------- /examples/website-chatbot-window/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "forceConsistentCasingInFileNames": true, 9 | "noEmit": true, 10 | "esModuleInterop": true, 11 | "module": "esnext", 12 | "moduleResolution": "node", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "jsx": "preserve", 16 | "incremental": true, 17 | "plugins": [ 18 | { 19 | "name": "next" 20 | } 21 | ], 22 | "paths": { 23 | "@/*": ["./*"] 24 | } 25 | }, 26 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 27 | "exclude": ["node_modules"] 28 | } 29 | -------------------------------------------------------------------------------- /examples/website-custom-api/.env.local.example: -------------------------------------------------------------------------------- 1 | OPENAI_API_KEY=xxxxxxx 2 | OPENAI_ASSISTANT_ID="" -------------------------------------------------------------------------------- /examples/website-custom-api/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: ['openassistantgpt'], 4 | }; 5 | -------------------------------------------------------------------------------- /examples/website-custom-api/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | 27 | # local env files 28 | .env*.local 29 | 30 | # vercel 31 | .vercel 32 | 33 | # typescript 34 | *.tsbuildinfo 35 | next-env.d.ts 36 | -------------------------------------------------------------------------------- /examples/website-custom-api/README.md: -------------------------------------------------------------------------------- 1 | # OpenAssistantGPT SDK, Chatbot Window Integration 2 | 3 | This example shows you how to use our handlers and add custom code to support more advanced logic. 4 | 5 | This example uses [OpenAssistantGPT SDK](https://openassistantgpt.io/), [Vercel AI SDK](https://sdk.vercel.ai/docs), [Next.js](https://nextjs.org/) and [OpenAI](https://openai.com) to create a ChatGPT-like AI-powered streaming chat bot. 6 | 7 | ## Deploy your own 8 | 9 | Deploy the example using [Vercel](https://vercel.com?utm_source=github): 10 | 11 | [](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2FOpenAssistantGPT%2FOpenAssistantGPT-SDK%2Ftree%2Fmain%2Fexamples%2Fwebsite-custom-api&env=OPENAI_ASSISTANT_ID,OPENAI_API_KEY&envDescription=Find%20all%20informations%20in%20OpenAI%20Platform.&envLink=https%3A%2F%2Fplatform.openai.com%2F) 12 | 13 | ## How to use 14 | 15 | Execute [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app) with [npm](https://docs.npmjs.com/cli/init), [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/), or [pnpm](https://pnpm.io) to bootstrap the example: 16 | 17 | ```bash 18 | npx create-next-app --example https://github.com/OpenAssistantGPT/OpenAssistantGPT-SDK/tree/main/examples/website-custom-api next-openassistantgpt-app 19 | ``` 20 | 21 | ```bash 22 | yarn create next-app --example https://github.com/OpenAssistantGPT/OpenAssistantGPT-SDK/tree/main/examples/website-custom-api next-openassistantgpt-app 23 | ``` 24 | 25 | ```bash 26 | pnpm create next-app --example https://github.com/OpenAssistantGPT/OpenAssistantGPT-SDK/tree/main/examples/website-custom-api next-openassistantgpt-app 27 | ``` 28 | 29 | To run the example locally you need to: 30 | 31 | 1. Sign up at [OpenAI's Developer Platform](https://platform.openai.com/signup). 32 | 2. Go to [OpenAI's dashboard](https://platform.openai.com/account/api-keys) and create an API KEY. 33 | 3. Set the required OpenAI environment variable as the token value as shown [the example env file](./.env.local.example) but in a new file called `.env.local` 34 | 4. `pnpm install` to install the required dependencies. 35 | 5. `pnpm dev` to launch the development server. 36 | 37 | ## Learn More 38 | 39 | To learn more about OpenAssistantGPT take a look at the following resources: 40 | 41 | - [OpenAssistantGPT](https://www.openassistantgpt.io/) 42 | -------------------------------------------------------------------------------- /examples/website-custom-api/app/api/[assistantId]/assistant/file/[fileId]/route.ts: -------------------------------------------------------------------------------- 1 | import { handleFileFunction } from '@openassistantgpt/assistant'; 2 | import OpenAI from 'openai'; 3 | import { z } from 'zod'; 4 | 5 | const routeContextSchema = z.object({ 6 | params: z.object({ 7 | assistantId: z.string(), 8 | fileId: z.string(), 9 | }), 10 | }); 11 | 12 | export async function GET( 13 | req: Request, 14 | context: z.infer, 15 | ) { 16 | const { params } = routeContextSchema.parse(context); 17 | 18 | const openai = new OpenAI({ 19 | apiKey: process.env.OPENAI_API_KEY, 20 | }); 21 | 22 | return handleFileFunction(openai, params.fileId); 23 | } 24 | -------------------------------------------------------------------------------- /examples/website-custom-api/app/api/[assistantId]/assistant/route.ts: -------------------------------------------------------------------------------- 1 | import { handleAssistant } from '@openassistantgpt/assistant'; 2 | import OpenAI from 'openai'; 3 | import { z } from 'zod'; 4 | 5 | const routeContextSchema = z.object({ 6 | params: z.object({ 7 | assistantId: z.string(), 8 | }), 9 | }); 10 | 11 | export async function POST( 12 | req: Request, 13 | context: z.infer, 14 | ) { 15 | const { params } = routeContextSchema.parse(context); 16 | 17 | const openai = new OpenAI({ 18 | apiKey: process.env.OPENAI_API_KEY, 19 | }); 20 | 21 | return handleAssistant( 22 | `/api/${params.assistantId}/assistant`, 23 | req, 24 | openai, 25 | process.env.OPENAI_ASSISTANT_ID || '', 26 | ); 27 | } 28 | -------------------------------------------------------------------------------- /examples/website-custom-api/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenAssistantGPT/chatbot-sdk/cb08d28e43d2e80d0d4d2e732855de02510da872/examples/website-custom-api/app/favicon.ico -------------------------------------------------------------------------------- /examples/website-custom-api/app/global.css: -------------------------------------------------------------------------------- 1 | /* src/global.css */ 2 | @tailwind base; 3 | @tailwind components; 4 | @tailwind utilities; 5 | -------------------------------------------------------------------------------- /examples/website-custom-api/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import '@openassistantgpt/ui/dist/index.css'; 2 | 3 | import { Inter } from 'next/font/google'; 4 | 5 | const inter = Inter({ subsets: ['latin'] }); 6 | 7 | export const metadata = { 8 | title: 'OpenAssistantGPT SDK Example', 9 | description: 'Example of using OpenAssistantGPT SDK in a Next.js website', 10 | }; 11 | 12 | export default function RootLayout({ 13 | children, 14 | }: { 15 | children: React.ReactNode; 16 | }) { 17 | return ( 18 | 19 | {children} 20 | 21 | ); 22 | } 23 | -------------------------------------------------------------------------------- /examples/website-custom-api/app/page.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | export default function Home() { 4 | return ( 5 | 13 | 27 | 28 | ); 29 | } 30 | -------------------------------------------------------------------------------- /examples/website-custom-api/app/window/page.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import { OpenAssistantGPTChat, ChatbotConfig } from '@openassistantgpt/ui'; 4 | 5 | export default function ChatPage() { 6 | const chatbot: ChatbotConfig = { 7 | id: '12345', 8 | name: 'OpenAssistantGPT', 9 | 10 | chatTitle: 'Chat with OpenAssistantGPT', 11 | welcomeMessage: 12 | "Welcome to OpenAssistantGPT! 🚀 I'm your AI assistant, crafted using this platform. How may I assist you today?", 13 | chatMessagePlaceHolder: 'Ask us any question...', 14 | 15 | rightToLeftLanguage: false, 16 | 17 | bubbleColor: 'linear-gradient(to top left, #003366, #336699)', 18 | bubbleTextColor: '#FFFFFF', 19 | 20 | chatHeaderBackgroundColor: '#FFFFFF', 21 | chatHeaderTextColor: '#52525b', 22 | 23 | chatbotReplyBackgroundColor: '#e4e4e7', 24 | chatbotReplyTextColor: '#000000', 25 | 26 | userReplyBackgroundColor: '#e4e4e7', 27 | userReplyTextColor: '#000000', 28 | 29 | chatbotLogoURL: 30 | 'https://gwetfkan2dovfoiz.public.blob.vercel-storage.com/search-8jZhOvOBPxuTmohrup5TPvSzrjsyog.png', 31 | chatInputStyle: 'default', 32 | 33 | chatHistoryEnabled: true, 34 | chatFileAttachementEnabled: true, 35 | 36 | displayFooterText: true, 37 | footerLink: 'https://www.openassistantgpt.io', 38 | footerTextName: 'OpenAssistantGPT', 39 | fontSize: '15px', 40 | 41 | messageSourceText: '', 42 | withChatMessageIcon: true, 43 | }; 44 | 45 | return ( 46 | 51 | ); 52 | } 53 | -------------------------------------------------------------------------------- /examples/website-custom-api/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = {}; 3 | 4 | module.exports = nextConfig; 5 | -------------------------------------------------------------------------------- /examples/website-custom-api/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "website-custom-api", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "@openassistantgpt/assistant": "workspace:latest", 13 | "@openassistantgpt/react": "workspace:latest", 14 | "@openassistantgpt/ui": "workspace:latest", 15 | "ai": "3.2.32", 16 | "buffer": "^6.0.3", 17 | "next": "14.2.5", 18 | "openai": "4.69.0", 19 | "react": "^18.3.1", 20 | "react-dom": "^18.3.1", 21 | "zfd": "^0.0.9", 22 | "zod": "3.23.8", 23 | "zod-form-data": "^2.0.2" 24 | }, 25 | "devDependencies": { 26 | "@types/node": "^20.17.4", 27 | "@types/react": "^18.3.12", 28 | "@types/react-dom": "^18.3.1", 29 | "autoprefixer": "^10.4.20", 30 | "eslint": "^7.32.0", 31 | "eslint-config-next": "14.2.3", 32 | "postcss": "^8.4.47", 33 | "tailwindcss": "^3.4.14", 34 | "typescript": "5.1.3" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /examples/website-custom-api/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /examples/website-custom-api/tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | content: [ 4 | './pages/**/*.{js,ts,jsx,tsx,mdx}', 5 | './components/**/*.{js,ts,jsx,tsx,mdx}', 6 | './app/**/*.{js,ts,jsx,tsx,mdx}', 7 | ], 8 | theme: { 9 | extend: { 10 | backgroundImage: { 11 | 'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))', 12 | 'gradient-conic': 13 | 'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))', 14 | }, 15 | }, 16 | }, 17 | 18 | plugins: [], 19 | }; 20 | -------------------------------------------------------------------------------- /examples/website-custom-api/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "forceConsistentCasingInFileNames": true, 9 | "noEmit": true, 10 | "esModuleInterop": true, 11 | "module": "esnext", 12 | "moduleResolution": "node", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "jsx": "preserve", 16 | "incremental": true, 17 | "plugins": [ 18 | { 19 | "name": "next" 20 | } 21 | ], 22 | "paths": { 23 | "@/*": ["./*"] 24 | } 25 | }, 26 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 27 | "exclude": ["node_modules"] 28 | } 29 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "build": "turbo build", 5 | "changeset": "changeset", 6 | "clean": "turbo clean", 7 | "dev": "turbo dev --no-cache --concurrency 16 --continue", 8 | "lint": "turbo lint", 9 | "prepare": "husky install", 10 | "prettier-check": "prettier --check \"**/*.{js,ts,tsx,md,mdx}\"", 11 | "type-check": "turbo type-check", 12 | "prettier-fix": "prettier --write \"**/*.{js,ts,tsx,md,mdx}\"", 13 | "publint": "turbo publint", 14 | "test": "turbo test", 15 | "ci:release": "turbo clean && turbo build && changeset publish", 16 | "ci:version": "changeset version && node .github/scripts/cleanup-examples-changesets.mjs && pnpm install --no-frozen-lockfile", 17 | "clean-examples": "node .github/scripts/cleanup-examples-changesets.mjs && pnpm install --no-frozen-lockfile", 18 | "check-docs-links": "node ./check-docs-links.js" 19 | }, 20 | "lint-staged": { 21 | "*": [ 22 | "prettier --ignore-unknown --write" 23 | ] 24 | }, 25 | "devDependencies": { 26 | "@changesets/cli": "^2.27.9", 27 | "@playwright/test": "^1.48.2", 28 | "chalk": "^5.3.0", 29 | "eslint": "^7.32.0", 30 | "eslint-config-openassistantgpt": "workspace:*", 31 | "husky": "^9.1.6", 32 | "lint-staged": "^15.2.10", 33 | "next": "14.2.15", 34 | "playwright": "^1.48.2", 35 | "prettier": "2.8.8", 36 | "publint": "0.2.9", 37 | "react": "19.0.0-rc-cc1ec60d0d-20240607", 38 | "react-dom": "19.0.0-rc-cc1ec60d0d-20240607", 39 | "turbo": "^2.2.3", 40 | "vitest": "1.6.0" 41 | }, 42 | "homepage": "https://openassistantgpt.io", 43 | "repository": { 44 | "type": "git", 45 | "url": "git+https://github.com/OpenAssistantGPT/OpenAssistantGPT-SDK.git" 46 | }, 47 | "license": "Apache License", 48 | "bugs": { 49 | "url": "https://github.com/OpenAssistantGPT/OpenAssistantGPT-SDK/issues" 50 | }, 51 | "keywords": [ 52 | "ai" 53 | ], 54 | "packageManager": "pnpm@8.6.9", 55 | "prettier": { 56 | "tabWidth": 2, 57 | "useTabs": false, 58 | "singleQuote": true, 59 | "arrowParens": "avoid", 60 | "trailingComma": "all" 61 | }, 62 | "name": "openassistantgpt-sdk" 63 | } 64 | -------------------------------------------------------------------------------- /packages/assistant/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: ['openassistantgpt'], 4 | }; 5 | -------------------------------------------------------------------------------- /packages/assistant/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @assistant 2 | 3 | ## 0.2.3 4 | 5 | ### Patch Changes 6 | 7 | - afefea5: add more file type that we can upload and fix issue where python and ruby were not working correcltt 8 | 9 | ## 0.2.2 10 | 11 | ### Patch Changes 12 | 13 | - d020f27: update issue with types on file handle function 14 | 15 | ## 0.2.1 16 | 17 | ### Patch Changes 18 | 19 | - 8d41f18: Update file type 20 | 21 | ## 0.2.0 22 | 23 | ### Minor Changes 24 | 25 | - 3f4f1d7: Support upload of multiple attachments and improve validation 26 | 27 | ## 0.1.2 28 | 29 | ### Patch Changes 30 | 31 | - b29c271: Change on error return status code when chatting 32 | 33 | ## 0.1.1 34 | 35 | ### Patch Changes 36 | 37 | - 4b57e1e: add support for extensions in the chat and improve mobile UX 38 | 39 | ## 0.1.0 40 | 41 | ### Minor Changes 42 | 43 | - 9aaa198: Add feature to support extensions in our chat compoenent, improve chat header in mobile mode. 44 | 45 | ## 0.0.6 46 | 47 | ### Patch Changes 48 | 49 | - df7561e: Add download transcript option and fix width of assistant reply 50 | 51 | ## 0.0.5 52 | 53 | ### Patch Changes 54 | 55 | - 3189cf8: Remove tool override when running stream. 56 | 57 | ## 0.0.4 58 | 59 | ### Patch Changes 60 | 61 | - 4737746: Update handlers to support parameters instead of having to use environment variable. You can now provide assistantId and OpenAI object in the function parameters. 62 | 63 | ## 0.0.3 64 | 65 | ### Patch Changes 66 | 67 | - 2a9002e: finish last doc update, fix latest bug there is no new feature in this release 68 | 69 | ## 0.0.2 70 | 71 | ### Patch Changes 72 | 73 | - fcacff1: Update all Git repository link 74 | 75 | ## 0.0.1 76 | 77 | ### Patch Changes 78 | 79 | - 151c8b0: Create the default library for the Official OpenAssistant SDK library and created all the required package to run a chatbot in few steps. 80 | -------------------------------------------------------------------------------- /packages/assistant/README.md: -------------------------------------------------------------------------------- 1 | # OpenAssistantGPT SDK: Assistant 2 | 3 | The object to use as an Assistant Response 4 | 5 | - AssistantResponse 6 | -------------------------------------------------------------------------------- /packages/assistant/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@openassistantgpt/assistant", 3 | "version": "0.2.3", 4 | "license": "Apache-2.0", 5 | "sideEffects": false, 6 | "main": "./dist/index.js", 7 | "module": "./dist/index.mjs", 8 | "types": "./dist/index.d.ts", 9 | "scripts": { 10 | "build": "tsup", 11 | "clean": "rm -rf dist", 12 | "dev": "tsup --watch", 13 | "lint": "eslint \"./**/*.ts*\"", 14 | "type-check": "tsc --noEmit", 15 | "prettier-check": "prettier --check \"./**/*.ts*\"", 16 | "test": "vitest --config vitest.config.js --run", 17 | "test:watch": "vitest --config vitest.config.js" 18 | }, 19 | "exports": { 20 | "./package.json": "./package.json", 21 | ".": { 22 | "types": "./dist/index.d.ts", 23 | "import": "./dist/index.mjs", 24 | "require": "./dist/index.js" 25 | } 26 | }, 27 | "dependencies": { 28 | "@ai-sdk/provider-utils": "1.0.5", 29 | "@ai-sdk/ui-utils": "0.0.20", 30 | "@vercel/blob": "^0.25.1", 31 | "ai": "^3.2.24", 32 | "openai": "^4.69.0", 33 | "swr": "2.2.5", 34 | "zod-form-data": "^2.0.2" 35 | }, 36 | "devDependencies": { 37 | "@openassistantgpt/tsconfig": "workspace:*", 38 | "@testing-library/jest-dom": "^6.6.3", 39 | "@testing-library/react": "^16.0.1", 40 | "@testing-library/user-event": "^14.5.2", 41 | "@types/node": "^20.16.11", 42 | "@types/react": "^18.3.11", 43 | "@types/react-dom": "^18.3.1", 44 | "eslint": "^7.32.0", 45 | "eslint-config-openassistantgpt": "workspace:*", 46 | "jsdom": "^24.1.3", 47 | "msw": "2.3.1", 48 | "react-dom": "^18.3.1", 49 | "tsup": "^7.2.0", 50 | "typescript": "5.1.3", 51 | "zod": "3.23.8" 52 | }, 53 | "peerDependencies": { 54 | "react": "^18 || ^19", 55 | "zod": "^3.0.0" 56 | }, 57 | "peerDependenciesMeta": { 58 | "react": { 59 | "optional": true 60 | }, 61 | "zod": { 62 | "optional": true 63 | } 64 | }, 65 | "engines": { 66 | "node": ">=18" 67 | }, 68 | "publishConfig": { 69 | "access": "public" 70 | }, 71 | "homepage": "https://openassistantgpt.io", 72 | "repository": { 73 | "type": "git", 74 | "url": "git+https://github.com/OpenAssistantGPT/OpenAssistantGPT-SDK.git" 75 | }, 76 | "bugs": { 77 | "url": "https://github.com/OpenAssistantGPT/OpenAssistantGPT-SDK/issues" 78 | }, 79 | "keywords": [ 80 | "ai", 81 | "vue" 82 | ] 83 | } 84 | -------------------------------------------------------------------------------- /packages/assistant/src/assistant-response.test.tsx: -------------------------------------------------------------------------------- 1 | import { expect } from 'vitest'; 2 | import { it } from 'vitest'; 3 | import { describe } from 'vitest'; 4 | 5 | describe('Assistant Resonse', () => { 6 | it('should send text', async () => { 7 | expect(true); 8 | }); 9 | }); 10 | -------------------------------------------------------------------------------- /packages/assistant/src/assistant/file/route.ts: -------------------------------------------------------------------------------- 1 | import { OpenAI } from 'openai'; 2 | import { z } from 'zod'; 3 | 4 | const routeContextSchema = z.object({ 5 | params: z.object({ 6 | openassistantgpt: z.array(z.string()), 7 | }), 8 | }); 9 | 10 | export async function handleFile( 11 | request: Request, 12 | context: z.infer, 13 | openai: OpenAI, 14 | ) { 15 | if (request.method !== 'GET') { 16 | return new Response('Method Not Allowed', { status: 405 }); 17 | } 18 | 19 | const { params } = routeContextSchema.parse(context); 20 | 21 | return handleFileFunction( 22 | openai, 23 | params.openassistantgpt[params.openassistantgpt.length - 1], 24 | ); 25 | } 26 | 27 | export async function handleFileFunction(openai: OpenAI, fileId: string) { 28 | const [file, fileContent] = await Promise.all([ 29 | openai.files.retrieve(fileId), 30 | openai.files.content(fileId), 31 | ]); 32 | 33 | return new Response(fileContent.body, { 34 | headers: { 35 | 'Content-Disposition': `attachment; filename="${file.filename}"`, 36 | }, 37 | }); 38 | } 39 | -------------------------------------------------------------------------------- /packages/assistant/src/assistant/route.ts: -------------------------------------------------------------------------------- 1 | import OpenAI from 'openai'; 2 | 3 | import { z } from 'zod'; 4 | import { AssistantResponse } from '../assistant-response'; 5 | import { 6 | codeInterpreterExtensionList, 7 | fileSearchExtensionList, 8 | } from '../file-extensions-list'; 9 | import { 10 | CodeInterpreterTool, 11 | FileSearchTool, 12 | } from 'openai/resources/beta/assistants'; 13 | import path from 'path'; 14 | 15 | const schema = z.object({ 16 | threadId: z.string().or(z.null()), 17 | message: z.string(), 18 | clientSidePrompt: z.string().or(z.undefined()), 19 | files: z.array(z.string()), 20 | data: z.record(z.string()).or(z.undefined()), 21 | }); 22 | 23 | export async function handleAssistant( 24 | basePath: string, 25 | req: Request, 26 | openai: OpenAI, 27 | assistantId: string, 28 | ) { 29 | if (req.method !== 'POST') { 30 | return new Response('Method Not Allowed', { status: 405 }); 31 | } 32 | 33 | try { 34 | const requestBody = await req.json(); 35 | const data = schema.parse(requestBody); 36 | 37 | // Create a thread if needed 38 | const threadId = data.threadId 39 | ? data.threadId 40 | : (await openai.beta.threads.create({})).id; 41 | 42 | let openAiFiles: OpenAI.Files.FileObject[] | null = null; 43 | if (data.files.length > 0) { 44 | openAiFiles = await Promise.all( 45 | data.files.map(async fileUrl => { 46 | const response = await fetch(fileUrl); 47 | const fileBuffer = await response.arrayBuffer(); 48 | const filename = fileUrl.split('/').pop() || 'unknown_file'; 49 | 50 | const file = new File([fileBuffer], filename, { 51 | type: 52 | response.headers.get('Content-Type') || 53 | 'application/octet-stream', 54 | }); 55 | 56 | return await openai.files.create({ 57 | file, 58 | purpose: 'assistants', 59 | }); 60 | }), 61 | ); 62 | } 63 | 64 | const attachments = openAiFiles?.map(file => ({ 65 | file_id: file.id, 66 | tools: [ 67 | codeInterpreterExtensionList.includes( 68 | file.filename.split('.').pop()?.toLocaleLowerCase()!, 69 | ) 70 | ? { type: 'code_interpreter' } 71 | : null, 72 | fileSearchExtensionList.includes(file.filename.split('.').pop()!) 73 | ? { type: 'file_search' } 74 | : null, 75 | ].filter(Boolean), 76 | })); 77 | 78 | // Add a message to the thread 79 | const createdMessage = await openai.beta.threads.messages.create( 80 | threadId!, 81 | { 82 | role: 'user' as 'user' | 'assistant', 83 | content: data.message.toString(), 84 | attachments: openAiFiles 85 | ? attachments?.map(attachment => ({ 86 | ...attachment, 87 | tools: attachment.tools.filter(tool => tool !== null) as ( 88 | | CodeInterpreterTool 89 | | FileSearchTool 90 | )[], 91 | })) 92 | : [], 93 | }, 94 | ); 95 | 96 | return AssistantResponse( 97 | { 98 | // @ts-ignore 99 | threadId, 100 | messageId: createdMessage.id, 101 | fileUrlPath: path.join(basePath, '/assistant/file/%ID%'), 102 | }, 103 | async ({ sendMessage, forwardStream, sendDataMessage }) => { 104 | try { 105 | // Run the assistant on the thread 106 | const runStream = openai.beta.threads.runs.stream(threadId!, { 107 | assistant_id: assistantId, 108 | instructions: (data.clientSidePrompt || '').replace('+', '') || '', 109 | }); 110 | 111 | let runResult = await forwardStream(runStream); 112 | 113 | // validate if there is any error 114 | if (runResult == undefined) { 115 | console.log(`Error running assistant on thread ${threadId}`); 116 | 117 | // set the error if last_error is not null 118 | let errorMessage = 'Unknown error'; 119 | // @ts-ignore 120 | if (runStream.currentEvent()?.data.last_error) { 121 | // @ts-ignore 122 | errorMessage = runStream.currentEvent()?.data.last_error.message; 123 | } 124 | 125 | sendMessage({ 126 | id: 'end', 127 | role: 'assistant', 128 | content: [ 129 | { 130 | type: 'text', 131 | text: { value: 'An error orrcured please try again later.' }, 132 | }, 133 | ], 134 | }); 135 | return; 136 | } 137 | } catch (error) { 138 | console.error(error); 139 | sendMessage({ 140 | id: 'end', 141 | role: 'assistant', 142 | content: [ 143 | { 144 | type: 'text', 145 | text: { value: 'An error orrcured please try again later.' }, 146 | }, 147 | ], 148 | }); 149 | } 150 | }, 151 | ); 152 | } catch (error) { 153 | console.error(error); 154 | if (error instanceof z.ZodError) { 155 | return new Response(JSON.stringify(error.issues), { status: 422 }); 156 | } 157 | 158 | if (error instanceof OpenAI.APIError) { 159 | return new Response(error.message, { status: 400 }); 160 | } 161 | 162 | return new Response(null, { status: 500 }); 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /packages/assistant/src/assistant/upload/route.ts: -------------------------------------------------------------------------------- 1 | import { z } from 'zod'; 2 | import { put } from '@vercel/blob'; 3 | import { randomUUID } from 'crypto'; 4 | 5 | const FileSchema = z.object({ 6 | file: z 7 | .any() 8 | .refine(file => file.size <= 5 * 1024 * 1024, { 9 | message: 'File size should be less than 5MB', 10 | }) 11 | .refine( 12 | file => 13 | [ 14 | 'text/x-csrc', // .c 15 | 'text/x-csharp', // .cs 16 | 'text/x-c++src', // .cpp 17 | 'application/msword', // .doc 18 | 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', // .docx 19 | 'text/html', // .html 20 | 'text/x-java-source', // .java 21 | 'application/json', // .json 22 | 'text/markdown', // .md 23 | 'application/pdf', // .pdf 24 | 'application/octet-stream', 25 | 'application/x-httpd-php', // .php 26 | 'application/vnd.openxmlformats-officedocument.presentationml.presentation', // .pptx 27 | 'text/x-python-script', // .py 28 | 'text/x-python', // .py 29 | 'application/x-ruby-script', // .rb 30 | 'application/x-tex', // .tex 31 | 'text/plain', // .txt 32 | 'text/css', // .css 33 | 'application/javascript', // .js 34 | 'application/x-sh', // .sh 35 | 'application/typescript', // .ts 36 | 'text/csv', // .csv 37 | 'image/jpeg', // .jpeg, .jpg 38 | 'image/png', // .png 39 | 'image/gif', // .gif 40 | 'application/x-tar', // .tar 41 | 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', // .xlsx 42 | 'application/xml', // .xml 43 | 'application/zip', // .zip 44 | ].includes(file.type), 45 | { 46 | message: 47 | 'Unsupported file type. Only C, CS, CPP, DOC, DOCX, HTML, JAVA, JSON, MD, PDF, PHP, PPTX, PY, RB, TEX, TXT, CSS, JS, SH, TS, CSV, JPEG, JPG, GIF, PNG, TAR, XLSX, XML, and ZIP are accepted.', 48 | }, 49 | ), 50 | }); 51 | 52 | export async function handleFileUpload(request: Request) { 53 | if (request.body === null) { 54 | return new Response('Request body is empty', { status: 400 }); 55 | } 56 | 57 | try { 58 | const formData = await request.formData(); 59 | const file = formData.get('file') as any; 60 | 61 | if (!file) { 62 | return new Response('No file uploaded', { status: 400 }); 63 | } 64 | 65 | const validatedFile = FileSchema.safeParse({ file }); 66 | 67 | if (!validatedFile.success) { 68 | const errorMessage = validatedFile.error.errors 69 | .map(error => error.message) 70 | .join(', '); 71 | 72 | return new Response(errorMessage, { status: 400 }); 73 | } 74 | 75 | const filename = file.name; 76 | const fileBuffer = await file.arrayBuffer(); 77 | 78 | try { 79 | const data = await put(`${randomUUID()}-${filename}`, fileBuffer, { 80 | access: 'public', 81 | }); 82 | 83 | return new Response( 84 | JSON.stringify({ 85 | url: data.url, 86 | pathname: filename, 87 | contentType: file.type, 88 | }), 89 | { headers: { 'Content-Type': 'application/json' } }, 90 | ); 91 | } catch (error) { 92 | return new Response('Upload failed', { status: 500 }); 93 | } 94 | } catch (error) { 95 | return new Response('Failed to process request', { status: 500 }); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /packages/assistant/src/file-extensions-list.ts: -------------------------------------------------------------------------------- 1 | export const fileSearchExtensionList = [ 2 | 'c', 3 | 'cs', 4 | 'cpp', 5 | 'doc', 6 | 'docx', 7 | 'html', 8 | 'java', 9 | 'json', 10 | 'md', 11 | 'pdf', 12 | 'php', 13 | 'pptx', 14 | 'py', 15 | 'py', 16 | 'rb', 17 | 'tex', 18 | 'txt', 19 | 'css', 20 | 'js', 21 | 'sh', 22 | 'ts', 23 | ]; 24 | 25 | export const codeInterpreterExtensionList = [ 26 | 'c', 27 | 'cs', 28 | 'cpp', 29 | 'doc', 30 | 'docx', 31 | 'html', 32 | 'java', 33 | 'json', 34 | 'md', 35 | 'pdf', 36 | 'php', 37 | 'pptx', 38 | 'py', 39 | 'rb', 40 | 'tex', 41 | 'txt', 42 | 'css', 43 | 'js', 44 | 'sh', 45 | 'ts', 46 | 'csv', 47 | 'jpeg', 48 | 'jpg', 49 | 'gif', 50 | 'png', 51 | 'tar', 52 | 'xlsx', 53 | 'xml', 54 | 'zip', 55 | ]; 56 | -------------------------------------------------------------------------------- /packages/assistant/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './assistant-response'; 2 | export * from './file-extensions-list'; 3 | export * from './route-handler'; 4 | export * from './assistant/route'; 5 | export * from './assistant/file/route'; 6 | export * from './assistant/upload/route'; 7 | -------------------------------------------------------------------------------- /packages/assistant/src/route-handler.ts: -------------------------------------------------------------------------------- 1 | import { handleAssistant } from './assistant/route'; 2 | import { handleFile } from './assistant/file/route'; 3 | import OpenAI from 'openai'; 4 | import { handleFileUpload } from './assistant/upload/route'; 5 | 6 | export class OpenAssistantGPT { 7 | constructor(private basePath: string) { 8 | this.basePath = this.basePath; 9 | } 10 | 11 | handler = async (req: any, res: any) => { 12 | // Parse the URL to get the pathname 13 | const pathname = new URL(req.url).pathname; 14 | 15 | // Split the pathname to get the parts 16 | const pathParts = pathname.split('/').filter(Boolean); 17 | 18 | const openai = new OpenAI({ 19 | // eslint-disable-next-line turbo/no-undeclared-env-vars 20 | apiKey: process.env.OPENAI_API_KEY, 21 | }); 22 | 23 | if (pathParts[pathParts.length - 1] === 'assistant') { 24 | // eslint-disable-next-line turbo/no-undeclared-env-vars 25 | // Handle /api/assistant 26 | const assistantId = process.env.OPENAI_ASSISTANT_ID || ''; 27 | return handleAssistant(this.basePath, req, openai, assistantId); 28 | } else if ( 29 | pathParts[pathParts.length - 1].match(/^.+$/) && 30 | pathParts[pathParts.length - 2] === 'file' && 31 | pathParts[pathParts.length - 3] === 'assistant' 32 | ) { 33 | // Handle /api/assistant/file/[fileId] 34 | return handleFile(req, res, openai); 35 | } else if ( 36 | // handle /api/assistant/upload 37 | pathParts[pathParts.length - 1] === 'upload' && 38 | pathParts[pathParts.length - 2] === 'assistant' 39 | ) { 40 | return handleFileUpload(req); 41 | } else { 42 | return new Response('Not Found', { status: 404 }); 43 | } 44 | }; 45 | } 46 | -------------------------------------------------------------------------------- /packages/assistant/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./node_modules/@openassistantgpt/tsconfig/react-library.json", 3 | "compilerOptions": { 4 | "target": "ES2018", 5 | "stripInternal": true 6 | }, 7 | "include": ["."], 8 | "exclude": ["*/dist", "dist", "build", "node_modules"] 9 | } 10 | -------------------------------------------------------------------------------- /packages/assistant/tsup.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'tsup'; 2 | 3 | export default defineConfig([ 4 | { 5 | entry: ['src/index.ts'], 6 | outDir: 'dist', 7 | banner: {}, 8 | format: ['cjs', 'esm'], 9 | external: ['vue'], 10 | dts: true, 11 | sourcemap: true, 12 | }, 13 | ]); 14 | -------------------------------------------------------------------------------- /packages/assistant/turbo.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "//" 4 | ], 5 | "globalEnv": [ 6 | "OPENAI_API_KEY", 7 | "OPENAI_ASSISTANT_ID" 8 | ], 9 | "tasks": { 10 | "build": { 11 | "outputs": [ 12 | "**/dist/**" 13 | ] 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /packages/assistant/vitest.config.js: -------------------------------------------------------------------------------- 1 | import react from '@vitejs/plugin-react'; 2 | import { defineConfig } from 'vite'; 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | test: { 8 | environment: 'jsdom', 9 | globals: true, 10 | include: ['src/**/*.test.ts', 'src/**/*.test.tsx'], 11 | }, 12 | }); 13 | -------------------------------------------------------------------------------- /packages/core/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: ['openassistantgpt'], 4 | }; 5 | -------------------------------------------------------------------------------- /packages/core/README.md: -------------------------------------------------------------------------------- 1 | # OpenAssistantGPT SDK: Core 2 | -------------------------------------------------------------------------------- /packages/core/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "openassistantgpt", 3 | "version": "0.3.13", 4 | "license": "Apache-2.0", 5 | "sideEffects": false, 6 | "main": "./dist/index.js", 7 | "module": "./dist/index.mjs", 8 | "types": "./dist/index.d.ts", 9 | "scripts": { 10 | "build": "tsup", 11 | "clean": "rm -rf dist", 12 | "dev": "tsup --watch", 13 | "lint": "eslint \"./**/*.ts*\"", 14 | "type-check": "tsc --noEmit", 15 | "prettier-check": "prettier --check \"./**/*.ts*\"", 16 | "test": "vitest --config vitest.config.js --run", 17 | "test:watch": "vitest --config vitest.config.js" 18 | }, 19 | "exports": { 20 | "./package.json": "./package.json", 21 | ".": { 22 | "types": "./dist/index.d.ts", 23 | "import": "./dist/index.mjs", 24 | "require": "./dist/index.js" 25 | } 26 | }, 27 | "dependencies": { 28 | "@openassistantgpt/assistant": "workspace:*", 29 | "@openassistantgpt/react": "workspace:*", 30 | "@openassistantgpt/ui": "workspace:*" 31 | }, 32 | "devDependencies": { 33 | "@openassistantgpt/tsconfig": "workspace:*", 34 | "@testing-library/jest-dom": "^6.6.3", 35 | "@testing-library/react": "^16.0.1", 36 | "@testing-library/user-event": "^14.5.2", 37 | "@types/node": "^20.16.11", 38 | "@types/react": "^18.3.11", 39 | "@types/react-dom": "^18.3.1", 40 | "eslint": "^7.32.0", 41 | "eslint-config-openassistantgpt": "workspace:*", 42 | "jsdom": "^24.1.3", 43 | "msw": "2.3.1", 44 | "react-dom": "^18.3.1", 45 | "tsup": "^7.2.0", 46 | "typescript": "5.1.3", 47 | "zod": "3.23.8" 48 | }, 49 | "peerDependencies": { 50 | "react": "^18 || ^19", 51 | "zod": "^3.0.0" 52 | }, 53 | "peerDependenciesMeta": { 54 | "react": { 55 | "optional": true 56 | }, 57 | "zod": { 58 | "optional": true 59 | } 60 | }, 61 | "engines": { 62 | "node": ">=18" 63 | }, 64 | "publishConfig": { 65 | "access": "public" 66 | }, 67 | "homepage": "https://openassistantgpt.io", 68 | "repository": { 69 | "type": "git", 70 | "url": "git+https://github.com/OpenAssistantGPT/OpenAssistantGPT-SDK.git" 71 | }, 72 | "bugs": { 73 | "url": "https://github.com/OpenAssistantGPT/OpenAssistantGPT-SDK/issues" 74 | }, 75 | "keywords": [ 76 | "ai" 77 | ] 78 | } 79 | -------------------------------------------------------------------------------- /packages/core/src/index.test.tsx: -------------------------------------------------------------------------------- 1 | import { expect } from 'vitest'; 2 | import { it } from 'vitest'; 3 | import { describe } from 'vitest'; 4 | 5 | describe('Assistant Resonse', () => { 6 | it('should send text', async () => { 7 | expect(true); 8 | }); 9 | }); 10 | -------------------------------------------------------------------------------- /packages/core/src/index.ts: -------------------------------------------------------------------------------- 1 | import { OpenAssistantGPTChat as chat } from '@openassistantgpt/ui'; 2 | export const OpenAssistantGPTChat = chat; 3 | export type { ChatbotConfig } from '@openassistantgpt/ui'; 4 | 5 | import { useAssistant as assistant } from '@openassistantgpt/react'; 6 | export const useAssistant = assistant; 7 | export type { Message } from '@openassistantgpt/react'; 8 | 9 | import { 10 | AssistantResponse as response, 11 | fileSearchExtensionList as fileSearchList, 12 | codeInterpreterExtensionList as codeInterpreterList, 13 | handleAssistant as assistantHandler, 14 | handleFile as fileHandler, 15 | handleFileFunction as fileFunction, 16 | handleFileUpload as fileUpload, 17 | } from '@openassistantgpt/assistant'; 18 | 19 | export const AssistantResponse = response; 20 | export const codeInterpreterExtensionList = codeInterpreterList; 21 | export const handleAssistant = assistantHandler; 22 | export const handleFile = fileHandler; 23 | export const handleFileFunction = fileFunction; 24 | export const handleFileUpload = fileUpload; 25 | export const fileSearchExtensionList = fileSearchList; 26 | 27 | export type { OpenAssistantGPT } from '@openassistantgpt/assistant'; 28 | -------------------------------------------------------------------------------- /packages/core/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./node_modules/@openassistantgpt/tsconfig/react-library.json", 3 | "compilerOptions": { 4 | "target": "ES2018", 5 | "stripInternal": true 6 | }, 7 | "include": ["."], 8 | "exclude": ["*/dist", "dist", "build", "node_modules"] 9 | } 10 | -------------------------------------------------------------------------------- /packages/core/tsup.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'tsup'; 2 | 3 | export default defineConfig([ 4 | { 5 | entry: ['src/index.ts'], 6 | outDir: 'dist', 7 | banner: {}, 8 | format: ['cjs', 'esm'], 9 | external: ['vue'], 10 | dts: true, 11 | sourcemap: true, 12 | }, 13 | ]); 14 | -------------------------------------------------------------------------------- /packages/core/turbo.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "//" 4 | ], 5 | "tasks": { 6 | "build": { 7 | "outputs": [ 8 | "**/dist/**" 9 | ] 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/core/vitest.config.js: -------------------------------------------------------------------------------- 1 | import react from '@vitejs/plugin-react'; 2 | import { defineConfig } from 'vite'; 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | test: { 8 | environment: 'jsdom', 9 | globals: true, 10 | include: ['src/**/*.test.ts', 'src/**/*.test.tsx'], 11 | }, 12 | }); 13 | -------------------------------------------------------------------------------- /packages/react/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: ['openassistantgpt'], 4 | }; 5 | -------------------------------------------------------------------------------- /packages/react/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @assistant 2 | 3 | ## 0.3.3 4 | 5 | ### Patch Changes 6 | 7 | - 344f91c: Handle after chat to actually call the function after the chat is completed 8 | 9 | ## 0.3.2 10 | 11 | ### Patch Changes 12 | 13 | - 2fcbfad: Add support for multiple sources and custom text before displaying the sources 14 | 15 | ## 0.3.1 16 | 17 | ### Patch Changes 18 | 19 | - d020f27: update issue with types on file handle function 20 | 21 | ## 0.3.0 22 | 23 | ### Minor Changes 24 | 25 | - 8d62b91: Add support for file references. You can now display the document where the assistant chatbot got his information from. 26 | 27 | ## 0.2.0 28 | 29 | ### Minor Changes 30 | 31 | - 3f4f1d7: Support upload of multiple attachments and improve validation 32 | 33 | ## 0.1.1 34 | 35 | ### Patch Changes 36 | 37 | - 4b57e1e: add support for extensions in the chat and improve mobile UX 38 | 39 | ## 0.1.0 40 | 41 | ### Minor Changes 42 | 43 | - 9aaa198: Add feature to support extensions in our chat compoenent, improve chat header in mobile mode. 44 | 45 | ## 0.0.4 46 | 47 | ### Patch Changes 48 | 49 | - df7561e: Add download transcript option and fix width of assistant reply 50 | 51 | ## 0.0.3 52 | 53 | ### Patch Changes 54 | 55 | - 2a9002e: finish last doc update, fix latest bug there is no new feature in this release 56 | 57 | ## 0.0.2 58 | 59 | ### Patch Changes 60 | 61 | - fcacff1: Update all Git repository link 62 | 63 | ## 0.0.1 64 | 65 | ### Patch Changes 66 | 67 | - 151c8b0: Create the default library for the Official OpenAssistant SDK library and created all the required package to run a chatbot in few steps. 68 | -------------------------------------------------------------------------------- /packages/react/README.md: -------------------------------------------------------------------------------- 1 | # OpenAssistantGPT SDK: React 2 | 3 | - useAssistant 4 | -------------------------------------------------------------------------------- /packages/react/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@openassistantgpt/react", 3 | "version": "0.3.3", 4 | "license": "Apache-2.0", 5 | "sideEffects": false, 6 | "main": "./dist/index.js", 7 | "module": "./dist/index.mjs", 8 | "types": "./dist/index.d.ts", 9 | "scripts": { 10 | "build": "tsup", 11 | "clean": "rm -rf dist", 12 | "dev": "tsup --watch", 13 | "lint": "eslint \"./**/*.ts*\"", 14 | "type-check": "tsc --noEmit", 15 | "prettier-check": "prettier --check \"./**/*.ts*\"", 16 | "test": "vitest --config vitest.config.js --run", 17 | "test:watch": "vitest --config vitest.config.js" 18 | }, 19 | "exports": { 20 | "./package.json": "./package.json", 21 | ".": { 22 | "types": "./dist/index.d.ts", 23 | "import": "./dist/index.mjs", 24 | "require": "./dist/index.js" 25 | } 26 | }, 27 | "dependencies": { 28 | "@ai-sdk/provider-utils": "1.0.5", 29 | "@ai-sdk/ui-utils": "0.0.20", 30 | "@vitejs/plugin-react": "^4.3.1", 31 | "ai": "^3.2.24", 32 | "openai": "^4.52.7", 33 | "swr": "2.2.5" 34 | }, 35 | "devDependencies": { 36 | "@openassistantgpt/tsconfig": "workspace:*", 37 | "@testing-library/jest-dom": "^6.6.3", 38 | "@testing-library/react": "^16.0.1", 39 | "@testing-library/user-event": "^14.5.2", 40 | "@types/node": "^20.16.11", 41 | "@types/react": "^18.3.11", 42 | "@types/react-dom": "^18.3.1", 43 | "eslint": "^7.32.0", 44 | "eslint-config-openassistantgpt": "workspace:*", 45 | "jsdom": "^24.1.3", 46 | "msw": "2.3.1", 47 | "react-dom": "^18.3.1", 48 | "tsup": "^7.2.0", 49 | "typescript": "5.1.3", 50 | "zod": "3.23.8" 51 | }, 52 | "peerDependencies": { 53 | "react": "^18 || ^19", 54 | "zod": "^3.0.0" 55 | }, 56 | "peerDependenciesMeta": { 57 | "react": { 58 | "optional": true 59 | }, 60 | "zod": { 61 | "optional": true 62 | } 63 | }, 64 | "engines": { 65 | "node": ">=18" 66 | }, 67 | "publishConfig": { 68 | "access": "public" 69 | }, 70 | "homepage": "https://openassistantgpt.io", 71 | "repository": { 72 | "type": "git", 73 | "url": "git+https://github.com/OpenAssistantGPT/OpenAssistantGPT-SDK.git" 74 | }, 75 | "bugs": { 76 | "url": "https://github.com/OpenAssistantGPT/OpenAssistantGPT-SDK/issues" 77 | }, 78 | "keywords": [ 79 | "ai" 80 | ] 81 | } 82 | -------------------------------------------------------------------------------- /packages/react/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './use-assistant'; 2 | -------------------------------------------------------------------------------- /packages/react/src/use-assistant.ui.test.tsx: -------------------------------------------------------------------------------- 1 | import { formatStreamPart } from '@ai-sdk/ui-utils'; 2 | import { 3 | mockFetchDataStream, 4 | mockFetchDataStreamWithGenerator, 5 | mockFetchError, 6 | } from '@ai-sdk/ui-utils/test'; 7 | import '@testing-library/jest-dom/vitest'; 8 | import { cleanup, findByText, render, screen } from '@testing-library/react'; 9 | import userEvent from '@testing-library/user-event'; 10 | import { useAssistant } from './use-assistant'; 11 | 12 | describe('stream data stream', () => { 13 | const TestComponent = () => { 14 | const { status, messages, error, append } = useAssistant({ 15 | api: '/api/assistant', 16 | }); 17 | 18 | return ( 19 | 20 | {status} 21 | {error ? {error.toString()} : <>>} 22 | {messages.map((m, idx) => ( 23 | 24 | {m.role === 'user' ? 'User: ' : 'AI: '} 25 | {m.content} 26 | 27 | ))} 28 | 29 | { 32 | append({ role: 'user', content: 'hi' }); 33 | }} 34 | /> 35 | 36 | ); 37 | }; 38 | 39 | beforeEach(() => { 40 | render(); 41 | }); 42 | 43 | afterEach(() => { 44 | vi.restoreAllMocks(); 45 | cleanup(); 46 | }); 47 | 48 | it('should show streamed response', async () => { 49 | const { requestBody } = mockFetchDataStream({ 50 | url: 'https://example.com/api/assistant', 51 | chunks: [ 52 | formatStreamPart('assistant_control_data', { 53 | threadId: 't0', 54 | messageId: 'm0', 55 | }), 56 | formatStreamPart('assistant_message', { 57 | id: 'm0', 58 | role: 'assistant', 59 | content: [{ type: 'text', text: { value: '' } }], 60 | }), 61 | // text parts: 62 | '0:"Hello"\n', 63 | '0:","\n', 64 | '0:" world"\n', 65 | '0:"."\n', 66 | ], 67 | }); 68 | 69 | await userEvent.click(screen.getByTestId('do-append')); 70 | 71 | await screen.findByTestId('message-0'); 72 | expect(screen.getByTestId('message-0')).toHaveTextContent('User: hi'); 73 | 74 | await screen.findByTestId('message-1'); 75 | expect(screen.getByTestId('message-1')).toHaveTextContent( 76 | 'AI: Hello, world.', 77 | ); 78 | 79 | // check that correct information was sent to the server: 80 | expect(typeof requestBody).toBe('object'); 81 | }); 82 | 83 | it('should show error response', async () => { 84 | mockFetchError({ statusCode: 500, errorMessage: 'Internal Error' }); 85 | 86 | await userEvent.click(screen.getByTestId('do-append')); 87 | }); 88 | 89 | describe('loading state', () => { 90 | it('should show loading state', async () => { 91 | let finishGeneration: ((value?: unknown) => void) | undefined; 92 | const finishGenerationPromise = new Promise(resolve => { 93 | finishGeneration = resolve; 94 | }); 95 | 96 | mockFetchDataStreamWithGenerator({ 97 | url: 'https://example.com/api/chat', 98 | chunkGenerator: (async function* generate() { 99 | const encoder = new TextEncoder(); 100 | 101 | yield encoder.encode( 102 | formatStreamPart('assistant_control_data', { 103 | threadId: 't0', 104 | messageId: 'm1', 105 | }), 106 | ); 107 | 108 | yield encoder.encode( 109 | formatStreamPart('assistant_message', { 110 | id: 'm1', 111 | role: 'assistant', 112 | content: [{ type: 'text', text: { value: '' } }], 113 | }), 114 | ); 115 | 116 | yield encoder.encode('0:"Hello"\n'); 117 | 118 | await finishGenerationPromise; 119 | })(), 120 | }); 121 | 122 | await userEvent.click(screen.getByTestId('do-append')); 123 | 124 | await screen.findByTestId('status'); 125 | expect(screen.getByTestId('status')).toHaveTextContent('in_progress'); 126 | 127 | finishGeneration?.(); 128 | 129 | await findByText(await screen.findByTestId('status'), 'awaiting_message'); 130 | expect(screen.getByTestId('status')).toHaveTextContent( 131 | 'awaiting_message', 132 | ); 133 | }); 134 | }); 135 | }); 136 | -------------------------------------------------------------------------------- /packages/react/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./node_modules/@openassistantgpt/tsconfig/react-library.json", 3 | "compilerOptions": { 4 | "target": "ES2018", 5 | "stripInternal": true 6 | }, 7 | "include": ["."], 8 | "exclude": ["*/dist", "dist", "build", "node_modules"] 9 | } 10 | -------------------------------------------------------------------------------- /packages/react/tsup.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'tsup'; 2 | 3 | export default defineConfig([ 4 | { 5 | entry: ['src/index.ts'], 6 | outDir: 'dist', 7 | banner: {}, 8 | format: ['cjs', 'esm'], 9 | external: ['vue'], 10 | dts: true, 11 | sourcemap: true, 12 | }, 13 | ]); 14 | -------------------------------------------------------------------------------- /packages/react/turbo.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "//" 4 | ], 5 | "tasks": { 6 | "build": { 7 | "outputs": [ 8 | "**/dist/**" 9 | ] 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/react/vitest.config.js: -------------------------------------------------------------------------------- 1 | import react from '@vitejs/plugin-react'; 2 | import { defineConfig } from 'vite'; 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | test: { 8 | environment: 'jsdom', 9 | globals: true, 10 | include: ['src/**/*.ui.test.ts', 'src/**/*.ui.test.tsx'], 11 | }, 12 | }); 13 | -------------------------------------------------------------------------------- /packages/ui/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: ['openassistantgpt'], 4 | }; 5 | -------------------------------------------------------------------------------- /packages/ui/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @openassistantgpt/ui 2 | 3 | ## 0.3.12 4 | 5 | ### Patch Changes 6 | 7 | - 344f91c: Handle after chat to actually call the function after the chat is completed 8 | - Updated dependencies [344f91c] 9 | - @openassistantgpt/react@0.3.3 10 | 11 | ## 0.3.11 12 | 13 | ### Patch Changes 14 | 15 | - 116076b: Add new feature to disable chat inputs 16 | 17 | ## 0.3.10 18 | 19 | ### Patch Changes 20 | 21 | - 5481399: add a parameter to be able to call a function before and after submitting a message 22 | 23 | ## 0.3.9 24 | 25 | ### Patch Changes 26 | 27 | - 2626b91: Update marging and padding issue 28 | 29 | ## 0.3.8 30 | 31 | ### Patch Changes 32 | 33 | - d61426f: Adjust pading in chat window when disabeling icon. 34 | 35 | ## 0.3.7 36 | 37 | ### Patch Changes 38 | 39 | - 91497dc: Add feature to remove all icons from chat 40 | 41 | ## 0.3.6 42 | 43 | ### Patch Changes 44 | 45 | - b7910da: Send message to parent window on message sent 46 | 47 | ## 0.3.5 48 | 49 | ### Patch Changes 50 | 51 | - d287b92: Fix scrolling animation that makes parent window scroll 52 | 53 | ## 0.3.4 54 | 55 | ### Patch Changes 56 | 57 | - 4bbfa94: Improve scrolling. Disable autoscroll when user is trying to scroll up when generating a message and add a button to scroll down when you are not at the buttom 58 | 59 | ## 0.3.3 60 | 61 | ### Patch Changes 62 | 63 | - 0043c44: feat: remove console log that is spamming the console 64 | 65 | ## 0.3.2 66 | 67 | ### Patch Changes 68 | 69 | - 2fcbfad: Add support for multiple sources and custom text before displaying the sources 70 | - Updated dependencies [2fcbfad] 71 | - @openassistantgpt/react@0.3.2 72 | 73 | ## 0.3.1 74 | 75 | ### Patch Changes 76 | 77 | - d020f27: update issue with types on file handle function 78 | - Updated dependencies [d020f27] 79 | - @openassistantgpt/react@0.3.1 80 | 81 | ## 0.3.0 82 | 83 | ### Minor Changes 84 | 85 | - 8d62b91: Add support for file references. You can now display the document where the assistant chatbot got his information from. 86 | 87 | ### Patch Changes 88 | 89 | - Updated dependencies [8d62b91] 90 | - @openassistantgpt/react@0.3.0 91 | 92 | ## 0.2.5 93 | 94 | ### Patch Changes 95 | 96 | - 5da68eb: fix issue when the copy in CodeBlock was breaking the page 97 | 98 | ## 0.2.4 99 | 100 | ### Patch Changes 101 | 102 | - 0387c04: Export toast to be able to use them in app 103 | 104 | ## 0.2.3 105 | 106 | ### Patch Changes 107 | 108 | - 994197f: Add scroll when there is too much attachments 109 | 110 | ## 0.2.2 111 | 112 | ### Patch Changes 113 | 114 | - d9169e0: Add max height and width to attachment preview 115 | 116 | ## 0.2.1 117 | 118 | ### Patch Changes 119 | 120 | - bed19ad: Use path in file upload 121 | 122 | ## 0.2.0 123 | 124 | ### Minor Changes 125 | 126 | - 3f4f1d7: Support upload of multiple attachments and improve validation 127 | 128 | ### Patch Changes 129 | 130 | - Updated dependencies [3f4f1d7] 131 | - @openassistantgpt/react@0.2.0 132 | 133 | ## 0.1.9 134 | 135 | ### Patch Changes 136 | 137 | - e4d2713: add feature to configure the fontsize 138 | 139 | ## 0.1.8 140 | 141 | ### Patch Changes 142 | 143 | - a55c6e7: Add option to stop the message generation when it is being generated 144 | 145 | ## 0.1.7 146 | 147 | ### Patch Changes 148 | 149 | - dadc8fd: Update icons 150 | 151 | ## 0.1.6 152 | 153 | ### Patch Changes 154 | 155 | - bdafd7c: Fix frontend error while copying message 156 | 157 | ## 0.1.5 158 | 159 | ### Patch Changes 160 | 161 | - 2635c63: Fix type error from String to string 162 | 163 | ## 0.1.4 164 | 165 | ### Patch Changes 166 | 167 | - 7303695: add parameters to support threadId changes 168 | 169 | ## 0.1.3 170 | 171 | ### Patch Changes 172 | 173 | - 675d106: Fix more scrolling issue 174 | 175 | ## 0.1.2 176 | 177 | ### Patch Changes 178 | 179 | - 4e5c500: Fix issue when chat history wasnt showing all items 180 | 181 | ## 0.1.1 182 | 183 | ### Patch Changes 184 | 185 | - 4b57e1e: add support for extensions in the chat and improve mobile UX 186 | - Updated dependencies [4b57e1e] 187 | - @openassistantgpt/react@0.1.1 188 | 189 | ## 0.1.0 190 | 191 | ### Minor Changes 192 | 193 | - 9aaa198: Add feature to support extensions in our chat compoenent, improve chat header in mobile mode. 194 | 195 | ### Patch Changes 196 | 197 | - Updated dependencies [9aaa198] 198 | - @openassistantgpt/react@0.1.0 199 | 200 | ## 0.0.7 201 | 202 | ### Patch Changes 203 | 204 | - ba1155a: Override max width of attribute prose 205 | 206 | ## 0.0.6 207 | 208 | ### Patch Changes 209 | 210 | - df7561e: Add download transcript option and fix width of assistant reply 211 | - Updated dependencies [df7561e] 212 | - @openassistantgpt/react@0.0.4 213 | 214 | ## 0.0.5 215 | 216 | ### Patch Changes 217 | 218 | - 4737746: Update handlers to support parameters instead of having to use environment variable. You can now provide assistantId and OpenAI object in the function parameters. 219 | 220 | ## 0.0.4 221 | 222 | ### Patch Changes 223 | 224 | - e14ba89: The tooltip component is now wrapped in the chat component, it is not exported anymore 225 | 226 | ## 0.0.3 227 | 228 | ### Patch Changes 229 | 230 | - 2a9002e: finish last doc update, fix latest bug there is no new feature in this release 231 | - Updated dependencies [2a9002e] 232 | - @openassistantgpt/react@0.0.3 233 | 234 | ## 0.0.2 235 | 236 | ### Patch Changes 237 | 238 | - fcacff1: Update all Git repository link 239 | - Updated dependencies [fcacff1] 240 | - @openassistantgpt/react@0.0.2 241 | 242 | ## 0.0.1 243 | 244 | ### Patch Changes 245 | 246 | - 151c8b0: Create the default library for the Official OpenAssistant SDK library and created all the required package to run a chatbot in few steps. 247 | - Updated dependencies [151c8b0] 248 | - @openassistantgpt/react@0.0.1 249 | -------------------------------------------------------------------------------- /packages/ui/README.md: -------------------------------------------------------------------------------- 1 | # OpenAssistantGPT SDK: UI 2 | 3 | [React](https://react.dev/) UI components 4 | 5 | - OpenAssistantGPTChat 6 | -------------------------------------------------------------------------------- /packages/ui/components/chat-footer-text.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { cn } from '@/lib/utils'; 4 | import { ExternalLink } from '@/components/external-link'; 5 | 6 | export function FooterText({ 7 | className, 8 | link, 9 | name, 10 | ...props 11 | }: React.ComponentProps<'p'> & { link: string; name: string }) { 12 | return ( 13 | 20 | Powered by {name} 21 | 22 | ); 23 | } 24 | -------------------------------------------------------------------------------- /packages/ui/components/chat-message-actions.tsx: -------------------------------------------------------------------------------- 1 | import { type Message } from '@openassistantgpt/react'; 2 | 3 | import { Button } from '@/components/ui/button'; 4 | import { useCopyToClipboard } from '@/hooks/use-copy-to-clipboard'; 5 | import { cn } from '@/lib/utils'; 6 | import { CheckIcon, CopyIcon } from 'lucide-react'; 7 | 8 | interface ChatMessageActionsProps extends React.ComponentProps<'div'> { 9 | message: Message; 10 | } 11 | 12 | export function ChatMessageActions({ 13 | message, 14 | className, 15 | ...props 16 | }: ChatMessageActionsProps) { 17 | const { isCopied, copyToClipboard } = useCopyToClipboard({ timeout: 2000 }); 18 | 19 | const onCopy = () => { 20 | if (isCopied) return; 21 | copyToClipboard(message.content); 22 | }; 23 | 24 | return ( 25 | 32 | 33 | {isCopied ? ( 34 | 35 | ) : ( 36 | 37 | )} 38 | Copy message 39 | 40 | 41 | ); 42 | } 43 | -------------------------------------------------------------------------------- /packages/ui/components/empty-placeholder.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | 3 | import { cn } from '@/lib/utils'; 4 | import { Icons } from '@/components/icons'; 5 | 6 | interface EmptyPlaceholderProps extends React.HTMLAttributes {} 7 | 8 | export function EmptyPlaceholder({ 9 | className, 10 | children, 11 | ...props 12 | }: EmptyPlaceholderProps) { 13 | return ( 14 | 21 | 22 | {children} 23 | 24 | 25 | ); 26 | } 27 | 28 | interface EmptyPlaceholderIconProps 29 | extends Partial> { 30 | name: string; 31 | } 32 | 33 | EmptyPlaceholder.Icon = function EmptyPlaceHolderIcon({ 34 | name, 35 | className, 36 | ...props 37 | }: EmptyPlaceholderIconProps) { 38 | const Icon: any = Icons[name]; 39 | 40 | if (!Icon) { 41 | return null; 42 | } 43 | 44 | return ( 45 | 46 | 50 | 51 | ); 52 | }; 53 | 54 | interface EmptyPlacholderTitleProps 55 | extends React.HTMLAttributes {} 56 | 57 | EmptyPlaceholder.Title = function EmptyPlaceholderTitle({ 58 | className, 59 | ...props 60 | }: EmptyPlacholderTitleProps) { 61 | return ( 62 | 63 | ); 64 | }; 65 | 66 | interface EmptyPlacholderDescriptionProps 67 | extends React.HTMLAttributes {} 68 | 69 | EmptyPlaceholder.Description = function EmptyPlaceholderDescription({ 70 | className, 71 | ...props 72 | }: EmptyPlacholderDescriptionProps) { 73 | return ( 74 | 81 | ); 82 | }; 83 | -------------------------------------------------------------------------------- /packages/ui/components/external-link.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export function ExternalLink({ 4 | href, 5 | children, 6 | }: { 7 | href: string; 8 | children: React.ReactNode; 9 | }) { 10 | return ( 11 | 16 | {children} 17 | 24 | 28 | 29 | 30 | ); 31 | } 32 | -------------------------------------------------------------------------------- /packages/ui/components/icons.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | AlertTriangle, 3 | ArrowRight, 4 | ChevronLeft, 5 | ChevronRight, 6 | Command, 7 | CreditCard, 8 | File, 9 | FileText, 10 | HelpCircle, 11 | Image, 12 | Laptop, 13 | Loader2, 14 | Moon, 15 | MoreVertical, 16 | Pizza, 17 | Plus, 18 | Settings, 19 | SunMedium, 20 | Trash, 21 | User, 22 | X, 23 | BotIcon, 24 | FolderClosed, 25 | LayoutDashboard, 26 | Key, 27 | Coins, 28 | ArrowUp, 29 | CheckCheck, 30 | ArrowDown, 31 | Import, 32 | BadgePlus, 33 | Copy, 34 | Download, 35 | Send, 36 | Loader, 37 | RefreshCcw, 38 | Paperclip, 39 | Lock, 40 | } from 'lucide-react'; 41 | 42 | export const Icons: any = { 43 | arrowDown: ArrowDown, 44 | lock: Lock, 45 | document: File, 46 | paperclip: Paperclip, 47 | reload: RefreshCcw, 48 | loading: Loader, 49 | send: Send, 50 | download: Download, 51 | copy: Copy, 52 | badgeplus: BadgePlus, 53 | import: Import, 54 | logo: Command, 55 | folder: FolderClosed, 56 | dashboard: LayoutDashboard, 57 | close: X, 58 | key: Key, 59 | checkcheck: CheckCheck, 60 | coin: Coins, 61 | spinner: Loader2, 62 | chevronLeft: ChevronLeft, 63 | chevronRight: ChevronRight, 64 | trash: Trash, 65 | post: FileText, 66 | page: File, 67 | media: Image, 68 | settings: Settings, 69 | billing: CreditCard, 70 | ellipsis: MoreVertical, 71 | add: Plus, 72 | bot: BotIcon, 73 | warning: AlertTriangle, 74 | user: User, 75 | arrowRight: ArrowRight, 76 | arrowUp: ArrowUp, 77 | help: HelpCircle, 78 | pizza: Pizza, 79 | sun: SunMedium, 80 | moon: Moon, 81 | laptop: Laptop, 82 | }; 83 | -------------------------------------------------------------------------------- /packages/ui/components/markdown.tsx: -------------------------------------------------------------------------------- 1 | import { FC, memo } from 'react'; 2 | import ReactMarkdown, { Options } from 'react-markdown'; 3 | 4 | export const MemoizedReactMarkdown: FC = memo( 5 | ReactMarkdown, 6 | (prevProps, nextProps) => 7 | prevProps.children === nextProps.children && 8 | prevProps.className === nextProps.className, 9 | ); 10 | -------------------------------------------------------------------------------- /packages/ui/components/preview-attachement.tsx: -------------------------------------------------------------------------------- 1 | import { Attachment } from '@/types/attachements'; 2 | import { LoaderIcon } from 'lucide-react'; 3 | 4 | export const PreviewAttachment = ({ 5 | attachment, 6 | isUploading = false, 7 | }: { 8 | attachment: Attachment; 9 | isUploading?: boolean; 10 | }) => { 11 | const { name, url, contentType } = attachment; 12 | 13 | return ( 14 | 15 | 16 | {contentType ? ( 17 | contentType.startsWith('image') ? ( 18 | // eslint-disable-next-line @next/next/no-img-element 19 | 27 | ) : ( 28 | 29 | ) 30 | ) : ( 31 | 32 | )} 33 | 34 | {isUploading && ( 35 | 36 | 37 | 38 | )} 39 | 40 | 41 | {name} 42 | 43 | ); 44 | }; 45 | -------------------------------------------------------------------------------- /packages/ui/components/ui/button.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { VariantProps, cva } from 'class-variance-authority'; 3 | 4 | import { cn } from '@/lib/utils'; 5 | 6 | const buttonVariants = cva( 7 | 'inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none ring-offset-background', 8 | { 9 | variants: { 10 | variant: { 11 | default: 'bg-primary text-primary-foreground hover:bg-primary/90', 12 | destructive: 13 | 'bg-destructive text-destructive-foreground hover:bg-destructive/90', 14 | outline: 15 | 'border border-input hover:bg-accent hover:text-accent-foreground', 16 | secondary: 17 | 'bg-secondary text-secondary-foreground hover:bg-secondary/80', 18 | ghost: 'hover:bg-accent hover:text-accent-foreground', 19 | link: 'underline-offset-4 hover:underline text-primary', 20 | nothing: '', 21 | }, 22 | size: { 23 | default: 'h-10 py-2 px-4', 24 | sm: 'h-9 px-3 rounded-md', 25 | lg: 'h-11 px-8 rounded-md', 26 | icon: 'py-1 px-1', 27 | xs: '', 28 | }, 29 | }, 30 | defaultVariants: { 31 | variant: 'default', 32 | size: 'default', 33 | }, 34 | }, 35 | ); 36 | 37 | export interface ButtonProps 38 | extends React.ButtonHTMLAttributes, 39 | VariantProps {} 40 | 41 | const Button = React.forwardRef( 42 | ({ className, variant, size, ...props }, ref) => { 43 | return ( 44 | 49 | ); 50 | }, 51 | ); 52 | Button.displayName = 'Button'; 53 | 54 | export { Button, buttonVariants }; 55 | -------------------------------------------------------------------------------- /packages/ui/components/ui/card.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | 3 | import { cn } from '@/lib/utils'; 4 | 5 | const Card = React.forwardRef< 6 | HTMLDivElement, 7 | React.HTMLAttributes 8 | >(({ className, ...props }, ref) => ( 9 | 17 | )); 18 | Card.displayName = 'Card'; 19 | 20 | const CardHeader = React.forwardRef< 21 | HTMLDivElement, 22 | React.HTMLAttributes 23 | >(({ className, ...props }, ref) => ( 24 | 29 | )); 30 | CardHeader.displayName = 'CardHeader'; 31 | 32 | const CardTitle = React.forwardRef< 33 | HTMLParagraphElement, 34 | React.HTMLAttributes 35 | >(({ className, ...props }, ref) => ( 36 | 44 | )); 45 | CardTitle.displayName = 'CardTitle'; 46 | 47 | const CardDescription = React.forwardRef< 48 | HTMLParagraphElement, 49 | React.HTMLAttributes 50 | >(({ className, ...props }, ref) => ( 51 | 56 | )); 57 | CardDescription.displayName = 'CardDescription'; 58 | 59 | const CardContent = React.forwardRef< 60 | HTMLDivElement, 61 | React.HTMLAttributes 62 | >(({ className, ...props }, ref) => ( 63 | 64 | )); 65 | CardContent.displayName = 'CardContent'; 66 | 67 | const CardFooter = React.forwardRef< 68 | HTMLDivElement, 69 | React.HTMLAttributes 70 | >(({ className, ...props }, ref) => ( 71 | 76 | )); 77 | CardFooter.displayName = 'CardFooter'; 78 | 79 | export { 80 | Card, 81 | CardHeader, 82 | CardFooter, 83 | CardTitle, 84 | CardDescription, 85 | CardContent, 86 | }; 87 | -------------------------------------------------------------------------------- /packages/ui/components/ui/codeblock.tsx: -------------------------------------------------------------------------------- 1 | import { FC, memo } from 'react'; 2 | import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'; 3 | import { coldarkCold } from 'react-syntax-highlighter/dist/cjs/styles/prism'; 4 | 5 | import { Button } from '@/components/ui/button'; 6 | import { Icons } from '@/components/icons'; 7 | import { useCopyToClipboardNoTimeout } from '@/hooks/use-copy-to-clipboard'; 8 | 9 | interface Props { 10 | language: string; 11 | value: string; 12 | } 13 | 14 | interface languageMap { 15 | [key: string]: string | undefined; 16 | } 17 | 18 | const programmingLanguages: languageMap = { 19 | javascript: '.js', 20 | python: '.py', 21 | java: '.java', 22 | c: '.c', 23 | cpp: '.cpp', 24 | 'c++': '.cpp', 25 | 'c#': '.cs', 26 | ruby: '.rb', 27 | php: '.php', 28 | swift: '.swift', 29 | 'objective-c': '.m', 30 | kotlin: '.kt', 31 | typescript: '.ts', 32 | go: '.go', 33 | perl: '.pl', 34 | rust: '.rs', 35 | scala: '.scala', 36 | haskell: '.hs', 37 | lua: '.lua', 38 | shell: '.sh', 39 | sql: '.sql', 40 | html: '.html', 41 | css: '.css', 42 | // add more file extensions here, make sure the key is same as language prop in CodeBlock.tsx component 43 | }; 44 | 45 | function generateRandomString(length: number, lowercase = false) { 46 | const chars = 'ABCDEFGHJKLMNPQRSTUVWXY3456789'; // excluding similar looking characters like Z, 2, I, 1, O, 0 47 | let result = ''; 48 | for (let i = 0; i < length; i++) { 49 | result += chars.charAt(Math.floor(Math.random() * chars.length)); 50 | } 51 | return lowercase ? result.toLowerCase() : result; 52 | } 53 | 54 | const CodeBlock: FC = memo(({ language, value }) => { 55 | const { copyToClipboard } = useCopyToClipboardNoTimeout(); 56 | 57 | const downloadAsFile = () => { 58 | if (typeof window === 'undefined') { 59 | return; 60 | } 61 | 62 | const fileExtension = programmingLanguages[language] || '.file'; 63 | const suggestedFileName = `file-${generateRandomString( 64 | 3, 65 | true, 66 | )}${fileExtension}`; 67 | const fileName = window.prompt('Enter file name' || '', suggestedFileName); 68 | 69 | if (!fileName) { 70 | // User pressed cancel on prompt. 71 | return; 72 | } 73 | 74 | const blob = new Blob([value], { type: 'text/plain' }); 75 | const url = URL.createObjectURL(blob); 76 | const link = document.createElement('a'); 77 | link.download = fileName; 78 | link.href = url; 79 | link.style.display = 'none'; 80 | document.body.appendChild(link); 81 | link.click(); 82 | document.body.removeChild(link); 83 | URL.revokeObjectURL(url); 84 | }; 85 | 86 | const onCopy = () => { 87 | copyToClipboard(value); 88 | }; 89 | 90 | return ( 91 | 92 | 93 | 94 | {language} 95 | 96 | 97 | 103 | 104 | Download 105 | 106 | 112 | 113 | Copy code 114 | 115 | 116 | 117 | 138 | {value} 139 | 140 | 141 | ); 142 | }); 143 | CodeBlock.displayName = 'CodeBlock'; 144 | 145 | export { CodeBlock }; 146 | -------------------------------------------------------------------------------- /packages/ui/components/ui/dialog.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import * as React from 'react'; 4 | import * as DialogPrimitive from '@radix-ui/react-dialog'; 5 | import { Cross2Icon } from '@radix-ui/react-icons'; 6 | 7 | import { cn } from '@/lib/utils'; 8 | 9 | const Dialog = DialogPrimitive.Root; 10 | 11 | const DialogTrigger = DialogPrimitive.Trigger; 12 | 13 | const DialogPortal = DialogPrimitive.Portal; 14 | 15 | const DialogClose = DialogPrimitive.Close; 16 | 17 | const DialogOverlay = React.forwardRef< 18 | React.ElementRef, 19 | React.ComponentPropsWithoutRef 20 | >(({ className, ...props }, ref) => ( 21 | 29 | )); 30 | DialogOverlay.displayName = DialogPrimitive.Overlay.displayName; 31 | 32 | const DialogContent = React.forwardRef< 33 | React.ElementRef, 34 | React.ComponentPropsWithoutRef 35 | >(({ className, children, ...props }, ref) => ( 36 | 37 | 38 | 46 | {children} 47 | 48 | 49 | Close 50 | 51 | 52 | 53 | )); 54 | DialogContent.displayName = DialogPrimitive.Content.displayName; 55 | 56 | const DialogHeader = ({ 57 | className, 58 | ...props 59 | }: React.HTMLAttributes) => ( 60 | 67 | ); 68 | DialogHeader.displayName = 'DialogHeader'; 69 | 70 | const DialogFooter = ({ 71 | className, 72 | ...props 73 | }: React.HTMLAttributes) => ( 74 | 81 | ); 82 | DialogFooter.displayName = 'DialogFooter'; 83 | 84 | const DialogTitle = React.forwardRef< 85 | React.ElementRef, 86 | React.ComponentPropsWithoutRef 87 | >(({ className, ...props }, ref) => ( 88 | 96 | )); 97 | DialogTitle.displayName = DialogPrimitive.Title.displayName; 98 | 99 | const DialogDescription = React.forwardRef< 100 | React.ElementRef, 101 | React.ComponentPropsWithoutRef 102 | >(({ className, ...props }, ref) => ( 103 | 108 | )); 109 | DialogDescription.displayName = DialogPrimitive.Description.displayName; 110 | 111 | export { 112 | Dialog, 113 | DialogPortal, 114 | DialogOverlay, 115 | DialogTrigger, 116 | DialogClose, 117 | DialogContent, 118 | DialogHeader, 119 | DialogFooter, 120 | DialogTitle, 121 | DialogDescription, 122 | }; 123 | -------------------------------------------------------------------------------- /packages/ui/components/ui/input.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | 3 | import { cn } from '@/lib/utils'; 4 | 5 | export interface InputProps 6 | extends React.InputHTMLAttributes {} 7 | 8 | const Input = React.forwardRef( 9 | ({ className, type, ...props }, ref) => { 10 | return ( 11 | 20 | ); 21 | }, 22 | ); 23 | Input.displayName = 'Input'; 24 | 25 | export { Input }; 26 | -------------------------------------------------------------------------------- /packages/ui/components/ui/label.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import * as React from 'react'; 4 | import * as LabelPrimitive from '@radix-ui/react-label'; 5 | import { VariantProps, cva } from 'class-variance-authority'; 6 | 7 | import { cn } from '@/lib/utils'; 8 | 9 | const labelVariants = cva( 10 | 'text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70', 11 | ); 12 | 13 | const Label = React.forwardRef< 14 | React.ElementRef, 15 | React.ComponentPropsWithoutRef & 16 | VariantProps 17 | >(({ className, ...props }, ref) => ( 18 | 19 | )); 20 | Label.displayName = LabelPrimitive.Root.displayName; 21 | 22 | export { Label }; 23 | -------------------------------------------------------------------------------- /packages/ui/components/ui/textarea.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | 3 | import { cn } from '@/lib/utils'; 4 | 5 | export interface TextareaProps 6 | extends React.TextareaHTMLAttributes {} 7 | 8 | const Textarea = React.forwardRef( 9 | ({ className, ...props }, ref) => { 10 | return ( 11 | 19 | ); 20 | }, 21 | ); 22 | Textarea.displayName = 'Textarea'; 23 | 24 | export { Textarea }; 25 | -------------------------------------------------------------------------------- /packages/ui/components/ui/toast.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import * as ToastPrimitives from '@radix-ui/react-toast'; 3 | import { VariantProps, cva } from 'class-variance-authority'; 4 | import { X } from 'lucide-react'; 5 | 6 | import { cn } from '@/lib/utils'; 7 | 8 | const ToastProvider = ToastPrimitives.Provider; 9 | 10 | const ToastViewport = React.forwardRef< 11 | React.ElementRef, 12 | React.ComponentPropsWithoutRef 13 | >(({ className, ...props }, ref) => ( 14 | 22 | )); 23 | ToastViewport.displayName = ToastPrimitives.Viewport.displayName; 24 | 25 | const toastVariants = cva( 26 | 'data-[swipe=move]:transition-none group relative pointer-events-auto flex w-full items-center justify-between space-x-4 overflow-hidden rounded-md border p-6 pr-8 shadow-lg transition-all data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 data-[state=open]:slide-in-from-top-full data-[state=open]:sm:slide-in-from-bottom-full data-[state=closed]:slide-out-to-right-full', 27 | { 28 | variants: { 29 | variant: { 30 | default: 'bg-background border', 31 | destructive: 32 | 'group destructive border-destructive bg-destructive text-destructive-foreground', 33 | }, 34 | }, 35 | defaultVariants: { 36 | variant: 'default', 37 | }, 38 | }, 39 | ); 40 | 41 | const Toast = React.forwardRef< 42 | React.ElementRef, 43 | React.ComponentPropsWithoutRef & 44 | VariantProps 45 | >(({ className, variant, ...props }, ref) => { 46 | return ( 47 | 52 | ); 53 | }); 54 | Toast.displayName = ToastPrimitives.Root.displayName; 55 | 56 | const ToastAction = React.forwardRef< 57 | React.ElementRef, 58 | React.ComponentPropsWithoutRef 59 | >(({ className, ...props }, ref) => ( 60 | 68 | )); 69 | ToastAction.displayName = ToastPrimitives.Action.displayName; 70 | 71 | const ToastClose = React.forwardRef< 72 | React.ElementRef, 73 | React.ComponentPropsWithoutRef 74 | >(({ className, ...props }, ref) => ( 75 | 84 | 85 | 86 | )); 87 | ToastClose.displayName = ToastPrimitives.Close.displayName; 88 | 89 | const ToastTitle = React.forwardRef< 90 | React.ElementRef, 91 | React.ComponentPropsWithoutRef 92 | >(({ className, ...props }, ref) => ( 93 | 98 | )); 99 | ToastTitle.displayName = ToastPrimitives.Title.displayName; 100 | 101 | const ToastDescription = React.forwardRef< 102 | React.ElementRef, 103 | React.ComponentPropsWithoutRef 104 | >(({ className, ...props }, ref) => ( 105 | 110 | )); 111 | ToastDescription.displayName = ToastPrimitives.Description.displayName; 112 | 113 | type ToastProps = React.ComponentPropsWithoutRef; 114 | 115 | type ToastActionElement = React.ReactElement; 116 | 117 | export { 118 | type ToastProps, 119 | type ToastActionElement, 120 | ToastProvider, 121 | ToastViewport, 122 | Toast, 123 | ToastTitle, 124 | ToastDescription, 125 | ToastClose, 126 | ToastAction, 127 | }; 128 | -------------------------------------------------------------------------------- /packages/ui/components/ui/tooltip.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import * as React from 'react'; 4 | import * as TooltipPrimitive from '@radix-ui/react-tooltip'; 5 | 6 | import { cn } from '@/lib/utils'; 7 | 8 | const TooltipProvider = TooltipPrimitive.Provider; 9 | 10 | const Tooltip = TooltipPrimitive.Root; 11 | 12 | const TooltipTrigger = TooltipPrimitive.Trigger; 13 | 14 | const TooltipContent = React.forwardRef< 15 | React.ElementRef, 16 | React.ComponentPropsWithoutRef 17 | >(({ className, sideOffset = 4, ...props }, ref) => ( 18 | 27 | )); 28 | TooltipContent.displayName = TooltipPrimitive.Content.displayName; 29 | 30 | export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }; 31 | -------------------------------------------------------------------------------- /packages/ui/components/ui/use-toast.tsx: -------------------------------------------------------------------------------- 1 | // Inspired by react-hot-toast library 2 | import * as React from 'react'; 3 | 4 | import { ToastActionElement, type ToastProps } from '@/components/ui/toast'; 5 | 6 | const TOAST_LIMIT = 1; 7 | const TOAST_REMOVE_DELAY = 1000000; 8 | 9 | type ToasterToast = ToastProps & { 10 | id: string; 11 | title?: React.ReactNode; 12 | description?: React.ReactNode; 13 | action?: ToastActionElement; 14 | }; 15 | 16 | const actionTypes = { 17 | ADD_TOAST: 'ADD_TOAST', 18 | UPDATE_TOAST: 'UPDATE_TOAST', 19 | DISMISS_TOAST: 'DISMISS_TOAST', 20 | REMOVE_TOAST: 'REMOVE_TOAST', 21 | } as const; 22 | 23 | let count = 0; 24 | 25 | function genId() { 26 | count = (count + 1) % Number.MAX_VALUE; 27 | return count.toString(); 28 | } 29 | 30 | type ActionType = typeof actionTypes; 31 | 32 | type Action = 33 | | { 34 | type: ActionType['ADD_TOAST']; 35 | toast: ToasterToast; 36 | } 37 | | { 38 | type: ActionType['UPDATE_TOAST']; 39 | toast: Partial; 40 | } 41 | | { 42 | type: ActionType['DISMISS_TOAST']; 43 | toastId?: ToasterToast['id']; 44 | } 45 | | { 46 | type: ActionType['REMOVE_TOAST']; 47 | toastId?: ToasterToast['id']; 48 | }; 49 | 50 | interface State { 51 | toasts: ToasterToast[]; 52 | } 53 | 54 | const toastTimeouts = new Map>(); 55 | 56 | const addToRemoveQueue = (toastId: string) => { 57 | if (toastTimeouts.has(toastId)) { 58 | return; 59 | } 60 | 61 | const timeout = setTimeout(() => { 62 | toastTimeouts.delete(toastId); 63 | dispatch({ 64 | type: 'REMOVE_TOAST', 65 | toastId: toastId, 66 | }); 67 | }, TOAST_REMOVE_DELAY); 68 | 69 | toastTimeouts.set(toastId, timeout); 70 | }; 71 | 72 | export const reducer = (state: State, action: Action): State => { 73 | switch (action.type) { 74 | case 'ADD_TOAST': 75 | return { 76 | ...state, 77 | toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT), 78 | }; 79 | 80 | case 'UPDATE_TOAST': 81 | return { 82 | ...state, 83 | toasts: state.toasts.map(t => 84 | t.id === action.toast.id ? { ...t, ...action.toast } : t, 85 | ), 86 | }; 87 | 88 | case 'DISMISS_TOAST': { 89 | const { toastId } = action; 90 | 91 | // ! Side effects ! - This could be extracted into a dismissToast() action, 92 | // but I'll keep it here for simplicity 93 | if (toastId) { 94 | addToRemoveQueue(toastId); 95 | } else { 96 | state.toasts.forEach(toast => { 97 | addToRemoveQueue(toast.id); 98 | }); 99 | } 100 | 101 | return { 102 | ...state, 103 | toasts: state.toasts.map(t => 104 | t.id === toastId || toastId === undefined 105 | ? { 106 | ...t, 107 | open: false, 108 | } 109 | : t, 110 | ), 111 | }; 112 | } 113 | case 'REMOVE_TOAST': 114 | if (action.toastId === undefined) { 115 | return { 116 | ...state, 117 | toasts: [], 118 | }; 119 | } 120 | return { 121 | ...state, 122 | toasts: state.toasts.filter(t => t.id !== action.toastId), 123 | }; 124 | } 125 | }; 126 | 127 | const listeners: Array<(state: State) => void> = []; 128 | 129 | let memoryState: State = { toasts: [] }; 130 | 131 | function dispatch(action: Action) { 132 | memoryState = reducer(memoryState, action); 133 | listeners.forEach(listener => { 134 | listener(memoryState); 135 | }); 136 | } 137 | 138 | interface Toast extends Omit {} 139 | 140 | function toast({ ...props }: Toast) { 141 | const id = genId(); 142 | 143 | const update = (props: ToasterToast) => 144 | dispatch({ 145 | type: 'UPDATE_TOAST', 146 | toast: { ...props, id }, 147 | }); 148 | const dismiss = () => dispatch({ type: 'DISMISS_TOAST', toastId: id }); 149 | 150 | dispatch({ 151 | type: 'ADD_TOAST', 152 | toast: { 153 | ...props, 154 | id, 155 | open: true, 156 | onOpenChange: open => { 157 | if (!open) dismiss(); 158 | }, 159 | }, 160 | }); 161 | 162 | return { 163 | id: id, 164 | dismiss, 165 | update, 166 | }; 167 | } 168 | 169 | function useToast() { 170 | const [state, setState] = React.useState(memoryState); 171 | 172 | React.useEffect(() => { 173 | listeners.push(setState); 174 | return () => { 175 | const index = listeners.indexOf(setState); 176 | if (index > -1) { 177 | listeners.splice(index, 1); 178 | } 179 | }; 180 | }, [state]); 181 | 182 | return { 183 | ...state, 184 | toast, 185 | dismiss: (toastId?: string) => dispatch({ type: 'DISMISS_TOAST', toastId }), 186 | }; 187 | } 188 | 189 | export { useToast, toast }; 190 | -------------------------------------------------------------------------------- /packages/ui/hooks/use-copy-to-clipboard.ts: -------------------------------------------------------------------------------- 1 | import { useState } from 'react'; 2 | 3 | export interface useCopyToClipboardProps { 4 | timeout?: number; 5 | } 6 | 7 | export function useCopyToClipboard({ 8 | timeout = 2000, 9 | }: useCopyToClipboardProps) { 10 | const [isCopied, setIsCopied] = useState(false); 11 | 12 | const copyToClipboard = (value: string) => { 13 | if (typeof window === 'undefined' || !navigator.clipboard?.writeText) { 14 | return; 15 | } 16 | 17 | if (!value) { 18 | return; 19 | } 20 | console.log(value); 21 | console.log(navigator.clipboard.writeText(value)); 22 | 23 | navigator.clipboard.writeText(value).then(() => { 24 | setIsCopied(true); 25 | window.setTimeout(() => { 26 | setIsCopied(false); 27 | }, timeout); 28 | }); 29 | }; 30 | 31 | return { isCopied, copyToClipboard }; 32 | } 33 | 34 | export function useCopyToClipboardNoTimeout() { 35 | const copyToClipboard = (value: string) => { 36 | if (typeof window === 'undefined' || !navigator.clipboard?.writeText) { 37 | return; 38 | } 39 | 40 | if (!value) { 41 | return; 42 | } 43 | 44 | navigator.clipboard.writeText(value); 45 | }; 46 | 47 | return { copyToClipboard }; 48 | } 49 | -------------------------------------------------------------------------------- /packages/ui/hooks/use-enter-submit.ts: -------------------------------------------------------------------------------- 1 | import { useRef, type RefObject } from 'react'; 2 | 3 | export function useEnterSubmit(): { 4 | formRef: RefObject; 5 | onKeyDown: (event: React.KeyboardEvent) => void; 6 | } { 7 | const formRef = useRef(null); 8 | 9 | const handleKeyDown = ( 10 | event: React.KeyboardEvent, 11 | ): void => { 12 | if ( 13 | event.key === 'Enter' && 14 | !event.shiftKey && 15 | !event.nativeEvent.isComposing 16 | ) { 17 | formRef.current?.requestSubmit(); 18 | event.preventDefault(); 19 | } 20 | }; 21 | 22 | return { formRef, onKeyDown: handleKeyDown }; 23 | } 24 | -------------------------------------------------------------------------------- /packages/ui/hooks/use-scroll-to-buttom.ts: -------------------------------------------------------------------------------- 1 | import { useEffect, useRef, RefObject, useState } from 'react'; 2 | 3 | export function useScrollToBottom( 4 | messages: any, 5 | ): [ 6 | RefObject, 7 | RefObject, 8 | boolean, // true or false is at buttom 9 | Function, 10 | ] { 11 | const containerRef = useRef(null); 12 | const endRef = useRef(null); 13 | const [shouldScroll, setShouldScroll] = useState(true); 14 | 15 | useEffect(() => { 16 | const handleScroll = () => { 17 | // Check if the user is scrolling near the bottom of the window 18 | const windowScrollY = window.scrollY + window.innerHeight; // Current scroll position + height of the window 19 | const documentHeight = document.documentElement.scrollHeight; // Total document height 20 | 21 | // Determine if the user is at the bottom (within a threshold of 100 pixels) 22 | const isNoButtom = windowScrollY <= documentHeight - 100; // Adjust threshold as needed 23 | setShouldScroll(!isNoButtom); 24 | }; 25 | 26 | // Attach the scroll event listener 27 | window.addEventListener('scroll', handleScroll); 28 | 29 | return () => { 30 | window.removeEventListener('scroll', handleScroll); 31 | }; 32 | }, []); 33 | 34 | useEffect(() => { 35 | const end = endRef.current; 36 | 37 | // Scroll to the end only if the user is at the bottom of the window 38 | if (end && shouldScroll) { 39 | document.documentElement.scrollTop = 40 | document.getElementById('end')!.offsetTop; 41 | //end.scrollIntoView({ behavior: 'instant' }); 42 | } 43 | }, [messages, shouldScroll]); 44 | 45 | function scrollToBottom() { 46 | const end = endRef.current; 47 | 48 | if (end) { 49 | //end.scrollIntoView({ behavior: 'smooth' }); 50 | document.documentElement.scrollTop = 51 | document.getElementById('end')!.offsetTop; 52 | } 53 | } 54 | 55 | return [containerRef, endRef, shouldScroll, scrollToBottom]; 56 | } 57 | -------------------------------------------------------------------------------- /packages/ui/lib/utils.ts: -------------------------------------------------------------------------------- 1 | import { type ClassValue, clsx } from 'clsx'; 2 | import { twMerge } from 'tailwind-merge'; 3 | 4 | export function cn(...inputs: ClassValue[]) { 5 | return twMerge(clsx(inputs)); 6 | } 7 | -------------------------------------------------------------------------------- /packages/ui/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@openassistantgpt/ui", 3 | "version": "0.3.12", 4 | "license": "Apache-2.0", 5 | "sideEffects": false, 6 | "main": "./dist/index.js", 7 | "module": "./dist/index.mjs", 8 | "types": "./dist/index.d.ts", 9 | "scripts": { 10 | "build": "tsup", 11 | "clean": "rm -rf dist", 12 | "dev": "tsup --watch", 13 | "lint": "eslint \"./**/*.ts*\"", 14 | "type-check": "tsc --noEmit", 15 | "prettier-check": "prettier --check \"./**/*.ts*\"", 16 | "test": "vitest --config vitest.config.js --run", 17 | "test:watch": "vitest --config vitest.config.js" 18 | }, 19 | "exports": { 20 | "./package.json": "./package.json", 21 | ".": { 22 | "types": "./dist/index.d.ts", 23 | "import": "./dist/index.mjs", 24 | "require": "./dist/index.js" 25 | }, 26 | "./dist/index.css": "./dist/index.css" 27 | }, 28 | "dependencies": { 29 | "@ai-sdk/provider-utils": "1.0.5", 30 | "@ai-sdk/ui-utils": "0.0.20", 31 | "@openassistantgpt/react": "workspace:^", 32 | "@radix-ui/react-dialog": "^1.1.1", 33 | "@radix-ui/react-dropdown-menu": "^2.1.1", 34 | "@radix-ui/react-icons": "^1.3.0", 35 | "@radix-ui/react-label": "^2.1.0", 36 | "@radix-ui/react-toast": "^1.2.1", 37 | "@radix-ui/react-tooltip": "^1.1.2", 38 | "@tailwindcss/typography": "^0.5.15", 39 | "autoprefixer": "^10.4.19", 40 | "better-react-mathjax": "^2.0.3", 41 | "class-variance-authority": "^0.7.0", 42 | "clsx": "^2.1.1", 43 | "lucide-react": "^0.408.0", 44 | "postcss-apply": "^0.12.0", 45 | "react-markdown": "^9.0.1", 46 | "react-syntax-highlighter": "^15.5.0", 47 | "remark-gfm": "^4.0.0", 48 | "remark-math": "^6.0.0", 49 | "swr": "2.2.5", 50 | "tailwind-merge": "^2.4.0", 51 | "tailwindcss": "^3.4.6", 52 | "tailwindcss-animate": "^1.0.7" 53 | }, 54 | "devDependencies": { 55 | "@openassistantgpt/tsconfig": "workspace:*", 56 | "@testing-library/jest-dom": "^6.6.3", 57 | "@testing-library/react": "^16.0.0", 58 | "@testing-library/user-event": "^14.5.1", 59 | "@types/node": "^20", 60 | "@types/react": "^18", 61 | "@types/react-dom": "^18", 62 | "@types/react-syntax-highlighter": "^15.5.13", 63 | "eslint": "^7.32.0", 64 | "eslint-config-openassistantgpt": "workspace:*", 65 | "jsdom": "^24.1.0", 66 | "msw": "2.3.1", 67 | "react-dom": "^18", 68 | "tsup": "^7.2.0", 69 | "typescript": "5.1.3", 70 | "zod": "3.23.8" 71 | }, 72 | "peerDependencies": { 73 | "react": "^18 || ^19", 74 | "zod": "^3.0.0" 75 | }, 76 | "peerDependenciesMeta": { 77 | "react": { 78 | "optional": true 79 | }, 80 | "zod": { 81 | "optional": true 82 | } 83 | }, 84 | "engines": { 85 | "node": ">=18" 86 | }, 87 | "publishConfig": { 88 | "access": "public" 89 | }, 90 | "homepage": "https://openassistantgpt.io", 91 | "repository": { 92 | "type": "git", 93 | "url": "git+https://github.com/OpenAssistantGPT/OpenAssistantGPT-SDK.git" 94 | }, 95 | "bugs": { 96 | "url": "https://github.com/OpenAssistantGPT/OpenAssistantGPT-SDK/issues" 97 | }, 98 | "keywords": [ 99 | "ai" 100 | ] 101 | } 102 | -------------------------------------------------------------------------------- /packages/ui/postcss.config.js: -------------------------------------------------------------------------------- 1 | // postcss.config.js 2 | 3 | module.exports = { 4 | plugins: { 5 | tailwindcss: {}, 6 | autoprefixer: {}, 7 | }, 8 | }; 9 | -------------------------------------------------------------------------------- /packages/ui/src/chatbot.test.tsx: -------------------------------------------------------------------------------- 1 | import { expect } from 'vitest'; 2 | import { it } from 'vitest'; 3 | import { describe } from 'vitest'; 4 | 5 | describe('Assistant Resonse', () => { 6 | it('should send text', async () => { 7 | expect(true); 8 | }); 9 | }); 10 | -------------------------------------------------------------------------------- /packages/ui/src/chatbot.ts: -------------------------------------------------------------------------------- 1 | export type ChatbotConfig = { 2 | id: string; 3 | name: string; 4 | chatTitle: string; 5 | welcomeMessage: string; 6 | chatMessagePlaceHolder: string; 7 | 8 | rightToLeftLanguage: boolean; 9 | 10 | bubbleColor: string; 11 | bubbleTextColor: string; 12 | 13 | chatHeaderBackgroundColor: string; 14 | chatHeaderTextColor: string; 15 | 16 | chatbotReplyBackgroundColor: string; 17 | chatbotReplyTextColor: string; 18 | 19 | userReplyBackgroundColor: string; 20 | userReplyTextColor: string; 21 | 22 | chatbotLogoURL: string; 23 | 24 | chatInputStyle: string; 25 | 26 | chatHistoryEnabled: boolean; 27 | chatFileAttachementEnabled: boolean; 28 | 29 | fontSize: string; 30 | 31 | displayFooterText: boolean; 32 | footerTextName: string; 33 | footerLink: string; 34 | 35 | messageSourceText: string; 36 | 37 | withChatMessageIcon: boolean; 38 | }; 39 | -------------------------------------------------------------------------------- /packages/ui/src/global.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | /* Chrome, Edge, and Safari */ 6 | *::-webkit-scrollbar { 7 | width: 20px; 8 | } 9 | 10 | ::-webkit-scrollbar-track { 11 | background-color: white; 12 | } 13 | 14 | ::-webkit-scrollbar-thumb { 15 | background-color: #d6dee1; 16 | } 17 | 18 | ::-webkit-scrollbar-thumb { 19 | background-color: #d6dee1; 20 | border-radius: 20px; 21 | } 22 | 23 | ::-webkit-scrollbar-thumb { 24 | background-color: #d6dee1; 25 | border-radius: 20px; 26 | border: 6px solid transparent; 27 | background-clip: content-box; 28 | } 29 | 30 | @layer base { 31 | :root { 32 | --background: 0 0% 100%; 33 | --foreground: 222.2 47.4% 11.2%; 34 | 35 | --muted: 210 40% 96.1%; 36 | --muted-foreground: 215.4 16.3% 46.9%; 37 | 38 | --popover: 0 0% 100%; 39 | --popover-foreground: 222.2 47.4% 11.2%; 40 | 41 | --border: 214.3 31.8% 91.4%; 42 | --input: 214.3 31.8% 91.4%; 43 | 44 | --card: 0 0% 100%; 45 | --card-foreground: 222.2 47.4% 11.2%; 46 | 47 | --primary: 222.2 47.4% 11.2%; 48 | --primary-foreground: 210 40% 98%; 49 | 50 | --secondary: 210 40% 96.1%; 51 | --secondary-foreground: 222.2 47.4% 11.2%; 52 | 53 | --accent: 210 40% 96.1%; 54 | --accent-foreground: 222.2 47.4% 11.2%; 55 | 56 | --destructive: 0 100% 50%; 57 | --destructive-foreground: 210 40% 98%; 58 | 59 | --ring: 215 20.2% 65.1%; 60 | 61 | --radius: 0.5rem; 62 | } 63 | } 64 | 65 | @layer base { 66 | * { 67 | @apply border-border; 68 | } 69 | 70 | body { 71 | @apply bg-background text-foreground; 72 | font-feature-settings: "rlig" 1, "calt" 1; 73 | } 74 | } -------------------------------------------------------------------------------- /packages/ui/src/index.ts: -------------------------------------------------------------------------------- 1 | import './global.css'; 2 | import { OpenAssistantGPTChat } from '@/components/chat'; 3 | import { ChatbotConfig } from './chatbot'; 4 | 5 | export { type ChatbotConfig }; 6 | export { OpenAssistantGPTChat }; 7 | export { useToast } from '@/components/ui/use-toast'; 8 | -------------------------------------------------------------------------------- /packages/ui/tailwind.config.js: -------------------------------------------------------------------------------- 1 | const { fontFamily } = require('tailwindcss/defaultTheme'); 2 | 3 | /** @type {import('tailwindcss').Config} */ 4 | module.exports = { 5 | content: [], 6 | theme: { 7 | container: { 8 | center: true, 9 | padding: '2rem', 10 | screens: { 11 | '2xl': '1400px', 12 | }, 13 | }, 14 | extend: { 15 | colors: { 16 | border: 'hsl(var(--border))', 17 | input: 'hsl(var(--input))', 18 | ring: 'hsl(var(--ring))', 19 | background: 'hsl(var(--background))', 20 | foreground: 'hsl(var(--foreground))', 21 | primary: { 22 | DEFAULT: 'hsl(var(--primary))', 23 | foreground: 'hsl(var(--primary-foreground))', 24 | }, 25 | secondary: { 26 | DEFAULT: 'hsl(var(--secondary))', 27 | foreground: 'hsl(var(--secondary-foreground))', 28 | }, 29 | destructive: { 30 | DEFAULT: 'hsl(var(--destructive))', 31 | foreground: 'hsl(var(--destructive-foreground))', 32 | }, 33 | muted: { 34 | DEFAULT: 'hsl(var(--muted))', 35 | foreground: 'hsl(var(--muted-foreground))', 36 | }, 37 | accent: { 38 | DEFAULT: 'hsl(var(--accent))', 39 | foreground: 'hsl(var(--accent-foreground))', 40 | }, 41 | popover: { 42 | DEFAULT: 'hsl(var(--popover))', 43 | foreground: 'hsl(var(--popover-foreground))', 44 | }, 45 | card: { 46 | DEFAULT: 'hsl(var(--card))', 47 | foreground: 'hsl(var(--card-foreground))', 48 | }, 49 | }, 50 | borderRadius: { 51 | lg: `var(--radius)`, 52 | md: `calc(var(--radius) - 2px)`, 53 | sm: 'calc(var(--radius) - 4px)', 54 | }, 55 | fontFamily: { 56 | sans: ['var(--font-sans)', ...fontFamily.sans], 57 | heading: ['var(--font-heading)', ...fontFamily.sans], 58 | }, 59 | keyframes: { 60 | 'accordion-down': { 61 | from: { height: 0 }, 62 | to: { height: 'var(--radix-accordion-content-height)' }, 63 | }, 64 | 'accordion-up': { 65 | from: { height: 'var(--radix-accordion-content-height)' }, 66 | to: { height: 0 }, 67 | }, 68 | }, 69 | animation: { 70 | 'accordion-down': 'accordion-down 0.2s ease-out', 71 | 'accordion-up': 'accordion-up 0.2s ease-out', 72 | }, 73 | typography: { 74 | DEFAULT: { 75 | css: { 76 | maxWidth: '100%', // add required value here 77 | }, 78 | }, 79 | }, 80 | }, 81 | }, 82 | content: [ 83 | './src/**/*.ts', 84 | './src/**/*.tsx', 85 | './components/**/*.tsx', 86 | './src/**/*.css', 87 | ], 88 | plugins: [require('tailwindcss-animate'), require('@tailwindcss/typography')], 89 | }; 90 | -------------------------------------------------------------------------------- /packages/ui/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./node_modules/@openassistantgpt/tsconfig/react-library.json", 3 | "compilerOptions": { 4 | "target": "ES2018", 5 | "stripInternal": true, 6 | "paths": { 7 | "@/*": [ 8 | "./*", 9 | ], 10 | } 11 | }, 12 | "include": ["."], 13 | "exclude": ["*/dist", "dist", "build", "node_modules"] 14 | } 15 | -------------------------------------------------------------------------------- /packages/ui/tsup.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'tsup'; 2 | 3 | export default defineConfig([ 4 | { 5 | entry: ['src/index.ts'], 6 | outDir: 'dist', 7 | banner: {}, 8 | format: ['cjs', 'esm'], 9 | external: ['vue'], 10 | dts: true, 11 | sourcemap: true, 12 | }, 13 | ]); 14 | -------------------------------------------------------------------------------- /packages/ui/turbo.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "//" 4 | ], 5 | "tasks": { 6 | "build": { 7 | "outputs": [ 8 | "**/dist/**" 9 | ] 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/ui/types/attachements.ts: -------------------------------------------------------------------------------- 1 | export interface Attachment { 2 | /** 3 | * The name of the attachment, usually the file name. 4 | */ 5 | name?: string; 6 | /** 7 | * A string indicating the [media type](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type). 8 | * By default, it's extracted from the pathname's extension. 9 | */ 10 | contentType?: string; 11 | /** 12 | * The URL of the attachment. It can either be a URL to a hosted file or a [Data URL](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URLs). 13 | */ 14 | url: string; 15 | } 16 | -------------------------------------------------------------------------------- /packages/ui/vitest.config.js: -------------------------------------------------------------------------------- 1 | import react from '@vitejs/plugin-react'; 2 | import { defineConfig } from 'vite'; 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | test: { 8 | environment: 'jsdom', 9 | globals: true, 10 | include: ['src/**/*.test.ts', 'src/**/*.test.tsx'], 11 | }, 12 | }); 13 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - 'apps/*' 3 | - 'packages/*' 4 | - 'tools/*' 5 | - 'examples/*' 6 | - 'website/*' 7 | -------------------------------------------------------------------------------- /tools/eslint-config/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # eslint-config-openassistantgpt 2 | 3 | ## 0.0.4 4 | 5 | ### Patch Changes 6 | 7 | - 4d7e93f: update version 8 | 9 | ## 0.0.2 10 | 11 | ### Patch Changes 12 | 13 | - df7561e: Add download transcript option and fix width of assistant reply 14 | 15 | ## 0.0.1 16 | 17 | ### Patch Changes 18 | 19 | - a10bf68: Config our project 20 | -------------------------------------------------------------------------------- /tools/eslint-config/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ['next', 'turbo', 'prettier'], 3 | rules: { 4 | '@next/next/no-html-link-for-pages': 'off', 5 | }, 6 | parserOptions: { 7 | babelOptions: { 8 | presets: [require.resolve('next/babel')], 9 | }, 10 | }, 11 | }; 12 | -------------------------------------------------------------------------------- /tools/eslint-config/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "eslint-config-openassistantgpt", 3 | "version": "0.0.4", 4 | "license": "MIT", 5 | "main": "index.js", 6 | "dependencies": { 7 | "eslint-config-next": "^14.2.5", 8 | "eslint-config-prettier": "^8.3.0", 9 | "eslint-config-turbo": "^2.0.9", 10 | "eslint-plugin-react": "7.37.2" 11 | }, 12 | "publishConfig": { 13 | "access": "public" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /tools/tsconfig/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @openassistantgpt/tsconfig 2 | 3 | ## 0.0.2 4 | 5 | ### Patch Changes 6 | 7 | - df7561e: Add download transcript option and fix width of assistant reply 8 | 9 | ## 0.0.1 10 | 11 | ### Patch Changes 12 | 13 | - a10bf68: Config our project 14 | -------------------------------------------------------------------------------- /tools/tsconfig/base.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "display": "Default", 4 | "compilerOptions": { 5 | "composite": false, 6 | "declaration": true, 7 | "declarationMap": true, 8 | "esModuleInterop": true, 9 | "forceConsistentCasingInFileNames": true, 10 | "inlineSources": false, 11 | "isolatedModules": true, 12 | "moduleResolution": "node", 13 | "noUnusedLocals": false, 14 | "noUnusedParameters": false, 15 | "preserveWatchOutput": true, 16 | "skipLibCheck": true, 17 | "strict": true, 18 | "types": ["@types/node", "vitest/globals"] 19 | }, 20 | "exclude": ["node_modules"] 21 | } 22 | -------------------------------------------------------------------------------- /tools/tsconfig/nextjs.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "display": "Next.js", 4 | "extends": "./base.json", 5 | "compilerOptions": { 6 | "allowJs": true, 7 | "declaration": false, 8 | "declarationMap": false, 9 | "incremental": true, 10 | "jsx": "preserve", 11 | "lib": ["dom", "dom.iterable", "esnext"], 12 | "module": "esnext", 13 | "noEmit": true, 14 | "resolveJsonModule": true, 15 | "target": "es5" 16 | }, 17 | "include": ["src", "next-env.d.ts"], 18 | "exclude": ["node_modules"] 19 | } 20 | -------------------------------------------------------------------------------- /tools/tsconfig/node14.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "display": "Node 14", 4 | "extends": "./base.json", 5 | "compilerOptions": { 6 | "lib": ["ES2020"], 7 | "module": "commonjs", 8 | "target": "ES2020" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /tools/tsconfig/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@openassistantgpt/tsconfig", 3 | "version": "0.0.2", 4 | "private": true, 5 | "license": "MIT", 6 | "publishConfig": { 7 | "access": "public" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /tools/tsconfig/react-library.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "display": "React Library", 4 | "extends": "./base.json", 5 | "compilerOptions": { 6 | "jsx": "react-jsx", 7 | "lib": ["dom", "ES2015"], 8 | "module": "ESNext", 9 | "target": "es6" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /turbo.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://turbo.build/schema.json", 3 | "globalEnv": [ 4 | "CI", 5 | "PORT", 6 | "OPENAI_ASSISTANT_ID", 7 | "OPENAI_API_KEY" 8 | ], 9 | "tasks": { 10 | "build": { 11 | "dependsOn": [ 12 | "^build" 13 | ], 14 | "env": [], 15 | "outputs": [ 16 | "dist/**", 17 | ".next/**", 18 | "!.next/cache/**" 19 | ] 20 | }, 21 | "lint": { 22 | "dependsOn": [ 23 | "^lint" 24 | ] 25 | }, 26 | "type-check": { 27 | "dependsOn": [ 28 | "^build", 29 | "build" 30 | ] 31 | }, 32 | "test": { 33 | "dependsOn": [ 34 | "^build", 35 | "build" 36 | ] 37 | }, 38 | "publint": { 39 | "dependsOn": [ 40 | "^build", 41 | "build" 42 | ] 43 | }, 44 | "clean": { 45 | "dependsOn": [ 46 | "^clean" 47 | ] 48 | }, 49 | "dev": { 50 | "cache": false, 51 | "persistent": true 52 | }, 53 | "prettier-check": {}, 54 | "integration-test": { 55 | "dependsOn": [ 56 | "^build", 57 | "build" 58 | ] 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /website/sdk/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: ['openassistantgpt', 'next/core-web-vitals'], 4 | }; 5 | -------------------------------------------------------------------------------- /website/sdk/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | .yarn/install-state.gz 8 | 9 | # testing 10 | /coverage 11 | 12 | # next.js 13 | /.next/ 14 | /out/ 15 | 16 | # production 17 | /build 18 | 19 | # misc 20 | .DS_Store 21 | *.pem 22 | 23 | # debug 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | 28 | # local env files 29 | .env*.local 30 | 31 | # vercel 32 | .vercel 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | next-env.d.ts 37 | -------------------------------------------------------------------------------- /website/sdk/README.md: -------------------------------------------------------------------------------- 1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). 2 | 3 | ## Getting Started 4 | 5 | First, run the development server: 6 | 7 | ```bash 8 | npm run dev 9 | # or 10 | yarn dev 11 | # or 12 | pnpm dev 13 | # or 14 | bun dev 15 | ``` 16 | 17 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. 18 | 19 | You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. 20 | 21 | This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font. 22 | 23 | ## Learn More 24 | 25 | To learn more about Next.js, take a look at the following resources: 26 | 27 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. 28 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. 29 | 30 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! 31 | 32 | ## Deploy on Vercel 33 | 34 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. 35 | 36 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. 37 | -------------------------------------------------------------------------------- /website/sdk/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenAssistantGPT/chatbot-sdk/cb08d28e43d2e80d0d4d2e732855de02510da872/website/sdk/app/favicon.ico -------------------------------------------------------------------------------- /website/sdk/app/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | :root { 6 | --foreground-rgb: 0, 0, 0; 7 | --background-start-rgb: 255, 255, 255; 8 | --background-end-rgb: 255, 255, 255; 9 | } 10 | 11 | body { 12 | color: rgb(var(--foreground-rgb)); 13 | background: linear-gradient(to bottom, 14 | transparent, 15 | rgb(var(--background-end-rgb))) rgb(var(--background-start-rgb)); 16 | } 17 | 18 | @layer utilities { 19 | .text-balance { 20 | text-wrap: balance; 21 | } 22 | } 23 | 24 | .containerCode { 25 | background: #23223a; 26 | width: 30rem; 27 | border-radius: 5px; 28 | padding: 1.7rem; 29 | } 30 | 31 | .code { 32 | white-space: nowrap; 33 | font-size: 0.9rem; 34 | color: white; 35 | } 36 | 37 | .code .imas { 38 | font-size: 0.9rem; 39 | color: rgb(255, 255, 255); 40 | display: inline; 41 | } 42 | 43 | .c2 { 44 | display: inline-block; 45 | margin-top: 5%; 46 | } 47 | 48 | .typed-out { 49 | overflow: hidden; 50 | border-right: .15em solid rgb(40, 77, 245); 51 | white-space: nowrap; 52 | margin-top: 10%; 53 | font-size: 0.9rem; 54 | color: cyan; 55 | animation: 56 | typing 1.5s steps(20, end) forwards, 57 | blinking .75s infinite; 58 | width: 0; 59 | } 60 | 61 | @keyframes typing { 62 | from { 63 | width: 0 64 | } 65 | 66 | to { 67 | width: 100%; 68 | } 69 | } 70 | 71 | @keyframes blinking { 72 | from { 73 | border-color: transparent 74 | } 75 | 76 | to { 77 | border-color: orange; 78 | } 79 | } -------------------------------------------------------------------------------- /website/sdk/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import './globals.css'; 2 | import { LandingPage } from '@/components/landing-page'; 3 | import { constructMetadata } from '@/lib/metadata'; 4 | import { Analytics } from '@vercel/analytics/react'; 5 | 6 | export const metadata = constructMetadata(); 7 | 8 | export default function RootLayout({ 9 | children, 10 | }: Readonly<{ 11 | children: any; 12 | }>) { 13 | return ( 14 | 15 | 16 | {children} 17 | 18 | ); 19 | } 20 | -------------------------------------------------------------------------------- /website/sdk/app/page.tsx: -------------------------------------------------------------------------------- 1 | import { Features } from '@/components/features'; 2 | import { Hero } from '@/components/hero'; 3 | import { TechCarousel } from '@/components/tech-carousel'; 4 | 5 | export default function Home() { 6 | return ( 7 | 8 | 9 | 10 | 11 | 12 | ); 13 | } 14 | -------------------------------------------------------------------------------- /website/sdk/components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "default", 4 | "rsc": true, 5 | "tsx": true, 6 | "tailwind": { 7 | "config": "tailwind.config.js", 8 | "css": "app/globals.css", 9 | "baseColor": "gray", 10 | "cssVariables": false 11 | }, 12 | "aliases": { 13 | "utils": "@/lib/utils", 14 | "components": "@/components" 15 | } 16 | } -------------------------------------------------------------------------------- /website/sdk/components/hero.tsx: -------------------------------------------------------------------------------- 1 | import { siteConfig } from '@/config/site'; 2 | import Image from 'next/image'; 3 | import Link from 'next/link'; 4 | import { Icons } from './icons'; 5 | 6 | export function Hero() { 7 | return ( 8 | 9 | 10 | 11 | 12 | 13 | 18 | Find us on 𝕏 19 | 20 | 21 | Easiest Chatbot SDK to use 22 | 23 | 24 | Fastest and easiest way to build a chatbot using Next.JS for 25 | your website using the OpenAI Assistant API. 26 | 27 | 28 | 29 | 35 | GitHub 36 | 37 | 38 | 43 | Learn More 44 | 45 | 46 | 47 | 48 | 54 | 55 | 56 | 57 | 58 | ); 59 | } 60 | -------------------------------------------------------------------------------- /website/sdk/components/icons.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | AlertTriangle, 3 | ArrowRight, 4 | Check, 5 | ChevronLeft, 6 | ChevronRight, 7 | Command, 8 | CreditCard, 9 | File, 10 | FileText, 11 | HelpCircle, 12 | Image, 13 | Laptop, 14 | Loader2, 15 | LucideProps, 16 | Moon, 17 | MoreVertical, 18 | Pizza, 19 | Plus, 20 | Settings, 21 | SunMedium, 22 | Trash, 23 | Twitter, 24 | User, 25 | X, 26 | BotIcon, 27 | FolderClosed, 28 | LayoutDashboard, 29 | LucideIcon, 30 | MessageSquare, 31 | Key, 32 | Coins, 33 | ArrowUp, 34 | CheckCheck, 35 | ArrowDown, 36 | Import, 37 | BadgePlus, 38 | Copy, 39 | Download, 40 | Send, 41 | Loader, 42 | RefreshCcw, 43 | Paperclip, 44 | Lock, 45 | History, 46 | PenToolIcon, 47 | } from 'lucide-react'; 48 | 49 | export type Icon = LucideIcon; 50 | 51 | export const Icons = { 52 | pen: PenToolIcon, 53 | history: History, 54 | lock: Lock, 55 | document: File, 56 | paperclip: Paperclip, 57 | reload: RefreshCcw, 58 | loading: Loader, 59 | send: Send, 60 | download: Download, 61 | copy: Copy, 62 | badgeplus: BadgePlus, 63 | import: Import, 64 | logo: Command, 65 | folder: FolderClosed, 66 | dashboard: LayoutDashboard, 67 | close: X, 68 | key: Key, 69 | checkcheck: CheckCheck, 70 | coin: Coins, 71 | spinner: Loader2, 72 | chevronLeft: ChevronLeft, 73 | chevronRight: ChevronRight, 74 | trash: Trash, 75 | post: FileText, 76 | page: File, 77 | media: Image, 78 | settings: Settings, 79 | billing: CreditCard, 80 | ellipsis: MoreVertical, 81 | add: Plus, 82 | bot: BotIcon, 83 | warning: AlertTriangle, 84 | user: User, 85 | arrowRight: ArrowRight, 86 | arrowUp: ArrowUp, 87 | arrowDown: ArrowDown, 88 | help: HelpCircle, 89 | pizza: Pizza, 90 | sun: SunMedium, 91 | moon: Moon, 92 | laptop: Laptop, 93 | google: ({ ...props }: LucideProps) => ( 94 | 102 | 106 | 110 | 114 | 118 | 119 | ), 120 | gitHub: ({ ...props }: LucideProps) => ( 121 | 131 | 135 | 136 | ), 137 | message: MessageSquare, 138 | twitter: Twitter, 139 | check: Check, 140 | }; 141 | -------------------------------------------------------------------------------- /website/sdk/components/landing-page.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import React from 'react'; 4 | import { SiteFooter } from '@/components/site-footer'; 5 | import { useEffect, useState } from 'react'; 6 | import { MainNav } from '@/components/main-nav'; 7 | import { marketingConfig } from '@/config/marketing'; 8 | import { Inter } from 'next/font/google'; 9 | import Link from 'next/link'; 10 | import Image from 'next/image'; 11 | 12 | const inter = Inter({ subsets: ['latin'] }); 13 | 14 | export function LandingPage({ children }: { children: React.ReactNode }) { 15 | const [isHeaderTransparent, setIsHeaderTransparent] = useState(true); 16 | 17 | useEffect(() => { 18 | const handleScroll = () => { 19 | const scrollTop = 20 | window.pageYOffset || document.documentElement.scrollTop; 21 | setIsHeaderTransparent(scrollTop === 0); 22 | }; 23 | 24 | window.addEventListener('scroll', handleScroll); 25 | return () => { 26 | window.removeEventListener('scroll', handleScroll); 27 | }; 28 | }, []); 29 | 30 | return ( 31 | 32 | 39 | 40 | 41 | 42 | 46 | 51 | 52 | 57 | 64 | - Once Click Deploy 65 | 66 | 67 | 68 | 69 | {children} 70 | 71 | 72 | 73 | ); 74 | } 75 | -------------------------------------------------------------------------------- /website/sdk/components/main-nav.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import * as React from 'react'; 4 | import Link from 'next/link'; 5 | import { useSelectedLayoutSegment } from 'next/navigation'; 6 | 7 | import { MainNavItem } from '@/types'; 8 | import { siteConfig } from '@/config/site'; 9 | import { cn } from '@/lib/utils'; 10 | import { Icons } from '@/components/icons'; 11 | import { MobileNav } from '@/components/mobile-nav'; 12 | 13 | interface MainNavProps { 14 | items?: MainNavItem[]; 15 | children?: React.ReactNode; 16 | } 17 | 18 | export function MainNav({ items, children }: MainNavProps) { 19 | const segment = useSelectedLayoutSegment(); 20 | const [showMobileMenu, setShowMobileMenu] = React.useState(false); 21 | 22 | return ( 23 | 24 | 25 | 26 | 27 | {siteConfig.name} 28 | 29 | 30 | {items?.length ? ( 31 | 32 | {items?.map((item, index) => ( 33 | 44 | {item.title} 45 | 46 | ))} 47 | 48 | ) : null} 49 | setShowMobileMenu(!showMobileMenu)} 52 | > 53 | {showMobileMenu ? : } 54 | Menu 55 | 56 | {showMobileMenu && items && ( 57 | {children} 58 | )} 59 | 60 | ); 61 | } 62 | -------------------------------------------------------------------------------- /website/sdk/components/mobile-nav.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import Link from 'next/link'; 3 | 4 | import { MainNavItem } from '@/types'; 5 | import { siteConfig } from '@/config/site'; 6 | import { cn } from '@/lib/utils'; 7 | import { useLockBody } from '@/hooks/use-lock-body'; 8 | import { Icons } from '@/components/icons'; 9 | 10 | interface MobileNavProps { 11 | items: MainNavItem[]; 12 | children?: React.ReactNode; 13 | } 14 | 15 | export function MobileNav({ items, children }: MobileNavProps) { 16 | useLockBody(); 17 | 18 | return ( 19 | 24 | 25 | 26 | 27 | {siteConfig.name} 28 | 29 | 30 | {items.map((item, index) => ( 31 | 39 | {item.title} 40 | 41 | ))} 42 | 43 | {children} 44 | 45 | 46 | ); 47 | } 48 | -------------------------------------------------------------------------------- /website/sdk/components/site-footer.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | 3 | import { siteConfig } from '@/config/site'; 4 | import { Icons } from '@/components/icons'; 5 | import Link from 'next/link'; 6 | 7 | interface SiteFooterProps extends React.HTMLAttributes { 8 | simpleFooter?: boolean; 9 | } 10 | 11 | export function SiteFooter({ simpleFooter, className }: SiteFooterProps) { 12 | return ( 13 | 82 | ); 83 | } 84 | -------------------------------------------------------------------------------- /website/sdk/components/tech-carousel.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import * as React from 'react'; 4 | import Image from 'next/image'; 5 | import { Card, CardContent } from '@/components/ui/card'; 6 | import { 7 | Carousel, 8 | CarouselContent, 9 | CarouselItem, 10 | } from '@/components/ui/carousel'; 11 | import Autoplay from 'embla-carousel-autoplay'; 12 | 13 | export function TechCarousel() { 14 | return ( 15 | 16 | 17 | 18 | Built using the latest technologies 19 | 20 | 28 | 29 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | ); 104 | } 105 | -------------------------------------------------------------------------------- /website/sdk/components/ui/button.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { Slot } from '@radix-ui/react-slot'; 3 | import { cva, type VariantProps } from 'class-variance-authority'; 4 | 5 | import { cn } from '@/lib/utils'; 6 | 7 | const buttonVariants = cva( 8 | 'inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-white transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-gray-950 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 dark:ring-offset-gray-950 dark:focus-visible:ring-gray-300', 9 | { 10 | variants: { 11 | variant: { 12 | default: 13 | 'bg-gray-900 text-gray-50 hover:bg-gray-900/90 dark:bg-gray-50 dark:text-gray-900 dark:hover:bg-gray-50/90', 14 | destructive: 15 | 'bg-red-500 text-gray-50 hover:bg-red-500/90 dark:bg-red-900 dark:text-gray-50 dark:hover:bg-red-900/90', 16 | outline: 17 | 'border border-gray-200 bg-white hover:bg-gray-100 hover:text-gray-900 dark:border-gray-800 dark:bg-gray-950 dark:hover:bg-gray-800 dark:hover:text-gray-50', 18 | secondary: 19 | 'bg-gray-100 text-gray-900 hover:bg-gray-100/80 dark:bg-gray-800 dark:text-gray-50 dark:hover:bg-gray-800/80', 20 | ghost: 21 | 'hover:bg-gray-100 hover:text-gray-900 dark:hover:bg-gray-800 dark:hover:text-gray-50', 22 | link: 'text-gray-900 underline-offset-4 hover:underline dark:text-gray-50', 23 | }, 24 | size: { 25 | default: 'h-10 px-4 py-2', 26 | sm: 'h-9 rounded-md px-3', 27 | lg: 'h-11 rounded-md px-8', 28 | icon: 'h-10 w-10', 29 | }, 30 | }, 31 | defaultVariants: { 32 | variant: 'default', 33 | size: 'default', 34 | }, 35 | }, 36 | ); 37 | 38 | export interface ButtonProps 39 | extends React.ButtonHTMLAttributes, 40 | VariantProps { 41 | asChild?: boolean; 42 | } 43 | 44 | const Button = React.forwardRef( 45 | ({ className, variant, size, asChild = false, ...props }, ref) => { 46 | const Comp = asChild ? Slot : 'button'; 47 | return ( 48 | 53 | ); 54 | }, 55 | ); 56 | Button.displayName = 'Button'; 57 | 58 | export { Button, buttonVariants }; 59 | -------------------------------------------------------------------------------- /website/sdk/components/ui/card.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | 3 | import { cn } from '@/lib/utils'; 4 | 5 | const Card = React.forwardRef< 6 | HTMLDivElement, 7 | React.HTMLAttributes 8 | >(({ className, ...props }, ref) => ( 9 | 17 | )); 18 | Card.displayName = 'Card'; 19 | 20 | const CardHeader = React.forwardRef< 21 | HTMLDivElement, 22 | React.HTMLAttributes 23 | >(({ className, ...props }, ref) => ( 24 | 29 | )); 30 | CardHeader.displayName = 'CardHeader'; 31 | 32 | const CardTitle = React.forwardRef< 33 | HTMLParagraphElement, 34 | React.HTMLAttributes 35 | >(({ className, ...props }, ref) => ( 36 | 44 | )); 45 | CardTitle.displayName = 'CardTitle'; 46 | 47 | const CardDescription = React.forwardRef< 48 | HTMLParagraphElement, 49 | React.HTMLAttributes 50 | >(({ className, ...props }, ref) => ( 51 | 56 | )); 57 | CardDescription.displayName = 'CardDescription'; 58 | 59 | const CardContent = React.forwardRef< 60 | HTMLDivElement, 61 | React.HTMLAttributes 62 | >(({ className, ...props }, ref) => ( 63 | 64 | )); 65 | CardContent.displayName = 'CardContent'; 66 | 67 | const CardFooter = React.forwardRef< 68 | HTMLDivElement, 69 | React.HTMLAttributes 70 | >(({ className, ...props }, ref) => ( 71 | 76 | )); 77 | CardFooter.displayName = 'CardFooter'; 78 | 79 | export { 80 | Card, 81 | CardHeader, 82 | CardFooter, 83 | CardTitle, 84 | CardDescription, 85 | CardContent, 86 | }; 87 | -------------------------------------------------------------------------------- /website/sdk/config/marketing.ts: -------------------------------------------------------------------------------- 1 | import { MarketingConfig } from '@/types'; 2 | 3 | export const marketingConfig: MarketingConfig = { 4 | mainNav: [], 5 | }; 6 | -------------------------------------------------------------------------------- /website/sdk/config/site.ts: -------------------------------------------------------------------------------- 1 | import { SiteConfig } from '@/types'; 2 | 3 | export const siteConfig: SiteConfig = { 4 | name: 'OpenAssistantGPT', 5 | description: 6 | "An Open-Source SaaS Platform for Crafting Chatbots with OpenAI's Assistant.", 7 | url: 'https://www.openassistantgpt.io/', 8 | ogImage: 'https://www.openassistantgpt.io/dashboard.png', 9 | links: { 10 | twitter: 'https://twitter.com/oassistantgpt', 11 | github: 'https://github.com/OpenAssistantGPT', 12 | productHunt: 'https://www.producthunt.com/posts/openassistantgpt-sdk', 13 | }, 14 | }; 15 | -------------------------------------------------------------------------------- /website/sdk/hooks/use-lock-body.ts: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | 3 | // @see https://usehooks.com/useLockBodyScroll. 4 | export function useLockBody() { 5 | React.useLayoutEffect((): (() => void) => { 6 | const originalStyle: string = window.getComputedStyle( 7 | document.body, 8 | ).overflow; 9 | document.body.style.overflow = 'hidden'; 10 | return () => (document.body.style.overflow = originalStyle); 11 | }, []); 12 | } 13 | -------------------------------------------------------------------------------- /website/sdk/lib/metadata.ts: -------------------------------------------------------------------------------- 1 | import { Metadata } from 'next'; 2 | 3 | export function constructMetadata({ 4 | title = `OpenAssistantGPT - Best chatbot SDK for the OpenAI Assistant`, 5 | description = `OpenAssistantGPT is the open-source platform for building chatbot using the OpenAI Assistant API. We offer seamless integration for effortlessly incorporating a chatbot into your website.`, 6 | image = 'https://openassistantgpt.io/thumbnail.png', 7 | icons = [ 8 | { 9 | rel: 'apple-touch-icon', 10 | sizes: '32x32', 11 | url: '/logo-32-32.png', 12 | }, 13 | { 14 | rel: 'icon', 15 | type: 'image/png', 16 | sizes: '32x32', 17 | url: '/logo-32-32.png', 18 | }, 19 | { 20 | rel: 'icon', 21 | type: 'image/png', 22 | sizes: '16x16', 23 | url: '/logo-32-32.png', 24 | }, 25 | ], 26 | noIndex = false, 27 | }: { 28 | title?: string; 29 | description?: string; 30 | image?: string | null; 31 | icons?: Metadata['icons']; 32 | noIndex?: boolean; 33 | } = {}): Metadata { 34 | return { 35 | title, 36 | description, 37 | openGraph: { 38 | title, 39 | description, 40 | ...(image && { 41 | images: [ 42 | { 43 | url: image, 44 | }, 45 | ], 46 | }), 47 | }, 48 | twitter: { 49 | title, 50 | description, 51 | ...(image && { 52 | card: 'summary_large_image', 53 | images: [image], 54 | }), 55 | creator: '@oassistantgpt', 56 | }, 57 | icons, 58 | metadataBase: new URL('https://openassistantgpt.io'), 59 | ...(noIndex && { 60 | robots: { 61 | index: false, 62 | follow: false, 63 | }, 64 | }), 65 | }; 66 | } 67 | -------------------------------------------------------------------------------- /website/sdk/lib/utils.ts: -------------------------------------------------------------------------------- 1 | import { siteConfig } from '@/config/site'; 2 | import { type ClassValue, clsx } from 'clsx'; 3 | import { twMerge } from 'tailwind-merge'; 4 | 5 | export function cn(...inputs: ClassValue[]) { 6 | return twMerge(clsx(inputs)); 7 | } 8 | 9 | export function formatDate(input: string | number): string { 10 | const date = new Date(input); 11 | return date.toLocaleDateString('en-US', { 12 | month: 'long', 13 | day: 'numeric', 14 | year: 'numeric', 15 | }); 16 | } 17 | 18 | export function sleep(ms: number) { 19 | return new Promise(resolve => setTimeout(resolve, ms)); 20 | } 21 | 22 | export function absoluteUrl(path: string) { 23 | return `${siteConfig.url}${path}`; 24 | } 25 | -------------------------------------------------------------------------------- /website/sdk/next.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = {}; 3 | 4 | export default nextConfig; 5 | -------------------------------------------------------------------------------- /website/sdk/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sdk-website", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "@radix-ui/react-slot": "^1.1.0", 13 | "@vercel/analytics": "^1.3.1", 14 | "class-variance-authority": "^0.7.0", 15 | "clsx": "^2.1.1", 16 | "embla-carousel-autoplay": "^8.3.0", 17 | "embla-carousel-react": "^8.3.0", 18 | "lucide-react": "^0.408.0", 19 | "next": "14.2.5", 20 | "react": "^18.3.1", 21 | "react-dom": "^18.3.1", 22 | "tailwind-merge": "^2.5.4" 23 | }, 24 | "devDependencies": { 25 | "@types/node": "^20.16.12", 26 | "@types/react": "^18.3.11", 27 | "@types/react-dom": "^18.3.1", 28 | "eslint": "^8.57.1", 29 | "eslint-config-next": "14.2.5", 30 | "postcss": "^8.4.47", 31 | "tailwindcss": "^3.4.14", 32 | "typescript": "^5.6.3" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /website/sdk/postcss.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('postcss-load-config').Config} */ 2 | const config = { 3 | plugins: { 4 | tailwindcss: {}, 5 | }, 6 | }; 7 | 8 | export default config; 9 | -------------------------------------------------------------------------------- /website/sdk/public/hero.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenAssistantGPT/chatbot-sdk/cb08d28e43d2e80d0d4d2e732855de02510da872/website/sdk/public/hero.png -------------------------------------------------------------------------------- /website/sdk/public/logo-32-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenAssistantGPT/chatbot-sdk/cb08d28e43d2e80d0d4d2e732855de02510da872/website/sdk/public/logo-32-32.png -------------------------------------------------------------------------------- /website/sdk/public/next.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /website/sdk/public/shadcn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenAssistantGPT/chatbot-sdk/cb08d28e43d2e80d0d4d2e732855de02510da872/website/sdk/public/shadcn.png -------------------------------------------------------------------------------- /website/sdk/public/tailwindcss.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenAssistantGPT/chatbot-sdk/cb08d28e43d2e80d0d4d2e732855de02510da872/website/sdk/public/tailwindcss.png -------------------------------------------------------------------------------- /website/sdk/public/turbo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenAssistantGPT/chatbot-sdk/cb08d28e43d2e80d0d4d2e732855de02510da872/website/sdk/public/turbo.png -------------------------------------------------------------------------------- /website/sdk/public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /website/sdk/tailwind.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from 'tailwindcss'; 2 | 3 | const config: Config = { 4 | content: [ 5 | './pages/**/*.{js,ts,jsx,tsx,mdx}', 6 | './components/**/*.{js,ts,jsx,tsx,mdx}', 7 | './app/**/*.{js,ts,jsx,tsx,mdx}', 8 | ], 9 | theme: { 10 | extend: { 11 | backgroundImage: { 12 | 'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))', 13 | 'gradient-conic': 14 | 'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))', 15 | }, 16 | keyframes: { 17 | typing: { 18 | '0%': { 19 | width: '0%', 20 | visibility: 'hidden', 21 | }, 22 | '100%': { 23 | width: '100%', 24 | }, 25 | }, 26 | blink: { 27 | '50%': { 28 | borderColor: 'transparent', 29 | }, 30 | '100%': { 31 | borderColor: 'white', 32 | }, 33 | }, 34 | }, 35 | animation: { 36 | typing: 'typing 2s steps(20) alternate, blink .7s infinite', 37 | }, 38 | }, 39 | }, 40 | plugins: [], 41 | }; 42 | export default config; 43 | -------------------------------------------------------------------------------- /website/sdk/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": [ 4 | "dom", 5 | "dom.iterable", 6 | "esnext" 7 | ], 8 | "allowJs": true, 9 | "skipLibCheck": true, 10 | "strict": true, 11 | "noEmit": true, 12 | "esModuleInterop": true, 13 | "module": "esnext", 14 | "moduleResolution": "bundler", 15 | "resolveJsonModule": true, 16 | "isolatedModules": true, 17 | "jsx": "preserve", 18 | "incremental": true, 19 | "plugins": [ 20 | { 21 | "name": "next" 22 | } 23 | ], 24 | "paths": { 25 | "@/*": [ 26 | "./*" 27 | ] 28 | }, 29 | "target": "ES2017" 30 | }, 31 | "include": [ 32 | "next-env.d.ts", 33 | "**/*.ts", 34 | "**/*.tsx", 35 | ".next/types/**/*.ts" 36 | ], 37 | "exclude": [ 38 | "node_modules" 39 | ] 40 | } 41 | -------------------------------------------------------------------------------- /website/sdk/types/index.d.ts: -------------------------------------------------------------------------------- 1 | export type SiteConfig = { 2 | name: string; 3 | description: string; 4 | url: string; 5 | ogImage: string; 6 | links: { 7 | twitter: string; 8 | github: string; 9 | productHunt: string; 10 | }; 11 | }; 12 | 13 | export type NavItem = { 14 | title: string; 15 | href: string; 16 | disabled?: boolean; 17 | }; 18 | 19 | export type MainNavItem = NavItem; 20 | 21 | export type MarketingConfig = { 22 | mainNav: MainNavItem[]; 23 | }; 24 | --------------------------------------------------------------------------------
20 | Powered by {name} 21 |
24 | Fastest and easiest way to build a chatbot using Next.JS for 25 | your website using the OpenAI Assistant API. 26 |