diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index 7bb69f45..00000000 --- a/.eslintrc.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "env": { - "browser": true, - "es6": true, - "node": true - }, - "extends": [ - "eslint:recommended", - "plugin:@typescript-eslint/eslint-recommended", - "plugin:@typescript-eslint/recommended", - "plugin:import/recommended", - "plugin:import/typescript", - "plugin:react/recommended", - "plugin:react-hooks/recommended" - ], - "parser": "@typescript-eslint/parser", - "parserOptions": { - "ecmaVersion": "latest", - "ecmaFeatures": { - "jsx": true - } - }, - "settings": { - "import/resolver": { - "alias": { - "map": [ - [ - "src", - "./src" - ] - ], - "extensions": [ - ".ts", - ".tsx" - ] - } - } - }, - "rules": { - "react/jsx-uses-react": "off", - "react/react-in-jsx-scope": "off" - } -} \ No newline at end of file diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml deleted file mode 100644 index b7c1755e..00000000 --- a/.github/FUNDING.yml +++ /dev/null @@ -1,12 +0,0 @@ -# These are supported funding model platforms - -github: [YanceyOfficial] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] -patreon: # Replace with a single Patreon username -open_collective: # Replace with a single Open Collective username -ko_fi: # Replace with a single Ko-fi username -tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel -community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry -liberapay: # Replace with a single Liberapay username -issuehunt: # Replace with a single IssueHunt username -otechie: # Replace with a single Otechie username -custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100755 index 518aeba7..00000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,32 +0,0 @@ ---- -name: Bug report -about: Create a report to help us improve -title: '' -labels: '' -assignees: '' ---- - -**Describe the bug** -A clear and concise description of what the bug is. - -**To Reproduce** -Steps to reproduce the behavior: - -1. Go to '...' -2. Click on '....' -3. Scroll down to '....' -4. See error - -**Expected behavior** -A clear and concise description of what you expected to happen. - -**Screenshots** -If applicable, add screenshots to help explain your problem. - -**Desktop (please complete the following information):** - -- OS: [e.g. macOS 13.2.1] -- Version [e.g. 1.0.0] - -**Additional context** -Add any other context about the problem here. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md deleted file mode 100755 index ee269da8..00000000 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ /dev/null @@ -1,26 +0,0 @@ - - -### Description - - - -### Additional context - - - ---- - -### What is the purpose of this pull request? - -- [ ] Bug fix -- [ ] New Feature -- [ ] Documentation update -- [ ] Other - -### Before submitting the PR, please make sure you do the following - -- [ ] Read the [Contributing Guidelines](https://github.com/YanceyOfficial/hyperchat/blob/master/CONTRIBUTING.md). -- [ ] Read the [Pull Request Guidelines](https://github.com/YanceyOfficial/hyperchat/blob/master/CONTRIBUTING.md#pull-request-guidelines) and follow the [Angular Team's Commit Message Guidelines](https://github.com/angular/angular/blob/master/CONTRIBUTING.md#commit). -- [ ] Check that there isn't already a PR that solves the problem the same way to avoid creating a duplicate. -- [ ] Provide a description in this PR that addresses **what** the PR is solving, or reference the issue that it solves (e.g. `fixes #123`). -- [ ] Ideally, include relevant tests that fail without this PR but pass with it. diff --git a/.github/dependabot.yml b/.github/dependabot.yml deleted file mode 100644 index 8ec5ac63..00000000 --- a/.github/dependabot.yml +++ /dev/null @@ -1,23 +0,0 @@ -# To get started with Dependabot version updates, you'll need to specify which -# package ecosystems to update and where the package manifests are located. -# Please see the documentation for all configuration options: -# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates - -version: 2 -updates: - - package-ecosystem: 'npm' - directory: '/' - schedule: - interval: 'weekly' - target-branch: 'master' - commit-message: - prefix: 'deps' - open-pull-requests-limit: 20 - - package-ecosystem: 'npm' - directory: '/website' - schedule: - interval: 'weekly' - target-branch: 'develop' - commit-message: - prefix: 'deps' - open-pull-requests-limit: 20 diff --git a/.github/workflows/cross-platform-release.yml b/.github/workflows/cross-platform-release.yml deleted file mode 100644 index db869e4d..00000000 --- a/.github/workflows/cross-platform-release.yml +++ /dev/null @@ -1,70 +0,0 @@ -name: 'cross-platform-release' - -on: - push: - branches: - - release - -# This is the example from the readme. -# On each push to the `release` branch it will create or update a GitHub release, build your app, and upload the artifacts to the release. - -jobs: - publish-tauri: - permissions: - contents: write - strategy: - fail-fast: false - matrix: - include: - - platform: 'macos-latest' # for Arm based macs (M1 and above). - args: '--target aarch64-apple-darwin' - - platform: 'macos-latest' # for Intel based macs. - args: '--target x86_64-apple-darwin' - - platform: 'ubuntu-22.04' # for Tauri v1 you could replace this with ubuntu-20.04. - args: '' - - platform: 'windows-latest' - args: '' - - runs-on: ${{ matrix.platform }} - steps: - - uses: actions/checkout@v4 - - - name: setup node - uses: actions/setup-node@v4 - with: - node-version: lts/* - - - name: setup pnpm - uses: pnpm/action-setup@v4 - with: - version: 9 - - - name: install Rust stable - uses: dtolnay/rust-toolchain@stable - with: - # Those targets are only used on macos runners so it's in an `if` to slightly speed up windows and linux builds. - targets: ${{ matrix.platform == 'macos-latest' && 'aarch64-apple-darwin,x86_64-apple-darwin' || '' }} - - - name: install dependencies (ubuntu only) - if: matrix.platform == 'ubuntu-22.04' # This must match the platform value defined above. - run: | - sudo apt-get update - sudo apt-get install -y libwebkit2gtk-4.0-dev libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf - # webkitgtk 4.0 is for Tauri v1 - webkitgtk 4.1 is for Tauri v2. - # You can remove the one that doesn't apply to your app to speed up the workflow a bit. - - - name: install frontend dependencies - run: pnpm install # change this to npm, pnpm or bun depending on which one you use. - - - uses: tauri-apps/tauri-action@v0 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }} - TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }} - with: - tagName: app-v__VERSION__ # the action automatically replaces \_\_VERSION\_\_ with the app version. - releaseName: 'App v__VERSION__' - releaseBody: 'See the assets to download this version and install.' - releaseDraft: true - prerelease: false - args: ${{ matrix.args }} diff --git a/.github/workflows/cross-platform-test.yml b/.github/workflows/cross-platform-test.yml deleted file mode 100644 index 79cf9e79..00000000 --- a/.github/workflows/cross-platform-test.yml +++ /dev/null @@ -1,60 +0,0 @@ -name: 'cross-platform-test' - -on: [pull_request] - -# This workflow will build your tauri app without uploading it anywhere. - -jobs: - test-tauri: - strategy: - fail-fast: false - matrix: - include: - - platform: 'macos-latest' # for Arm based macs (M1 and above). - args: '--target aarch64-apple-darwin' - - platform: 'macos-latest' # for Intel based macs. - args: '--target x86_64-apple-darwin' - - platform: 'ubuntu-22.04' # for Tauri v1 you could replace this with ubuntu-20.04. - args: '' - - platform: 'windows-latest' - args: '' - - runs-on: ${{ matrix.platform }} - steps: - - uses: actions/checkout@v4 - - - name: setup node - uses: actions/setup-node@v4 - with: - node-version: lts/* - - - name: setup pnpm - uses: pnpm/action-setup@v4 - with: - version: 9 - - - name: install Rust stable - uses: dtolnay/rust-toolchain@stable - with: - # Those targets are only used on macos runners so it's in an `if` to slightly speed up windows and linux builds. - targets: ${{ matrix.platform == 'macos-latest' && 'aarch64-apple-darwin,x86_64-apple-darwin' || '' }} - - - name: install dependencies (ubuntu only) - if: matrix.platform == 'ubuntu-22.04' # This must match the platform value defined above. - run: | - sudo apt-get update - sudo apt-get install -y libwebkit2gtk-4.0-dev libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf - # webkitgtk 4.0 is for Tauri v1 - webkitgtk 4.1 is for Tauri v2. - # You can remove the one that doesn't apply to your app to speed up the workflow a bit. - - - name: install frontend dependencies - run: pnpm install # change this to npm, pnpm or bun depending on which one you use. - - # If tagName and releaseId are omitted tauri-action will only build the app and won't try to upload any assets. - - uses: tauri-apps/tauri-action@v0 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }} - TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }} - with: - args: ${{ matrix.args }} diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml new file mode 100644 index 00000000..f8fb1918 --- /dev/null +++ b/.github/workflows/playwright.yml @@ -0,0 +1,27 @@ +name: Playwright Tests +on: + push: + branches: [main, master] + pull_request: + branches: [main, master] +jobs: + test: + timeout-minutes: 60 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: lts/* + - name: Install dependencies + run: npm install -g pnpm && pnpm install + - name: Install Playwright Browsers + run: pnpm exec playwright install --with-deps + - name: Run Playwright tests + run: pnpm exec playwright test + - uses: actions/upload-artifact@v4 + if: ${{ !cancelled() }} + with: + name: playwright-report + path: playwright-report/ + retention-days: 30 diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml deleted file mode 100644 index fc33996b..00000000 --- a/.github/workflows/release-please.yml +++ /dev/null @@ -1,24 +0,0 @@ -on: - push: - branches: - - master - -permissions: - contents: write - pull-requests: write - -name: release-please - -jobs: - release-please: - runs-on: ubuntu-latest - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - steps: - - uses: googleapis/release-please-action@v4 - with: - release-type: node - package-name: release-please-action - extra-files: | - src-tauri/Cargo.toml - src-tauri/tauri.conf.json diff --git a/.github/workflows/slack-notify.yml b/.github/workflows/slack-notify.yml deleted file mode 100644 index 71fd9497..00000000 --- a/.github/workflows/slack-notify.yml +++ /dev/null @@ -1,17 +0,0 @@ -on: [push, pull_request] -name: slack-notification -jobs: - slackNotification: - name: Slack Notification when Pushing - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: Slack Notification when Pushing - uses: rtCamp/action-slack-notify@v2 - env: - SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} - SLACK_CHANNEL: github-actions - SLACK_TITLE: '${{ github.actor }} is ${{ github.event_name }}ing the ${{ github.ref }} to ${{ github.repository }}.' - SLACK_FOOTER: 'Powered by Yancey Inc. and its affiliates.' - SLACK_COLOR: ${{ job.status }} - SLACK_MESSAGE: 'Commit: ${{ github.event.head_commit.message }}.' diff --git a/.gitignore b/.gitignore index 6c52bd72..7ba605ae 100644 --- a/.gitignore +++ b/.gitignore @@ -1,24 +1,51 @@ -# Logs -logs -*.log +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/versions + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug npm-debug.log* yarn-debug.log* yarn-error.log* -pnpm-debug.log* -lerna-debug.log* +.pnpm-debug.log* -node_modules -dist -dist-ssr -*.local +# env files (can opt-in for committing if needed) +.env* -# Editor directories and files -.idea -.DS_Store -*.suo -*.ntvs* -*.njsproj -*.sln -*.sw? +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts + +# Database data +lib/db/data/* -.env \ No newline at end of file +# Playwright +node_modules/ +/test-results/ +/playwright-report/ +/blob-report/ +/playwright/.cache/ diff --git a/.husky/pre-commit b/.husky/pre-commit deleted file mode 100755 index 2312dc58..00000000 --- a/.husky/pre-commit +++ /dev/null @@ -1 +0,0 @@ -npx lint-staged diff --git a/.lintstagedrc.js b/.lintstagedrc.js deleted file mode 100644 index 43c8ee21..00000000 --- a/.lintstagedrc.js +++ /dev/null @@ -1,3 +0,0 @@ -export default { - 'src/*.{js,jsx,ts,tsx}': ['pnpm run prettier', 'pnpm run lint'] -} diff --git a/.npmrc b/.npmrc index a835b235..bcaafc32 100644 --- a/.npmrc +++ b/.npmrc @@ -1,2 +1,2 @@ -registry=https://registry.npmjs.org/ -auto-install-peers=true \ No newline at end of file + +registry=https://registry.npmjs.org/ \ No newline at end of file diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 00000000..85aee5a5 --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +v20 \ No newline at end of file diff --git a/.vscode/extensions.json b/.vscode/extensions.json deleted file mode 100644 index 24d7cc6d..00000000 --- a/.vscode/extensions.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "recommendations": ["tauri-apps.tauri-vscode", "rust-lang.rust-analyzer"] -} diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index e5352d63..00000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "files.associations": { - "*.css": "tailwindcss" - }, - "editor.quickSuggestions": { - "strings": true - }, - "tailwindCSS.includeLanguages": { - "html": "html", - "javascript": "javascript" - } -} diff --git a/AUTHORS b/AUTHORS deleted file mode 100644 index 8717e939..00000000 --- a/AUTHORS +++ /dev/null @@ -1,6 +0,0 @@ -# Below is a list of people and organizations that have contributed -# to the Lighthouse project. Names should be added to the list like so: -# -# Name/Organization - -Yancey Leo diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index b8d06667..00000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,266 +0,0 @@ -# Changelog - -## [2.0.1](https://github.com/HyperChatBot/hyperchat/compare/v1.0.5...v2.0.1) (2024-10-18) - -### Bug Fixes - -- delete image icon isn't shown in dark mode ([a20c5bb](https://github.com/HyperChatBot/hyperchat/commit/a20c5bb3bc3c1672c55a94f090c8c11564c8521f)) - -## [2.0.0](https://github.com/HyperChatBot/hyperchat/compare/v1.0.5...v2.0.0) (2024-10-18) - -### Features - -- update to tauri v2 - -## [1.0.5](https://github.com/Hyper-Chat-Bot/hyperchat/compare/v1.0.4...v1.0.5) (2023-10-07) - -### Bug Fixes - -- uses DATE_MED instead DATE_FULL for the better visual experience ([686895d](https://github.com/Hyper-Chat-Bot/hyperchat/commit/686895d0a5629d19b5ac66c89d1d42c2fa60d97f)) - -## [1.0.4](https://github.com/HyperChatBot/hyperchat/compare/v1.0.3...v1.0.4) (2023-08-01) - -### Bug Fixes - -- allow local and azure assets in csp ([f7de69c](https://github.com/HyperChatBot/hyperchat/commit/f7de69c4e8e4b79289d540b90e1e90925c2250c9)) -- azure image generation should return 202 status code for continuous request ([fa6ac62](https://github.com/HyperChatBot/hyperchat/commit/fa6ac6271d7e8b6894b98e7fd561a5576e6eb11a)) -- reset the value of input:type=file when the request finished ([6534f98](https://github.com/HyperChatBot/hyperchat/commit/6534f9880cef375a598ebd3bfad6acf884db0115)) - -## [1.0.3](https://github.com/HyperChatBot/hyperchat/compare/v1.0.2...v1.0.3) (2023-07-25) - -### Bug Fixes - -- remake 32x32 icon ([aea7089](https://github.com/HyperChatBot/hyperchat/commit/aea7089c01c5480e1943bfdb7867ee2c0770811e)) - -## [1.0.2](https://github.com/HyperChatBot/hyperchat/compare/v1.0.1...v1.0.2) (2023-07-25) - -### Bug Fixes - -- show common toast if request error ([a6275ba](https://github.com/HyperChatBot/hyperchat/commit/a6275bab837697f44f9ad6743a46d70d1999e256)) - -## [1.0.1](https://github.com/HyperChatBot/hyperchat/compare/v1.0.0...v1.0.1) (2023-07-25) - -### Bug Fixes - -- remove showErrorToast ([0b46792](https://github.com/HyperChatBot/hyperchat/commit/0b4679246ebda726da60095ce0d83af735a66d6b)) - -## 1.0.0 (2023-07-24) - -### Features - -- access husky, commitlint and lintstage ([44ce86b](https://github.com/HyperChatBot/hyperchat/commit/44ce86b64d978c24605e90f8f1c6cf475eee2937)) -- access husky, commitlint and lintstage ([0f06706](https://github.com/HyperChatBot/hyperchat/commit/0f0670604cb794dc2579630964aa4f6a6cff970b)) -- access husky, commitlint and lintstage ([be59fc5](https://github.com/HyperChatBot/hyperchat/commit/be59fc5b6342741ce8063a8e56ebffbe37d66033)) -- access husky, commitlint and lintstage ([737005e](https://github.com/HyperChatBot/hyperchat/commit/737005e307b3619775185cffca96206a5e5f39e2)) -- access wavesurfer ([9ecae98](https://github.com/HyperChatBot/hyperchat/commit/9ecae9811a114a7fc4b5961bac3a1cccbcb5484b)) -- add basic stylesheet for markdown table ([fd66748](https://github.com/HyperChatBot/hyperchat/commit/fd6674835fcd3f9c18534796a7855050a545d6b5)) -- add claude settings ([15bee53](https://github.com/HyperChatBot/hyperchat/commit/15bee53e7faa9e13bfee818fd2d6789e29583257)) -- add edit ([8022823](https://github.com/HyperChatBot/hyperchat/commit/8022823607c8dd68176d8072bd0ed1e73a0e8f24)) -- add Empty ChatItem ([9fe2330](https://github.com/HyperChatBot/hyperchat/commit/9fe2330706c00a2a773d12d7d10209795d03b613)) -- add inputPlaceholders ([b3e3ed2](https://github.com/HyperChatBot/hyperchat/commit/b3e3ed2d1b3e1ed0ebeecbc413961773161a691b)) -- add loading spinner ([2c1c0ec](https://github.com/HyperChatBot/hyperchat/commit/2c1c0ec8302d5ddd40cdc6e20258f3dd0dcbb37a)) -- add loading="lazy" for img ([4a845a1](https://github.com/HyperChatBot/hyperchat/commit/4a845a1ef87b74b0919e6c6cd4d187bbc36a5eed)) -- add more db schema ([489c850](https://github.com/HyperChatBot/hyperchat/commit/489c850639cc7e4259c4624f5e2dfaeac9969861)) -- add no-scrollbar if sidebar too long ([ebcb6ad](https://github.com/HyperChatBot/hyperchat/commit/ebcb6adf421526c891b622995b6c26821740c58e)) -- add openai hooks ([a9c7b85](https://github.com/HyperChatBot/hyperchat/commit/a9c7b85cb1a1ccfc8dcceeb6756bcb04fbdb037d)) -- add project meta files, such as github action ([bc83411](https://github.com/HyperChatBot/hyperchat/commit/bc834114746de606d016da3e86b5e02a35daf100)) -- add question_created_at and answer_created_at ([c06b7c3](https://github.com/HyperChatBot/hyperchat/commit/c06b7c36a5ecc38d047bb3b6b4034ca7f9a107fb)) -- add rollback when error ([e7b5f14](https://github.com/HyperChatBot/hyperchat/commit/e7b5f149ce61333ac65101ec746d0b1fd4608229)) -- add routers ([f021908](https://github.com/HyperChatBot/hyperchat/commit/f021908c5fb34327e2c6aceedcd49a9888f84c44)) -- avoid user activity when loading ([675b3d6](https://github.com/HyperChatBot/hyperchat/commit/675b3d6fb5045ddcf5f270ac38d8e4d4ae043d95)) -- backoff current messsage when fail ([c5029c8](https://github.com/HyperChatBot/hyperchat/commit/c5029c8d2276414370740c44236cc6a2e7bc3ba7)) -- chanage html title ([185e071](https://github.com/HyperChatBot/hyperchat/commit/185e0710614dfbfc374527a1f737c702ed51fd03)) -- change bot logo ([1b0f578](https://github.com/HyperChatBot/hyperchat/commit/1b0f578a256846aeee91b244444b4dad5b4b6166)) -- change productName ([ba96042](https://github.com/HyperChatBot/hyperchat/commit/ba96042766da3df52c1236f658d510ec36d42d67)) -- change svg icon for audio translation ([7023e8f](https://github.com/HyperChatBot/hyperchat/commit/7023e8fc39085a8c8b45bdd7d36c61778bdde972)) -- create embeddings schema ([937c235](https://github.com/HyperChatBot/hyperchat/commit/937c23514d1e6d8e8694789088fd0d548e8cdce3)) -- css optimization ([ba921d4](https://github.com/HyperChatBot/hyperchat/commit/ba921d4383e07a9ff492f2bf0609b698c1a02c44)) -- dark bg ([b7728b3](https://github.com/HyperChatBot/hyperchat/commit/b7728b32f47216525a8554c529017b31a4210bdd)) -- decoupling all db operations to `useDB` ([1f0770d](https://github.com/HyperChatBot/hyperchat/commit/1f0770dfa024cc1bfbfa661b7d025612b2acda67)) -- delete mock image ([c6d8e8f](https://github.com/HyperChatBot/hyperchat/commit/c6d8e8fdfe6382812d147fda93cb0914df2751b7)) -- delete useless files ([35014c2](https://github.com/HyperChatBot/hyperchat/commit/35014c2ccc3b03aacd8ef91c9a66a47415fd9f1b)) -- delete useless files ([c07e322](https://github.com/HyperChatBot/hyperchat/commit/c07e322f5d00690f7d159fa6b76f319dd08d5afc)) -- delete useless icons ([15199d3](https://github.com/HyperChatBot/hyperchat/commit/15199d3f87b85cfcf0310d108886225315738d90)) -- do not refresh conversations when streaming ([44b68b3](https://github.com/HyperChatBot/hyperchat/commit/44b68b31b5adbe5b8ed1fcb4850e355c86830c12)) -- extract common conversation system ([65f2256](https://github.com/HyperChatBot/hyperchat/commit/65f22569dad3eee94cf72965251c27e9eff79a31)) -- extract ConversationBox component ([5c9b3dc](https://github.com/HyperChatBot/hyperchat/commit/5c9b3dc6180916f02a7e78f9b95a6c81e578b669)) -- extract generateEmptyMessage ([014f118](https://github.com/HyperChatBot/hyperchat/commit/014f118d2dae51fe0312d18498735174c2d6fe91)) -- extract InputBox component ([a92119d](https://github.com/HyperChatBot/hyperchat/commit/a92119d24165a538aa579fbbc15f6ba8d8e6f07c)) -- extract only two router items ([aa847ce](https://github.com/HyperChatBot/hyperchat/commit/aa847ce9a9ca1801eaa5daa136bbdca6b65afb25)) -- extract updateMessageState ([3135504](https://github.com/HyperChatBot/hyperchat/commit/31355042221fd7ab6b3da8fe5ddbd45f87dbda1b)) -- extract useChatCompletionStream ([84e7de4](https://github.com/HyperChatBot/hyperchat/commit/84e7de46c3530dc98dbd49e828ae4a4165742bf8)) -- finish all configurations form ([a940892](https://github.com/HyperChatBot/hyperchat/commit/a9408928d5145d0f76786367e9a29dd74e6446b8)) -- finish ChatBubble components ([c895476](https://github.com/HyperChatBot/hyperchat/commit/c895476b9a5c8c0ebe96bd6d1f8aacac08c1469a)) -- finish ContractHeader components ([5223534](https://github.com/HyperChatBot/hyperchat/commit/52235345c0f2dccff5b4dfeed4640ca9e1522823)) -- finish message card's style ([3d30f61](https://github.com/HyperChatBot/hyperchat/commit/3d30f6162b459fb9bebb9da7e53b2f2c025f9a84)) -- finish message list components ([7c6465d](https://github.com/HyperChatBot/hyperchat/commit/7c6465de246afbbd309efb1e3802691a79a58d70)) -- finish theme toggle ([fadd8d6](https://github.com/HyperChatBot/hyperchat/commit/fadd8d69a99fa6b4c5148428f8296df2cb4fe62f)) -- ignore catch error types ([5412306](https://github.com/HyperChatBot/hyperchat/commit/54123066e80d0fbb4a2153f5b830e322b9b1ee91)) -- initial repo ([9ba8b3d](https://github.com/HyperChatBot/hyperchat/commit/9ba8b3d58463093b44f3fe99ef075439531d3b82)) -- initial repo ([6f70f52](https://github.com/HyperChatBot/hyperchat/commit/6f70f5283fdefddf520eda1494b522718e198470)) -- lazy components ([ce78ab1](https://github.com/HyperChatBot/hyperchat/commit/ce78ab1bb5690b8a9a20dd20e531e8dea9edd22b)) -- new type ([c1147ea](https://github.com/HyperChatBot/hyperchat/commit/c1147ea60b935518c46daff5200278842dc99667)) -- performance optimization ([ef9f281](https://github.com/HyperChatBot/hyperchat/commit/ef9f281ab213bf14970780e6152fd8bbd4ade8da)) -- reduce the threshold for new product access. ([d4b59d1](https://github.com/HyperChatBot/hyperchat/commit/d4b59d14bdeba83d56c8fe27b4c3242b96ee1870)) -- reduce the threshold for new product access. ([4864d95](https://github.com/HyperChatBot/hyperchat/commit/4864d952cfb9a9997b7b32d2a71882425f194a3c)) -- reduce the threshold for new product access. ([805e4cb](https://github.com/HyperChatBot/hyperchat/commit/805e4cb44e5e10021dc1daba7e50df6468c33fba)) -- register svg icons ([294b788](https://github.com/HyperChatBot/hyperchat/commit/294b788654156a368f76e5421be0be87ccff169c)) -- register svg icons ([660e12e](https://github.com/HyperChatBot/hyperchat/commit/660e12eeed64da69d32a7aa92ff427db03726e7c)) -- remove srcoll to bottom for the better performance ([b594651](https://github.com/HyperChatBot/hyperchat/commit/b594651634f1619d590acecdf6c371eaa2ed3a7f)) -- rename to ([8a88d96](https://github.com/HyperChatBot/hyperchat/commit/8a88d9640d3281f9a01c0f1784627c2a82615840)) -- rename to ([6536f0f](https://github.com/HyperChatBot/hyperchat/commit/6536f0f3129177715e1eb943fd38cd15aa2d2d3e)) -- rename to ([70ecbb4](https://github.com/HyperChatBot/hyperchat/commit/70ecbb4453f3d125fb03bbe693de1ac1c0a9d85a)) -- rename to ([06b2144](https://github.com/HyperChatBot/hyperchat/commit/06b214411ff914257afe123b721cf44073858c7c)) -- rename recoil's key ([31611f8](https://github.com/HyperChatBot/hyperchat/commit/31611f86913b52c244979996219948badb5d32e2)) -- set update settings ([48476d7](https://github.com/HyperChatBot/hyperchat/commit/48476d7348a6e172328dfdf8b7b798050da62801)) -- settings params for every openai hooks ([44828f6](https://github.com/HyperChatBot/hyperchat/commit/44828f6c6d6d60024d641d32678a8d3368095e1c)) -- show in InputBox if loading ([74fb71d](https://github.com/HyperChatBot/hyperchat/commit/74fb71d93a52a3e8ba5406cd4b7320ee9e45500d)) -- show file tooltips if use audio products ([aecbcc9](https://github.com/HyperChatBot/hyperchat/commit/aecbcc95b23b60d19fe7a8ec9d9c3a83ceb1e7b7)) -- show Loading component if refresh conversation data ([97d7f2f](https://github.com/HyperChatBot/hyperchat/commit/97d7f2ffc7db8f10606de79115930fd2079af8ab)) -- store to indexedDB ([b7799a4](https://github.com/HyperChatBot/hyperchat/commit/b7799a4292e5ad1fbb9155ddf41588dacfde7f5f)) -- support audio translation ([b96c468](https://github.com/HyperChatBot/hyperchat/commit/b96c4689482cfa945934a982a3d48e87a9904805)) -- support dexie import and export ([6a1dbed](https://github.com/HyperChatBot/hyperchat/commit/6a1dbedf5f33325c09fc49ac1d03f4fc9ef571ef)) -- supports [@emoji-mart](https://github.com/emoji-mart) ([ca5e2b3](https://github.com/HyperChatBot/hyperchat/commit/ca5e2b3cafa7b3bf4bf24c95f62e8fa8ef88588a)) -- supports audio translation ([87dccc3](https://github.com/HyperChatBot/hyperchat/commit/87dccc3d90faf8b483f020a90daba31b356c3111)) -- supports basic dark mode ([a3a4bc4](https://github.com/HyperChatBot/hyperchat/commit/a3a4bc4ba8b7971437a8a49fdc7d73d37eb8c04a)) -- supports basic markdown render ([9ebf8c4](https://github.com/HyperChatBot/hyperchat/commit/9ebf8c4b84d1f436d5f4323840f0456b79ffc7c7)) -- supports configuration for very products ([92e086a](https://github.com/HyperChatBot/hyperchat/commit/92e086a966e925761175b2e538f890931a72273a)) -- supports context with a greedy strategy ([18194bc](https://github.com/HyperChatBot/hyperchat/commit/18194bc9ae8dc32c8e4afdb6c395043f56a65ad5)) -- supports custom assistant avatar ([1c9758c](https://github.com/HyperChatBot/hyperchat/commit/1c9758c2c8d4300b3f928254bb4cbfb783ae69c2)) -- supports delete conversation ([a3bbae8](https://github.com/HyperChatBot/hyperchat/commit/a3bbae889e4d04e12297e229d8dbc59c3656e809)) -- supports modify summary ([c6dcc8c](https://github.com/HyperChatBot/hyperchat/commit/c6dcc8c8355f7df978680683b78168c5559c83cf)) -- supports online status ([9d012b3](https://github.com/HyperChatBot/hyperchat/commit/9d012b38e1463ae84b90f9d219e1c8670e2705ff)) -- supports router ([34edd6a](https://github.com/HyperChatBot/hyperchat/commit/34edd6a6832f0e0f1a5866920e2008377e9e020e)) -- supports scroll to bottom ([616e560](https://github.com/HyperChatBot/hyperchat/commit/616e5600e19ae78a928ecdbac8c5c9944095415a)) -- supports to moderation ([b93f98c](https://github.com/HyperChatBot/hyperchat/commit/b93f98c8cb8ecdce64f130f24911a00c5ed7adc5)) -- supports useSettings ([9b12aaf](https://github.com/HyperChatBot/hyperchat/commit/9b12aaf0aeee41671165ce3d5686b2156d6749a5)) -- switch to dexiejs ([7d28106](https://github.com/HyperChatBot/hyperchat/commit/7d281067fe2f57abe5d021969a7c92e38d21270e)) -- The first version ([4e77c27](https://github.com/HyperChatBot/hyperchat/commit/4e77c2770944a1dbb417cacdd12ab8b9aa692c07)) -- The first version ([764e6ef](https://github.com/HyperChatBot/hyperchat/commit/764e6ef05b6a123d057b93d3d9986abba8372067)) -- try basic rxdb ([1b49616](https://github.com/HyperChatBot/hyperchat/commit/1b4961646f15c05f57b077a2641f0dd470743a22)) -- try context ([a5b99ca](https://github.com/HyperChatBot/hyperchat/commit/a5b99cafc85461f86293a121a8b9cff1f8e531dc)) -- try selector setter ([abe869c](https://github.com/HyperChatBot/hyperchat/commit/abe869cab556b8d699356652f65b52fc741d1e3a)) -- try uploader ([9c58594](https://github.com/HyperChatBot/hyperchat/commit/9c58594d628c7c5d3e8e3905fd34bd46556ca865)) -- try wavesurfer ([3dc7c06](https://github.com/HyperChatBot/hyperchat/commit/3dc7c06b8e4154db11d77896cc1945dc20907330)) -- update chats state from updating curr chat selector ([20f3ea8](https://github.com/HyperChatBot/hyperchat/commit/20f3ea81e033535c5469094e563bec3063c17f61)) -- update configuration ([d23f1bd](https://github.com/HyperChatBot/hyperchat/commit/d23f1bdd90a3082cd1c190ff1d62ae2dd6c81f10)) -- update error strategy ([caa3c60](https://github.com/HyperChatBot/hyperchat/commit/caa3c60514c8ff7e7a54ef09c56424bab79f4bb7)) -- update form id ([416605e](https://github.com/HyperChatBot/hyperchat/commit/416605eb1acf7781858211259aeff2249ae9bd62)) -- update formik config ([6f30578](https://github.com/HyperChatBot/hyperchat/commit/6f30578c1215755e1344fe53a91ab408c17582cd)) -- update logo ([e162d18](https://github.com/HyperChatBot/hyperchat/commit/e162d183ccf09f1c8f916c8d0098c9e3a20821f2)) -- update newcomer's guide ([9a6ecb4](https://github.com/HyperChatBot/hyperchat/commit/9a6ecb4299ff910f18da8d511b238554e00bb4b7)) -- update response value name ([c8926ae](https://github.com/HyperChatBot/hyperchat/commit/c8926aedca925c798bf46090fd4d741d150f86f3)) -- update settings form ([91d0592](https://github.com/HyperChatBot/hyperchat/commit/91d05923bc8eedf4339c502cdf04b1538d55bbba)) -- update useChatCompletion error ([4b4fe73](https://github.com/HyperChatBot/hyperchat/commit/4b4fe73ded53c6a1e0a94ed22e27a10b2ceb9b66)) -- update useTheme ([e296046](https://github.com/HyperChatBot/hyperchat/commit/e29604616496027df18c3e26cfec89156564c612)) -- use dexie instead of rxdb ([b06a37e](https://github.com/HyperChatBot/hyperchat/commit/b06a37ec793a2f3e260c5f4c9ffed62014556292)) -- use dynamic updater endpoint ([ccc4722](https://github.com/HyperChatBot/hyperchat/commit/ccc472241137b468d8673d3286e4a3eedc5f1183)) -- use fetch stream ([ca424ae](https://github.com/HyperChatBot/hyperchat/commit/ca424aefc747c000e99020a38ee21c9c7b27762b)) -- use locale time format ([79afe31](https://github.com/HyperChatBot/hyperchat/commit/79afe3112da94280cf1d62c9a82273fc361acee4)) -- use mui instead of flowbite ([5f5a769](https://github.com/HyperChatBot/hyperchat/commit/5f5a7693ef7981bc7a0ef2b80fa0e4be5aa8525d)) -- use snakeCaseToTitleCase instead of conversationTitles ([48cde7e](https://github.com/HyperChatBot/hyperchat/commit/48cde7eaf2efc8a3fc9057bd3f6a1cd9c92ada8f)) -- use textarea instead of input ([7648af4](https://github.com/HyperChatBot/hyperchat/commit/7648af4a8d07c3c0137b425f74e122469ed190ba)) -- uses new state updater ([15601ee](https://github.com/HyperChatBot/hyperchat/commit/15601ee8a9ffbf82410dbb03bcdedb18e3845c7e)) -- wip ([9224852](https://github.com/HyperChatBot/hyperchat/commit/92248526e2d5e124d711ba6e70ebac9114897fa2)) -- **wip:** add landing website ([928d08f](https://github.com/HyperChatBot/hyperchat/commit/928d08f16404965c819be28519b017b246eec9df)) -- **wip:** add landing website ([53adeab](https://github.com/HyperChatBot/hyperchat/commit/53adeabf2773e07942b9ccd754c1436c692de144)) -- **wip:** add network status ([687c882](https://github.com/HyperChatBot/hyperchat/commit/687c882cf371c8e50ba900deb87589acd964072b)) -- **wip:** dark settings ([dc3bb95](https://github.com/HyperChatBot/hyperchat/commit/dc3bb95544846bff00aeed7e92cfa394657e2a56)) -- **wip:** finish basic form elements ([a0f8ede](https://github.com/HyperChatBot/hyperchat/commit/a0f8ede128bd1bc3019d92d8338cdeb0d74fda29)) -- **wip:** supports azure openai api ([516da09](https://github.com/HyperChatBot/hyperchat/commit/516da09ecf1d0ce63ae64d7421ebf9861dba9f7b)) -- **wip:** supports azure openai api for sidebar ([b10d97b](https://github.com/HyperChatBot/hyperchat/commit/b10d97b34cc179eb13e6c3633a3de96e88f6d739)) -- **wip:** supports azure openai api for sidebar ([a6d4133](https://github.com/HyperChatBot/hyperchat/commit/a6d4133937995ef2fd97c683eaf7a14aafbdef2c)) -- **wip:** supports azure settings paramsr ([e8179df](https://github.com/HyperChatBot/hyperchat/commit/e8179dfac7bf0135e38a7f5406a575df6a35977b)) -- **wip:** supports router ([c1f3f03](https://github.com/HyperChatBot/hyperchat/commit/c1f3f03bf6385e84127d9a4efda6f722f439b6a2)) -- **wip:** try split message ([f855a34](https://github.com/HyperChatBot/hyperchat/commit/f855a34ba8fc0975dda9354f46d37b918d415a4b)) -- **wip:** try switch to split mode ([38ff6c6](https://github.com/HyperChatBot/hyperchat/commit/38ff6c641878681206678860616b458e0ddd544b)) -- **wip:** update initial dialog ([2d0b824](https://github.com/HyperChatBot/hyperchat/commit/2d0b8241db0247a2be587a2cfab004cf184234af)) - -### Bug Fixes - -- add when update configuration ([cb54f62](https://github.com/HyperChatBot/hyperchat/commit/cb54f621a7b7221083b26897de9e36b7a7b39ea7)) -- add unsafe-inline to render mui ([b9612b1](https://github.com/HyperChatBot/hyperchat/commit/b9612b1ed84a3455bff0f1a21b7e6b6e9e8a34d5)) -- add updated_at when modify conversation title or avatar ([698cb7b](https://github.com/HyperChatBot/hyperchat/commit/698cb7b9dc8b1b6c91696598b4ab13e15b4817ff)) -- cannot visit a product if the product's company have not register api keys ([e5cb551](https://github.com/HyperChatBot/hyperchat/commit/e5cb551b8733267a11bc490a48e3d7c97cc921c8)) -- currConversation state ([3173002](https://github.com/HyperChatBot/hyperchat/commit/317300209f4b8a60205c822e87885d93bf64a6fb)) -- delete props for react-markdown element ([5eb7afe](https://github.com/HyperChatBot/hyperchat/commit/5eb7afeea424df495f4a59b52088d57e64c96e6d)) -- fix contact header's style ([aaed988](https://github.com/HyperChatBot/hyperchat/commit/aaed9888874e9d89679a846fcecd397907c4b190)) -- fix input box ([e6d8e76](https://github.com/HyperChatBot/hyperchat/commit/e6d8e766d0b8b113be59075bb5627ac130cba666)) -- fix spelling mistake of ([81bef54](https://github.com/HyperChatBot/hyperchat/commit/81bef540fd860d351d11a5df8db2ba6f5ceebdb8)) -- fix textarea line ([51f3b0d](https://github.com/HyperChatBot/hyperchat/commit/51f3b0ddf064b30558b570060bbc9d0f6db7ec1d)) -- if `response_format` is `text`, `vtt` `or `srt`, the result is `translation.data` ([c49d19a](https://github.com/HyperChatBot/hyperchat/commit/c49d19a1fe1724d9141c5109a62216bb3ebb1147)) -- if no `stop` pass null ([cbad896](https://github.com/HyperChatBot/hyperchat/commit/cbad8964cab29afa0ee170f595621eaa05497654)) -- listen prefers-color-scheme:dark) change needs to settings object ready ([b95a87f](https://github.com/HyperChatBot/hyperchat/commit/b95a87f6b5348eefba17a4503ead6312ccf4426b)) -- listen prefers-color-scheme:dark) change needs to settings object ready ([a5fff12](https://github.com/HyperChatBot/hyperchat/commit/a5fff12b7226e245c1fbb1f46a58081235e45664)) -- only submit secret key can close initial dialog ([c361876](https://github.com/HyperChatBot/hyperchat/commit/c361876adace439d2f7eb2c61a60b9f5d79ce1c5)) -- read settings theme when init app ([d7d8534](https://github.com/HyperChatBot/hyperchat/commit/d7d8534cf4e1578096e3f3116692f7d8de4ee7b8)) -- rollback empty messsage into currConversationState when error catched ([c8d68e2](https://github.com/HyperChatBot/hyperchat/commit/c8d68e2c9bbc99e62fccdf44c4a4908c857c6568)) -- set loading to when error catched ([85766bc](https://github.com/HyperChatBot/hyperchat/commit/85766bc007d8f65d441a968ad9b44d44164c753a)) -- show mainPurple color when input in dark mode ([863328d](https://github.com/HyperChatBot/hyperchat/commit/863328d64bceca98715e273d411d7e00d4bb4228)) -- update CSP for fetch api ([70418fe](https://github.com/HyperChatBot/hyperchat/commit/70418fedf37de1eb1cac13dc17a8db28680ad73f)) -- use conversationTitles instead of snakeCaseTotitleCase ([cb098dc](https://github.com/HyperChatBot/hyperchat/commit/cb098dcaf786bafc820ecaa72e43358edd10bf6c)) -- uses onCompositionStart and onCompositionEnd to avoid conflict with ([cf238c7](https://github.com/HyperChatBot/hyperchat/commit/cf238c7c8f71a20df5d81051121763bd3195f5de)) -- uses onCompositionStart and onCompositionEnd to avoid conflict with ([01b49e8](https://github.com/HyperChatBot/hyperchat/commit/01b49e8ab4f8c2f5aea6714fb54c23ab11be1109)) - -## [0.0.0](https://github.com/Hyper-Chat-Bot/hyperchat/compare/v1.0.0...v0.0.0) (2023-07-24) - -### Bug Fixes - -- add when update configuration ([cb54f62](https://github.com/Hyper-Chat-Bot/hyperchat/commit/cb54f621a7b7221083b26897de9e36b7a7b39ea7)) -- add updated_at when modify conversation title or avatar ([698cb7b](https://github.com/Hyper-Chat-Bot/hyperchat/commit/698cb7b9dc8b1b6c91696598b4ab13e15b4817ff)) -- cannot visit a product if the product's company have not register api keys ([e5cb551](https://github.com/Hyper-Chat-Bot/hyperchat/commit/e5cb551b8733267a11bc490a48e3d7c97cc921c8)) -- delete props for react-markdown element ([5eb7afe](https://github.com/Hyper-Chat-Bot/hyperchat/commit/5eb7afeea424df495f4a59b52088d57e64c96e6d)) -- fix spelling mistake of ([81bef54](https://github.com/Hyper-Chat-Bot/hyperchat/commit/81bef540fd860d351d11a5df8db2ba6f5ceebdb8)) -- if `response_format` is `text`, `vtt` `or `srt`, the result is `translation.data` ([c49d19a](https://github.com/Hyper-Chat-Bot/hyperchat/commit/c49d19a1fe1724d9141c5109a62216bb3ebb1147)) -- if no `stop` pass null ([cbad896](https://github.com/Hyper-Chat-Bot/hyperchat/commit/cbad8964cab29afa0ee170f595621eaa05497654)) -- listen prefers-color-scheme:dark) change needs to settings object ready ([b95a87f](https://github.com/Hyper-Chat-Bot/hyperchat/commit/b95a87f6b5348eefba17a4503ead6312ccf4426b)) -- listen prefers-color-scheme:dark) change needs to settings object ready ([a5fff12](https://github.com/Hyper-Chat-Bot/hyperchat/commit/a5fff12b7226e245c1fbb1f46a58081235e45664)) -- update CSP for fetch api ([70418fe](https://github.com/Hyper-Chat-Bot/hyperchat/commit/70418fedf37de1eb1cac13dc17a8db28680ad73f)) -- use conversationTitles instead of snakeCaseTotitleCase ([cb098dc](https://github.com/Hyper-Chat-Bot/hyperchat/commit/cb098dcaf786bafc820ecaa72e43358edd10bf6c)) -- uses onCompositionStart and onCompositionEnd to avoid conflict with ([cf238c7](https://github.com/Hyper-Chat-Bot/hyperchat/commit/cf238c7c8f71a20df5d81051121763bd3195f5de)) -- uses onCompositionStart and onCompositionEnd to avoid conflict with ([01b49e8](https://github.com/Hyper-Chat-Bot/hyperchat/commit/01b49e8ab4f8c2f5aea6714fb54c23ab11be1109)) - -### Features - -- access husky, commitlint and lintstage ([44ce86b](https://github.com/Hyper-Chat-Bot/hyperchat/commit/44ce86b64d978c24605e90f8f1c6cf475eee2937)) -- access husky, commitlint and lintstage ([0f06706](https://github.com/Hyper-Chat-Bot/hyperchat/commit/0f0670604cb794dc2579630964aa4f6a6cff970b)) -- access husky, commitlint and lintstage ([be59fc5](https://github.com/Hyper-Chat-Bot/hyperchat/commit/be59fc5b6342741ce8063a8e56ebffbe37d66033)) -- access husky, commitlint and lintstage ([737005e](https://github.com/Hyper-Chat-Bot/hyperchat/commit/737005e307b3619775185cffca96206a5e5f39e2)) -- add basic stylesheet for markdown table ([fd66748](https://github.com/Hyper-Chat-Bot/hyperchat/commit/fd6674835fcd3f9c18534796a7855050a545d6b5)) -- add claude settings ([15bee53](https://github.com/Hyper-Chat-Bot/hyperchat/commit/15bee53e7faa9e13bfee818fd2d6789e29583257)) -- add loading="lazy" for img ([4a845a1](https://github.com/Hyper-Chat-Bot/hyperchat/commit/4a845a1ef87b74b0919e6c6cd4d187bbc36a5eed)) -- add no-scrollbar if sidebar too long ([ebcb6ad](https://github.com/Hyper-Chat-Bot/hyperchat/commit/ebcb6adf421526c891b622995b6c26821740c58e)) -- add rollback when error ([e7b5f14](https://github.com/Hyper-Chat-Bot/hyperchat/commit/e7b5f149ce61333ac65101ec746d0b1fd4608229)) -- avoid user activity when loading ([675b3d6](https://github.com/Hyper-Chat-Bot/hyperchat/commit/675b3d6fb5045ddcf5f270ac38d8e4d4ae043d95)) -- decoupling all db operations to `useDB` ([1f0770d](https://github.com/Hyper-Chat-Bot/hyperchat/commit/1f0770dfa024cc1bfbfa661b7d025612b2acda67)) -- do not refresh conversations when streaming ([44b68b3](https://github.com/Hyper-Chat-Bot/hyperchat/commit/44b68b31b5adbe5b8ed1fcb4850e355c86830c12)) -- finish all configurations form ([a940892](https://github.com/Hyper-Chat-Bot/hyperchat/commit/a9408928d5145d0f76786367e9a29dd74e6446b8)) -- ignore catch error types ([5412306](https://github.com/Hyper-Chat-Bot/hyperchat/commit/54123066e80d0fbb4a2153f5b830e322b9b1ee91)) -- lazy components ([ce78ab1](https://github.com/Hyper-Chat-Bot/hyperchat/commit/ce78ab1bb5690b8a9a20dd20e531e8dea9edd22b)) -- new type ([c1147ea](https://github.com/Hyper-Chat-Bot/hyperchat/commit/c1147ea60b935518c46daff5200278842dc99667)) -- performance optimization ([ef9f281](https://github.com/Hyper-Chat-Bot/hyperchat/commit/ef9f281ab213bf14970780e6152fd8bbd4ade8da)) -- reduce the threshold for new product access. ([4864d95](https://github.com/Hyper-Chat-Bot/hyperchat/commit/4864d952cfb9a9997b7b32d2a71882425f194a3c)) -- reduce the threshold for new product access. ([805e4cb](https://github.com/Hyper-Chat-Bot/hyperchat/commit/805e4cb44e5e10021dc1daba7e50df6468c33fba)) -- rename to ([8a88d96](https://github.com/Hyper-Chat-Bot/hyperchat/commit/8a88d9640d3281f9a01c0f1784627c2a82615840)) -- rename to ([6536f0f](https://github.com/Hyper-Chat-Bot/hyperchat/commit/6536f0f3129177715e1eb943fd38cd15aa2d2d3e)) -- rename recoil's key ([31611f8](https://github.com/Hyper-Chat-Bot/hyperchat/commit/31611f86913b52c244979996219948badb5d32e2)) -- show in InputBox if loading ([74fb71d](https://github.com/Hyper-Chat-Bot/hyperchat/commit/74fb71d93a52a3e8ba5406cd4b7320ee9e45500d)) -- show file tooltips if use audio products ([aecbcc9](https://github.com/Hyper-Chat-Bot/hyperchat/commit/aecbcc95b23b60d19fe7a8ec9d9c3a83ceb1e7b7)) -- show Loading component if refresh conversation data ([97d7f2f](https://github.com/Hyper-Chat-Bot/hyperchat/commit/97d7f2ffc7db8f10606de79115930fd2079af8ab)) -- support dexie import and export ([6a1dbed](https://github.com/Hyper-Chat-Bot/hyperchat/commit/6a1dbedf5f33325c09fc49ac1d03f4fc9ef571ef)) -- supports configuration for very products ([92e086a](https://github.com/Hyper-Chat-Bot/hyperchat/commit/92e086a966e925761175b2e538f890931a72273a)) -- supports context with a greedy strategy ([18194bc](https://github.com/Hyper-Chat-Bot/hyperchat/commit/18194bc9ae8dc32c8e4afdb6c395043f56a65ad5)) -- try context ([a5b99ca](https://github.com/Hyper-Chat-Bot/hyperchat/commit/a5b99cafc85461f86293a121a8b9cff1f8e531dc)) -- update configuration ([d23f1bd](https://github.com/Hyper-Chat-Bot/hyperchat/commit/d23f1bdd90a3082cd1c190ff1d62ae2dd6c81f10)) -- update newcomer's guide ([9a6ecb4](https://github.com/Hyper-Chat-Bot/hyperchat/commit/9a6ecb4299ff910f18da8d511b238554e00bb4b7)) -- update useChatCompletion error ([4b4fe73](https://github.com/Hyper-Chat-Bot/hyperchat/commit/4b4fe73ded53c6a1e0a94ed22e27a10b2ceb9b66)) -- use dynamic updater endpoint ([ccc4722](https://github.com/Hyper-Chat-Bot/hyperchat/commit/ccc472241137b468d8673d3286e4a3eedc5f1183)) -- use snakeCaseToTitleCase instead of conversationTitles ([48cde7e](https://github.com/Hyper-Chat-Bot/hyperchat/commit/48cde7eaf2efc8a3fc9057bd3f6a1cd9c92ada8f)) -- uses new state updater ([15601ee](https://github.com/Hyper-Chat-Bot/hyperchat/commit/15601ee8a9ffbf82410dbb03bcdedb18e3845c7e)) -- **wip:** supports azure openai api ([516da09](https://github.com/Hyper-Chat-Bot/hyperchat/commit/516da09ecf1d0ce63ae64d7421ebf9861dba9f7b)) -- **wip:** supports azure openai api for sidebar ([b10d97b](https://github.com/Hyper-Chat-Bot/hyperchat/commit/b10d97b34cc179eb13e6c3633a3de96e88f6d739)) -- **wip:** supports azure openai api for sidebar ([a6d4133](https://github.com/Hyper-Chat-Bot/hyperchat/commit/a6d4133937995ef2fd97c683eaf7a14aafbdef2c)) -- **wip:** supports azure settings paramsr ([e8179df](https://github.com/Hyper-Chat-Bot/hyperchat/commit/e8179dfac7bf0135e38a7f5406a575df6a35977b)) -- **wip:** try split message ([f855a34](https://github.com/Hyper-Chat-Bot/hyperchat/commit/f855a34ba8fc0975dda9354f46d37b918d415a4b)) -- **wip:** try switch to split mode ([38ff6c6](https://github.com/Hyper-Chat-Bot/hyperchat/commit/38ff6c641878681206678860616b458e0ddd544b)) -- **wip:** update initial dialog ([2d0b824](https://github.com/Hyper-Chat-Bot/hyperchat/commit/2d0b8241db0247a2be587a2cfab004cf184234af)) diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md deleted file mode 100755 index 5e4ff13e..00000000 --- a/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,45 +0,0 @@ -# Code Of Conduct - -## Our Pledge - -In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, political party, or sexual identity and orientation. Note, however, that religion, political party, or other ideological affiliation provide no exemptions for the behavior we outline as unacceptable in this Code of Conduct. - -## Our Standards - -Examples of behavior that contributes to creating a positive environment include: - -- Using welcoming and inclusive language -- Being respectful of differing viewpoints and experiences -- Gracefully accepting constructive criticism -- Focusing on what is best for the community -- Showing empathy towards other community members - -Examples of unacceptable behavior by participants include: - -- The use of sexualized language or imagery and unwelcome sexual attention or advances -- Trolling, insulting/derogatory comments, and personal or political attacks -- Public or private harassment -- Publishing others' private information, such as a physical or electronic address, without explicit permission -- Other conduct which could reasonably be considered inappropriate in a professional setting - -## Our Responsibilities - -Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. - -Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. - -## Scope - -This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. - -## Enforcement - -Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team by DM at [Hyper Chat](https://discord.gg/tHzYjTqn). All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. - -Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. - -## Attribution - -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html - -[homepage]: https://www.contributor-covenant.org diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100755 index dbe2b211..00000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,29 +0,0 @@ -# Hyper Chat Contributing Guide - -Hi! We are really excited that you are interested in contributing to Hyper Chat. Before submitting your contribution, please make sure to take a moment and read through the following guide: - -## Repo Setup - -To develop and test the core `Hyper Chat` package, please respect the [Tauri Guide](https://tauri.app/v1/guides/). - -## Pull Request Guidelines - -- Checkout a topic branch from a base branch, e.g. `master`, and merge back against that branch. - -- If adding a new feature: - - - Add accompanying test case. - - Provide a convincing reason to add this feature. Ideally, you should open a suggestion issue first and have it approved before working on it. - -- If fixing bug: - - - If you are resolving a special issue, add `(fix #xxxx[,#xxxx])` (#xxxx is the issue id) in your PR title for a better release log, e.g. `fix: update entities encoding/decoding (fix #3899)`. - - Provide a detailed description of the bug in the PR. Live demo preferred. - - Add appropriate test coverage if applicable. - -- It's OK to have multiple small commits as you work on the PR - GitHub can automatically squash them before merging. - -- Make sure tests pass! - -- Commit messages must follow the [Angular Team's Commit Message Guidelines](https://github.com/angular/angular/blob/master/CONTRIBUTING.md#commit) so that changelogs can be automatically generated. Commit messages are automatically validated before commit. -- No need to worry about code style as long as you have installed the dev dependencies - modified files are automatically formatted with Prettier on commit. diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 01b7950e..00000000 --- a/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2023 Yancey Leo - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/README.md b/README.md index 293ab699..e215bc4c 100644 --- a/README.md +++ b/README.md @@ -1,94 +1,36 @@ -# Hyper Chat +This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app). -![Hyper Chat](./screenshots/chat-completion.png) +## Getting Started -[![CodeQL](https://github.com/HyperChatBot/hyperchat/actions/workflows/github-code-scanning/codeql/badge.svg?branch=master)](https://github.com/HyperChatBot/hyperchat/actions/workflows/github-code-scanning/codeql) -[![Release](https://github.com/HyperChatBot/hyperchat/actions/workflows/cross-platform-release.yml/badge.svg)](https://github.com/HyperChatBot/hyperchat/actions/workflows/cross-platform-release.yml) -[![Test](https://github.com/HyperChatBot/hyperchat/actions/workflows/cross-platform-test.yml/badge.svg)](https://github.com/HyperChatBot/hyperchat/actions/workflows/cross-platform-test.yml) -[![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](https://opensource.org/licenses/MIT) -[![Code Style](https://img.shields.io/badge/code%20style-prettier-green)](https://prettier.io/) -[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-green.svg)](https://github.com/HyperChatBot/hyperchat/pulls) -[![Node](https://img.shields.io/badge/Node.js-%3E%3D18.19.0-green.svg)](https://nodejs.org/en/) -[![Rust](https://img.shields.io/badge/Rust-%3E%3D1.81.0-orange.svg)](https://nodejs.org/en/) -[![Version](https://img.shields.io/badge/Version-v2.0.1-blue.svg)](https://nodejs.org/en/) -[![Twitter](https://img.shields.io/badge/Twitter-Connect-brightgreen?logo=twitter)](https://twitter/YanceyOfficial) +First, run the development server: -## Introduction +```bash +npm run dev +# or +yarn dev +# or +pnpm dev +# or +bun dev +``` -Hyper Chat is a high-performance cross-platform AI chat application for desktop that is compatible with both OpenAI and Azure OpenAI services' APIs. In addition, Hyper Chat also provides features such as Text Completion, Image Generation, Audio Transcription, and Audio Translation. +Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. -## To start using Hyper Chat +You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. -You can download Hyper Chat on our [Landing Page](https://hyperchat.yancey.app), or manual download on [GitHub Release](https://github.com/HyperChatBot/hyperchat/releases/). +This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel. -We always keep the dev tools(eg: Command + Option + I) open in the production environment. In Hyper Chat, everything is transparent and controllable. +## Learn More -### macOS +To learn more about Next.js, take a look at the following resources: -As Hyper Chat is not planning to be released on the App Store, you may encounter the following issue when you open it for the first time. Please follow the steps below to resolve it: +- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. +- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. -![can't-be-oepn-in-macos](./screenshots/can't-be-oepn-in-macos.png) +You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome! -1. Move the Hyper Chat.app to the /Applications directory. -2. Open your terminal App, execute the command `chmod +x /Applications/Hyper\ Chat.app/Contents/MacOS/Hyper\ Chat`. +## Deploy on Vercel -## To start developing Hyper Chat +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. -### Prerequisites - -We have chosen [Tauri](https://tauri.app/) as our cross-platform base. Please make sure that [Rust](https://www.rust-lang.org/) is installed on your system. - -Then, to install Tauri CLI globally, please follow the tutorial on [create-tauri-app](https://github.com/tauri-apps/create-tauri-app). We recommend using `cargo install tauri-cli`. - -Additionally, we use [React](https://react.dev/) + [Vite](https://vitejs.dev/) for rendering and packaging pages, so please install [Node.js](https://nodejs.org/en) and [pnpm](https://pnpm.io/) globally in advance. - -### Recommended IDE Setup - -- [VS Code](https://code.visualstudio.com/) -- [Tauri](https://marketplace.visualstudio.com/items?itemName=tauri-apps.tauri-vscode) -- [rust-analyzer](https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer) -- [Prettier](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) -- [Tailwind CSS IntelliSense](https://marketplace.visualstudio.com/items?itemName=bradlc.vscode-tailwindcss) -- [Eslint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) - -### Available Scripts - -- To start tauri development window, you can execute `cargo tauri dev`. -- To build the bundle, you can execute `cargo tauri build`. - -## Contributing - -The main purpose of this repository is to continue to evolve Hyper Chat, making it faster and easier to use. Development of Hyper Chat happens in the open on GitHub, and we are grateful to the community for contributing bugfixes and improvements. Read below to learn how you can take part in improving Hyper Chat. - -### [Code of Conduct](./CODE_OF_CONDUCT.md) - -Hyper Chat has adopted a Code of Conduct that we expect project participants to adhere to. Please read [the full text](./CODE_OF_CONDUCT.md) so that you can understand what actions will and will not be tolerated. - -### [Contributing Guide](./CONTRIBUTING.md) - -Read our [contributing guide](./CONTRIBUTING.md) to learn about our development process, how to propose bugfixes and improvements, and how to build and test your changes to Hyper Chat. - -### Good Issues - -Please make sure to read the [Issue Reporting Checklist](./.github/ISSUE_TEMPLATE/bug_report.md) before opening an issue. Issues not conforming to the guidelines may be closed immediately. - -## Upgrade Plans - -We are continuously working to enhance Hyper Chat's capabilities and performance. Here are some of the features and upgrades that we plan to add in the future releases: - -- Support function call and plugin -- Support audio input -- Support for Claude, Gemini, Llama and so on -- Improve Performance - -## Discussions - -If you have any questions or feedback about Hyper Chat, please visit our [official discussion forum](https://github.com/orgs/HyperChatBot/discussions/71) to start a conversation with our team or other users. We are committed to making Hyper Chat the best possible chat application, and your feedback plays a crucial role in achieving this goal. - -## Thanks - -The UI design is inspired by [Chat-Web-App-UI-Kit](https://www.figma.com/community/file/1167012734150108159/Chat-Web-App-UI-Kit), Thank you [Figma UI Free](https://www.figma.com/@figmauifree)! - -## License - -Hyper Chat is licensed under the terms of the [MIT licensed](https://opensource.org/licenses/MIT). +Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details. diff --git a/SECURITY.md b/SECURITY.md deleted file mode 100644 index c6e25a22..00000000 --- a/SECURITY.md +++ /dev/null @@ -1,7 +0,0 @@ -# Reporting Security Issues - -If you discover a security issue in Hyper Chat, please report it by sending an email to [yanceyofficial@gmail.com](mailto:yanceyofficial@gmail.com). - -This will allow us to assess the risk, and make a fix available before we add a bug report to the GitHub repository. - -Thanks for helping make Hyper Chat safe for everyone! diff --git a/app/(ai-mail)/ai-mail/page.tsx b/app/(ai-mail)/ai-mail/page.tsx new file mode 100644 index 00000000..4fbf3b70 --- /dev/null +++ b/app/(ai-mail)/ai-mail/page.tsx @@ -0,0 +1,35 @@ +'use client' + +import { Card } from '@/components/ui/card' +import { useEffect, useState } from 'react' + +export default function AiMail() { + const [messages, setMessages] = useState([]) + + useEffect(() => { + const eventSource = new EventSource('/api/ai-mail') + + eventSource.onmessage = (event) => { + setMessages((prev) => [...prev, event.data]) + } + + eventSource.onerror = (error) => { + console.error('SSE error:', error) + eventSource.close() + } + + return () => { + eventSource.close() + } + }, []) + + return ( +
+ {messages.map((message, idx) => ( + + {message} + + ))} +
+ ) +} diff --git a/app/(ai-mail)/api/ai-mail/route.ts b/app/(ai-mail)/api/ai-mail/route.ts new file mode 100644 index 00000000..d4f8a6de --- /dev/null +++ b/app/(ai-mail)/api/ai-mail/route.ts @@ -0,0 +1,29 @@ +import AiMail from './sdk' + +export async function GET() { + const { readable, writable } = new TransformStream() + const writer = writable.getWriter() + const encoder = new TextEncoder() + + const sendMessage = async (data: string) => { + await writer.write(encoder.encode(`data: ${data}\n\n`)) + } + + const sse = async () => { + const aiMail = new AiMail() + const info = await aiMail.initialize() + if (info instanceof Error === false && info.usable) { + aiMail.watchNewMail(sendMessage) + } + } + + sse() + + return new Response(readable, { + headers: { + 'Content-Type': 'text/event-stream', + 'Cache-Control': 'no-cache', + Connection: 'keep-open' + } + }) +} diff --git a/app/(ai-mail)/api/ai-mail/sdk.ts b/app/(ai-mail)/api/ai-mail/sdk.ts new file mode 100644 index 00000000..6e9e7bf9 --- /dev/null +++ b/app/(ai-mail)/api/ai-mail/sdk.ts @@ -0,0 +1,104 @@ +import { openai } from '@ai-sdk/openai' +import { generateText } from 'ai' +import { ImapFlow } from 'imapflow' +import { Source, simpleParser } from 'mailparser' + +class AiMail { + private imapFlowClient: ImapFlow + + constructor() { + this.imapFlowClient = new ImapFlow({ + host: 'imap.gmail.com', + port: 993, + secure: true, + auth: { + user: process.env.GMAIL_ADDRESS as string, + pass: process.env.GMAIL_PASSWORD + } + }) + } + + public async initialize() { + try { + await this.imapFlowClient.connect() + await this.imapFlowClient.mailboxOpen('INBOX') + return this.getMailInfo() + } catch { + return new Error('Could not connect Mail service.') + } + } + + public getMailInfo() { + return { + authenticated: this.imapFlowClient.authenticated, + capabilities: this.imapFlowClient.capabilities, + enabled: this.imapFlowClient.enabled, + id: this.imapFlowClient.id, + idling: this.imapFlowClient.idling, + mailbox: this.imapFlowClient.mailbox, + secureConnection: this.imapFlowClient.secureConnection, + serverInfo: this.imapFlowClient.serverInfo, + usable: this.imapFlowClient.usable + } + } + + private async aiAnalyze(html: string) { + try { + const { text } = await generateText({ + model: openai('gpt-4o'), + system: + 'You are a helpful assistant to summarize the given Mail html string. Less than 100 words.', + messages: [{ role: 'user', content: html }] + }) + + return text + } catch (err) { + console.error('AI Analysis failed', err) + } + } + + public watchNewMail(callback: (text: string) => void) { + this.imapFlowClient.on('exists', () => { + this.fetchTheNewestMail() + .then((text) => { + if (typeof text === 'string') { + callback(text) + } + }) + .catch(() => { + // TODO: + }) + }) + } + + private fetchTheNewestMail = async () => { + try { + const message = await this.imapFlowClient.fetchOne('*', { source: true }) + const source = Buffer.from(message.source) + const response = await this.parseMail(source) + + if (typeof response?.html === 'string') { + return this.aiAnalyze(response.html) + } + } catch (err) { + console.error('Failed to fetch Mail', err) + } + } + + private parseMail = async (source: Source) => { + try { + const parsedMail = await simpleParser(source) + + return { + subject: parsedMail.subject, + text: parsedMail.text, + html: parsedMail.html, + attachments: parsedMail.attachments + } + } catch (err) { + console.error('Failed to parse Mail', err) + } + } +} + +export default AiMail diff --git a/app/(ai-mail)/layout.tsx b/app/(ai-mail)/layout.tsx new file mode 100644 index 00000000..f2e0f678 --- /dev/null +++ b/app/(ai-mail)/layout.tsx @@ -0,0 +1,15 @@ +import { SidebarInset, SidebarProvider } from '@/components/ui/sidebar' + +export default function RootLayout({ + children +}: Readonly<{ + children: React.ReactNode +}>) { + return ( + + +
{children}
+
+
+ ) +} diff --git a/app/(chat)/actions.ts b/app/(chat)/actions.ts new file mode 100644 index 00000000..6c830af2 --- /dev/null +++ b/app/(chat)/actions.ts @@ -0,0 +1,36 @@ +'use server' + +import { Setting } from '@/lib/db/schema' +import { createGoogleGenerativeAI } from '@ai-sdk/google' +import { createOpenAI } from '@ai-sdk/openai' +import { generateText, Message } from 'ai' + +export async function generateTitleFromUserMessage({ + message, + setting +}: { + setting: Setting + message: Message +}) { + const openai = createOpenAI({ + apiKey: setting.openaiApiKey, + baseURL: setting.openaiBaseUrl + }) + + const gemini = createGoogleGenerativeAI({ + apiKey: setting.googleApiKey + }) + + const { text: title } = await generateText({ + // model: gemini('gemini-2.0-flash-001'), + model: openai('gpt-4o'), + system: `\n + - you will generate a short title based on the first message a user begins a conversation with + - ensure it is not more than 80 characters long + - the title should be a summary of the user's message + - do not use quotes or colons`, + prompt: JSON.stringify(message) + }) + + return title +} diff --git a/app/(chat)/api/chat/route.ts b/app/(chat)/api/chat/route.ts new file mode 100644 index 00000000..037a8663 --- /dev/null +++ b/app/(chat)/api/chat/route.ts @@ -0,0 +1,128 @@ +import { regularPrompt } from '@/lib/ai/prompts' +import { toolFn as calculator } from '@/lib/ai/tools/calculator' +import { toolFn as getCurrencyRate } from '@/lib/ai/tools/get-currency-rate' +import { toolFn as getDate } from '@/lib/ai/tools/get-date' +import { toolFn as getWeather } from '@/lib/ai/tools/get-weather' +import { + deleteChatById, + getChatById, + saveChat, + saveMessages +} from '@/lib/db/queries' +import { Setting } from '@/lib/db/schema' +import { getMostRecentUserMessage, sanitizeResponseMessages } from '@/lib/utils' +// import { createGoogleGenerativeAI } from '@ai-sdk/google' +import { createOpenAI } from '@ai-sdk/openai' +import { createDataStreamResponse, streamText, type Message } from 'ai' +import { v4 as uuidV4 } from 'uuid' +import { generateTitleFromUserMessage } from '../../actions' + +export const maxDuration = 60 + +export async function POST(request: Request) { + const { + id, + setting, + messages + }: { id: string; messages: Array; setting: Setting } = + await request.json() + + const userMessage = getMostRecentUserMessage(messages) + + if (!userMessage) { + return new Response('No user message found', { status: 400 }) + } + const chat = await getChatById({ id }) + if (!chat) { + const title = await generateTitleFromUserMessage({ + message: userMessage, + setting + }) + await saveChat({ id, title }) + } + + await saveMessages({ + messages: [{ ...userMessage, createdAt: new Date(), chatId: id }] + }) + + const openai = createOpenAI({ + apiKey: setting.openaiApiKey, + baseURL: setting.openaiBaseUrl + }) + + // const gemini = createGoogleGenerativeAI({ + // apiKey: setting.googleApiKey + // }) + + return createDataStreamResponse({ + execute: (dataStream) => { + const result = streamText({ + // model: gemini('gemini-2.0-flash-001'), + model: openai('gpt-4o'), + system: regularPrompt, + messages, + maxSteps: 20, + experimental_generateMessageId: uuidV4, + // providerOptions: { + // openai: { + // reasoningEffort: 'medium' + // } + // }, + tools: { + ...calculator, + ...getWeather, + ...getCurrencyRate, + ...getDate + }, + onFinish: async ({ response, reasoning }) => { + try { + const sanitizedResponseMessages = sanitizeResponseMessages({ + messages: response.messages, + reasoning + }) + + await saveMessages({ + messages: sanitizedResponseMessages.map((message) => { + return { + id: message.id, + chatId: id, + role: message.role, + content: message.content, + createdAt: new Date() + } + }) + }) + } catch { + console.error('Failed to save chat') + } + } + }) + + result.mergeIntoDataStream(dataStream, { + sendReasoning: true + }) + }, + onError: (e) => { + return e instanceof Error ? e.message : 'Oops, an error occured!' + } + }) +} + +export async function DELETE(request: Request) { + const { searchParams } = new URL(request.url) + const id = searchParams.get('id') + + if (!id) { + return new Response('Not Found', { status: 404 }) + } + + try { + await deleteChatById({ id }) + + return new Response('Chat deleted', { status: 200 }) + } catch { + return new Response('An error occurred while processing your request', { + status: 500 + }) + } +} diff --git a/app/(chat)/api/document/route.ts b/app/(chat)/api/document/route.ts new file mode 100644 index 00000000..3571846c --- /dev/null +++ b/app/(chat)/api/document/route.ts @@ -0,0 +1,103 @@ +import { auth } from '@/app/(auth)/auth' +import { ArtifactKind } from '@/components/artifact' +import { + deleteDocumentsByIdAfterTimestamp, + getDocumentsById, + saveDocument +} from '@/lib/db/queries' + +export async function GET(request: Request) { + const { searchParams } = new URL(request.url) + const id = searchParams.get('id') + + if (!id) { + return new Response('Missing id', { status: 400 }) + } + + const session = await auth() + + if (!session || !session.user) { + return new Response('Unauthorized', { status: 401 }) + } + + const documents = await getDocumentsById({ id }) + + const [document] = documents + + if (!document) { + return new Response('Not Found', { status: 404 }) + } + + if (document.userId !== session.user.id) { + return new Response('Unauthorized', { status: 401 }) + } + + return Response.json(documents, { status: 200 }) +} + +export async function POST(request: Request) { + const { searchParams } = new URL(request.url) + const id = searchParams.get('id') + + if (!id) { + return new Response('Missing id', { status: 400 }) + } + + const session = await auth() + + if (!session) { + return new Response('Unauthorized', { status: 401 }) + } + + const { + content, + title, + kind + }: { content: string; title: string; kind: ArtifactKind } = + await request.json() + + if (session.user?.id) { + const document = await saveDocument({ + id, + content, + title, + kind, + userId: session.user.id + }) + + return Response.json(document, { status: 200 }) + } + return new Response('Unauthorized', { status: 401 }) +} + +export async function PATCH(request: Request) { + const { searchParams } = new URL(request.url) + const id = searchParams.get('id') + + const { timestamp }: { timestamp: string } = await request.json() + + if (!id) { + return new Response('Missing id', { status: 400 }) + } + + const session = await auth() + + if (!session || !session.user) { + return new Response('Unauthorized', { status: 401 }) + } + + const documents = await getDocumentsById({ id }) + + const [document] = documents + + if (document.userId !== session.user.id) { + return new Response('Unauthorized', { status: 401 }) + } + + await deleteDocumentsByIdAfterTimestamp({ + id, + timestamp: new Date(timestamp) + }) + + return new Response('Deleted', { status: 200 }) +} diff --git a/app/(chat)/api/files/upload/route.ts b/app/(chat)/api/files/upload/route.ts new file mode 100644 index 00000000..f1818e71 --- /dev/null +++ b/app/(chat)/api/files/upload/route.ts @@ -0,0 +1,91 @@ +import { put } from '@vercel/blob' +import { NextResponse } from 'next/server' +import { z } from 'zod' + +import { auth } from '@/app/(auth)/auth' + +// Use Blob instead of File since File is not available in Node.js environment +const FileSchema = z.object({ + file: z + .instanceof(Blob) + .refine((file) => file.size <= 5 * 1024 * 1024, { + message: 'File size should be less than 5MB' + }) + // Update the file type based on the kind of files you want to accept + .refine((file) => ['image/jpeg', 'image/png'].includes(file.type), { + message: 'File type should be JPEG or PNG' + }) +}) + +export async function POST(request: Request) { + const session = await auth() + + if (!session) { + return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }) + } + + if (request.body === null) { + return new Response('Request body is empty', { status: 400 }) + } + + try { + const formData = await request.formData() + const file = formData.get('file') as Blob + + if (!file) { + return NextResponse.json({ error: 'No file uploaded' }, { status: 400 }) + } + + const validatedFile = FileSchema.safeParse({ file }) + + if (!validatedFile.success) { + const errorMessage = validatedFile.error.errors + .map((error) => error.message) + .join(', ') + + return NextResponse.json({ error: errorMessage }, { status: 400 }) + } + + // Get filename from formData since Blob doesn't have name property + const filename = (formData.get('file') as File).name + const fileBuffer = await file.arrayBuffer() + + try { + const data = await put(`${filename}`, fileBuffer, { + access: 'public' + }) + + return NextResponse.json(data) + } catch (error) { + return NextResponse.json({ error: 'Upload failed' }, { status: 500 }) + } + } catch (error) { + return NextResponse.json( + { error: 'Failed to process request' }, + { status: 500 } + ) + } +} + +// import { +// generateChunksByRecursiveCharacterTextSplitter, +// generateEmbeddings, +// loadPDF, +// } from '@/lib/ai/document-to-embeddings' +// import { storeEmbeddingsToDb } from '@/lib/db/queries' +// import { NextResponse } from 'next/server' + +// export async function POST(req: Request) { +// const formData = await req.formData() +// const pdfFile = formData.get('pdf') as Blob +// const docs = await loadPDF(pdfFile) +// const chunks = await generateChunksByRecursiveCharacterTextSplitter(docs) +// const embeddings = await generateEmbeddings( +// chunks.map((chunk) => chunk.pageContent) +// ) +// await storeEmbeddingsToDb(embeddings) + +// return NextResponse.json({ +// success: true +// }) +// } diff --git a/app/(chat)/api/history/route.ts b/app/(chat)/api/history/route.ts new file mode 100644 index 00000000..82f49c56 --- /dev/null +++ b/app/(chat)/api/history/route.ts @@ -0,0 +1,6 @@ +import { getChats } from '@/lib/db/queries' + +export async function GET() { + const chats = await getChats() + return Response.json(chats) +} diff --git a/app/(chat)/api/setting/route.ts b/app/(chat)/api/setting/route.ts new file mode 100644 index 00000000..6acc0b55 --- /dev/null +++ b/app/(chat)/api/setting/route.ts @@ -0,0 +1,14 @@ +import { getSetting, updateSetting } from '@/lib/db/queries' +import { Setting } from '@/lib/db/schema' + +export async function GET() { + const setting = await getSetting() + return Response.json(setting, { status: 200 }) +} + +export async function POST(request: Request) { + const payload: Setting = await request.json() + const setting = await updateSetting(payload) + + return Response.json(setting, { status: 200 }) +} diff --git a/app/(chat)/api/suggestions/route.ts b/app/(chat)/api/suggestions/route.ts new file mode 100644 index 00000000..404c057c --- /dev/null +++ b/app/(chat)/api/suggestions/route.ts @@ -0,0 +1,33 @@ +import { auth } from '@/app/(auth)/auth' +import { getSuggestionsByDocumentId } from '@/lib/db/queries' + +export async function GET(request: Request) { + const { searchParams } = new URL(request.url) + const documentId = searchParams.get('documentId') + + if (!documentId) { + return new Response('Not Found', { status: 404 }) + } + + const session = await auth() + + if (!session || !session.user) { + return new Response('Unauthorized', { status: 401 }) + } + + const suggestions = await getSuggestionsByDocumentId({ + documentId + }) + + const [suggestion] = suggestions + + if (!suggestion) { + return Response.json([], { status: 200 }) + } + + if (suggestion.userId !== session.user.id) { + return new Response('Unauthorized', { status: 401 }) + } + + return Response.json(suggestions, { status: 200 }) +} diff --git a/app/(chat)/api/upload-pdf/route.ts b/app/(chat)/api/upload-pdf/route.ts new file mode 100644 index 00000000..e69de29b diff --git a/app/(chat)/api/vote/route.ts b/app/(chat)/api/vote/route.ts new file mode 100644 index 00000000..d84a9c7a --- /dev/null +++ b/app/(chat)/api/vote/route.ts @@ -0,0 +1,48 @@ +import { auth } from '@/app/(auth)/auth' +import { getVotesByChatId, voteMessage } from '@/lib/db/queries' + +export async function GET(request: Request) { + const { searchParams } = new URL(request.url) + const chatId = searchParams.get('chatId') + + if (!chatId) { + return new Response('chatId is required', { status: 400 }) + } + + const session = await auth() + + if (!session || !session.user || !session.user.email) { + return new Response('Unauthorized', { status: 401 }) + } + + const votes = await getVotesByChatId({ id: chatId }) + + return Response.json(votes, { status: 200 }) +} + +export async function PATCH(request: Request) { + const { + chatId, + messageId, + type + }: { chatId: string; messageId: string; type: 'up' | 'down' } = + await request.json() + + if (!chatId || !messageId || !type) { + return new Response('messageId and type are required', { status: 400 }) + } + + const session = await auth() + + if (!session || !session.user || !session.user.email) { + return new Response('Unauthorized', { status: 401 }) + } + + await voteMessage({ + chatId, + messageId, + type: type + }) + + return new Response('Message voted', { status: 200 }) +} diff --git a/app/(chat)/chat/[id]/page.tsx b/app/(chat)/chat/[id]/page.tsx new file mode 100644 index 00000000..b9b29179 --- /dev/null +++ b/app/(chat)/chat/[id]/page.tsx @@ -0,0 +1,22 @@ +import { Chat } from '@/components/chatbox/chat' +import { getChatById, getMessagesByChatId } from '@/lib/db/queries' +import { convertToUIMessages } from '@/lib/utils' +import { notFound } from 'next/navigation' + +export default async function Page(props: { params: Promise<{ id: string }> }) { + const params = await props.params + const { id } = params + const chat = await getChatById({ id }) + + if (!chat) { + notFound() + } + + const messagesFromDb = await getMessagesByChatId({ + id + }) + + return ( + + ) +} diff --git a/app/(chat)/layout.tsx b/app/(chat)/layout.tsx new file mode 100644 index 00000000..1e9241f8 --- /dev/null +++ b/app/(chat)/layout.tsx @@ -0,0 +1,44 @@ +import { SidebarRight } from '@/components/chatbox/config' +import { AppSidebar } from '@/components/layout/app-sidebar' +import { NavActions } from '@/components/layout/nav-actions' +import { SettingsDialog } from '@/components/setting/settings-dialog' +import { Separator } from '@/components/ui/separator' +import { + SidebarInset, + SidebarProvider, + SidebarTrigger +} from '@/components/ui/sidebar' +import { Toaster } from '@/components/ui/sonner' + +import { Provider } from 'jotai' + +export default function RootLayout({ + children +}: Readonly<{ + children: React.ReactNode +}>) { + return ( + + + + +
+
+
+ + +
+
+ +
+
+ {children} + + +
+
+ +
+
+ ) +} diff --git a/app/(chat)/page.tsx b/app/(chat)/page.tsx new file mode 100644 index 00000000..1e6588ea --- /dev/null +++ b/app/(chat)/page.tsx @@ -0,0 +1,7 @@ +import { Chat } from '@/components/chatbox/chat' +import { v4 as uuidV4 } from 'uuid' + +export default async function Page() { + const id = uuidV4() + return +} diff --git a/app/(deep-research)/api/deep-research/route.ts b/app/(deep-research)/api/deep-research/route.ts new file mode 100644 index 00000000..20832b3b --- /dev/null +++ b/app/(deep-research)/api/deep-research/route.ts @@ -0,0 +1,70 @@ +import { deepResearch } from '@/lib/ai/deep-research/deep-research' +import { writeFinalReport } from '@/lib/ai/deep-research/final-report' +import { sendSse } from '@/lib/ai/deep-research/sse' +import { NextRequest, NextResponse } from 'next/server' +import { z } from 'zod' + +const querySchema = z.object({ + query: z.string().min(1), + breadth: z.coerce.number().min(2).max(10).default(4), + depth: z.coerce.number().min(1).max(5).default(2) +}) + +export async function GET(request: NextRequest) { + const searchParams = Object.fromEntries(request.nextUrl.searchParams) + const deserializedSearchParams = querySchema.safeParse(searchParams) + + if (!deserializedSearchParams.success) { + return NextResponse.json( + { error: deserializedSearchParams.error.format() }, + { status: 400 } + ) + } + + const headers = { + 'Content-Type': 'text/event-stream', + 'Cache-Control': 'no-cache, no-transform', + Connection: 'keep-alive' + } + + const stream = new ReadableStream({ + async start(controller) { + const startTimestamp = performance.now() + sendSse(controller, 'Starting research...') + const { learnings, visitedUrls } = await deepResearch({ + ...deserializedSearchParams.data, + controller + }) + + sendSse( + controller, + `Learnings:\n${learnings.map((learning) => `- ${learning}`).join('\n')}` + ) + sendSse( + controller, + `Visited URLs (${visitedUrls.size}):\n${[...visitedUrls.keys()].map((url) => `- ${url}`).join('\n')}` + ) + sendSse(controller, 'Writing final report...') + + const report = await writeFinalReport({ + prompt: deserializedSearchParams.data.query, + learnings, + visitedUrls + }) + + sendSse(controller, report) + sendSse( + controller, + `It took a total of ${((performance.now() - startTimestamp) / 1000 / 60).toFixed(2)} minutes.` + ) + + sendSse(controller, '__END__') + + request.signal.onabort = () => { + controller.close() + } + } + }) + + return new Response(stream, { headers }) +} diff --git a/app/(deep-research)/api/feedback/route.ts b/app/(deep-research)/api/feedback/route.ts new file mode 100644 index 00000000..c9163085 --- /dev/null +++ b/app/(deep-research)/api/feedback/route.ts @@ -0,0 +1,9 @@ +import { generateFeedback } from '@/lib/ai/deep-research/feedback' +import { NextResponse } from 'next/server' + +export async function POST(request: Request) { + const { query }: { query: string } = await request.json() + const feedback = await generateFeedback({ query }) + + return NextResponse.json(feedback) +} diff --git a/app/(deep-research)/deep-research/page.tsx b/app/(deep-research)/deep-research/page.tsx new file mode 100644 index 00000000..dcbbb517 --- /dev/null +++ b/app/(deep-research)/deep-research/page.tsx @@ -0,0 +1,267 @@ +'use client' + +import Markdown from '@/components/chatbox/markdown' +import { Button } from '@/components/ui/button' +import { Card } from '@/components/ui/card' +import { + Form, + FormControl, + FormDescription, + FormField, + FormItem, + FormLabel, + FormMessage +} from '@/components/ui/form' +import { Input } from '@/components/ui/input' +import { Separator } from '@/components/ui/separator' +import { Textarea } from '@/components/ui/textarea' +import { zodResolver } from '@hookform/resolvers/zod' +import { Loader2 } from 'lucide-react' +import { useEffect, useRef, useState } from 'react' +import { useFieldArray, useForm } from 'react-hook-form' +import { z } from 'zod' + +const formSchema = z.object({ + query: z.string().min(1), + breadth: z.coerce.number().min(2).max(10).default(4), + depth: z.coerce.number().min(1).max(5).default(2), + feedbacks: z.array( + z.object({ + question: z.string().min(1), + answer: z.string().min(1) + }) + ) +}) + +enum Steps { + AskForFeedback, + FillInFeedback, + RunDeepSearch +} + +export default function DeepResearch() { + const [loading, setLoading] = useState(false) + const [steps, setSteps] = useState(Steps.AskForFeedback) + const [messages, setMessages] = useState([]) + const ref = useRef(null) + + const form = useForm>({ + resolver: zodResolver(formSchema), + defaultValues: { + query: '', + breadth: 4, + depth: 2, + feedbacks: [] + } + }) + + const { fields } = useFieldArray({ + control: form.control, + name: 'feedbacks' + }) + + async function fetchFeedback(values: z.infer) { + setLoading(true) + + try { + const response = await fetch('/api/feedback', { + method: 'POST', + body: JSON.stringify({ query: values.query }) + }) + const questions: string[] = await response.json() + form.setValue( + 'feedbacks', + questions.map((question) => ({ + question, + answer: '' + })) + ) + + setSteps(Steps.FillInFeedback) + } finally { + setLoading(false) + } + } + + function onSubmit(values: z.infer) { + if (steps === Steps.AskForFeedback) { + fetchFeedback(values) + } + + if (steps === Steps.FillInFeedback) { + setSteps(Steps.RunDeepSearch) + } + } + + useEffect(() => { + if (steps !== Steps.RunDeepSearch) return + + const { query, feedbacks, breadth, depth } = form.getValues() + + const combinedQuery = ` + Initial Query: ${query} + Follow-up Questions and Answers: + ${feedbacks.map(({ question, answer }) => `Q: ${question}\nA: ${answer}`).join('\n')} + ` + + const params = new URLSearchParams() + params.append('query', combinedQuery) + params.append('breadth', breadth.toString()) + params.append('depth', depth.toString()) + const encodedQuery = params.toString() + + const source = new EventSource(`/api/deep-research?${encodedQuery}`) + + source.onopen = () => { + setLoading(true) + console.log('SSE connection opened') + } + + source.onmessage = (event) => { + try { + const { data } = JSON.parse(event.data) + if (data === '__END__') { + setLoading(false) + source.close() + } else { + setMessages((prev) => [...prev, data]) + } + } catch (error) { + console.error('Error parsing event data:', error) + source.close() + } + } + + source.onerror = (error) => { + console.error('SSE error:', error) + if (source.readyState === EventSource.CLOSED) { + console.log('SSE connection closed') + } + source.close() + } + + return () => { + if (source) { + console.log('SSE connection closed by component unmount') + source.close() + } + } + }, [form, steps]) + + useEffect(() => { + if (ref.current) { + ref.current.scrollTo(0, ref.current.scrollHeight) + } + }, [messages]) + + return ( +
+ +
+ + ( + + +