diff --git a/.github/scripts/rename-app-beta.sh b/.github/scripts/rename-app-beta.sh new file mode 100644 index 0000000000..a12d1d635a --- /dev/null +++ b/.github/scripts/rename-app-beta.sh @@ -0,0 +1,47 @@ +#!/bin/bash + +# Check if the correct number of arguments is provided +if [ "$#" -ne 1 ]; then + echo "Usage: $0 " + exit 1 +fi + +INPUT_JSON_FILE="$1" + +# Check if the input file exists +if [ ! -f "$INPUT_JSON_FILE" ]; then + echo "Input file not found: $INPUT_JSON_FILE" + exit 1 +fi + +# Use jq to transform the content +jq ' + .name = "jan-beta" | + .productName = "Jan-beta" | + .build.appId = "jan-beta.ai.app" | + .build.productName = "Jan-beta" | + .build.appId = "jan-beta.ai.app" | + .build.protocols[0].name = "Jan-beta" | + .build.protocols[0].schemes = ["jan-beta"] | + .build.artifactName = "jan-beta-${os}-${arch}-${version}.${ext}" | + .build.publish[0].channel = "beta" +' "$INPUT_JSON_FILE" > ./package.json.tmp + +cat ./package.json.tmp + +rm $INPUT_JSON_FILE +mv ./package.json.tmp $INPUT_JSON_FILE + +# Update the layout file +LAYOUT_FILE_PATH="web/app/layout.tsx" + +if [ ! -f "$LAYOUT_FILE_PATH" ]; then + echo "File does not exist: $LAYOUT_FILE_PATH" + exit 1 +fi + +# Perform the replacements +sed -i -e "s#Jan#Jan-beta#g" "$LAYOUT_FILE_PATH" + +# Notify completion +echo "File has been updated: $LAYOUT_FILE_PATH" \ No newline at end of file diff --git a/.github/scripts/rename-uninstaller-beta.sh b/.github/scripts/rename-uninstaller-beta.sh new file mode 100644 index 0000000000..c322825dab --- /dev/null +++ b/.github/scripts/rename-uninstaller-beta.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +# File path to be modified +FILE_PATH="electron/scripts/uninstaller.nsh" + +# Check if the file exists +if [ ! -f "$FILE_PATH" ]; then + echo "File does not exist: $FILE_PATH" + exit 1 +fi + +# Perform the replacements +sed -i -e "s#jan#jan-beta#g" "$FILE_PATH" + +# Notify completion +echo "File has been updated: $FILE_PATH" \ No newline at end of file diff --git a/.github/scripts/rename-workspace-beta.sh b/.github/scripts/rename-workspace-beta.sh new file mode 100644 index 0000000000..6286d18898 --- /dev/null +++ b/.github/scripts/rename-workspace-beta.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +# File path to be modified +FILE_PATH="$1" + +# Check if the file exists +if [ ! -f "$FILE_PATH" ]; then + echo "File does not exist: $FILE_PATH" + exit 1 +fi + +# Perform the replacements +sed -i -e 's/yarn workspace jan/yarn workspace jan-beta/g' "$FILE_PATH" + +# Notify completion +echo "File has been updated: $FILE_PATH" \ No newline at end of file diff --git a/.github/workflows/auto-trigger-jan-docs.yaml b/.github/workflows/auto-trigger-jan-docs.yaml deleted file mode 100644 index a3001a9e0e..0000000000 --- a/.github/workflows/auto-trigger-jan-docs.yaml +++ /dev/null @@ -1,25 +0,0 @@ -name: Trigger Docs Workflow - -on: - release: - types: - - published - workflow_dispatch: - push: - branches: - - ci/auto-trigger-jan-docs-for-new-release - -jobs: - trigger_docs_workflow: - runs-on: ubuntu-latest - - steps: - - name: Trigger external workflow using GitHub API - env: - GITHUB_TOKEN: ${{ secrets.PAT_SERVICE_ACCOUNT }} - run: | - curl -X POST \ - -H "Accept: application/vnd.github.v3+json" \ - -H "Authorization: token $GITHUB_TOKEN" \ - https://api.github.com/repos/janhq/docs/actions/workflows/jan-docs.yml/dispatches \ - -d '{"ref":"main"}' diff --git a/.github/workflows/clean-cloudflare-page-preview-url-and-r2.yml b/.github/workflows/clean-cloudflare-page-preview-url-and-r2.yml new file mode 100644 index 0000000000..2e85f7a6d9 --- /dev/null +++ b/.github/workflows/clean-cloudflare-page-preview-url-and-r2.yml @@ -0,0 +1,52 @@ +name: "Clean old cloudflare pages preview urls and nightly build" +on: + schedule: + - cron: "0 0 * * *" # every day at 00:00 + workflow_dispatch: + +jobs: + clean-cloudflare-pages-preview-urls: + strategy: + matrix: + project: ["nitro", "docs"] + runs-on: ubuntu-latest + steps: + - uses: actions/setup-python@v4 + with: + python-version: '3.x' + - name: install requests + run: | + python3 -m pip install requests pytz tqdm + - name: Python Inline script + uses: jannekem/run-python-script-action@v1 + with: + script: | + import requests + from datetime import datetime, UTC + from pytz import timezone + from tqdm import tqdm + + # Configuration + endpoint = "https://api.cloudflare.com/client/v4/accounts/${{ secrets.CLOUDFLARE_ACCOUNT_ID }}/pages/projects/${{ matrix.project }}/deployments" + expiration_days = 3 + headers = { + "Content-Type": "application/json;charset=UTF-8", + "Authorization": "Bearer ${{ secrets.CLOUDFLARE_API_TOKEN }}" + } + utc_tz = timezone('UTC') + + # Fetch the list of deployments + response = requests.get(endpoint, headers=headers) + deployments = response.json() + + for deployment in tqdm(deployments['result']): + # Calculate the age of the deployment + created_on = datetime.strptime(deployment['created_on'], "%Y-%m-%dT%H:%M:%S.%fZ").replace(tzinfo=utc_tz) + if (datetime.now(UTC) - created_on).days > expiration_days: + # Delete the deployment + delete_response = requests.delete(f"{endpoint}/{deployment['id']}", headers=headers) + if delete_response.status_code == 200: + print(f"Deleted deployment: {deployment['id']}") + else: + print(f"Failed to delete deployment: {deployment['id']}") + diff --git a/.github/workflows/jan-docs-new-release.yaml b/.github/workflows/jan-docs-new-release.yaml new file mode 100644 index 0000000000..2acca92de3 --- /dev/null +++ b/.github/workflows/jan-docs-new-release.yaml @@ -0,0 +1,63 @@ +name: Deploy Docs on new release + +on: + release: + types: + - published + - edited + - released + +jobs: + deploy: + name: Deploy to CloudFlare Pages + env: + CLOUDFLARE_PROJECT_NAME: docs + runs-on: ubuntu-latest + permissions: + contents: write + deployments: write + pull-requests: write + steps: + - uses: actions/checkout@v4 + with: + ref: dev + - uses: actions/setup-node@v3 + with: + node-version: 18 + + - name: Install jq + uses: dcarbone/install-jq-action@v2.0.1 + + - name: Fill env vars + working-directory: docs + run: | + env_example_file=".env.example" + touch .env + while IFS= read -r line || [[ -n "$line" ]]; do + if [[ "$line" == *"="* ]]; then + var_name=$(echo $line | cut -d '=' -f 1) + echo $var_name + var_value="$(jq -r --arg key "$var_name" '.[$key]' <<< "$SECRETS")" + echo "$var_name=$var_value" >> .env + fi + done < "$env_example_file" + env: + SECRETS: '${{ toJson(secrets) }}' + + - name: Install dependencies + working-directory: docs + run: yarn install + - name: Build website + working-directory: docs + run: export NODE_ENV=production && yarn build && cp _redirects out/_redirects + + - name: Publish to Cloudflare Pages Production + uses: cloudflare/pages-action@v1 + with: + apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} + accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} + projectName: ${{ env.CLOUDFLARE_PROJECT_NAME }} + directory: ./docs/out + branch: dev + # Optional: Enable this if you want to have GitHub Deployments triggered + gitHubToken: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/jan-docs.yml b/.github/workflows/jan-docs.yml new file mode 100644 index 0000000000..ada038e83f --- /dev/null +++ b/.github/workflows/jan-docs.yml @@ -0,0 +1,88 @@ +name: Jan Docs + +on: + push: + branches: + - dev + paths: + - 'docs/**' + - '.github/workflows/jan-docs.yml' + pull_request: + paths: + - 'docs/**' + - '.github/workflows/jan-docs.yml' + # Review gh actions docs if you want to further define triggers, paths, etc + # https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#on + workflow_dispatch: + +jobs: + deploy: + name: Deploy to CloudFlare Pages + env: + CLOUDFLARE_PROJECT_NAME: docs + runs-on: ubuntu-latest + permissions: + contents: write + deployments: write + pull-requests: write + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: 18 + + - name: Install jq + uses: dcarbone/install-jq-action@v2.0.1 + + - name: Fill env vars + working-directory: docs + run: | + env_example_file=".env.example" + touch .env + while IFS= read -r line || [[ -n "$line" ]]; do + if [[ "$line" == *"="* ]]; then + var_name=$(echo $line | cut -d '=' -f 1) + echo $var_name + var_value="$(jq -r --arg key "$var_name" '.[$key]' <<< "$SECRETS")" + echo "$var_name=$var_value" >> .env + fi + done < "$env_example_file" + env: + SECRETS: '${{ toJson(secrets) }}' + + - name: Install dependencies + working-directory: docs + run: yarn install + - name: Build website + working-directory: docs + run: export NODE_ENV=production && yarn build && cp _redirects out/_redirects + + - name: Publish to Cloudflare Pages PR Preview and Staging + if: github.event_name == 'pull_request' + uses: cloudflare/pages-action@v1 + with: + apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} + accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} + projectName: ${{ env.CLOUDFLARE_PROJECT_NAME }} + directory: ./docs/out + # Optional: Enable this if you want to have GitHub Deployments triggered + gitHubToken: ${{ secrets.GITHUB_TOKEN }} + id: deployCloudflarePages + + - uses: mshick/add-pr-comment@v2 + if: github.event_name == 'pull_request' + with: + message: | + Preview URL: ${{ steps.deployCloudflarePages.outputs.url }} + + - name: Publish to Cloudflare Pages Production + if: (github.event_name == 'push' && github.ref == 'refs/heads/dev') || (github.event_name == 'workflow_dispatch' && github.ref == 'refs/heads/dev') + uses: cloudflare/pages-action@v1 + with: + apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} + accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} + projectName: ${{ env.CLOUDFLARE_PROJECT_NAME }} + directory: ./docs/out + branch: dev + # Optional: Enable this if you want to have GitHub Deployments triggered + gitHubToken: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/jan-electron-build-beta.yml b/.github/workflows/jan-electron-build-beta.yml new file mode 100644 index 0000000000..4f26252668 --- /dev/null +++ b/.github/workflows/jan-electron-build-beta.yml @@ -0,0 +1,136 @@ +name: Electron Builder - Beta Build + +on: + push: + tags: ["v[0-9]+.[0-9]+.[0-9]+-rc[0-9]+-beta"] + +jobs: + # Job create Update app version based on latest release tag with build number and save to output + get-update-version: + uses: ./.github/workflows/template-get-update-version.yml + + create-draft-release: + runs-on: ubuntu-latest + if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') + outputs: + upload_url: ${{ steps.create_release.outputs.upload_url }} + version: ${{ steps.get_version.outputs.version }} + permissions: + contents: write + steps: + - name: Extract tag name without v prefix + id: get_version + run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_ENV && echo "::set-output name=version::${GITHUB_REF#refs/tags/v}" + env: + GITHUB_REF: ${{ github.ref }} + - name: Create Draft Release + id: create_release + uses: softprops/action-gh-release@v2 + with: + tag_name: ${{ github.ref_name }} + token: ${{ secrets.GITHUB_TOKEN }} + name: "${{ env.VERSION }}" + draft: true + prerelease: false + generate_release_notes: true + + build-macos-x64: + uses: ./.github/workflows/template-build-macos-x64.yml + secrets: inherit + needs: [get-update-version] + with: + ref: ${{ github.ref }} + public_provider: github + new_version: ${{ needs.get-update-version.outputs.new_version }} + beta: true + + build-macos-arm64: + uses: ./.github/workflows/template-build-macos-arm64.yml + secrets: inherit + needs: [get-update-version] + with: + ref: ${{ github.ref }} + public_provider: github + new_version: ${{ needs.get-update-version.outputs.new_version }} + beta: true + + build-windows-x64: + uses: ./.github/workflows/template-build-windows-x64.yml + secrets: inherit + needs: [get-update-version] + with: + ref: ${{ github.ref }} + public_provider: github + new_version: ${{ needs.get-update-version.outputs.new_version }} + beta: true + + build-linux-x64: + uses: ./.github/workflows/template-build-linux-x64.yml + secrets: inherit + needs: [get-update-version] + with: + ref: ${{ github.ref }} + public_provider: github + new_version: ${{ needs.get-update-version.outputs.new_version }} + beta: true + + combine-beta-mac-yml: + needs: [build-macos-x64, build-macos-arm64, create-draft-release, build-windows-x64, build-linux-x64] + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - name: Getting the repo + uses: actions/checkout@v3 + + - name: Download mac-x64 artifacts + uses: actions/download-artifact@v4 + with: + name: beta-mac-x64 + path: ./beta-mac-x64 + - name: Download mac-arm artifacts + uses: actions/download-artifact@v4 + with: + name: beta-mac-arm64 + path: ./beta-mac-arm64 + + - name: 'Merge beta-mac.yml' + # unfortunately electron-builder doesn't understand that we have two different releases for mac-x64 and mac-arm, so we need to manually merge the latest files + # see https://github.com/electron-userland/electron-builder/issues/5592 + run: | + ls -la . + ls -la ./beta-mac-x64 + ls -la ./beta-mac-arm64 + ls -la ./electron + cp ./electron/merge-latest-ymls.js /tmp/merge-beta-ymls.js + npm install js-yaml --prefix /tmp + node /tmp/merge-beta-ymls.js ./beta-mac-x64/beta-mac.yml ./beta-mac-arm64/beta-mac.yml ./beta-mac.yml + cat ./beta-mac.yml + + - name: Yet Another Upload Release Asset Action + uses: shogo82148/actions-upload-release-asset@v1.7.2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ needs.create-draft-release.outputs.upload_url }} + asset_path: ./beta-mac.yml + asset_name: beta-mac.yml + asset_content_type: text/yaml + overwrite: true + + - name: Upload beta-mac.yml + run: | + aws s3 cp ./beta-mac.yml "s3://${{ secrets.DELTA_AWS_S3_BUCKET_NAME }}/temp-beta/beta-mac.yml" + # sync temp-beta to beta by copy files that are different or new + aws s3 sync "s3://${{ secrets.DELTA_AWS_S3_BUCKET_NAME }}/temp-beta/" "s3://${{ secrets.DELTA_AWS_S3_BUCKET_NAME }}/beta/" + env: + AWS_ACCESS_KEY_ID: ${{ secrets.DELTA_AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.DELTA_AWS_SECRET_ACCESS_KEY }} + AWS_DEFAULT_REGION: ${{ secrets.DELTA_AWS_REGION }} + AWS_EC2_METADATA_DISABLED: "true" + + - name: set release to prerelease + run: | + gh release edit v${{ needs.create-draft-release.outputs.version }} --draft=false --prerelease + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/jan-electron-build-nightly.yml b/.github/workflows/jan-electron-build-nightly.yml index af1a2baa95..d790809904 100644 --- a/.github/workflows/jan-electron-build-nightly.yml +++ b/.github/workflows/jan-electron-build-nightly.yml @@ -80,7 +80,7 @@ jobs: new_version: ${{ needs.get-update-version.outputs.new_version }} combine-latest-mac-yml: - needs: [set-public-provider, build-macos-x64, build-macos-arm64] + needs: [set-public-provider, build-macos-x64, build-macos-arm64, build-windows-x64, build-linux-x64] runs-on: ubuntu-latest steps: - name: Getting the repo @@ -114,7 +114,8 @@ jobs: - name: Upload latest-mac.yml if: ${{ needs.set-public-provider.outputs.public_provider == 'aws-s3' }} run: | - aws s3 cp ./latest-mac.yml "s3://${{ secrets.DELTA_AWS_S3_BUCKET_NAME }}/latest/latest-mac.yml" + aws s3 cp ./latest-mac.yml "s3://${{ secrets.DELTA_AWS_S3_BUCKET_NAME }}/temp-latest/latest-mac.yml" + aws s3 sync s3://${{ secrets.DELTA_AWS_S3_BUCKET_NAME }}/temp-latest/ s3://${{ secrets.DELTA_AWS_S3_BUCKET_NAME }}/latest/ env: AWS_ACCESS_KEY_ID: ${{ secrets.DELTA_AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.DELTA_AWS_SECRET_ACCESS_KEY }} diff --git a/.github/workflows/jan-electron-linter-and-test.yml b/.github/workflows/jan-electron-linter-and-test.yml index f441f4cdaa..4e20d6c5f8 100644 --- a/.github/workflows/jan-electron-linter-and-test.yml +++ b/.github/workflows/jan-electron-linter-and-test.yml @@ -105,9 +105,9 @@ jobs: make test env: CSC_IDENTITY_AUTO_DISCOVERY: 'false' - TURBO_API: '${{ secrets.TURBO_API }}' - TURBO_TEAM: 'macos' - TURBO_TOKEN: '${{ secrets.TURBO_TOKEN }}' + # TURBO_API: '${{ secrets.TURBO_API }}' + # TURBO_TEAM: 'macos' + # TURBO_TOKEN: '${{ secrets.TURBO_TOKEN }}' test-on-macos-pr-target: if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository @@ -185,10 +185,10 @@ jobs: npm config set registry ${{ secrets.NPM_PROXY }} --global yarn config set registry ${{ secrets.NPM_PROXY }} --global make test - env: - TURBO_API: '${{ secrets.TURBO_API }}' - TURBO_TEAM: 'windows' - TURBO_TOKEN: '${{ secrets.TURBO_TOKEN }}' + # env: + # TURBO_API: '${{ secrets.TURBO_API }}' + # TURBO_TEAM: 'windows' + # TURBO_TOKEN: '${{ secrets.TURBO_TOKEN }}' test-on-windows-pr: if: (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository) runs-on: windows-desktop-default-windows-security @@ -233,10 +233,10 @@ jobs: npm config set registry ${{ secrets.NPM_PROXY }} --global yarn config set registry ${{ secrets.NPM_PROXY }} --global make test - env: - TURBO_API: '${{ secrets.TURBO_API }}' - TURBO_TEAM: 'windows' - TURBO_TOKEN: '${{ secrets.TURBO_TOKEN }}' + # env: + # TURBO_API: '${{ secrets.TURBO_API }}' + # TURBO_TEAM: 'windows' + # TURBO_TOKEN: '${{ secrets.TURBO_TOKEN }}' test-on-windows-pr-target: if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository @@ -314,10 +314,10 @@ jobs: npm config set registry ${{ secrets.NPM_PROXY }} --global yarn config set registry ${{ secrets.NPM_PROXY }} --global make test - env: - TURBO_API: '${{ secrets.TURBO_API }}' - TURBO_TEAM: 'linux' - TURBO_TOKEN: '${{ secrets.TURBO_TOKEN }}' + # env: + # TURBO_API: '${{ secrets.TURBO_API }}' + # TURBO_TEAM: 'linux' + # TURBO_TOKEN: '${{ secrets.TURBO_TOKEN }}' coverage-check: runs-on: [self-hosted, Linux, ubuntu-desktop] @@ -354,10 +354,10 @@ jobs: make lint yarn build:test yarn test:coverage - env: - TURBO_API: '${{ secrets.TURBO_API }}' - TURBO_TEAM: 'linux' - TURBO_TOKEN: '${{ secrets.TURBO_TOKEN }}' + # env: + # TURBO_API: '${{ secrets.TURBO_API }}' + # TURBO_TEAM: 'linux' + # TURBO_TOKEN: '${{ secrets.TURBO_TOKEN }}' - name: Generate Code Coverage report id: code-coverage diff --git a/.github/workflows/template-build-linux-x64.yml b/.github/workflows/template-build-linux-x64.yml index 386a0ee4f6..496d153aee 100644 --- a/.github/workflows/template-build-linux-x64.yml +++ b/.github/workflows/template-build-linux-x64.yml @@ -19,6 +19,10 @@ on: required: false type: string default: '/latest/' + beta: + required: false + type: boolean + default: false secrets: DELTA_AWS_S3_BUCKET_NAME: required: false @@ -56,17 +60,29 @@ jobs: mv /tmp/package.json electron/package.json jq --arg version "${{ inputs.new_version }}" '.version = $version' web/package.json > /tmp/package.json mv /tmp/package.json web/package.json - jq '.build.publish = [{"provider": "generic", "url": "${{ secrets.CLOUDFLARE_R2_PUBLIC_URL }}", "channel": "latest"}, {"provider": "s3", "acl": null, "bucket": "${{ secrets.DELTA_AWS_S3_BUCKET_NAME }}", "region": "${{ secrets.DELTA_AWS_REGION}}", "path": "${{ inputs.aws_s3_prefix }}", "channel": "latest"}]' electron/package.json > /tmp/package.json + jq '.build.publish = [{"provider": "generic", "url": "${{ secrets.CLOUDFLARE_R2_PUBLIC_URL }}", "channel": "latest"}, {"provider": "s3", "acl": null, "bucket": "${{ secrets.DELTA_AWS_S3_BUCKET_NAME }}", "region": "${{ secrets.DELTA_AWS_REGION}}", "path": "temp-latest", "channel": "latest"}]' electron/package.json > /tmp/package.json + mv /tmp/package.json electron/package.json + cat electron/package.json + + - name: Change App Name for beta version + if: inputs.beta == true + shell: bash + run: | + chmod +x .github/scripts/rename-app-beta.sh + .github/scripts/rename-app-beta.sh ./electron/package.json + chmod +x .github/scripts/rename-workspace-beta.sh + .github/scripts/rename-workspace-beta.sh ./package.json + echo "------------------------" + cat ./electron/package.json + echo "------------------------" + cat ./package.json + jq '.build.publish = [{"provider": "generic", "url": "https://delta.jan.ai/beta", "channel": "beta"}, {"provider": "github", "owner": "janhq", "repo": "jan", "channel": "beta"}, {"provider": "s3", "acl": null, "bucket": "${{ secrets.DELTA_AWS_S3_BUCKET_NAME }}", "region": "${{ secrets.DELTA_AWS_REGION}}", "path": "temp-beta", "channel": "beta"}]' electron/package.json > /tmp/package.json mv /tmp/package.json electron/package.json cat electron/package.json - name: Update app version base on tag if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') && inputs.public_provider == 'github' run: | - if [[ ! "${VERSION_TAG}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then - echo "Error: Tag is not valid!" - exit 1 - fi jq --arg version "${VERSION_TAG#v}" '.version = $version' electron/package.json > /tmp/package.json mv /tmp/package.json electron/package.json jq --arg version "${VERSION_TAG#v}" '.version = $version' web/package.json > /tmp/package.json @@ -92,7 +108,7 @@ jobs: AWS_MAX_ATTEMPTS: "5" - name: Build and publish app to github - if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') && inputs.public_provider == 'github' + if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') && inputs.public_provider == 'github' && inputs.beta == false run: | make build-and-publish env: @@ -100,6 +116,17 @@ jobs: ANALYTICS_ID: ${{ secrets.JAN_APP_UMAMI_PROJECT_API_KEY }} ANALYTICS_HOST: ${{ secrets.JAN_APP_UMAMI_URL }} + - name: Build and publish app to github + if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') && inputs.public_provider == 'github' && inputs.beta == true + run: | + make build-and-publish + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + AWS_ACCESS_KEY_ID: ${{ secrets.DELTA_AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.DELTA_AWS_SECRET_ACCESS_KEY }} + AWS_EC2_METADATA_DISABLED: "true" + AWS_MAX_ATTEMPTS: "5" + - name: Upload Artifact .deb file if: inputs.public_provider != 'github' uses: actions/upload-artifact@v4 diff --git a/.github/workflows/template-build-macos-arm64.yml b/.github/workflows/template-build-macos-arm64.yml index 40d40164f2..40cdda627d 100644 --- a/.github/workflows/template-build-macos-arm64.yml +++ b/.github/workflows/template-build-macos-arm64.yml @@ -19,6 +19,10 @@ on: required: false type: string default: '/latest/' + beta: + required: false + type: boolean + default: false secrets: DELTA_AWS_S3_BUCKET_NAME: required: false @@ -68,7 +72,7 @@ jobs: jq --arg version "${{ inputs.new_version }}" '.version = $version' web/package.json > /tmp/package.json mv /tmp/package.json web/package.json - jq '.build.publish = [{"provider": "generic", "url": "${{ secrets.CLOUDFLARE_R2_PUBLIC_URL }}", "channel": "latest"}, {"provider": "s3", "acl": null, "bucket": "${{ secrets.DELTA_AWS_S3_BUCKET_NAME }}", "region": "${{ secrets.DELTA_AWS_REGION}}", "path": "${{ inputs.aws_s3_prefix }}", "channel": "latest"}]' electron/package.json > /tmp/package.json + jq '.build.publish = [{"provider": "generic", "url": "${{ secrets.CLOUDFLARE_R2_PUBLIC_URL }}", "channel": "latest"}, {"provider": "s3", "acl": null, "bucket": "${{ secrets.DELTA_AWS_S3_BUCKET_NAME }}", "region": "${{ secrets.DELTA_AWS_REGION}}", "path": "temp-latest", "channel": "latest"}]' electron/package.json > /tmp/package.json mv /tmp/package.json electron/package.json jq --arg teamid "${{ secrets.APPLE_TEAM_ID }}" '.build.mac.notarize.teamId = $teamid' electron/package.json > /tmp/package.json @@ -76,13 +80,25 @@ jobs: cat electron/package.json + - name: Change App Name for beta version + if: inputs.beta == true + shell: bash + run: | + chmod +x .github/scripts/rename-app-beta.sh + .github/scripts/rename-app-beta.sh ./electron/package.json + chmod +x .github/scripts/rename-workspace-beta.sh + .github/scripts/rename-workspace-beta.sh ./package.json + echo "------------------------" + cat ./electron/package.json + echo "------------------------" + cat ./package.json + jq '.build.publish = [{"provider": "generic", "url": "https://delta.jan.ai/beta", "channel": "beta"}, {"provider": "github", "owner": "janhq", "repo": "jan", "channel": "beta"}, {"provider": "s3", "acl": null, "bucket": "${{ secrets.DELTA_AWS_S3_BUCKET_NAME }}", "region": "${{ secrets.DELTA_AWS_REGION}}", "path": "temp-beta", "channel": "beta"}]' electron/package.json > /tmp/package.json + mv /tmp/package.json electron/package.json + cat electron/package.json + - name: Update app version base on tag if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') && inputs.public_provider == 'github' run: | - if [[ ! "${VERSION_TAG}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then - echo "Error: Tag is not valid!" - exit 1 - fi jq --arg version "${VERSION_TAG#v}" '.version = $version' electron/package.json > /tmp/package.json mv /tmp/package.json electron/package.json jq --arg version "${VERSION_TAG#v}" '.version = $version' web/package.json > /tmp/package.json @@ -131,7 +147,7 @@ jobs: AWS_MAX_ATTEMPTS: "5" - name: Build and publish app to github - if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') && inputs.public_provider == 'github' + if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') && inputs.public_provider == 'github' && inputs.beta == false run: | make build-and-publish env: @@ -146,6 +162,25 @@ jobs: ANALYTICS_ID: ${{ secrets.JAN_APP_UMAMI_PROJECT_API_KEY }} ANALYTICS_HOST: ${{ secrets.JAN_APP_UMAMI_URL }} + - name: Build and publish app to github + if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') && inputs.public_provider == 'github' && inputs.beta == true + run: | + make build-and-publish + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + CSC_LINK: "/tmp/codesign.p12" + CSC_KEY_PASSWORD: ${{ secrets.CODE_SIGN_P12_PASSWORD }} + CSC_IDENTITY_AUTO_DISCOVERY: "true" + APPLE_ID: ${{ secrets.APPLE_ID }} + APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }} + APP_PATH: "." + DEVELOPER_ID: ${{ secrets.DEVELOPER_ID }} + AWS_ACCESS_KEY_ID: ${{ secrets.DELTA_AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.DELTA_AWS_SECRET_ACCESS_KEY }} + AWS_DEFAULT_REGION: auto + AWS_EC2_METADATA_DISABLED: "true" + AWS_MAX_ATTEMPTS: "5" + - name: Upload Artifact if: inputs.public_provider != 'github' uses: actions/upload-artifact@v4 @@ -154,7 +189,15 @@ jobs: path: ./electron/dist/jan-mac-arm64-${{ inputs.new_version }}.dmg - name: Upload Artifact + if: inputs.beta == false uses: actions/upload-artifact@v4 with: name: latest-mac-arm64 - path: ./electron/dist/latest-mac.yml \ No newline at end of file + path: ./electron/dist/latest-mac.yml + + - name: Upload Artifact + if: inputs.beta == true + uses: actions/upload-artifact@v4 + with: + name: beta-mac-arm64 + path: ./electron/dist/beta-mac.yml \ No newline at end of file diff --git a/.github/workflows/template-build-macos-x64.yml b/.github/workflows/template-build-macos-x64.yml index b7103fd065..f139797af0 100644 --- a/.github/workflows/template-build-macos-x64.yml +++ b/.github/workflows/template-build-macos-x64.yml @@ -19,6 +19,10 @@ on: required: false type: string default: '/latest/' + beta: + required: false + type: boolean + default: false secrets: DELTA_AWS_S3_BUCKET_NAME: required: false @@ -68,7 +72,7 @@ jobs: jq --arg version "${{ inputs.new_version }}" '.version = $version' web/package.json > /tmp/package.json mv /tmp/package.json web/package.json - jq '.build.publish = [{"provider": "generic", "url": "${{ secrets.CLOUDFLARE_R2_PUBLIC_URL }}", "channel": "latest"}, {"provider": "s3", "acl": null, "bucket": "${{ secrets.DELTA_AWS_S3_BUCKET_NAME }}", "region": "${{ secrets.DELTA_AWS_REGION}}", "path": "${{ inputs.aws_s3_prefix }}", "channel": "latest"}]' electron/package.json > /tmp/package.json + jq '.build.publish = [{"provider": "generic", "url": "${{ secrets.CLOUDFLARE_R2_PUBLIC_URL }}", "channel": "latest"}, {"provider": "s3", "acl": null, "bucket": "${{ secrets.DELTA_AWS_S3_BUCKET_NAME }}", "region": "${{ secrets.DELTA_AWS_REGION}}", "path": "temp-latest", "channel": "latest"}]' electron/package.json > /tmp/package.json mv /tmp/package.json electron/package.json jq --arg teamid "${{ secrets.APPLE_TEAM_ID }}" '.build.mac.notarize.teamId = $teamid' electron/package.json > /tmp/package.json @@ -76,13 +80,25 @@ jobs: cat electron/package.json + - name: Change App Name for beta version + if: inputs.beta == true + shell: bash + run: | + chmod +x .github/scripts/rename-app-beta.sh + .github/scripts/rename-app-beta.sh ./electron/package.json + chmod +x .github/scripts/rename-workspace-beta.sh + .github/scripts/rename-workspace-beta.sh ./package.json + echo "------------------------" + cat ./electron/package.json + echo "------------------------" + cat ./package.json + jq '.build.publish = [{"provider": "generic", "url": "https://delta.jan.ai/beta", "channel": "beta"}, {"provider": "github", "owner": "janhq", "repo": "jan", "channel": "beta"}, {"provider": "s3", "acl": null, "bucket": "${{ secrets.DELTA_AWS_S3_BUCKET_NAME }}", "region": "${{ secrets.DELTA_AWS_REGION}}", "path": "temp-beta", "channel": "beta"}]' electron/package.json > /tmp/package.json + mv /tmp/package.json electron/package.json + cat electron/package.json + - name: Update app version base on tag if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') && inputs.public_provider == 'github' run: | - if [[ ! "${VERSION_TAG}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then - echo "Error: Tag is not valid!" - exit 1 - fi jq --arg version "${VERSION_TAG#v}" '.version = $version' electron/package.json > /tmp/package.json mv /tmp/package.json electron/package.json jq --arg version "${VERSION_TAG#v}" '.version = $version' web/package.json > /tmp/package.json @@ -131,7 +147,7 @@ jobs: AWS_MAX_ATTEMPTS: "5" - name: Build and publish app to github - if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') && inputs.public_provider == 'github' + if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') && inputs.public_provider == 'github' && inputs.beta == false run: | make build-and-publish env: @@ -146,6 +162,25 @@ jobs: ANALYTICS_ID: ${{ secrets.JAN_APP_UMAMI_PROJECT_API_KEY }} ANALYTICS_HOST: ${{ secrets.JAN_APP_UMAMI_URL }} + - name: Build and publish app to github + if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') && inputs.public_provider == 'github' && inputs.beta == true + run: | + make build-and-publish + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + CSC_LINK: "/tmp/codesign.p12" + CSC_KEY_PASSWORD: ${{ secrets.CODE_SIGN_P12_PASSWORD }} + CSC_IDENTITY_AUTO_DISCOVERY: "true" + APPLE_ID: ${{ secrets.APPLE_ID }} + APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }} + APP_PATH: "." + DEVELOPER_ID: ${{ secrets.DEVELOPER_ID }} + AWS_ACCESS_KEY_ID: ${{ secrets.DELTA_AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.DELTA_AWS_SECRET_ACCESS_KEY }} + AWS_DEFAULT_REGION: auto + AWS_EC2_METADATA_DISABLED: "true" + AWS_MAX_ATTEMPTS: "5" + - name: Upload Artifact if: inputs.public_provider != 'github' uses: actions/upload-artifact@v4 @@ -154,7 +189,15 @@ jobs: path: ./electron/dist/jan-mac-x64-${{ inputs.new_version }}.dmg - name: Upload Artifact + if: inputs.beta == false uses: actions/upload-artifact@v4 with: name: latest-mac-x64 - path: ./electron/dist/latest-mac.yml \ No newline at end of file + path: ./electron/dist/latest-mac.yml + + - name: Upload Artifact + if: inputs.beta == true + uses: actions/upload-artifact@v4 + with: + name: beta-mac-x64 + path: ./electron/dist/beta-mac.yml \ No newline at end of file diff --git a/.github/workflows/template-build-windows-x64.yml b/.github/workflows/template-build-windows-x64.yml index b1110e3160..ffe94fecc0 100644 --- a/.github/workflows/template-build-windows-x64.yml +++ b/.github/workflows/template-build-windows-x64.yml @@ -19,6 +19,10 @@ on: required: false type: string default: '/latest/' + beta: + required: false + type: boolean + default: false secrets: DELTA_AWS_S3_BUCKET_NAME: required: false @@ -69,21 +73,37 @@ jobs: jq --arg version "${{ inputs.new_version }}" '.version = $version' web/package.json > /tmp/package.json mv /tmp/package.json web/package.json - jq '.build.publish = [{"provider": "generic", "url": "${{ secrets.CLOUDFLARE_R2_PUBLIC_URL }}", "channel": "latest"}, {"provider": "s3", "acl": null, "bucket": "${{ secrets.DELTA_AWS_S3_BUCKET_NAME }}", "region": "${{ secrets.DELTA_AWS_REGION}}", "path": "${{ inputs.aws_s3_prefix }}", "channel": "latest"}]' electron/package.json > /tmp/package.json + jq '.build.publish = [{"provider": "generic", "url": "${{ secrets.CLOUDFLARE_R2_PUBLIC_URL }}", "channel": "latest"}, {"provider": "s3", "acl": null, "bucket": "${{ secrets.DELTA_AWS_S3_BUCKET_NAME }}", "region": "${{ secrets.DELTA_AWS_REGION}}", "path": "temp-latest", "channel": "latest"}]' electron/package.json > /tmp/package.json mv /tmp/package.json electron/package.json jq '.build.win.sign = "./sign.js"' electron/package.json > /tmp/package.json mv /tmp/package.json electron/package.json cat electron/package.json + - name: Change App Name for beta version + if: inputs.beta == true + shell: bash + run: | + chmod +x .github/scripts/rename-app-beta.sh + .github/scripts/rename-app-beta.sh ./electron/package.json + chmod +x .github/scripts/rename-workspace-beta.sh + .github/scripts/rename-workspace-beta.sh ./package.json + chmod +x .github/scripts/rename-uninstaller-beta.sh + .github/scripts/rename-uninstaller-beta.sh + echo "------------------------" + cat ./electron/package.json + echo "------------------------" + cat ./package.json + echo "------------------------" + cat ./electron/scripts/uninstaller.nsh + jq '.build.publish = [{"provider": "generic", "url": "https://delta.jan.ai/beta", "channel": "beta"}, {"provider": "github", "owner": "janhq", "repo": "jan", "channel": "beta"}, {"provider": "s3", "acl": null, "bucket": "${{ secrets.DELTA_AWS_S3_BUCKET_NAME }}", "region": "${{ secrets.DELTA_AWS_REGION}}", "path": "temp-beta", "channel": "beta"}]' electron/package.json > /tmp/package.json + mv /tmp/package.json electron/package.json + cat electron/package.json + - name: Update app version base on tag if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') && inputs.public_provider == 'github' shell: bash run: | - if [[ ! "${VERSION_TAG}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then - echo "Error: Tag is not valid!" - exit 1 - fi jq --arg version "${VERSION_TAG#v}" '.version = $version' electron/package.json > /tmp/package.json mv /tmp/package.json electron/package.json jq --arg version "${VERSION_TAG#v}" '.version = $version' web/package.json > /tmp/package.json @@ -113,7 +133,7 @@ jobs: AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }} AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }} AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }} - AZURE_CERT_NAME: ${{ secrets.AZURE_CERT_NAME }} + AZURE_CERT_NAME: homebrewltd AWS_ACCESS_KEY_ID: ${{ secrets.DELTA_AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.DELTA_AWS_SECRET_ACCESS_KEY }} AWS_DEFAULT_REGION: auto @@ -121,7 +141,7 @@ jobs: AWS_MAX_ATTEMPTS: "5" - name: Build app and publish app to github - if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') && inputs.public_provider == 'github' + if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') && inputs.public_provider == 'github' && inputs.beta == false run: | make build-and-publish env: @@ -132,7 +152,25 @@ jobs: AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }} AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }} AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }} - AZURE_CERT_NAME: ${{ secrets.AZURE_CERT_NAME }} + AZURE_CERT_NAME: homebrewltd + + - name: Build app and publish app to github + if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') && inputs.public_provider == 'github' && inputs.beta == true + run: | + make build-and-publish + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + AWS_ACCESS_KEY_ID: ${{ secrets.DELTA_AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.DELTA_AWS_SECRET_ACCESS_KEY }} + AWS_DEFAULT_REGION: auto + AWS_EC2_METADATA_DISABLED: "true" + AWS_MAX_ATTEMPTS: "5" + AZURE_KEY_VAULT_URI: ${{ secrets.AZURE_KEY_VAULT_URI }} + AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }} + AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }} + AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }} + # AZURE_CERT_NAME: ${{ secrets.AZURE_CERT_NAME }} + AZURE_CERT_NAME: homebrewltd - name: Upload Artifact if: inputs.public_provider != 'github' diff --git a/README.md b/README.md index e1622b0812..ecede5bd9b 100644 --- a/README.md +++ b/README.md @@ -19,8 +19,7 @@ - Discord

->[!Warning] ->**Jan is currently in Development**: Expect breaking changes and bugs! +> [!Warning] >**Jan is currently in Development**: Expect breaking changes and bugs! Jan is an open-source ChatGPT alternative that runs 100% offline on your computer. @@ -45,31 +44,31 @@ Jan is an open-source ChatGPT alternative that runs 100% offline on your compute Stable (Recommended) - + jan.exe - + Intel - + M1/M2/M3/M4 - + jan.deb - + jan.AppImage @@ -78,31 +77,31 @@ Jan is an open-source ChatGPT alternative that runs 100% offline on your compute Experimental (Nightly Build) - + jan.exe - + Intel - + M1/M2/M3/M4 - + jan.deb - + jan.AppImage diff --git a/docs/.env.example b/docs/.env.example new file mode 100644 index 0000000000..4048b604cb --- /dev/null +++ b/docs/.env.example @@ -0,0 +1 @@ +GTM_ID=xxxx \ No newline at end of file diff --git a/docs/.eslintrc.json b/docs/.eslintrc.json new file mode 100644 index 0000000000..bffb357a71 --- /dev/null +++ b/docs/.eslintrc.json @@ -0,0 +1,3 @@ +{ + "extends": "next/core-web-vitals" +} diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 0000000000..00bba9bb29 --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1,37 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js +.yarn/install-state.gz + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# local env files +.env*.local +.env + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts diff --git a/docs/.prettierignore b/docs/.prettierignore new file mode 100644 index 0000000000..fc8972f9ec --- /dev/null +++ b/docs/.prettierignore @@ -0,0 +1,5 @@ +.next/ +node_modules/ +dist/ +*.mdx +*.hbs \ No newline at end of file diff --git a/docs/.prettierrc b/docs/.prettierrc new file mode 100644 index 0000000000..a4207953be --- /dev/null +++ b/docs/.prettierrc @@ -0,0 +1,7 @@ +{ + "semi": false, + "singleQuote": true, + "quoteProps": "consistent", + "trailingComma": "es5", + "endOfLine": "auto" +} diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000000..11b68f26b3 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,66 @@ +# Website & Docs + +This website is built using [Nextra](https://nextra.site/), a modern static website generator. + +### Information Architecture + +We try to **keep routes consistent** to maintain SEO. + +- **`/guides/`**: Guides on how to use the Jan application. For end users who are directly using Jan. + +- **`/developer/`**: Developer docs on how to extend Jan. These pages are about what people can build with our software. + +- **`/api-reference/`**: Reference documentation for the Jan API server, written in Swagger/OpenAPI format. + +- **`/changelog/`**: A list of changes made to the Jan application with each release. + +- **`/blog/`**: A blog for the Jan application. + +## How to Contribute + +Refer to the [Contributing Guide](https://github.com/janhq/jan/blob/main/CONTRIBUTING.md) for more comprehensive information on how to contribute to the Jan project. + +### Pre-requisites and Installation + +- [Node.js](https://nodejs.org/en/) (version 20.0.0 or higher) +- [yarn](https://yarnpkg.com/) (version 1.22.0 or higher) + +#### Installation + +```bash +cd jan/docs +yarn install +yarn dev +``` + +This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server. + +#### Build + +```bash +yarn build +``` + +This command generates static content into the `build` directory and can be served using any static contents hosting service. + +### Deployment + +Using SSH: + +```bash +USE_SSH=true yarn deploy +``` + +Not using SSH: + +```bash +GIT_USER= yarn deploy +``` + +If you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch. + +### Preview URL, Pre-release and Publishing Documentation + +- When a pull request is created, the preview URL will be automatically commented on the pull request. + +- The documentation will then be published to [https://jan.ai/](https://jan.ai/) when the pull request is merged to `main`. diff --git a/docs/_redirects b/docs/_redirects new file mode 100644 index 0000000000..0fd614917d --- /dev/null +++ b/docs/_redirects @@ -0,0 +1,685 @@ +/team /about/team 302 +/about/teams /about/team 302 +/about/faq /docs 302 +/about/acknowledgements /docs 302 +/about/community /about 302 +/guides /docs 302 +/docs/troubleshooting/failed-to-fetch /docs/troubleshooting 302 +/guides/troubleshooting/gpu-not-used /docs/troubleshooting#troubleshooting-nvidia-gpu 302 +/guides/troubleshooting /docs/troubleshooting 302 +/docs/troubleshooting/stuck-on-broken-build /docs/troubleshooting 302 +/docs/troubleshooting/somethings-amiss /docs/troubleshooting 302 +/docs/troubleshooting/how-to-get-error-logs /docs/troubleshooting 302 +/docs/troubleshooting/permission-denied /docs/troubleshooting 302 +/docs/troubleshooting/unexpected-token /docs/troubleshooting 302 +/docs/troubleshooting/undefined-issue /docs/troubleshooting 302 +/getting-started/troubleshooting /docs/troubleshooting 302 +/docs/troubleshooting/gpu-not-used /docs/troubleshooting 302 +/guides/integrations/openrouter /docs/remote-models/openrouter 302 +/guides/integrations/continue /integrations/coding/continue-dev 302 +/docs/extension-capabilities /docs/extensions 302 +/guides/using-extensions /docs/extensions 302 +/docs/extension-guides /docs/extensions 302 +/features/extensions /docs/extensions 302 +/integrations/tensorrt /docs/built-in/tensorrt-llm 302 +/guides/using-models/integrate-with-remote-server /docs/remote-inference/generic-openai 302 +/guides/using-models/customize-engine-settings /docs/built-in/llama-cpp 302 +/developers/plugins/azure-openai /docs/remote-models/openai 302 +/docs/api-reference/assistants /api-reference#tag/assistants 302 +/docs/api-reference/models/list /api-reference#tag/models 302 +/docs/api-reference/threads /api-reference#tag/chat 302 +/docs/api-reference/messages /api-reference#tag/messages 302 +/docs/api-reference/models /api-reference#tag/models 302 +/chat /docs/threads 302 +/guides/chatting/manage-history /docs/threads/ 302 +/guides/chatting/start-thread /docs/threads/ 302 +/guides/using-server /docs/local-api/ 302 +/guides/using-server/server /docs/local-api#step-2-srt-and-use-the-built-in-api-server 302 +/docs/get-started /docs 302 +/guides/how-jan-works /about/how-we-work 302 +/acknowledgements /about/acknowledgements 302 +/community /about/community 302 +/faq /about/faq 302 +/how-we-work /about/how-we-work 302 +/wall-of-love /about/wall-of-love 302 +/guides/troubleshooting/failed-to-fetch /docs/troubleshooting 302 +/docs/troubleshooting/gpu-not-used /docs/troubleshooting 302 +/docs/troubleshooting/failed-to-fetch /docs/troubleshooting 302 +/guides/ /docs 302 +/guides/quickstart/ /docs/quickstart 302 +/guides/models/ /docs/models 302 +/guides/threads/ /docs/threads 302 +/guides/local-api/ /docs/local-api 302 +/guides/advanced/ /docs/settings 302 +/guides/engines/llamacpp/ /docs/built-in/llama-cpp 302 +/guides/engines/tensorrt-llm/ /docs/built-in/tensorrt-llm 302 +/guides/engines/lmstudio/ /docs/local-models/lmstudio 302 +/guides/engines/ollama/ /docs/built-in/llama-cpp 302 +/guides/engines/groq/ /docs/remote-models/groq 302 +/guides/engines/mistral/ /docs/remote-models/mistralai 302 +/guides/engines/openai/ /docs/remote-models/openai 302 +/guides/engines/remote-server/ /docs/remote-inference/generic-openai 302 +/extensions/ /docs/extensions 302 +/integrations/discord/ /integrations/messaging/llmcord 302 +/discord https://discord.gg/FTk2MvZwJH 301 +/integrations/interpreter/ /integrations/function-calling/interpreter 302 +/integrations/raycast/ /integrations/workflow-automation/raycast 302 +/docs/integrations/raycast /integrations/workflow-automation/raycast 302 +/docs/integrations /integrations 302 +/docs/engineering/files/ /docs 302 +/integrations/openrouter/ /docs/remote-models/openrouter 302 +/integrations/continue/ /integrations/coding/continue-dev 302 +/troubleshooting/ /docs/troubleshooting 302 +/changelog/changelog-v0.4.9/ /changelog 302 +/changelog/changelog-v0.4.8/ /changelog 302 +/changelog/changelog-v0.4.7/ /changelog 302 +/changelog/changelog-v0.4.6/ /changelog 302 +/changelog/changelog-v0.4.5/ /changelog 302 +/changelog/changelog-v0.4.4/ /changelog 302 +/changelog/changelog-v0.4.3/ /changelog 302 +/changelog/changelog-v0.4.2/ /changelog 302 +/changelog/changelog-v0.4.1/ /changelog 302 +/changelog/changelog-v0.4.0/ /changelog 302 +/changelog/changelog-v0.3.3/ /changelog 302 +/changelog/changelog-v0.3.2/ /changelog 302 +/changelog/changelog-v0.3.1/ /changelog 302 +/changelog/changelog-v0.3.0/ /changelog 302 +/changelog/changelog-v0.2.3/ /changelog 302 +/changelog/changelog-v0.2.2/ /changelog 302 +/changelog/changelog-v0.2.1/ /changelog 302 +/changelog/changelog-v0.2.0/ /changelog 302 +/team/ /about/team 302 +/team/contributor-program/ /about/team 302 +/team/join-us/ /about/team 302 +/how-we-work/ /about/how-we-work 302 +/how-we-work/strategy/ /about/how-we-work/strategy 302 +/how-we-work/project-management/ /about/how-we-work/project-management 302 +/engineering/ /about/how-we-work/engineering 302 +/engineering/ci-cd/ /about/how-we-work/engineering/ci-cd 302 +/engineering/qa/ /about/how-we-work/engineering/qa 302 +/how-we-work/product-design/ /about 302 +/about/how-we-work/product-design /about 302 +/how-we-work/analytics/ /about/how-we-work/analytics 302 +/how-we-work/website-docs/ /about/how-we-work/website-docs 302 +/blog/postmortems/january-10-2024-bitdefender-false-positive-flag/ /post/bitdefender 302 +/guides/error-codes/something-amiss/ /docs/troubleshooting#somethings-amiss 302 +/guides/error-codes/how-to-get-error-logs/ /docs/troubleshooting#how-to-get-error-logs 302 +/guides/chatting/ /docs/threads 302 +/guides/integration/openinterpreter/ /integrations/function-calling/interpreter 302 +/developer/build-assistant/ /docs/assistants 302 +/guides/integrations/ /integrations 302 +/specs/hub/ /docs 302 +/install/windows/ /docs/desktop/windows 302 +/install/linux/ /docs/desktop/linux 302 +/install/nightly/ /docs/desktop/windows 302 +/docs/engineering/fine-tuning/ /docs 302 +/developer/assistant/ /docs/assistants 302 +/guides/common-error/broken-build/ /docs/troubleshooting#broken-build 302 +/guides/using-server/using-server/ /docs/local-api 302 +/guides/integrations/azure-openai-service/ /docs/remote-models/openai 302 +/specs/messages/ /docs/threads 302 +/docs/engineering/models/ /docs/models 302 +/docs/specs/assistants/ /docs/assistants 302 +/docs/engineering/chats/ /docs/threads 302 +/guides/using-extensions/extension-settings/ /docs/extensions 302 +/guides/models/customize-engine/ /docs/models 302 +/guides/integration/mistral/ /docs/remote-models/mistralai 302 +/guides/common-error/ /docs/troubleshooting 302 +/guides/integrations/ollama/ /docs/local-models/ollama 302 +/server-suite/ /api-reference 302 +/guides/integrations/lmstudio/ /docs/local-models/lmstudio 302 +/guides/integrations/mistral-ai/ /docs/remote-models/mistralai 302 +/guides/start-server/ /docs/local-api 302 +/guides/changelog/ /changelog 302 +/guides/models-list/ /docs/models 302 +/guides/thread/ /docs/threads 302 +/docs/engineering/messages/ /docs/threads 302 +/guides/faqs/ /about/faq 302 +/docs/integrations/openrouter/ /docs/remote-models/openrouter 302 +/guides/windows /docs/desktop/windows 302 +/docs/integrations/ollama/ /docs/local-models/ollama 302 +/api/overview/ /api-reference 302 +/docs/extension-guides/ /docs/extensions 302 +/specs/settings/ /docs 302 +/docs/UI/ /docs 302 +/guides/using-models/import-models-using-absolute-filepath/ /docs/models 302 +/install/docker/ /docs/desktop 302 +/install/ /docs/desktop 302 +/install/from-source/ /docs/desktop 302 +/docs/installation/server /docs/desktop 302 +/v1/models /docs/models 302 +/guides/advanced-settings/ /docs/settings 302 +/guides/using-models/install-from-hub/ /docs/models/manage-models#download-from-jan-hub 302 +/guides/using-models/import-manually/ /docs/models 302 +/docs/team/contributor-program/ /about/team 302 +/docs/modules/models /docs/models 302 +/getting-started/install/linux /docs/desktop/linux 302 +/guides/chatting/start-thread/ /docs/threads 302 +/api/files/ /docs 302 +/specs/threads/ /docs/threads 302 +/about/brand-assets /about 302 +/guides/chatting/upload-images/ /docs/threads 302 +/guides/using-models/customize-models/ /docs/models 302 +/docs/modules/models/ /docs/models 302 +/getting-started/install/linux/ /docs/desktop/linux 302 +/specs/chats/ /docs/threads 302 +/specs/engine/ /docs 302 +/specs/data-structures /docs 302 +/docs/extension-capabilities/ /docs/extensions 302 +/docs/get-started/use-local-server/ /docs/local-api 302 +/guides/how-jan-works/ /about/how-we-work 302 +/guides/install/cloud-native /docs/desktop 302 +/guides/windows/ /docs/desktop/windows 302 +/specs/ /docs 302 +/docs/get-started/build-extension/ /docs/extensions 302 +/specs/files/ /docs 302 +/guides/using-models/package-models/ /docs/models 302 +/install/overview/ /docs/desktop/windows 302 +/docs/get-started/extension-anatomy/ /docs/extensions 302 +/docs/get-started/ /docs 302 +/guides/mac/ /docs/desktop/mac 302 +/intro/ /about 302 +/specs/fine-tuning/ /docs 302 +/guides/server/ /docs/desktop 302 +/specs/file-based/ /docs 302 +/docs/extension-guides/monitoring/ /docs/extensions 302 +/api/ /api-reference 302 +/getting-started/build-an-app /docs/quickstart 302 +/features/ai-models/ /docs/models 302 +/reference/store/ /api-reference 302 +/tutorials/build-chat-app /docs/quickstart 302 +/features/acceleration /docs/built-in/llama-cpp 302 +/getting-started/install/mac /docs/desktop/mac 302 +docs/guides/fine-tuning/what-models-can-be-fine-tuned /docs 302 +/docs/specs/threads /docs/threads 302 +/docs/api-reference/fine-tuning /api-reference 302 +/docs/guides/speech-to-text/prompting /docs/quickstart 302 +/docs/guides/legacy-fine-tuning/analyzing-your-fine-tuned-model /docs 302 +/getting-started/install/windows /docs/desktop/windows 302 +/docs/modules/assistants /docs/assistants 302 +/docs/modules/chats /docs/threads 302 +/docs/specs/chats /docs/threads 302 +/docs/modules/files /docs 302 +/tutorials/build-rag-app /docs/tools/retrieval 302 +/docs/models/model-endpoint-compatibility /docs/models 302 +/docs/guides/legacy-fine-tuning/creating-training-data /docs 302 +/docs/specs/models /docs/models 302 +/docs/guides/safety-best-practices/end-user-ids /docs/quickstart 302 +/docs/modules/assistants/ /docs/assistants 302 +/docs/models/overview /docs/models 302 +/docs/api-reference/files /api-reference 302 +/docs/models/tts /docs/models 302 +/docs/guides/fine-tuning /docs 302 +/docs/specs/files /docs 302 +/docs/modules/threads /docs/threads 302 +/guides/linux /docs/desktop/linux 302 +/developer/build-engine/engine-anatomy/ /docs 302 +/developer/engine/ /docs 302 +/docs/product/system-monitor/ /docs 302 +/docs/product/settings/ /docs 302 +/developer/build-assistant/your-first-assistant/ /docs 302 +/engineering/research/ /docs 302 +/guides/troubleshooting/gpu-not-used/ /docs/troubleshooting#troubleshooting-nvidia-gpu 302 +/troubleshooting/gpu-not-used/ /docs/troubleshooting#troubleshooting-nvidia-gpu 302 +/docs/integrations/langchain/ /integrations 302 +/onboarding/ /docs/quickstart 302 +/cortex/docs https://cortex.so/ 301 +/installation/hardware/ /docs/desktop/windows 302 +/docs/features/load-unload /docs 302 +/guides/chatting/upload-docs/ /docs/threads 302 +/developer/build-extension/package-your-assistant/ /docs 302 +/blog/hello-world /blog 302 +/docs/get-started/build-on-mobile/ /docs/quickstart 302 +/ai/anything-v4 /docs 302 +/nitro /docs 302 +/tokenizer /docs 302 +/hardware/examples/3090x1-@dan-jan /docs 302 +/guides/concepts/ /about 302 +/platform/ /docs 302 +/hardware/examples/AMAZON-LINK-HERE /docs 302 +/guides/threads/?productId=openai&prompt=What /docs 302 +/guides/threads/?productId=openjourney&prompt=realistic%20portrait%20of%20an%20gray%20dog,%20bright%20eyes,%20radiant%20and%20ethereal%20intricately%20detailed%20photography,%20cinematic%20lighting,%2050mm%20lens%20with%20bokeh /docs 302 +/guides/threads/?productId=openjourney&prompt=old,%20female%20robot,%20metal,%20rust,%20wisible%20wires,%20destroyed,%20sad,%20dark,%20dirty,%20looking%20at%20viewer,%20portrait,%20photography,%20detailed%20skin,%20realistic,%20photo-realistic,%208k,%20highly%20detailed,%20full%20length%20frame,%20High%20detail%20RAW%20color%20art,%20piercing,%20diffused%20soft%20lighting,%20shallow%20depth%20of%20field,%20sharp%20focus,%20hyperrealism,%20cinematic%20lighting /docs 302 +/guides/threads/?productId=openjourney&prompt=a%20young%20caucasian%20man%20holding%20his%20chin.pablo%20picasso%20style,%20acrylic%20painting,%20trending%20on%20pixiv%20fanbox,%20palette%20knife%20and%20brush.%20strokes /docs 302 +/guides/threads/?productId=airoboros&prompt=Let%27s%20role%20play.%20You%20are%20a%20robot%20in%20a%20post-apocalyptic%20world. /docs 302 +/chat?productId=pirsus-epic-realism /docs 302 +/chat?productId=ether-blu-mix /docs 302 +/chat?productId=deliberate /docs 302 +/chat?productId=wizard_vicuna /docs 302 +/chat?productId=disneypixar /docs 302 +/chat?productId=meina-mix /docs 302 +/chat?productId=anything-v4 /docs 302 +/chat?productId=airoboros /docs 302 +/chat?productId=ghost-mix /docs 302 +/ai/toonyou /docs 302 +/chat?productId=xrica-mix /docs 302 +/ai/openai /docs 302 +/chat?productId=been-you /docs 302 +/chat?productId=toonyou /docs 302 +/handbook/product-and-community/ /about/community 302 +/handbook/contributing-to-jan/how-to-get-involved-and-faq/ /about 302 +/handbook/engineering-exellence/one-the-tools-what-we-use-and-why/ /about 302 +/handbook/from-spaghetti-flinging-to-strategy/how-we-gtm/ /about/how-we-work/strategy 302 +/handbook/product-and-community/our-okrs/ /about 302 +/products-and-innovations/philosophy-behind-product-development/ /about 302 +/handbook/core-contributors/ /about/team 302 +/handbook/contributing-to-jan/feedback-channels/ /about/how-we-work 302 +/handbook/meet-jan/ /docs 302 +/handbook/engineering-exellence/ /about 302 +/blog/tags/hello/ /blog 302 +/about/community/events/nvidia-llm-day-nov-23/ /about 302 +/guides/gpus-and-vram /docs 302 +/careers/ /about/team 302 +/handbook/engineering/ /about/team 302 +/handbook/products-and-innovations/ /about 302 +/handbook/contributing-to-jan/ /about 302 +/handbook/meet-jan/vision-and-mission/ /about 302 +/handbook/products-and-innovations/roadmap-present-and-future-directions/ /about 302 +/handbook/what-we-do/ /about/team 302 +/handbook/onboarding/ /docs 302 +/handbook/products-and-innovations/overview-of-jan-framework-and-its-applications/ /docs 302 +/handbook/product/ /docs 302 +/running /docs 302 +/running?model=Open%20Journey%20SD /docs 302 +/ai/been-you /about 302 +/tokenizer?view=bpe /docs 302 +/docs/engineering/ /docs 302 +/developer/install-and-prerequisites#system-requirements /docs/desktop/windows 302 +/guides/quickstart /docs/quickstart 302 +/guides/models /docs/models 302 +/guides/threads /docs/threads 302 +/guides/local-api /docs/local-api 302 +/guides/advanced /docs/settings 302 +/guides/engines/llamacpp /docs/built-in/llama-cpp 302 +/guides/engines/tensorrt-llm /docs/built-in/tensorrt-llm 302 +/guides/engines/lmstudio /docs/local-models/lmstudio 302 +/guides/engines/ollama /docs/local-models/ollama 302 +/guides/engines/groq /docs/remote-models/groq 302 +/guides/engines/mistral /docs/remote-models/mistralai 302 +/guides/engines/openai /docs/remote-models/openai 302 +/guides/engines/remote-server /docs/remote-inference/generic-openai 302 +/extensions /docs/extensions 302 +/integrations/discord /integrations/messaging/llmcord 302 +/docs/integrations/discord /integrations/messaging/llmcord 302 +/integrations/interpreter /integrations/function-calling/interpreter 302 +/integrations/raycast /integrations/workflow-automation/raycast 302 +/integrations/openrouter /docs/remote-models/openrouter 302 +/integrations/continue /integrations/coding/continue-dev 302 +/troubleshooting /docs/troubleshooting 302 +/changelog/changelog-v0.4.9 /changelog 302 +/changelog/changelog-v0.4.8 /changelog 302 +/changelog/changelog-v0.4.7 /changelog 302 +/changelog/changelog-v0.4.6 /changelog 302 +/changelog/changelog-v0.4.5 /changelog 302 +/changelog/changelog-v0.4.4 /changelog 302 +/changelog/changelog-v0.4.3 /changelog 302 +/changelog/changelog-v0.4.2 /changelog 302 +/changelog/changelog-v0.4.1 /changelog 302 +/changelog/changelog-v0.4.0 /changelog 302 +/changelog/changelog-v0.3.3 /changelog 302 +/changelog/changelog-v0.3.2 /changelog 302 +/changelog/changelog-v0.3.1 /changelog 302 +/changelog/changelog-v0.3.0 /changelog 302 +/changelog/changelog-v0.2.3 /changelog 302 +/changelog/changelog-v0.2.2 /changelog 302 +/changelog/changelog-v0.2.1 /changelog 302 +/changelog/changelog-v0.2.0 /changelog 302 +/guides/troubleshooting/ /docs/troubleshooting 302 +/docs/troubleshooting/failed-to-fetch/ /docs/troubleshooting 302 +/docs/troubleshooting/stuck-on-broken-build/ /docs/troubleshooting 302 +/docs/troubleshooting/somethings-amiss/ /docs/troubleshooting 302 +/docs/troubleshooting/how-to-get-error-logs/ /docs/troubleshooting 302 +/docs/troubleshooting/permission-denied/ /docs/troubleshooting 302 +/docs/troubleshooting/unexpected-token/ /docs/troubleshooting 302 +/docs/troubleshooting/undefined-issue/ /docs/troubleshooting 302 +/getting-started/troubleshooting/ /docs/troubleshooting 302 +/docs/troubleshooting/gpu-not-used/ /docs/troubleshooting#troubleshooting-nvidia-gpu 302 +/guides/integrations/openrouter/ /docs/remote-models/openrouter 302 +/guides/integrations/continue/ /integrations/coding/continue-dev 302 +/guides/using-extensions/ /docs/extensions 302 +/features/extensions/ /docs/extensions 302 +/integrations/tensorrt /docs/built-in/tensorrt-llm 302 +/integrations/tensorrt/ /docs/built-in/tensorrt-llm 302 +/guides/using-models/integrate-with-remote-server/ /docs/remote-inference/generic-openai 302 +/guides/using-models/customize-engine-settings/ /docs/built-in/llama-cpp 302 +/developers/plugins/azure-openai/ /docs/remote-models/openai 302 +/docs/api-reference/assistants/ /api-reference#tag/assistants 302 +/docs/api-reference/models/list/ /api-reference#tag/models 302 +/docs/api-reference/threads/ /api-reference#tag/chat 302 +/docs/api-reference/messages/ /api-reference#tag/messages 302 +/docs/api-reference/models/ /api-reference#tag/models 302 +/chat/ /docs/threads 302 +/guides/chatting/manage-history/ /docs/threads/ 302 +/guides/using-server/ /docs/local-api 302 +/guides/using-server/server /docs/local-api 302 +/guides/server /docs/desktop 302 +/acknowledgements/ /about/acknowledgements 302 +/community/ /about/community 302 +/faq/ /about/faq 302 +/wall-of-love/ /about/wall-of-love 302 +/guides/troubleshooting/failed-to-fetch/ /docs/troubleshooting 302 +/docs/troubleshooting/gpu-not-used/ /docs/troubleshooting#troubleshooting-nvidia-gpu 302 +/docs/troubleshooting/failed-to-fetch/ /docs/troubleshooting 302 +/team/contributor-program /about/team 302 +/team/join-us /about/team 302 +/how-we-work/strategy /about/how-we-work/strategy 302 +/how-we-work/strategy/ /about/how-we-work/strategy 302 +/how-we-work/project-management /about/how-we-work/project-management 302 +/engineering /about/how-we-work/engineering 302 +/engineering/ci-cd /about/how-we-work/engineering/ci-cd 302 +/engineering/qa /about/how-we-work/engineering/qa 302 +/how-we-work/product-design /about 302 +/how-we-work/analytics /about/how-we-work/analytics 302 +/how-we-work/website-docs /about/how-we-work/website-docs 302 +/blog/postmortems/january-10-2024-bitdefender-false-positive-flag /post/bitdefender 302 +/guides/error-codes/something-amiss /docs/troubleshooting#somethings-amiss 302 +/guides/error-codes/how-to-get-error-logs /docs/troubleshooting#how-to-get-error-logs 302 +/guides/chatting /docs/threads 302 +/guides/integration/openinterpreter /integrations/function-calling/interpreter 302 +/developer/build-assistant /docs/assistants 302 +/guides/integrations /integrations 302 +/specs/hub /docs 302 +/install/windows /docs/desktop/windows 302 +/install/linux /docs/desktop/linux 302 +/install/nightly /docs/desktop/windows 302 +/docs/engineering/fine-tuning /docs 302 +/developer/assistant /docs/assistants 302 +/guides/common-error/broken-build /docs/troubleshooting#broken-build 302 +/guides/using-server/using-server /docs/local-api 302 +/guides/integrations/azure-openai-service /docs/remote-models/openai 302 +/specs/messages /docs/threads 302 +/docs/engineering/models /docs/models 302 +/docs/specs/assistants /docs/assistants 302 +/docs/engineering/chats /docs/threads 302 +/guides/using-extensions/extension-settings /docs/extensions 302 +/guides/models/customize-engine /docs/models 302 +/guides/integration/mistral /docs/remote-models/mistralai 302 +/guides/common-error /docs/troubleshooting 302 +/guides/integrations/ollama /docs/local-models/ollama 302 +/server-suite /api-reference 302 +/guides/integrations/lmstudio /docs/local-models/lmstudio 302 +/guides/integrations/mistral-ai /docs/remote-models/mistralai 302 +/guides/start-server /docs/local-api 302 +/guides/changelog /changelog 302 +/guides/models-list /docs/models 302 +/guides/thread /docs/threads 302 +/docs/engineering/messages /docs/threads 302 +/guides/faqs /about/faq 302 +/docs/integrations/openrouter /docs/remote-models/openrouter 302 +/docs/integrations/ollama/ /docs/local-models/ollama 302 +/api/overview /api-reference 302 +/docs/extension-guides /docs/extensions 302 +/specs/settings /docs 302 +/docs/UI /docs 302 +/guides/using-models/import-models-using-absolute-filepath /docs/models 302 +/install/docker /docs/desktop 302 +/v1/models/ /docs/models 302 +/guides/using-models/import-manually /docs/models 302 +/docs/team/contributor-program /about/team 302 +/guides/chatting/start-thread /docs/threads 302 +/api/files /docs 302 +/specs/threads /docs/threads 302 +/about/brand-assets/ /about 302 +/guides/chatting/upload-images /docs/threads 302 +/guides/using-models/customize-models /docs/models 302 +/specs/chats /docs/threads 302 +/specs/engine /docs 302 +/specs/data-structures/ /docs 302 +/docs/extension-capabilities /docs/extensions 302 +/docs/get-started/use-local-server /docs/local-api 302 +/guides/install/cloud-native/ /docs/desktop 302 +/guides/install/ /docs/desktop 302 +/docs/installation/desktop /docs/desktop 302 +/specs /docs 302 +/docs/get-started/build-extension /docs/extensions 302 +/specs/files /docs 302 +/guides/using-models/package-models /docs/models 302 +/guides/using-models/ /docs/models 302 +/install/overview /docs/desktop/windows 302 +/developer/prereq/ /docs 302 +/docs/get-started/extension-anatomy /docs/extensions 302 +/guides/mac /docs/desktop/mac 302 +/intro /about 302 +/specs/fine-tuning /docs 302 +/specs/file-based /docs 302 +/docs/extension-guides/monitoring /docs/extensions 302 +/api /api-reference 302 +/getting-started/build-an-app/ /docs/quickstart 302 +/features/ai-models /docs/models 302 +/reference/store /api-reference 302 +/tutorials/build-chat-app/ /docs/quickstart 302 +/features/acceleration/ /docs/built-in/llama-cpp 302 +/getting-started/install/mac/ /docs/desktop/mac 302 +docs/guides/fine-tuning/what-models-can-be-fine-tuned/ /docs 302 +/docs/specs/threads/ /docs/threads 302 +/docs/api-reference/fine-tuning/ /api-reference 302 +/docs/guides/speech-to-text/prompting/ /docs/quickstart 302 +/docs/guides/legacy-fine-tuning/analyzing-your-fine-tuned-model/ /docs 302 +/getting-started/install/windows/ /docs/desktop/windows 302 +/docs/modules/chats/ /docs/threads 302 +/docs/specs/chats/ /docs/threads 302 +/docs/modules/files/ /docs 302 +/tutorials/build-rag-app/ /docs/tools/retrieval 302 +/docs/models/model-endpoint-compatibility/ /docs/models 302 +/docs/guides/legacy-fine-tuning/creating-training-data/ /docs 302 +/docs/specs/models/ /docs/models 302 +/docs/guides/safety-best-practices/end-user-ids/ /docs/quickstart 302 +/docs/models/overview/ /docs/models 302 +/docs/api-reference/files/ /api-reference 302 +/docs/models/tts/ /docs/models 302 +/docs/guides/fine-tuning/ /docs 302 +/docs/specs/files/ /docs 302 +/docs/modules/threads/ /docs/threads 302 +/guides/linux/ /docs/desktop/linux 302 +/developer/build-engine/engine-anatomy /docs 302 +/developer/engine /docs 302 +/docs/product/system-monitor /docs 302 +/docs/product/settings /docs 302 +/developer/build-assistant/your-first-assistant /docs 302 +/engineering/research /docs 302 +/docs/integrations/langchain /integrations 302 +/onboarding /docs/quickstart 302 +/installation/hardware /docs/desktop/windows 302 +/docs/features/load-unload/ /docs 302 +/guides/chatting/upload-docs /docs/threads 302 +/developer/build-extension/package-your-assistant /docs 302 +/blog/hello-world/ /blog 302 +/docs/get-started/build-on-mobile /docs/quickstart 302 +/ai/anything-v4/ /docs 302 +/nitro/ /docs 302 +/tokenizer/ /docs 302 +/hardware/examples/3090x1-@dan-jan/ /docs 302 +/guides/concepts /about 302 +/platform /docs 302 +/hardware/examples/AMAZON-LINK-HERE/ /docs 302 +/guides/threads/?productId=openai&prompt=What/ /docs 302 +/guides/threads/?productId=openjourney&prompt=realistic%20portrait%20of%20an%20gray%20dog,%20bright%20eyes,%20radiant%20and%20ethereal%20intricately%20detailed%20photography,%20cinematic%20lighting,%2050mm%20lens%20with%20bokeh/ /docs 302 +/guides/threads/?productId=openjourney&prompt=old,%20female%20robot,%20metal,%20rust,%20wisible%20wires,%20destroyed,%20sad,%20dark,%20dirty,%20looking%20at%20viewer,%20portrait,%20photography,%20detailed%20skin,%20realistic,%20photo-realistic,%208k,%20highly%20detailed,%20full%20length%20frame,%20High%20detail%20RAW%20color%20art,%20piercing,%20diffused%20soft%20lighting,%20shallow%20depth%20of%20field,%20sharp%20focus,%20hyperrealism,%20cinematic%20lighting/ /docs 302 +/guides/threads/?productId=openjourney&prompt=a%20young%20caucasian%20man%20holding%20his%20chin.pablo%20picasso%20style,%20acrylic%20painting,%20trending%20on%20pixiv%20fanbox,%20palette%20knife%20and%20brush.%20strokes/ /docs 302 +/guides/threads/?productId=airoboros&prompt=Let%27s%20role%20play.%20You%20are%20a%20robot%20in%20a%20post-apocalyptic%20world./ /docs 302 +/chat?productId=pirsus-epic-realism/ /docs 302 +/chat?productId=ether-blu-mix/ /docs 302 +/chat?productId=deliberate/ /docs 302 +/chat?productId=wizard_vicuna/ /docs 302 +/chat?productId=disneypixar/ /docs 302 +/chat?productId=meina-mix/ /docs 302 +/chat?productId=anything-v4/ /docs 302 +/chat?productId=airoboros/ /docs 302 +/chat?productId=ghost-mix/ /docs 302 +/ai/toonyou/ /docs 302 +/chat?productId=xrica-mix/ /docs 302 +/ai/openai/ /docs 302 +/chat?productId=been-you/ /docs 302 +/chat?productId=toonyou/ /docs 302 +/handbook/product-and-community /about/community 302 +/handbook/contributing-to-jan/how-to-get-involved-and-faq /about 302 +/handbook/engineering-exellence/one-the-tools-what-we-use-and-why /about 302 +/handbook/from-spaghetti-flinging-to-strategy/how-we-gtm /about/how-we-work/strategy 302 +/handbook/product-and-community/our-okrs /about 302 +/products-and-innovations/philosophy-behind-product-development /about 302 +/handbook/core-contributors /about/team 302 +/handbook/contributing-to-jan/feedback-channels /about/how-we-work 302 +/handbook/meet-jan /docs 302 +/handbook/engineering-exellence /about 302 +/blog/tags/hello /blog 302 +/about/community/events/nvidia-llm-day-nov-23 /about 302 +/guides/gpus-and-vram/ /docs 302 +/careers /about/team 302 +/handbook/engineering /about/team 302 +/handbook/products-and-innovations /about 302 +/handbook/contributing-to-jan /about 302 +/handbook/meet-jan/vision-and-mission /about 302 +/handbook/products-and-innovations/roadmap-present-and-future-directions /about 302 +/handbook/what-we-do /about/team 302 +/handbook/onboarding /docs 302 +/handbook/products-and-innovations/overview-of-jan-framework-and-its-applications /docs 302 +/handbook/product /docs 302 +/running/ /docs 302 +/running?model=Open%20Journey%20SD/ /docs 302 +/ai/been-you/ /about 302 +/tokenizer?view=bpe/ /docs 302 +/docs/engineering /docs 302 +/developer /docs 302 +/developer/ /docs 302 +/developer/architecture /docs/architecture 302 +/developer/architecture/ /docs/architecture 302 +/developer/file-based /docs 302 +/developer/file-based/ /docs 302 +/developer/framework /docs 302 +/developer/framework/ /docs 302 +/developer/framework/engineering /docs 302 +/developer/framework/engineering/ /docs 302 +/developer/framework/engineering/assistants /docs/assistants 302 +/developer/framework/engineering/assistants/ /docs/assistants 302 +/developer/framework/engineering/chats /docs/threads 302 +/developer/framework/engineering/chats/ /docs/threads 302 +/developer/framework/engineering/engine /docs 302 +/developer/framework/engineering/engine/ /docs 302 +/developer/framework/engineering/files /docs 302 +/developer/framework/engineering/files/ /docs 302 +/developer/framework/engineering/fine-tuning /docs 302 +/developer/framework/engineering/fine-tuning/ /docs 302 +/developer/framework/engineering/messages /docs/threads 302 +/developer/framework/engineering/messages/ /docs/threads 302 +/developer/framework/engineering/models /docs/models 302 +/developer/framework/engineering/models/ /docs/models 302 +/developer/framework/engineering/prompts /docs 302 +/developer/framework/engineering/prompts/ /docs 302 +/developer/framework/engineering/threads /docs/threads 302 +/developer/framework/engineering/threads/ /docs/threads 302 +/developer/framework/product /docs 302 +/developer/framework/product/ /docs 302 +/developer/framework/product/chat /docs/threads 302 +/developer/framework/product/chat/ /docs/threads 302 +/developer/framework/product/hub /docs 302 +/developer/framework/product/hub/ /docs 302 +/developer/framework/product/jan /about 302 +/developer/framework/product/jan/ /about 302 +/developer/framework/product/settings /docs/settings 302 +/developer/framework/product/settings/ /docs/settings 302 +/developer/framework/product/system-monitor /docs 302 +/developer/framework/product/system-monitor/ /docs 302 +/developer/user-interface /docs 302 +/developer/user-interface/ /docs 302 +/docs/desktop /docs/desktop/windows 302 +/docs/desktop/ /docs/desktop/windows 302 +/docs/inferences/groq /docs/remote-models/groq 302 +/docs/inferences/groq/ /docs/remote-models/groq 302 +/docs/inferences/llamacpp /docs/built-in/llama-cpp 302 +/docs/inferences/llamacpp/ /docs/built-in/llama-cpp 302 +/docs/inferences/lmstudio /docs/local-models/lmstudio 302 +/docs/inferences/lmstudio/ /docs/local-models/lmstudio 302 +/docs/inferences/mistralai /docs/remote-models/mistralai 302 +/docs/inferences/mistralai/ /docs/remote-models/mistralai 302 +/docs/inferences/ollama /docs/local-models/ollama 302 +/docs/inferences/ollama/ /docs/local-models/ollama 302 +/docs/inferences/openai /docs/remote-models/openai 302 +/docs/inferences/openai/ /docs/remote-models/openai 302 +/docs/inferences/remote-server-integration /docs/remote-inference/generic-openai 302 +/docs/inferences/remote-server-integration/ /docs/remote-inference/generic-openai 302 +/docs/inferences/tensorrtllm /docs/built-in/tensorrt-llm 302 +/docs/inferences/tensorrtllm/ /docs/built-in/tensorrt-llm 302 +/docs/integrations/router /docs/remote-models/openrouter 302 +/docs/integrations/router/ /docs/remote-models/openrouter 302 +/docs/server /docs/local-api 302 +/docs/server/ /docs/local-api 302 +/features/ /docs 302 +/features /docs 302 +/features/local/ /docs/local-api 302 +/features/local /docs/local-api 302 +/guides/providers/tensorrt-llm /docs/built-in/tensorrt-llm 302 +/guides/providers/tensorrt-llm/ /docs/built-in/tensorrt-llm 302 +/hardware/recommendations/by-model/ /docs 302 +/hardware/recommendations/by-hardware/ /docs 302 +/product /docs 302 +/product/features /docs 302 +/product/features/agents-framework /docs 302 +/product/features/api-server /docs/local-api 302 +/product/features/data-security /docs 302 +/product/features/extensions-framework /docs/extensions 302 +/product/features/local /docs 302 +/product/features/remote /docs 302 +/product/home-server /docs/local-api 302 +/guides/providers/tensorrt-llm/ /docs/built-in/tensorrt-llm 302 +/docs/tools /docs/tools/retrieval 302 +/docs/local-inference/llamacpp /docs/built-in/llama-cpp 302 +/docs/local-inference/tensorrtllm /docs/built-in/tensorrt-llm 302 +/guides/using-server/server/ /docs/local-api 302 +/integrations/coding/vscode /integrations/coding/continue-dev 302 +/docs/integrations/interpreter /integrations/function-calling/interpreter 302 +/cortex/built-in/llama-cpp /docs 302 +/docs/desktop-installation/linux /docs/desktop/linux 302 +/docs/desktop-installation/windows /docs/desktop/windows 302 +/docs/desktop-installation/mac /docs/desktop/mac 302 +/desktop/ /docs/desktop 302 +/developer/ui/ /docs 302 +/docs/local-inference/lmstudio /docs/local-models/lmstudio 302 +/docs/local-inference/ollama /docs/local-models/ollama 302 +/docs/remote-inference/openai /docs/remote-models/openai 302 +/docs/remote-inference/groq /docs/remote-models/groq 302 +/docs/remote-inference/mistralai /docs/remote-models/mistralai 302 +/docs/remote-inference/openrouter /docs/remote-models/openrouter 302 +/docs/remote-inference/generic-openai /docs/remote-models/generic-openai 302 +/docs/desktop-installation /docs/desktop 302 +/hardware/concepts/gpu-and-vram/ /docs 302 +/hardware/recommendations/by-usecase/ /docs 302 +/about/how-we-work/strategy /about 302 +/docs/engineering/assistants/ /docs 302 +/cortex https://cortex.so/docs/ 301 +/cortex/quickstart https://cortex.so/docs/quickstart 301 +/cortex/hardware https://cortex.so/docs/hardware 301 +/cortex/installation https://cortex.so/docs/category/installation 301 +/cortex/installation/mac https://cortex.so/docs/instalation/mac 301 +/cortex/installation/windows https://cortex.so/docs/instalation/windows 301 +/cortex/installation/linux https://cortex.so/docs/instalation/linux 301 +/cortex/command-line https://cortex.so/docs/command-line 301 +/cortex/ts-library https://cortex.so/docs/ts-library 301 +/cortex/py-library https://cortex.so/docs/py-library 301 +/cortex/server https://cortex.so/docs/server 301 +/cortex/text-generation https://cortex.so/docs/text-generation 301 +/cortex/cli https://cortex.so/docs/cli/ 301 +/cortex/cli/init https://cortex.so/docs/cli/init 301 +/cortex/cli/pull https://cortex.so/docs/cli/pull 301 +/cortex/cli/run https://cortex.so/docs/cli/run 301 +/cortex/cli/models https://cortex.so/docs/cli/models/ 301 +/cortex/cli/models/download https://cortex.so/docs/cli/models/download 301 +/cortex/cli/models/list https://cortex.so/docs/cli/models/list 301 +/cortex/cli/models/get https://cortex.so/docs/cli/models/get 301 +/cortex/cli/models/update https://cortex.so/docs/cli/models/update 301 +/cortex/cli/models/start https://cortex.so/docs/cli/models/start 301 +/cortex/cli/models/stop https://cortex.so/docs/cli/models/stop 301 +/cortex/cli/models/remove https://cortex.so/docs/cli/models/remove 301 +/cortex/cli/ps https://cortex.so/docs/cli/ps 301 +/cortex/cli/chat https://cortex.so/docs/cli/chat 301 +/cortex/cli/kill https://cortex.so/docs/cli/kill 301 +/cortex/cli/serve https://cortex.so/docs/cli/serve 301 +/cortex/architecture https://cortex.so/docs/architecture 301 +/cortex/cortex-cpp https://cortex.so/docs/cortex-cpp 301 +/cortex/cortex-llamacpp https://cortex.so/docs/cortex-llamacpp 301 +/api-reference https://cortex.so/api-reference 301 +/docs/assistants /docs 302 +/docs/server-installation/ /docs/desktop 302 +/docs/server-installation/onprem /docs/desktop 302 +/docs/server-installation/aws /docs/desktop 302 +/docs/server-installation/gcp /docs/desktop 302 +/docs/server-installation/azure /docs/desktop 302 \ No newline at end of file diff --git a/docs/next-sitemap.config.js b/docs/next-sitemap.config.js new file mode 100644 index 0000000000..d3c5d3e231 --- /dev/null +++ b/docs/next-sitemap.config.js @@ -0,0 +1,7 @@ +/** @type {import('next-sitemap').IConfig} */ +module.exports = { + siteUrl: 'https://jan.ai/', + generateRobotsTxt: true, + changefreq: 'daily', + priority: 1.0, +} diff --git a/docs/next.config.mjs b/docs/next.config.mjs new file mode 100644 index 0000000000..92b8fb4610 --- /dev/null +++ b/docs/next.config.mjs @@ -0,0 +1,38 @@ +/** @type {import('next').NextConfig} */ + +import nextra from 'nextra' +import { remarkCodeHike } from '@code-hike/mdx' + +const withNextra = nextra({ + theme: 'nextra-theme-docs', + themeConfig: './theme.config.tsx', + defaultShowCopyCode: true, + latex: true, + mdxOptions: { + remarkPlugins: [ + [ + remarkCodeHike, + { + theme: 'dark-plus', + showCopyButton: true, + skipLanguages: ['mermaid'], + }, + ], + ], + }, +}) + +const nextConfig = { + reactStrictMode: true, + output: 'export', + env: { + GTM_ID: process.env.GTM_ID, + }, + transpilePackages: ['@scalar', 'react-tweet'], + images: { + formats: ['image/webp'], + unoptimized: true, + }, +} + +export default withNextra(nextConfig) diff --git a/docs/package.json b/docs/package.json new file mode 100644 index 0000000000..b2b74aba75 --- /dev/null +++ b/docs/package.json @@ -0,0 +1,62 @@ +{ + "name": "docs", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "npx serve@latest out", + "lint": "next lint", + "create:blogpost": "plop create-blogpost", + "postbuild": "next-sitemap" + }, + "dependencies": { + "@code-hike/mdx": "^0.9.0", + "@next/third-parties": "^14.1.4", + "@radix-ui/react-dialog": "^1.0.5", + "@radix-ui/react-icons": "^1.3.0", + "@radix-ui/react-tooltip": "^1.0.7", + "@scalar/api-reference-react": "^0.1.31", + "@theguild/remark-mermaid": "^0.0.6", + "autoprefixer": "^10.0.1", + "axios": "^1.6.8", + "date-fns": "^3.6.0", + "embla-carousel-auto-height": "^8.0.0", + "embla-carousel-auto-scroll": "^8.0.0", + "embla-carousel-autoplay": "^8.0.0", + "embla-carousel-react": "^8.0.0", + "fs": "^0.0.1-security", + "gray-matter": "^4.0.3", + "lucide-react": "^0.372.0", + "next": "^14.1.4", + "next-seo": "^6.5.0", + "next-sitemap": "^4.2.3", + "nextra": "^2.13.4", + "nextra-theme-docs": "^2.13.4", + "path": "^0.12.7", + "plop": "^4.0.1", + "plop-helper-date": "^1.0.0", + "react": "^18", + "react-dom": "^18", + "react-hook-form": "^7.51.1", + "react-icons": "^5.0.1", + "react-markdown": "^9.0.1", + "react-share": "^5.1.0", + "react-tweet": "^3.2.0", + "sass": "^1.72.0", + "sharp": "^0.33.3", + "tailwind-merge": "^2.2.2", + "tailwindcss": "^3.3.0" + }, + "devDependencies": { + "@types/node": "^20", + "@types/react": "^18", + "@types/react-dom": "^18", + "eslint": "^8", + "eslint-config-next": "14.1.4", + "postcss": "^8", + "prettier": "^3.2.5", + "typescript": "^5" + }, + "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e" +} diff --git a/docs/plopfile.js b/docs/plopfile.js new file mode 100644 index 0000000000..a31caa8898 --- /dev/null +++ b/docs/plopfile.js @@ -0,0 +1,64 @@ +const capitalize = (str) => { + return str.charAt(0).toUpperCase() + str.slice(1) +} + +const camelCase = (str) => { + return str.replace(/[-_](\w)/g, (_, c) => c.toUpperCase()) +} + +const categories = ['building-jan', 'research'] + +/** + * @param {import("plop").NodePlopAPI} plop + */ +module.exports = function main(plop) { + plop.setHelper('capitalize', (text) => { + return capitalize(camelCase(text)) + }) + + plop.load('plop-helper-date') + + plop.setGenerator('create-blogpost', { + description: 'Generates a blog post', + prompts: [ + { + type: 'list', + name: 'categories', + message: 'what is categories of blog post: ', + choices: categories, + }, + { + type: 'input', + name: 'slug', + message: 'Enter slug of blog post: ', + }, + { + type: 'input', + name: 'title', + message: 'Enter title of blog post: ', + }, + { + type: 'input', + name: 'description', + message: 'The description of blog post: ', + }, + ], + + actions(answers) { + const actions = [] + if (!answers) return actions + const { categories, slug, title, description } = answers + + actions.push({ + type: 'addMany', + templateFiles: 'templates/**', + destination: `./src/pages/post`, + globOptions: { dot: true }, + data: { categories, slug, title, description }, + abortOnFail: true, + }) + + return actions + }, + }) +} diff --git a/docs/postcss.config.js b/docs/postcss.config.js new file mode 100644 index 0000000000..33ad091d26 --- /dev/null +++ b/docs/postcss.config.js @@ -0,0 +1,6 @@ +module.exports = { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +} diff --git a/docs/public/assets/fonts/PPEditorialNew-Regular.otf b/docs/public/assets/fonts/PPEditorialNew-Regular.otf new file mode 100644 index 0000000000..778c9025d9 Binary files /dev/null and b/docs/public/assets/fonts/PPEditorialNew-Regular.otf differ diff --git a/docs/public/assets/fonts/PPEditorialNew-RegularItalic.otf b/docs/public/assets/fonts/PPEditorialNew-RegularItalic.otf new file mode 100644 index 0000000000..d20c33a638 Binary files /dev/null and b/docs/public/assets/fonts/PPEditorialNew-RegularItalic.otf differ diff --git a/docs/public/assets/fonts/PPEditorialNew-Ultrabold.otf b/docs/public/assets/fonts/PPEditorialNew-Ultrabold.otf new file mode 100644 index 0000000000..507b09150d Binary files /dev/null and b/docs/public/assets/fonts/PPEditorialNew-Ultrabold.otf differ diff --git a/docs/public/assets/fonts/PPEditorialNew-UltraboldItalic.otf b/docs/public/assets/fonts/PPEditorialNew-UltraboldItalic.otf new file mode 100644 index 0000000000..58282cceb6 Binary files /dev/null and b/docs/public/assets/fonts/PPEditorialNew-UltraboldItalic.otf differ diff --git a/docs/public/assets/fonts/PPEditorialNew-Ultralight.otf b/docs/public/assets/fonts/PPEditorialNew-Ultralight.otf new file mode 100644 index 0000000000..59addeb80b Binary files /dev/null and b/docs/public/assets/fonts/PPEditorialNew-Ultralight.otf differ diff --git a/docs/public/assets/fonts/PPEditorialNew-UltralightItalic.otf b/docs/public/assets/fonts/PPEditorialNew-UltralightItalic.otf new file mode 100644 index 0000000000..d3e636b53a Binary files /dev/null and b/docs/public/assets/fonts/PPEditorialNew-UltralightItalic.otf differ diff --git a/docs/public/assets/images/changelog/Jan_v0.4.3.gif b/docs/public/assets/images/changelog/Jan_v0.4.3.gif new file mode 100644 index 0000000000..c6dc943f74 Binary files /dev/null and b/docs/public/assets/images/changelog/Jan_v0.4.3.gif differ diff --git a/docs/public/assets/images/changelog/Jan_v0.4.5.gif b/docs/public/assets/images/changelog/Jan_v0.4.5.gif new file mode 100644 index 0000000000..17ed2821b7 Binary files /dev/null and b/docs/public/assets/images/changelog/Jan_v0.4.5.gif differ diff --git a/docs/public/assets/images/changelog/jan release v0.4.12.jpg b/docs/public/assets/images/changelog/jan release v0.4.12.jpg new file mode 100644 index 0000000000..d208828412 Binary files /dev/null and b/docs/public/assets/images/changelog/jan release v0.4.12.jpg differ diff --git a/docs/public/assets/images/changelog/jan-v0-4-14-phi3.gif b/docs/public/assets/images/changelog/jan-v0-4-14-phi3.gif new file mode 100644 index 0000000000..845554e1c9 Binary files /dev/null and b/docs/public/assets/images/changelog/jan-v0-4-14-phi3.gif differ diff --git a/docs/public/assets/images/changelog/jan-v0.5.4.jpg b/docs/public/assets/images/changelog/jan-v0.5.4.jpg new file mode 100644 index 0000000000..2eff7e96ae Binary files /dev/null and b/docs/public/assets/images/changelog/jan-v0.5.4.jpg differ diff --git a/docs/public/assets/images/changelog/jan_cohere_commandr.gif b/docs/public/assets/images/changelog/jan_cohere_commandr.gif new file mode 100644 index 0000000000..d22e1e6ce8 Binary files /dev/null and b/docs/public/assets/images/changelog/jan_cohere_commandr.gif differ diff --git a/docs/public/assets/images/changelog/jan_hugging_face.gif b/docs/public/assets/images/changelog/jan_hugging_face.gif new file mode 100644 index 0000000000..de98689b37 Binary files /dev/null and b/docs/public/assets/images/changelog/jan_hugging_face.gif differ diff --git a/docs/public/assets/images/changelog/jan_llama3.gif b/docs/public/assets/images/changelog/jan_llama3.gif new file mode 100644 index 0000000000..aee9415e84 Binary files /dev/null and b/docs/public/assets/images/changelog/jan_llama3.gif differ diff --git a/docs/public/assets/images/changelog/jan_mistral_api.gif b/docs/public/assets/images/changelog/jan_mistral_api.gif new file mode 100644 index 0000000000..cc44ae1678 Binary files /dev/null and b/docs/public/assets/images/changelog/jan_mistral_api.gif differ diff --git a/docs/public/assets/images/changelog/jan_nvidia_nim_support.gif b/docs/public/assets/images/changelog/jan_nvidia_nim_support.gif new file mode 100644 index 0000000000..d67edfc95c Binary files /dev/null and b/docs/public/assets/images/changelog/jan_nvidia_nim_support.gif differ diff --git a/docs/public/assets/images/changelog/jan_product_update_feature.gif b/docs/public/assets/images/changelog/jan_product_update_feature.gif new file mode 100644 index 0000000000..da17adbdd6 Binary files /dev/null and b/docs/public/assets/images/changelog/jan_product_update_feature.gif differ diff --git a/docs/public/assets/images/changelog/jan_supports_claude_3_5.gif b/docs/public/assets/images/changelog/jan_supports_claude_3_5.gif new file mode 100644 index 0000000000..9c9ea8c8b8 Binary files /dev/null and b/docs/public/assets/images/changelog/jan_supports_claude_3_5.gif differ diff --git a/docs/public/assets/images/changelog/jan_update_groq.gif b/docs/public/assets/images/changelog/jan_update_groq.gif new file mode 100644 index 0000000000..3527bf3b6e Binary files /dev/null and b/docs/public/assets/images/changelog/jan_update_groq.gif differ diff --git a/docs/public/assets/images/changelog/jan_update_latex.gif b/docs/public/assets/images/changelog/jan_update_latex.gif new file mode 100644 index 0000000000..11a6fc4f6e Binary files /dev/null and b/docs/public/assets/images/changelog/jan_update_latex.gif differ diff --git a/docs/public/assets/images/changelog/jan_v0.4.13_update.gif b/docs/public/assets/images/changelog/jan_v0.4.13_update.gif new file mode 100644 index 0000000000..5141eddfc4 Binary files /dev/null and b/docs/public/assets/images/changelog/jan_v0.4.13_update.gif differ diff --git a/docs/public/assets/images/changelog/jan_v0.5.0.gif b/docs/public/assets/images/changelog/jan_v0.5.0.gif new file mode 100644 index 0000000000..305c7d657a Binary files /dev/null and b/docs/public/assets/images/changelog/jan_v0.5.0.gif differ diff --git a/docs/public/assets/images/changelog/jan_v0_4_13_openai_gpt4o.gif b/docs/public/assets/images/changelog/jan_v0_4_13_openai_gpt4o.gif new file mode 100644 index 0000000000..480565cc04 Binary files /dev/null and b/docs/public/assets/images/changelog/jan_v0_4_13_openai_gpt4o.gif differ diff --git a/docs/public/assets/images/changelog/janv0.5.3.gif b/docs/public/assets/images/changelog/janv0.5.3.gif new file mode 100644 index 0000000000..c2226a2004 Binary files /dev/null and b/docs/public/assets/images/changelog/janv0.5.3.gif differ diff --git a/docs/public/assets/images/general/homebrew-dark.svg b/docs/public/assets/images/general/homebrew-dark.svg new file mode 100644 index 0000000000..39a598f30b --- /dev/null +++ b/docs/public/assets/images/general/homebrew-dark.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/docs/public/assets/images/general/homebrew-white.svg b/docs/public/assets/images/general/homebrew-white.svg new file mode 100644 index 0000000000..6145752b3d --- /dev/null +++ b/docs/public/assets/images/general/homebrew-white.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/docs/public/assets/images/general/logo-mark.svg b/docs/public/assets/images/general/logo-mark.svg new file mode 100644 index 0000000000..188c822f64 --- /dev/null +++ b/docs/public/assets/images/general/logo-mark.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/docs/public/assets/images/general/og-image.png b/docs/public/assets/images/general/og-image.png new file mode 100644 index 0000000000..c601470791 Binary files /dev/null and b/docs/public/assets/images/general/og-image.png differ diff --git a/docs/public/assets/images/general/og-throughput-benchmark.png b/docs/public/assets/images/general/og-throughput-benchmark.png new file mode 100644 index 0000000000..6bb63d03ca Binary files /dev/null and b/docs/public/assets/images/general/og-throughput-benchmark.png differ diff --git a/docs/public/assets/images/homepage/app-frame-dark-fixed.webp b/docs/public/assets/images/homepage/app-frame-dark-fixed.webp new file mode 100644 index 0000000000..638f9347ac Binary files /dev/null and b/docs/public/assets/images/homepage/app-frame-dark-fixed.webp differ diff --git a/docs/public/assets/images/homepage/app-frame-light-fixed.png b/docs/public/assets/images/homepage/app-frame-light-fixed.png new file mode 100644 index 0000000000..ec2dc3a87b Binary files /dev/null and b/docs/public/assets/images/homepage/app-frame-light-fixed.png differ diff --git a/docs/public/assets/images/homepage/app-frame-light-fixed.webp b/docs/public/assets/images/homepage/app-frame-light-fixed.webp new file mode 100644 index 0000000000..6db003e43f Binary files /dev/null and b/docs/public/assets/images/homepage/app-frame-light-fixed.webp differ diff --git a/docs/public/assets/images/homepage/assistant-dark.png b/docs/public/assets/images/homepage/assistant-dark.png new file mode 100644 index 0000000000..f7d737a518 Binary files /dev/null and b/docs/public/assets/images/homepage/assistant-dark.png differ diff --git a/docs/public/assets/images/homepage/assistant-light.png b/docs/public/assets/images/homepage/assistant-light.png new file mode 100644 index 0000000000..6d50e29d67 Binary files /dev/null and b/docs/public/assets/images/homepage/assistant-light.png differ diff --git a/docs/public/assets/images/homepage/extension-dark.png b/docs/public/assets/images/homepage/extension-dark.png new file mode 100644 index 0000000000..b85e16cf45 Binary files /dev/null and b/docs/public/assets/images/homepage/extension-dark.png differ diff --git a/docs/public/assets/images/homepage/extension-light.png b/docs/public/assets/images/homepage/extension-light.png new file mode 100644 index 0000000000..55677a494a Binary files /dev/null and b/docs/public/assets/images/homepage/extension-light.png differ diff --git a/docs/public/assets/images/homepage/features01.png b/docs/public/assets/images/homepage/features01.png new file mode 100644 index 0000000000..30174f13fd Binary files /dev/null and b/docs/public/assets/images/homepage/features01.png differ diff --git a/docs/public/assets/images/homepage/features01.webp b/docs/public/assets/images/homepage/features01.webp new file mode 100644 index 0000000000..1b19799950 Binary files /dev/null and b/docs/public/assets/images/homepage/features01.webp differ diff --git a/docs/public/assets/images/homepage/features01dark.png b/docs/public/assets/images/homepage/features01dark.png new file mode 100644 index 0000000000..f556da3200 Binary files /dev/null and b/docs/public/assets/images/homepage/features01dark.png differ diff --git a/docs/public/assets/images/homepage/features01dark.webp b/docs/public/assets/images/homepage/features01dark.webp new file mode 100644 index 0000000000..7d71cb5315 Binary files /dev/null and b/docs/public/assets/images/homepage/features01dark.webp differ diff --git a/docs/public/assets/images/homepage/features02.png b/docs/public/assets/images/homepage/features02.png new file mode 100644 index 0000000000..56688c0507 Binary files /dev/null and b/docs/public/assets/images/homepage/features02.png differ diff --git a/docs/public/assets/images/homepage/features02.webp b/docs/public/assets/images/homepage/features02.webp new file mode 100644 index 0000000000..eed502a146 Binary files /dev/null and b/docs/public/assets/images/homepage/features02.webp differ diff --git a/docs/public/assets/images/homepage/features02dark.png b/docs/public/assets/images/homepage/features02dark.png new file mode 100644 index 0000000000..92943878fe Binary files /dev/null and b/docs/public/assets/images/homepage/features02dark.png differ diff --git a/docs/public/assets/images/homepage/features02dark.webp b/docs/public/assets/images/homepage/features02dark.webp new file mode 100644 index 0000000000..3f6bf854de Binary files /dev/null and b/docs/public/assets/images/homepage/features02dark.webp differ diff --git a/docs/public/assets/images/homepage/features03.png b/docs/public/assets/images/homepage/features03.png new file mode 100644 index 0000000000..290a8812c6 Binary files /dev/null and b/docs/public/assets/images/homepage/features03.png differ diff --git a/docs/public/assets/images/homepage/features03.webp b/docs/public/assets/images/homepage/features03.webp new file mode 100644 index 0000000000..a735004797 Binary files /dev/null and b/docs/public/assets/images/homepage/features03.webp differ diff --git a/docs/public/assets/images/homepage/features03dark.png b/docs/public/assets/images/homepage/features03dark.png new file mode 100644 index 0000000000..3afff92906 Binary files /dev/null and b/docs/public/assets/images/homepage/features03dark.png differ diff --git a/docs/public/assets/images/homepage/features03dark.webp b/docs/public/assets/images/homepage/features03dark.webp new file mode 100644 index 0000000000..a280eea49c Binary files /dev/null and b/docs/public/assets/images/homepage/features03dark.webp differ diff --git a/docs/public/assets/images/homepage/features04.png b/docs/public/assets/images/homepage/features04.png new file mode 100644 index 0000000000..b9e08f3a2a Binary files /dev/null and b/docs/public/assets/images/homepage/features04.png differ diff --git a/docs/public/assets/images/homepage/features04.webp b/docs/public/assets/images/homepage/features04.webp new file mode 100644 index 0000000000..e9ef1f1326 Binary files /dev/null and b/docs/public/assets/images/homepage/features04.webp differ diff --git a/docs/public/assets/images/homepage/features04dark.png b/docs/public/assets/images/homepage/features04dark.png new file mode 100644 index 0000000000..997dd42bad Binary files /dev/null and b/docs/public/assets/images/homepage/features04dark.png differ diff --git a/docs/public/assets/images/homepage/features04dark.webp b/docs/public/assets/images/homepage/features04dark.webp new file mode 100644 index 0000000000..d4a8641a14 Binary files /dev/null and b/docs/public/assets/images/homepage/features04dark.webp differ diff --git a/docs/public/assets/images/homepage/features05.png b/docs/public/assets/images/homepage/features05.png new file mode 100644 index 0000000000..b60c655744 Binary files /dev/null and b/docs/public/assets/images/homepage/features05.png differ diff --git a/docs/public/assets/images/homepage/features05.webp b/docs/public/assets/images/homepage/features05.webp new file mode 100644 index 0000000000..6a6e57c6f8 Binary files /dev/null and b/docs/public/assets/images/homepage/features05.webp differ diff --git a/docs/public/assets/images/homepage/features05dark.png b/docs/public/assets/images/homepage/features05dark.png new file mode 100644 index 0000000000..a4bd8e05c8 Binary files /dev/null and b/docs/public/assets/images/homepage/features05dark.png differ diff --git a/docs/public/assets/images/homepage/features05dark.webp b/docs/public/assets/images/homepage/features05dark.webp new file mode 100644 index 0000000000..9ca8731a8c Binary files /dev/null and b/docs/public/assets/images/homepage/features05dark.webp differ diff --git a/docs/public/assets/images/homepage/glow.png b/docs/public/assets/images/homepage/glow.png new file mode 100644 index 0000000000..099422e51e Binary files /dev/null and b/docs/public/assets/images/homepage/glow.png differ diff --git a/docs/public/assets/images/homepage/icon.png b/docs/public/assets/images/homepage/icon.png new file mode 100644 index 0000000000..786eada6b5 Binary files /dev/null and b/docs/public/assets/images/homepage/icon.png differ diff --git a/docs/public/assets/images/homepage/lifehacker-dark.png b/docs/public/assets/images/homepage/lifehacker-dark.png new file mode 100644 index 0000000000..69f26b9d40 Binary files /dev/null and b/docs/public/assets/images/homepage/lifehacker-dark.png differ diff --git a/docs/public/assets/images/homepage/lifehacker-light.png b/docs/public/assets/images/homepage/lifehacker-light.png new file mode 100644 index 0000000000..a9b31c1ed2 Binary files /dev/null and b/docs/public/assets/images/homepage/lifehacker-light.png differ diff --git a/docs/public/assets/images/homepage/mac-system-black.svg b/docs/public/assets/images/homepage/mac-system-black.svg new file mode 100644 index 0000000000..0b866815d7 --- /dev/null +++ b/docs/public/assets/images/homepage/mac-system-black.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/docs/public/assets/images/homepage/mac-system-white.svg b/docs/public/assets/images/homepage/mac-system-white.svg new file mode 100644 index 0000000000..4539db6eb2 --- /dev/null +++ b/docs/public/assets/images/homepage/mac-system-white.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/docs/public/assets/images/homepage/mapbase-dark.png b/docs/public/assets/images/homepage/mapbase-dark.png new file mode 100644 index 0000000000..cecde27a81 Binary files /dev/null and b/docs/public/assets/images/homepage/mapbase-dark.png differ diff --git a/docs/public/assets/images/homepage/mapbase-dark.webp b/docs/public/assets/images/homepage/mapbase-dark.webp new file mode 100644 index 0000000000..b59026f519 Binary files /dev/null and b/docs/public/assets/images/homepage/mapbase-dark.webp differ diff --git a/docs/public/assets/images/homepage/mapbase-light.png b/docs/public/assets/images/homepage/mapbase-light.png new file mode 100644 index 0000000000..bd38d8a2b8 Binary files /dev/null and b/docs/public/assets/images/homepage/mapbase-light.png differ diff --git a/docs/public/assets/images/homepage/mapbase-light.webp b/docs/public/assets/images/homepage/mapbase-light.webp new file mode 100644 index 0000000000..413c98e844 Binary files /dev/null and b/docs/public/assets/images/homepage/mapbase-light.webp differ diff --git a/docs/public/favicon.ico b/docs/public/favicon.ico new file mode 100644 index 0000000000..ca006fa7d5 Binary files /dev/null and b/docs/public/favicon.ico differ diff --git a/docs/public/openapi/jan.json b/docs/public/openapi/jan.json new file mode 100644 index 0000000000..c3abaf7609 --- /dev/null +++ b/docs/public/openapi/jan.json @@ -0,0 +1,2131 @@ +{ + "openapi": "3.0.0", + "paths": { + "/messages": { + "post": { + "operationId": "MessagesController_create", + "summary": "Create message", + "description": "Creates a message in a thread.", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateMessageDto" + } + } + } + }, + "responses": { + "201": { + "description": "The message has been successfully created.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateMessageDto" + } + } + } + } + }, + "tags": [ + "Messages" + ] + }, + "get": { + "operationId": "MessagesController_findAll", + "summary": "List messages", + "description": "Retrieves all the messages in a thread.", + "parameters": [], + "responses": { + "200": { + "description": "Ok", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListMessagesResponseDto" + } + } + } + } + }, + "tags": [ + "Messages" + ] + } + }, + "/messages/{id}": { + "get": { + "operationId": "MessagesController_findOne", + "summary": "Retrieve message", + "description": "Retrieves a specific message defined by a message's `id`.", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "The unique identifier of the message.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Ok", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetMessageResponseDto" + } + } + } + } + }, + "tags": [ + "Messages" + ] + }, + "patch": { + "operationId": "MessagesController_update", + "summary": "Update message", + "description": "Updates a specific message defined by a message's `id`.", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "The unique identifier of the message.", + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateMessageDto" + } + } + } + }, + "responses": { + "200": { + "description": "The message has been successfully updated.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateMessageDto" + } + } + } + } + }, + "tags": [ + "Messages" + ] + }, + "delete": { + "operationId": "MessagesController_remove", + "summary": "Delete message", + "description": "Deletes a specific message defined by a message's `id`.", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "The unique identifier of the message.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Successfully deleted the message.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeleteMessageResponseDto" + } + } + } + } + }, + "tags": [ + "Messages" + ] + } + }, + "/threads": { + "post": { + "operationId": "ThreadsController_create", + "summary": "Create thread", + "description": "Creates a new thread.", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateThreadDto" + } + } + } + }, + "responses": { + "201": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ThreadEntity" + } + } + } + } + }, + "tags": [ + "Threads" + ] + }, + "get": { + "operationId": "ThreadsController_findAll", + "summary": "List threads", + "description": "Lists all the available threads along with its configurations.", + "parameters": [], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ThreadEntity" + } + } + } + } + } + }, + "tags": [ + "Threads" + ] + } + }, + "/threads/{id}": { + "get": { + "operationId": "ThreadsController_findOne", + "summary": "Get thread", + "description": "Retrieves a thread along with its configurations.", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "The unique identifier of the thread.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Ok", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetThreadResponseDto" + } + } + } + } + }, + "tags": [ + "Threads" + ] + }, + "patch": { + "operationId": "ThreadsController_update", + "summary": "Update thread", + "description": "Updates a thread's configurations.", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "The unique identifier of the thread.", + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateThreadDto" + } + } + } + }, + "responses": { + "200": { + "description": "The thread has been successfully updated.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateThreadDto" + } + } + } + } + }, + "tags": [ + "Threads" + ] + }, + "delete": { + "operationId": "ThreadsController_remove", + "summary": "Delete thread", + "description": "Deletes a specific thread defined by a thread `id` .", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "The unique identifier of the thread.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "The thread has been successfully deleted.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeleteThreadResponseDto" + } + } + } + } + }, + "tags": [ + "Threads" + ] + } + }, + "/models": { + "post": { + "operationId": "ModelsController_create", + "summary": "Create model", + "description": "Creates a model `.json` instance file manually.", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateModelDto" + } + } + } + }, + "responses": { + "201": { + "description": "The model has been successfully created.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StartModelSuccessDto" + } + } + } + } + }, + "tags": [ + "Models" + ] + }, + "get": { + "operationId": "ModelsController_findAll", + "summary": "List models", + "description": "Lists the currently available models, and provides basic information about each one such as the owner and availability. [Equivalent to OpenAI's list model](https://platform.openai.com/docs/api-reference/models/list).", + "parameters": [], + "responses": { + "200": { + "description": "Ok", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListModelsResponseDto" + } + } + } + } + }, + "tags": [ + "Models" + ] + } + }, + "/models/{modelId}/start": { + "post": { + "operationId": "ModelsController_startModel", + "summary": "Start model", + "description": "Starts a model operation defined by a model `id`.", + "parameters": [ + { + "name": "modelId", + "required": true, + "in": "path", + "description": "The unique identifier of the model.", + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelSettingParamsDto" + } + } + } + }, + "responses": { + "200": { + "description": "The model has been successfully started.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StartModelSuccessDto" + } + } + } + } + }, + "tags": [ + "Models" + ] + } + }, + "/models/{modelId}/stop": { + "post": { + "operationId": "ModelsController_stopModel", + "summary": "Stop model", + "description": "Stops a model operation defined by a model `id`.", + "parameters": [ + { + "name": "modelId", + "required": true, + "in": "path", + "description": "The unique identifier of the model.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "The model has been successfully stopped.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StartModelSuccessDto" + } + } + } + } + }, + "tags": [ + "Models" + ] + } + }, + "/models/download/{modelId}": { + "get": { + "operationId": "ModelsController_downloadModel", + "summary": "Download model", + "description": "Downloads a specific model instance.", + "parameters": [ + { + "name": "modelId", + "required": true, + "in": "path", + "description": "The unique identifier of the model.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Ok", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DownloadModelResponseDto" + } + } + } + } + }, + "tags": [ + "Models" + ] + } + }, + "/models/{id}": { + "get": { + "operationId": "ModelsController_findOne", + "summary": "Get model", + "description": "Retrieves a model instance, providing basic information about the model such as the owner and permissions. [Equivalent to OpenAI's list model](https://platform.openai.com/docs/api-reference/models/retrieve).", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "The unique identifier of the model.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Ok", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelDto" + } + } + } + } + }, + "tags": [ + "Models" + ] + }, + "patch": { + "operationId": "ModelsController_update", + "summary": "Update model", + "description": "Updates a model instance defined by a model's `id`.", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "The unique identifier of the model.", + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateModelDto" + } + } + } + }, + "responses": { + "200": { + "description": "The model has been successfully updated.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateModelDto" + } + } + } + } + }, + "tags": [ + "Models" + ] + }, + "delete": { + "operationId": "ModelsController_remove", + "summary": "Delete model", + "description": "Deletes a model. [Equivalent to OpenAI's delete model](https://platform.openai.com/docs/api-reference/models/delete).", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "The unique identifier of the model.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "The model has been successfully deleted.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeleteModelResponseDto" + } + } + } + } + }, + "tags": [ + "Models" + ] + } + }, + "/chat/completions": { + "post": { + "operationId": "ChatController_create", + "summary": "Create chat completion", + "description": "Creates a model response for the given conversation.", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateChatCompletionDto" + } + } + } + }, + "responses": { + "200": { + "description": "Ok", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ChatCompletionResponseDto" + } + } + } + } + }, + "tags": [ + "Inference" + ] + } + }, + "/assistants": { + "post": { + "operationId": "AssistantsController_create", + "summary": "Create assistant", + "description": "Creates a new assistant.", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateAssistantDto" + } + } + } + }, + "responses": { + "201": { + "description": "The assistant has been successfully created." + } + }, + "tags": [ + "Assistants" + ] + }, + "get": { + "operationId": "AssistantsController_findAll", + "summary": "List assistants", + "description": "Retrieves all the available assistants along with their settings.", + "parameters": [], + "responses": { + "200": { + "description": "Ok", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AssistantEntity" + } + } + } + } + } + }, + "tags": [ + "Assistants" + ] + } + }, + "/assistants/{id}": { + "get": { + "operationId": "AssistantsController_findOne", + "summary": "Get assistant", + "description": "Retrieves a specific assistant defined by an assistant's `id`.", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "The unique identifier of the assistant.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Ok", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AssistantEntity" + } + } + } + } + }, + "tags": [ + "Assistants" + ] + }, + "delete": { + "operationId": "AssistantsController_remove", + "summary": "Delete assistant", + "description": "Deletes a specific assistant defined by an assistant's `id`.", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "The unique identifier of the assistant.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "The assistant has been successfully deleted.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeleteAssistantResponseDto" + } + } + } + } + }, + "tags": [ + "Assistants" + ] + } + } + }, + "info": { + "title": "Cortex API", + "description": "Cortex API provides a command-line interface (CLI) for seamless interaction with large language models (LLMs). Fully compatible with the [OpenAI API](https://platform.openai.com/docs/api-reference), it enables straightforward command execution and management of LLM interactions.", + "version": "1.0", + "contact": {} + }, + "tags": [ + { + "name": "Inference", + "description": "This endpoint initiates interaction with a Language Learning Model (LLM)." + }, + { + "name": "Assistants", + "description": "These endpoints manage the lifecycle of an Assistant within a conversation thread." + }, + { + "name": "Models", + "description": "These endpoints provide a list and descriptions of all available models within the Cortex framework." + }, + { + "name": "Messages", + "description": "These endpoints manage the retrieval and storage of conversation content, including responses from LLMs and other metadata related to chat interactions." + }, + { + "name": "Threads", + "description": "These endpoints handle the creation, retrieval, updating, and deletion of conversation threads." + } + ], + "servers": [ + { + "url": "http://localhost:1337" + }, + { + "url": "http://localhost:1337/v1" + } + ], + "components": { + "schemas": { + "ContentValueDto": { + "type": "object", + "properties": { + "value": { + "type": "string", + "description": "The text's value." + }, + "annotations": { + "description": "The text's annotation that categorize the text.", + "type": "array", + "items": { + "type": "string" + } + }, + "name": { + "type": "string", + "description": "The name or title of the text." + }, + "size": { + "type": "number", + "description": "The text's size in bytes." + } + }, + "required": [ + "value", + "annotations" + ] + }, + "ThreadContentDto": { + "type": "object", + "properties": { + "type": { + "enum": [ + "text", + "image", + "pdf" + ], + "type": "string", + "description": "The type of content." + }, + "text": { + "description": "The content details.", + "allOf": [ + { + "$ref": "#/components/schemas/ContentValueDto" + } + ] + } + }, + "required": [ + "type", + "text" + ] + }, + "CreateMessageDto": { + "type": "object", + "properties": { + "thread_id": { + "type": "string", + "description": "The ID of the thread to which the message will be posted." + }, + "assistant_id": { + "type": "string", + "description": "The assistant's unique identifier." + }, + "role": { + "enum": [ + "system", + "assistant", + "user" + ], + "type": "string", + "description": "The sources of the messages." + }, + "content": { + "description": "The content of the messages.", + "type": "array", + "items": { + "$ref": "#/components/schemas/ThreadContentDto" + } + }, + "status": { + "enum": [ + "ready", + "pending", + "error", + "stopped" + ], + "type": "string", + "description": "Current status of the message." + }, + "metadata": { + "type": "object", + "description": "Optional dictionary for additional unstructured message information." + }, + "type": { + "type": "string", + "description": "Type of the message." + }, + "error_code": { + "enum": [ + "invalid_api_key", + "insufficient_quota", + "invalid_request_error", + "unknown" + ], + "type": "string", + "description": "Specifies the cause of any error." + } + }, + "required": [ + "thread_id", + "role", + "content", + "status" + ] + }, + "ListMessageObjectDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "msg_abc123", + "description": "The identifier of the message." + }, + "object": { + "type": "string", + "example": "thread.message", + "description": "Type of the object, indicating it's a thread message." + }, + "created_at": { + "type": "integer", + "example": 1699017614, + "description": "Unix timestamp representing the creation time of the message." + }, + "thread_id": { + "type": "string", + "example": "thread_abc123", + "description": "Identifier of the thread to which this message belongs." + }, + "role": { + "type": "string", + "example": "user", + "description": "Role of the sender, either 'user' or 'assistant'." + }, + "file_ids": { + "description": "Array of file IDs associated with the message, if any.", + "example": [], + "type": "array", + "items": { + "type": "string" + } + }, + "assistant_id": { + "type": "string", + "nullable": true, + "description": "Identifier of the assistant involved in the message, if applicable.", + "example": null + }, + "run_id": { + "type": "string", + "nullable": true, + "description": "Run ID associated with the message, if applicable.", + "example": null + }, + "metadata": { + "type": "object", + "example": {}, + "description": "Metadata associated with the message." + } + }, + "required": [ + "id", + "object", + "created_at", + "thread_id", + "role", + "file_ids", + "assistant_id", + "run_id", + "metadata" + ] + }, + "ListMessagesResponseDto": { + "type": "object", + "properties": { + "object": { + "type": "string", + "example": "list", + "description": "Type of the object, indicating it's a list." + }, + "data": { + "description": "Array of message objects.", + "type": "array", + "items": { + "$ref": "#/components/schemas/ListMessageObjectDto" + } + }, + "first_id": { + "type": "string", + "example": "msg_abc123", + "description": "Identifier of the first message in the list." + }, + "last_id": { + "type": "string", + "example": "msg_abc456", + "description": "Identifier of the last message in the list." + }, + "has_more": { + "type": "boolean", + "example": false, + "description": "Indicates whether there are more messages to retrieve." + } + }, + "required": [ + "object", + "data", + "first_id", + "last_id", + "has_more" + ] + }, + "ContentDto": { + "type": "object", + "properties": { + "type": { + "type": "string", + "example": "text", + "description": "Type of content, e.g., \"text\"." + }, + "text": { + "type": "object", + "example": { + "value": "How does AI work? Explain it in simple terms.", + "annotations": [] + }, + "description": "Text content of the message along with any annotations." + } + }, + "required": [ + "type", + "text" + ] + }, + "GetMessageResponseDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "msg_abc123", + "description": "The identifier of the message." + }, + "object": { + "type": "string", + "example": "thread.message", + "description": "Type of the object, indicating it's a thread message.", + "default": "thread.message" + }, + "created_at": { + "type": "integer", + "example": 1699017614, + "description": "Unix timestamp representing the creation time of the message." + }, + "thread_id": { + "type": "string", + "example": "thread_abc123", + "description": "Identifier of the thread to which this message belongs." + }, + "role": { + "type": "string", + "example": "user", + "description": "Role of the sender, either 'user' or 'assistant'." + }, + "content": { + "description": "Array of content objects detailing the message content.", + "type": "array", + "items": { + "$ref": "#/components/schemas/ContentDto" + } + }, + "file_ids": { + "example": [], + "description": "Array of file IDs associated with the message, if any.", + "type": "array", + "items": { + "type": "string" + } + }, + "assistant_id": { + "type": "string", + "nullable": true, + "example": null, + "description": "Identifier of the assistant involved in the message, if applicable." + }, + "run_id": { + "type": "string", + "nullable": true, + "example": null, + "description": "Run ID associated with the message, if applicable." + }, + "metadata": { + "type": "object", + "example": {}, + "description": "Metadata associated with the message." + } + }, + "required": [ + "id", + "object", + "created_at", + "thread_id", + "role", + "content", + "file_ids", + "assistant_id", + "run_id", + "metadata" + ] + }, + "UpdateMessageDto": { + "type": "object", + "properties": {} + }, + "DeleteMessageResponseDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "message_123", + "description": "The identifier of the message that was deleted." + }, + "object": { + "type": "string", + "example": "message", + "description": "Type of the object, indicating it's a message.", + "default": "message" + }, + "deleted": { + "type": "boolean", + "example": true, + "description": "Indicates whether the message was successfully deleted." + } + }, + "required": [ + "id", + "object", + "deleted" + ] + }, + "ModelSettingParamsDto": { + "type": "object", + "properties": { + "ctx_len": { + "type": "number", + "description": "Sets the maximum input the model can use to generate a response, it varies with the model used." + }, + "ngl": { + "type": "number", + "description": "Determines GPU layer usage." + }, + "embedding": { + "type": "boolean", + "description": "Enables embedding utilization for tasks like document-enhanced chat in RAG-based applications." + }, + "n_parallel": { + "type": "number", + "description": "Number of parallel processing units to use." + }, + "cpu_threads": { + "type": "number", + "description": "Determines CPU inference threads, limited by hardware and OS. " + }, + "prompt_template": { + "type": "string", + "description": "A predefined text or framework that guides the AI model's response generation." + }, + "system_prompt": { + "type": "string", + "description": "Specific prompt used by the system for generating model outputs." + }, + "ai_prompt": { + "type": "string", + "description": "The prompt fed into the AI, typically to guide or specify the nature of the content it should generate." + }, + "user_prompt": { + "type": "string", + "description": "Customizable prompt input by the user to direct the model’s output generation." + }, + "llama_model_path": { + "type": "string", + "description": "File path to a specific llama model." + }, + "mmproj": { + "type": "string", + "description": "The mmproj is a projection matrix that is used to project the embeddings from CLIP into tokens usable by llama/mistral." + }, + "cont_batching": { + "type": "boolean", + "description": "Controls continuous batching, enhancing throughput for LLM inference." + }, + "vision_model": { + "type": "boolean", + "description": "Specifies if a vision-based model (for image processing) should be used." + }, + "text_model": { + "type": "boolean", + "description": "Specifies if a text-based model is to be utilized, for tasks like text generation or analysis." + } + } + }, + "ModelRuntimeParamsDto": { + "type": "object", + "properties": { + "temperature": { + "type": "number", + "description": "Influences the randomness of the model's output." + }, + "token_limit": { + "type": "number", + "description": "Sets the maximum number of pieces (like words or characters) the model will produce at one time." + }, + "top_k": { + "type": "number", + "description": "Limits the model's choices when it's deciding what to write next." + }, + "top_p": { + "type": "number", + "description": "Sets probability threshold for more relevant outputs." + }, + "stream": { + "type": "boolean", + "description": "Determines the format for output generation. If set to `true`, the output is generated continuously, allowing for real-time streaming of responses. If set to `false`, the output is delivered in a single JSON file." + }, + "max_tokens": { + "type": "number", + "description": "Sets the upper limit on the number of tokens the model can generate in a single output." + }, + "stop": { + "description": "Defines specific tokens or phrases that signal the model to stop producing further output.", + "type": "array", + "items": { + "type": "string" + } + }, + "frequency_penalty": { + "type": "number", + "description": "Modifies the likelihood of the model repeating the same words or phrases within a single output." + }, + "presence_penalty": { + "type": "number", + "description": "Reduces the likelihood of repeating tokens, promoting novelty in the output." + }, + "engine": { + "type": "string", + "description": "The engine used to run the model." + } + } + }, + "CreateThreadModelInfoDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The unique identifier of the thread." + }, + "settings": { + "description": "The settings of the thread.", + "allOf": [ + { + "$ref": "#/components/schemas/ModelSettingParamsDto" + } + ] + }, + "parameters": { + "description": "The parameters of the thread.", + "allOf": [ + { + "$ref": "#/components/schemas/ModelRuntimeParamsDto" + } + ] + }, + "engine": { + "type": "string", + "description": "The engine used in the thread to operate the model." + } + }, + "required": [ + "id", + "settings", + "parameters" + ] + }, + "AssistantToolDto": { + "type": "object", + "properties": { + "type": { + "type": "string", + "description": "The type of the assistant's tool." + }, + "enabled": { + "type": "boolean", + "description": "Enable or disable the assistant's tool." + }, + "settings": { + "type": "object", + "description": "The setting of the assistant's tool." + } + }, + "required": [ + "type", + "enabled", + "settings" + ] + }, + "CreateThreadAssistantDto": { + "type": "object", + "properties": { + "assistant_id": { + "type": "string", + "description": "The unique identifier of the assistant." + }, + "assistant_name": { + "type": "string", + "description": "The name of the assistant." + }, + "model": { + "description": "The model's unique identifier and settings.", + "allOf": [ + { + "$ref": "#/components/schemas/CreateThreadModelInfoDto" + } + ] + }, + "instructions": { + "type": "string", + "description": "The assistant's specific instructions." + }, + "tools": { + "description": "The thread's tool(Knowledge Retrieval) configurations.", + "type": "array", + "items": { + "$ref": "#/components/schemas/AssistantToolDto" + } + } + }, + "required": [ + "assistant_id", + "assistant_name", + "model" + ] + }, + "CreateThreadDto": { + "type": "object", + "properties": { + "title": { + "type": "string", + "description": "The title of the thread." + }, + "assistants": { + "description": "The details of the thread's settings.", + "type": "array", + "items": { + "$ref": "#/components/schemas/CreateThreadAssistantDto" + } + } + }, + "required": [ + "title", + "assistants" + ] + }, + "ThreadEntity": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "object": { + "type": "string" + }, + "title": { + "type": "string" + }, + "assistants": { + "type": "array", + "items": { + "type": "object" + } + }, + "createdAt": { + "type": "number" + }, + "updatedAt": { + "type": "number" + }, + "metadata": { + "type": "object" + } + }, + "required": [ + "id", + "object", + "title", + "assistants", + "createdAt" + ] + }, + "GetThreadResponseDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "thread_abc123", + "description": "The identifier of the thread." + }, + "object": { + "type": "string", + "example": "thread", + "description": "Type of the object" + }, + "created_at": { + "type": "integer", + "example": 1699014083, + "description": "Unix timestamp representing the creation time of the thread." + }, + "assistants": { + "example": [ + "assistant-001" + ], + "description": "List of assistants involved in the thread.", + "type": "array", + "items": { + "type": "string" + } + }, + "metadata": { + "type": "object", + "example": {}, + "description": "Metadata associated with the thread." + }, + "messages": { + "example": [], + "description": "List of messages within the thread.", + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "id", + "object", + "created_at", + "assistants", + "metadata", + "messages" + ] + }, + "UpdateThreadDto": { + "type": "object", + "properties": {} + }, + "DeleteThreadResponseDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "thread_123", + "description": "The identifier of the thread that was deleted." + }, + "object": { + "type": "string", + "example": "thread", + "description": "Type of the object, indicating it's a thread.", + "default": "thread" + }, + "deleted": { + "type": "boolean", + "example": true, + "description": "Indicates whether the thread was successfully deleted." + } + }, + "required": [ + "id", + "object", + "deleted" + ] + }, + "ModelArtifactDto": { + "type": "object", + "properties": { + "url": { + "type": "string", + "description": "The URL source of the model." + } + }, + "required": [ + "url" + ] + }, + "ModelMetadataDto": { + "type": "object", + "properties": { + "author": { + "type": "string", + "description": "The author of the model." + }, + "tags": { + "description": "The model's tags.", + "type": "array", + "items": { + "type": "string" + } + }, + "size": { + "type": "number", + "description": "The model's size." + }, + "cover": { + "type": "string", + "description": "The model's cover." + } + }, + "required": [ + "author", + "tags", + "size" + ] + }, + "CreateModelDto": { + "type": "object", + "properties": { + "version": { + "type": "string", + "description": "The version of the model." + }, + "format": { + "enum": [ + "gguf", + "api" + ], + "type": "string", + "description": "The state format of the model." + }, + "sources": { + "description": "The URL sources from which the model downloaded or accessed.", + "type": "array", + "items": { + "$ref": "#/components/schemas/ModelArtifactDto" + } + }, + "id": { + "type": "string", + "description": "The unique identifier of the model." + }, + "name": { + "type": "string", + "description": "The name of the model." + }, + "description": { + "type": "string", + "description": "A brief description of the model." + }, + "settings": { + "description": "The settings parameters of the model.", + "allOf": [ + { + "$ref": "#/components/schemas/ModelSettingParamsDto" + } + ] + }, + "parameters": { + "description": "The parameters configuration of the model.", + "allOf": [ + { + "$ref": "#/components/schemas/ModelRuntimeParamsDto" + } + ] + }, + "metadata": { + "description": "The metadata of the model.", + "allOf": [ + { + "$ref": "#/components/schemas/ModelMetadataDto" + } + ] + }, + "engine": { + "type": "string", + "description": "The engine used to run the model." + } + }, + "required": [ + "version", + "format", + "sources", + "id", + "name", + "description", + "settings", + "parameters", + "metadata", + "engine" + ] + }, + "StartModelSuccessDto": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "The success or error message displayed when a model is successfully loaded or fails to load." + }, + "modelId": { + "type": "string", + "description": "The unique identifier of the model." + } + }, + "required": [ + "message", + "modelId" + ] + }, + "DownloadModelResponseDto": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "Starting download mistral-ins-7b-q4", + "description": "Message indicates Jan starting download corresponding model." + } + }, + "required": [ + "message" + ] + }, + "ModelDto": { + "type": "object", + "properties": { + "source_url": { + "type": "string", + "example": "https://huggingface.co/janhq/trinity-v1.2-GGUF/resolve/main/trinity-v1.2.Q4_K_M.gguf", + "description": "URL to the source of the model." + }, + "id": { + "type": "string", + "example": "trinity-v1.2-7b", + "description": "Unique identifier used in chat-completions model_name, matches folder name." + }, + "object": { + "type": "string", + "example": "model" + }, + "name": { + "type": "string", + "example": "Trinity-v1.2 7B Q4", + "description": "Name of the model." + }, + "version": { + "type": "string", + "default": "1.0", + "description": "The version number of the model." + }, + "description": { + "type": "string", + "example": "Trinity is an experimental model merge using the Slerp method. Recommended for daily assistance purposes.", + "description": "Description of the model." + }, + "format": { + "type": "string", + "example": "gguf", + "description": "State format of the model, distinct from the engine." + }, + "ctx_len": { + "type": "number", + "description": "Context length.", + "example": 4096 + }, + "prompt_template": { + "type": "string", + "example": "system\n{system_message}\nuser\n{prompt}\nassistant" + }, + "temperature": { + "type": "number", + "example": 0.7 + }, + "top_p": { + "type": "number", + "example": 0.95 + }, + "stream": { + "type": "boolean", + "example": true + }, + "max_tokens": { + "type": "number", + "example": 4096 + }, + "stop": { + "example": [], + "type": "array", + "items": { + "type": "string" + } + }, + "frequency_penalty": { + "type": "number", + "example": 0 + }, + "presence_penalty": { + "type": "number", + "example": 0 + }, + "author": { + "type": "string", + "example": "Jan" + }, + "tags": { + "example": [ + "7B", + "Merged", + "Featured" + ], + "type": "array", + "items": { + "type": "string" + } + }, + "size": { + "type": "number", + "example": 4370000000 + }, + "cover": { + "type": "string", + "example": "https://raw.githubusercontent.com/janhq/jan/main/models/trinity-v1.2-7b/cover.png" + }, + "engine": { + "type": "string", + "example": "cortex" + } + }, + "required": [ + "source_url", + "id", + "object", + "name", + "version", + "description", + "format", + "ctx_len", + "prompt_template", + "temperature", + "top_p", + "stream", + "max_tokens", + "stop", + "frequency_penalty", + "presence_penalty", + "author", + "tags", + "size", + "cover", + "engine" + ] + }, + "ListModelsResponseDto": { + "type": "object", + "properties": { + "object": { + "type": "string", + "example": "list", + "enum": [ + "list" + ] + }, + "data": { + "description": "List of models", + "type": "array", + "items": { + "$ref": "#/components/schemas/ModelDto" + } + } + }, + "required": [ + "object", + "data" + ] + }, + "UpdateModelDto": { + "type": "object", + "properties": {} + }, + "DeleteModelResponseDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "mistral-ins-7b-q4", + "description": "The identifier of the model that was deleted." + }, + "object": { + "type": "string", + "example": "model", + "description": "Type of the object, indicating it's a model.", + "default": "model" + }, + "deleted": { + "type": "boolean", + "example": true, + "description": "Indicates whether the model was successfully deleted." + } + }, + "required": [ + "id", + "object", + "deleted" + ] + }, + "ChatCompletionMessage": { + "type": "object", + "properties": { + "content": { + "type": "string", + "description": "The Content of the chat message." + }, + "role": { + "enum": [ + "system", + "assistant", + "user" + ], + "type": "string", + "description": "The role of the entity in the chat completion." + } + }, + "required": [ + "content", + "role" + ] + }, + "CreateChatCompletionDto": { + "type": "object", + "properties": { + "messages": { + "description": "Array of chat messages to be used for generating the chat completion.", + "type": "array", + "items": { + "$ref": "#/components/schemas/ChatCompletionMessage" + } + }, + "model": { + "type": "string", + "description": "The unique identifier of the model." + }, + "stream": { + "type": "boolean", + "description": "Determines the format for output generation. If set to `true`, the output is generated continuously, allowing for real-time streaming of responses. If set to `false`, the output is delivered in a single JSON file." + }, + "max_tokens": { + "type": "number", + "description": "Sets the upper limit on the number of tokens the model can generate in a single output." + }, + "stop": { + "description": "Defines specific tokens or phrases that signal the model to stop producing further output.", + "type": "array", + "items": { + "type": "string" + } + }, + "frequency_penalty": { + "type": "number", + "description": "Modifies the likelihood of the model repeating the same words or phrases within a single output." + }, + "presence_penalty": { + "type": "number", + "description": "Reduces the likelihood of repeating tokens, promoting novelty in the output." + }, + "temperature": { + "type": "number", + "description": "Influences the randomness of the model's output." + }, + "top_p": { + "type": "number", + "description": "Sets probability threshold for more relevant outputs." + } + }, + "required": [ + "messages", + "model", + "stream", + "max_tokens", + "stop", + "frequency_penalty", + "presence_penalty", + "temperature", + "top_p" + ] + }, + "MessageDto": { + "type": "object", + "properties": { + "content": { + "type": "string", + "description": "The textual content of the chat message or completion generated by the model." + }, + "role": { + "type": "string", + "description": "The role of the participant in the chat, such as 'user' or 'system', indicating who is the sender of the message." + } + }, + "required": [ + "content", + "role" + ] + }, + "ChoiceDto": { + "type": "object", + "properties": { + "finish_reason": { + "type": "string", + "description": "The reason the chat completion ended, typically indicating whether the model completed the text naturally or was cut off." + }, + "index": { + "type": "number", + "description": "The index of the completion relative to other generated completions, useful for identifying its order in a batch request." + }, + "message": { + "description": "An object representing the message details involved in the chat completion, encapsulated within a MessageDto.", + "allOf": [ + { + "$ref": "#/components/schemas/MessageDto" + } + ] + } + }, + "required": [ + "finish_reason", + "index", + "message" + ] + }, + "UsageDto": { + "type": "object", + "properties": { + "completion_tokens": { + "type": "number", + "description": "The number of tokens used in the completion part of the response generated by the model." + }, + "prompt_tokens": { + "type": "number", + "description": "The number of tokens used in the prompt part of the chat input, which is provided to the model." + }, + "total_tokens": { + "type": "number", + "description": "The total number of tokens used in both the prompt and the completion, summarizing the entire token count of the chat operation." + } + }, + "required": [ + "completion_tokens", + "prompt_tokens", + "total_tokens" + ] + }, + "ChatCompletionResponseDto": { + "type": "object", + "properties": { + "choices": { + "description": "A list of choices generated by the chat model.", + "type": "array", + "items": { + "$ref": "#/components/schemas/ChoiceDto" + } + }, + "created": { + "type": "number", + "description": "The timestamp of when the chat completion was created, expressed as a Unix timestamp." + }, + "id": { + "type": "string", + "description": "The unique identifier for the chat completion." + }, + "model": { + "type": "string", + "description": "The identifier of the model used to generate the chat completion." + }, + "object": { + "type": "string", + "description": "The type of object, typically set to 'chat_completion' to denote the nature of the API response." + }, + "system_fingerprint": { + "type": "string", + "description": "A unique fingerprint that identifies the system configuration used during the chat completion." + }, + "usage": { + "description": "An object representing the usage statistics of the model for the current completion.", + "allOf": [ + { + "$ref": "#/components/schemas/UsageDto" + } + ] + } + }, + "required": [ + "choices", + "created", + "id", + "model", + "object", + "system_fingerprint", + "usage" + ] + }, + "CreateAssistantDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The unique identifier of the assistant." + }, + "avatar": { + "type": "string", + "description": "The avatar of the assistant." + }, + "name": { + "type": "string", + "description": "The name of the assistant." + }, + "description": { + "type": "string", + "description": "The description of the assistant." + }, + "model": { + "type": "string", + "description": "The model of the assistant." + }, + "instructions": { + "type": "string", + "description": "The instructions for the assistant." + }, + "tools": { + "description": "The tools associated with the assistant.", + "type": "array", + "items": { + "$ref": "#/components/schemas/AssistantToolDto" + } + }, + "file_ids": { + "description": "The identifiers of the files that have been uploaded to the thread.", + "type": "array", + "items": { + "type": "string" + } + }, + "metadata": { + "type": "object", + "description": "The metadata of the assistant." + } + }, + "required": [ + "id", + "avatar", + "name", + "description", + "model", + "instructions", + "tools", + "file_ids" + ] + }, + "AssistantEntity": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "avatar": { + "type": "string" + }, + "thread_location": { + "type": "string" + }, + "object": { + "type": "string" + }, + "created_at": { + "type": "number" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "model": { + "type": "string" + }, + "instructions": { + "type": "string" + }, + "tools": { + "type": "array", + "items": { + "type": "object" + } + }, + "file_ids": { + "type": "array", + "items": { + "type": "string" + } + }, + "metadata": { + "type": "object" + } + }, + "required": [ + "id", + "avatar", + "object", + "created_at", + "name", + "model", + "file_ids" + ] + }, + "DeleteAssistantResponseDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "assistant_123", + "description": "The identifier of the assistant that was deleted." + }, + "object": { + "type": "string", + "example": "assistant", + "description": "Type of the object, indicating it's a assistant.", + "default": "assistant" + }, + "deleted": { + "type": "boolean", + "example": true, + "description": "Indicates whether the assistant was successfully deleted." + } + }, + "required": [ + "id", + "object", + "deleted" + ] + } + } + } +} \ No newline at end of file diff --git a/docs/public/robots.txt b/docs/public/robots.txt new file mode 100644 index 0000000000..e4d048b618 --- /dev/null +++ b/docs/public/robots.txt @@ -0,0 +1,9 @@ +# * +User-agent: * +Allow: / + +# Host +Host: https://jan.ai/ + +# Sitemaps +Sitemap: https://jan.ai/sitemap.xml diff --git a/docs/public/sitemap-0.xml b/docs/public/sitemap-0.xml new file mode 100644 index 0000000000..b74cbb2372 --- /dev/null +++ b/docs/public/sitemap-0.xml @@ -0,0 +1,129 @@ + + +https://jan.ai2024-09-09T08:19:45.721Zdaily1 +https://jan.ai/about2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/about/handbook2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/about/handbook/analytics2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/about/handbook/engineering2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/about/handbook/engineering/ci-cd2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/about/handbook/engineering/qa2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/about/handbook/product-design2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/about/handbook/project-management2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/about/handbook/strategy2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/about/handbook/website-docs2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/about/investors2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/about/team2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/about/vision2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/about/wall-of-love2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/blog2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/changelog2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/changelog/2023-12-21-faster-inference-across-platform2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/changelog/2024-01-16-settings-options-right-panel2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/changelog/2024-01-29-local-api-server2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/changelog/2024-02-05-jan-data-folder2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/changelog/2024-02-26-home-servers-with-helm2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/changelog/2024-03-06-ui-revamp-settings2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/changelog/2024-03-11-import-models2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/changelog/2024-03-19-nitro-tensorrt-llm-extension2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/changelog/2024-04-02-groq-api-integration2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/changelog/2024-04-15-new-mistral-extension2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/changelog/2024-04-25-llama3-command-r-hugginface2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/changelog/2024-05-20-llamacpp-upgrade-new-remote-models2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/changelog/2024-05-28-cohere-aya-23-8b-35b-phi-3-medium2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/changelog/2024-06-21-nvidia-nim-support2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/changelog/2024-07-15-claude-3-5-support2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/changelog/2024-09-01-llama3-1-gemma2-support2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/cortex2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/cortex/architecture2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/cortex/assistants2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/cortex/build-extension2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/cortex/cli2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/cortex/cli/chat2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/cortex/cli/init2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/cortex/cli/kill2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/cortex/cli/models2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/cortex/cli/models/download2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/cortex/cli/models/get2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/cortex/cli/models/list2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/cortex/cli/models/remove2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/cortex/cli/models/start2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/cortex/cli/models/stop2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/cortex/cli/models/update2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/cortex/cli/ps2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/cortex/cli/pull2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/cortex/cli/run2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/cortex/cli/serve2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/cortex/command-line2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/cortex/cortex-cpp2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/cortex/cortex-llamacpp2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/cortex/cortex-openvino2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/cortex/cortex-python2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/cortex/cortex-tensorrt-llm2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/cortex/embeddings2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/cortex/embeddings/overview2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/cortex/error-codes2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/cortex/ext-architecture2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/cortex/fine-tuning2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/cortex/fine-tuning/overview2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/cortex/function-calling2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/cortex/hardware2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/cortex/installation2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/cortex/installation/linux2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/cortex/installation/mac2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/cortex/installation/windows2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/cortex/model-operations2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/cortex/model-operations/overview2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/cortex/py-library2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/cortex/quickstart2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/cortex/rag2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/cortex/rag/overview2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/cortex/server2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/cortex/text-generation2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/cortex/ts-library2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/cortex/vision2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/cortex/vision/overview2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/docs2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/docs/assistants2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/docs/built-in/llama-cpp2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/docs/built-in/tensorrt-llm2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/docs/data-folder2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/docs/desktop2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/docs/desktop/linux2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/docs/desktop/mac2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/docs/desktop/windows2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/docs/error-codes2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/docs/extensions2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/docs/installing-extension2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/docs/models2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/docs/models/manage-models2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/docs/models/model-parameters2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/docs/quickstart2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/docs/remote-models/anthropic2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/docs/remote-models/azure2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/docs/remote-models/cohere2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/docs/remote-models/generic-openai2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/docs/remote-models/groq2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/docs/remote-models/martian2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/docs/remote-models/mistralai2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/docs/remote-models/nvidia-nim2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/docs/remote-models/openai2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/docs/remote-models/openrouter2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/docs/remote-models/triton2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/docs/settings2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/docs/shortcuts2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/docs/threads2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/docs/tools/retrieval2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/docs/troubleshooting2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/download2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/integrations2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/integrations/coding/continue-dev2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/integrations/function-calling/interpreter2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/integrations/messaging/llmcord2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/integrations/workflow-automation/raycast2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/post/benchmarking-nvidia-tensorrt-llm2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/post/bitdefender2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/post/data-is-moat2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/post/rag-is-not-enough2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/privacy2024-09-09T08:19:45.722Zdaily1 +https://jan.ai/support2024-09-09T08:19:45.722Zdaily1 + \ No newline at end of file diff --git a/docs/public/sitemap.xml b/docs/public/sitemap.xml new file mode 100644 index 0000000000..af0068d277 --- /dev/null +++ b/docs/public/sitemap.xml @@ -0,0 +1,4 @@ + + +https://jan.ai/sitemap-0.xml + \ No newline at end of file diff --git a/docs/src/components/APIReference/index.tsx b/docs/src/components/APIReference/index.tsx new file mode 100644 index 0000000000..c18e522c45 --- /dev/null +++ b/docs/src/components/APIReference/index.tsx @@ -0,0 +1,41 @@ +'use client' + +import { ApiReferenceReact } from '@scalar/api-reference-react' +import { useTheme } from 'nextra-theme-docs' +import { useIsomorphicLayoutEffect } from '@/hooks/useIsomorphicLayoutEffect' + +export const APIReference = () => { + const { theme, resolvedTheme } = useTheme() + + useIsomorphicLayoutEffect(() => { + if (theme === 'dark') { + localStorage.setItem('isDark', 'true') + } else { + localStorage.setItem('isDark', 'false') + } + + if (resolvedTheme === 'dark') { + localStorage.setItem('isDark', 'true') + } else { + localStorage.setItem('isDark', 'false') + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [theme, resolvedTheme]) + + return ( + <> + + + ) +} + +export default APIReference diff --git a/docs/src/components/Blog/CTA/index.tsx b/docs/src/components/Blog/CTA/index.tsx new file mode 100644 index 0000000000..79d4de5c9a --- /dev/null +++ b/docs/src/components/Blog/CTA/index.tsx @@ -0,0 +1,32 @@ +import ThemeImage from '@/components/ThemeImage' +import NewsletterForm from '@/components/NewsletterForm' +import SocialShareButton from '@/components/SocialShareButton' + +const CTABlog = () => { + return ( +
+ +

+ The Soul of a New Machine +

+

+ {`To stay updated on all of Jan's research, subscribe to The Soul of a New Machine`} +

+
+ + +
+
+ ) +} + +export default CTABlog diff --git a/docs/src/components/Blog/index.tsx b/docs/src/components/Blog/index.tsx new file mode 100644 index 0000000000..d7ec1cdb46 --- /dev/null +++ b/docs/src/components/Blog/index.tsx @@ -0,0 +1,141 @@ +import { useData } from 'nextra/data' +import { format } from 'date-fns' +import { useRouter, useSearchParams } from 'next/navigation' + +import Link from 'next/link' +import { Cards } from 'nextra/components' +import { twMerge } from 'tailwind-merge' + +const Blog = () => { + const blogPost = useData() + const searchParams = useSearchParams() + const search = searchParams?.get('category') + const router = useRouter() + + const staticCategories = [ + { + name: 'Building Jan', + id: 'building-jan', + }, + { + name: 'Research', + id: 'research', + }, + ] + + return ( +
+
+

+ Blog +

+
+

+ The latest updates from Jan. See  + + Changelog + +  for more product updates. +

+
+ +
+
    +
  • { + router.push(`blog/`) + }} + className={twMerge( + 'cursor-pointer py-1 px-2 lg:px-3 rounded-full', + search === null && + 'dark:bg-blue-400 bg-blue-500 font-medium text-white' + )} + > +

    All Categories

    +
  • + {staticCategories.map((cat, i) => { + return ( +
  • { + router.push(`blog/?category=${cat.id}`) + }} + className={twMerge( + 'cursor-pointer py-1 px-2 lg:px-3 rounded-full', + cat.id === search && + 'dark:bg-blue-400 bg-blue-500 font-medium text-white' + )} + > +

    {cat.name}

    +
  • + ) + })} +
+
+ + + {blogPost + .filter((post: BlogPostsThumbnail) => { + if (search) { + return post.categories?.includes(String(search)) + } else { + return post + } + }) + .map((post: BlogPostsThumbnail, i: number) => { + return ( + +
+
+
+ {post.categories?.map((cat, i) => { + return ( +

+ {cat?.replaceAll('-', ' ')} +

+ ) + })} +

+ {format(String(post.date), 'MMMM do, yyyy')} +

+
+
+
+
+
+ {post.title} +
+

+ {post.description} +

+

+ Read more... +

+
+ + ) + })} +
+
+
+ ) +} + +export default Blog diff --git a/docs/src/components/Changelog/ChangelogHeader.tsx b/docs/src/components/Changelog/ChangelogHeader.tsx new file mode 100644 index 0000000000..7ae5074770 --- /dev/null +++ b/docs/src/components/Changelog/ChangelogHeader.tsx @@ -0,0 +1,41 @@ +import React from 'react' +import { format } from 'date-fns' +import Image from 'next/image' +import Link from 'next/link' +import { ArrowLeft } from 'lucide-react' + +type ChangelogHeaderProps = { + title: string + ogImage: string + date: any +} + +const ChangelogHeader = (props: ChangelogHeaderProps) => { + const { title, ogImage, date } = props + + return ( +
+ + + Back to changelog + +
+

+ {format(String(date), 'MMMM do, yyyy') || null} +

+
{title}
+
+ {ogImage && ( + {title} + )} +
+ ) +} + +export default ChangelogHeader diff --git a/docs/src/components/Changelog/index.tsx b/docs/src/components/Changelog/index.tsx new file mode 100644 index 0000000000..897cd56294 --- /dev/null +++ b/docs/src/components/Changelog/index.tsx @@ -0,0 +1,164 @@ +import { format } from 'date-fns' + +import { useData } from 'nextra/data' +import Image from 'next/image' +import Link from 'next/link' +import { useState } from 'react' +import { useForm } from 'react-hook-form' + +const Changelog = () => { + const data = useData() + + const { register, handleSubmit, reset } = useForm({ + defaultValues: { + email: '', + }, + }) + + const [formMessage, setFormMessage] = useState('') + + const onSubmit = (data: { email: string }) => { + const { email } = data + const options = { + method: 'POST', + + body: JSON.stringify({ + updateEnabled: false, + email, + listIds: [14], + }), + } + + if (email) { + fetch('https://brevo.jan.ai/', options) + .then((response) => response.json()) + .then((response) => { + if (response.id) { + setFormMessage('You have successfully joined our newsletter') + } else { + setFormMessage(response.message) + } + reset() + setTimeout(() => { + setFormMessage('') + }, 5000) + }) + .catch((err) => console.error(err)) + } + } + + return ( +
+
+

+ Changelog +

+
+

+ Latest release updates from the Jan team. Check out our  + + Roadmap + +  {`to see what's next.`} +

+ +
+
+ + +
+ {formMessage &&

{formMessage}

} +
+
+
+
+ {data?.map((log: Changelog, i: number) => { + return ( +
+
+

+ {format(log?.date, 'MMMM do, yyyy')} +

+
+ +
+
+
+
+
+ {log?.ogImage && ( + {log?.title} + )} +
+ {log?.title} +
+ {log?.description && ( +

+ {log?.description} +

+ )} +

+ New release Jan App v{log?.version} +

+
+
+
+
+ +
+ ) + })} +
+
+
+ +
+ + View Prior Updates + +
+
+ ) +} + +export default Changelog diff --git a/docs/src/components/Download/CardDownload.tsx b/docs/src/components/Download/CardDownload.tsx new file mode 100644 index 0000000000..f75543d621 --- /dev/null +++ b/docs/src/components/Download/CardDownload.tsx @@ -0,0 +1,159 @@ +import React, { useState, useEffect } from 'react' +import { IconType } from 'react-icons/lib' +import { FaWindows, FaApple, FaLinux } from 'react-icons/fa' +import { twMerge } from 'tailwind-merge' +import { DownloadIcon } from 'lucide-react' + +type Props = { + lastRelease: any +} + +type SystemType = { + name: string + label: string + logo: IconType + fileFormat: string + href?: string +} + +const systemsTemplate: SystemType[] = [ + { + name: 'Mac M1, M2, M3', + label: 'Apple Silicon', + logo: FaApple, + fileFormat: '{appname}-mac-arm64-{tag}.dmg', + }, + { + name: 'Mac (Intel)', + label: 'Apple Intel', + logo: FaApple, + fileFormat: '{appname}-mac-x64-{tag}.dmg', + }, + { + name: 'Windows', + label: 'Standard (64-bit)', + logo: FaWindows, + fileFormat: '{appname}-win-x64-{tag}.exe', + }, + { + name: 'Linux (AppImage)', + label: 'AppImage', + logo: FaLinux, + fileFormat: '{appname}-linux-x86_64-{tag}.AppImage', + }, + { + name: 'Linux (deb)', + label: 'Deb', + logo: FaLinux, + fileFormat: '{appname}-linux-amd64-{tag}.deb', + }, +] + +const groupTemnplate = [ + { label: 'MacOS', name: 'mac', logo: FaApple }, + { label: 'Windows', name: 'windows', logo: FaWindows }, + { label: 'Linux', name: 'linux', logo: FaLinux }, +] + +export default function CardDownload({ lastRelease }: Props) { + const [systems, setSystems] = useState(systemsTemplate) + + const extractAppName = (fileName: string) => { + const regex = /^(.*?)-(?:mac|win|linux)-(?:arm64|x64|amd64|x86_64)-.*$/ + const match = fileName.match(regex) + return match ? match[1] : null + } + + useEffect(() => { + const updateDownloadLinks = async () => { + try { + // Extract appname from the first asset name + const firstAssetName = lastRelease.assets[0].name + const appname = extractAppName(firstAssetName) + + if (!appname) { + console.error( + 'Failed to extract appname from file name:', + firstAssetName + ) + + return + } + + // Remove 'v' at the start of the tag_name + const tag = lastRelease.tag_name.startsWith('v') + ? lastRelease.tag_name.substring(1) + : lastRelease.tag_name + + const updatedSystems = systems.map((system) => { + const downloadUrl = system.fileFormat + .replace('{appname}', appname) + .replace('{tag}', tag) + return { + ...system, + href: `https://github.com/janhq/jan/releases/download/${lastRelease.tag_name}/${downloadUrl}`, + } + }) + + setSystems(updatedSystems) + } catch (error) { + console.error('Failed to update download links:', error) + } + } + + updateDownloadLinks() + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []) + + const renderDownloadLink = (group: string) => { + return ( + <> + {systems + .filter((x) => x.name.toLowerCase().includes(group)) + .map((system, i) => ( +
+ + {system.label} + + +
+ ))} + + ) + } + + return ( +
+
+ {groupTemnplate.map((item, i) => { + return ( +
+
+
+
+ +
+
{item.label}
+
+
+ {renderDownloadLink(item.name)} +
+
+
+ ) + })} +
+
+ ) +} diff --git a/docs/src/components/Download/index.tsx b/docs/src/components/Download/index.tsx new file mode 100644 index 0000000000..d5dc4c41d6 --- /dev/null +++ b/docs/src/components/Download/index.tsx @@ -0,0 +1,37 @@ +import { useData } from 'nextra/data' +import CardDownload from './CardDownload' + +const Download = () => { + const { lastRelease } = useData() + return ( +
+
+

+ Download Jan for your desktop +

+

+ Turn your computer into an AI computer +

+
+ +
+ +
+
+ ) +} + +export default Download diff --git a/docs/src/components/DropdownDownload/index.tsx b/docs/src/components/DropdownDownload/index.tsx new file mode 100644 index 0000000000..87461122eb --- /dev/null +++ b/docs/src/components/DropdownDownload/index.tsx @@ -0,0 +1,228 @@ +import { useCallback, useEffect, useState } from 'react' +import { FaWindows, FaApple, FaLinux } from 'react-icons/fa' +import { IconType } from 'react-icons/lib' +import { IoChevronDownOutline } from 'react-icons/io5' +import { useClickOutside } from '@/hooks/useClickOutside' +import { twMerge } from 'tailwind-merge' + +type Props = { + lastRelease: any +} + +type SystemType = { + name: string + logo: IconType + fileFormat: string + href?: string +} + +type GpuInfo = { + renderer: string + vendor: string + type: string +} + +const systemsTemplate: SystemType[] = [ + { + name: 'Download for Mac (M1/M2/M3)', + logo: FaApple, + fileFormat: '{appname}-mac-arm64-{tag}.dmg', + }, + { + name: 'Download for Mac (Intel)', + logo: FaApple, + fileFormat: '{appname}-mac-x64-{tag}.dmg', + }, + { + name: 'Download for Windows', + logo: FaWindows, + fileFormat: '{appname}-win-x64-{tag}.exe', + }, + { + name: 'Download for Linux (AppImage)', + logo: FaLinux, + fileFormat: '{appname}-linux-x86_64-{tag}.AppImage', + }, + { + name: 'Download for Linux (deb)', + logo: FaLinux, + fileFormat: '{appname}-linux-amd64-{tag}.deb', + }, +] + +const extractAppName = (fileName: string) => { + const regex = /^(.*?)-(?:mac|win|linux)-(?:arm64|x64|x86_64|amd64)-.*$/ + const match = fileName.match(regex) + return match ? match[1] : null +} + +const DropdownDownload = ({ lastRelease }: Props) => { + const [systems, setSystems] = useState(systemsTemplate) + const [defaultSystem, setDefaultSystem] = useState(systems[0]) + const [open, setOpen] = useState(false) + const [gpuInfo, setGpuInfo] = useState({ + renderer: '', + vendor: '', + type: '', + }) + + const changeDefaultSystem = useCallback( + async (systems: SystemType[]) => { + const userAgent = navigator.userAgent + if (userAgent.includes('Windows')) { + // windows user + setDefaultSystem(systems[2]) + } else if (userAgent.includes('Linux')) { + // linux user + setDefaultSystem(systems[3]) + } else if (userAgent.includes('Mac OS')) { + if (gpuInfo.type === 'Apple Silicon') { + setDefaultSystem(systems[0]) + } else { + setDefaultSystem(systems[1]) + } + } else { + setDefaultSystem(systems[1]) + } + }, + [gpuInfo.type] + ) + + function getUnmaskedInfo(gl: WebGLRenderingContext): { + renderer: string + vendor: string + } { + const unMaskedInfo = { + renderer: '', + vendor: '', + } + const dbgRenderInfo = gl.getExtension('WEBGL_debug_renderer_info') + if (dbgRenderInfo) { + unMaskedInfo.renderer = gl.getParameter( + dbgRenderInfo.UNMASKED_RENDERER_WEBGL + ) + unMaskedInfo.vendor = gl.getParameter(dbgRenderInfo.UNMASKED_VENDOR_WEBGL) + } + + return unMaskedInfo + } + + function detectGPU() { + const canvas = document.createElement('canvas') + const gl = + canvas.getContext('webgl') || + (canvas.getContext('experimental-webgl') as WebGLRenderingContext) + if (gl) { + const gpuInfo = getUnmaskedInfo(gl) + + let gpuType = 'Unknown GPU vendor or renderer.' + if (gpuInfo.renderer.includes('Apple')) { + gpuType = 'Apple Silicon' + } else if ( + gpuInfo.renderer.includes('Intel') || + gpuInfo.vendor.includes('Intel') + ) { + gpuType = 'Intel' + } + setGpuInfo({ + renderer: gpuInfo.renderer, + vendor: gpuInfo.vendor, + type: gpuType, + }) + } else { + setGpuInfo({ + renderer: 'N/A', + vendor: 'N/A', + type: 'Unable to initialize WebGL.', + }) + } + } + + useEffect(() => { + const updateDownloadLinks = async () => { + try { + const firstAssetName = await lastRelease.assets[0]?.name + const appname = extractAppName(firstAssetName) + if (!appname) { + console.error( + 'Failed to extract appname from file name:', + firstAssetName + ) + changeDefaultSystem(systems) + return + } + const tag = lastRelease.tag_name.startsWith('v') + ? lastRelease.tag_name.substring(1) + : lastRelease.tag_name + + const updatedSystems = systems.map((system) => { + const downloadUrl = system.fileFormat + .replace('{appname}', appname) + .replace('{tag}', tag) + return { + ...system, + href: `https://github.com/janhq/jan/releases/download/${lastRelease.tag_name}/${downloadUrl}`, + } + }) + setSystems(updatedSystems) + changeDefaultSystem(updatedSystems) + } catch (error) { + console.error('Failed to update download links:', error) + } + } + + if (gpuInfo.type.length === 0) { + detectGPU() + } + updateDownloadLinks() + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [gpuInfo]) + + const [menu, setMenu] = useState(null) + + const [refDropdownContent, setRefDropdownContent] = + useState(null) + useClickOutside(() => setOpen(false), null, [menu, refDropdownContent]) + + return ( +
+ + + {defaultSystem.name} + + + {open && ( +
+ {systems.map((system) => ( + + ))} +
+ )} +
+ ) +} + +export default DropdownDownload diff --git a/docs/src/components/FaqBox/index.tsx b/docs/src/components/FaqBox/index.tsx new file mode 100644 index 0000000000..3e561d8b66 --- /dev/null +++ b/docs/src/components/FaqBox/index.tsx @@ -0,0 +1,21 @@ +import React, { PropsWithChildren } from 'react' + +type Props = { + title: string +} & PropsWithChildren + +const FAQBox = ({ title, children }: Props) => { + return ( +
+ + {title} + +
{children}
+
+ ) +} + +export default FAQBox diff --git a/docs/src/components/FooterMenu/index.tsx b/docs/src/components/FooterMenu/index.tsx new file mode 100644 index 0000000000..7b144a9562 --- /dev/null +++ b/docs/src/components/FooterMenu/index.tsx @@ -0,0 +1,254 @@ +import React, { useState } from 'react' +import ThemeImage from '@/components/ThemeImage' +import { AiOutlineGithub } from 'react-icons/ai' +import { RiTwitterXFill } from 'react-icons/ri' + +import { BiLogoDiscordAlt } from 'react-icons/bi' +import { useForm } from 'react-hook-form' +import LogoMark from '@/components/LogoMark' +import { FaLinkedin } from 'react-icons/fa' + +const socials = [ + { + icon: ( + + ), + href: 'https://twitter.com/jandotai', + }, + { + icon: ( + + ), + href: 'https://discord.com/invite/FTk2MvZwJH', + }, + { + icon: ( + + ), + href: 'https://github.com/janhq/jan', + }, + { + icon: , + href: 'https://www.linkedin.com/company/homebrewltd', + }, +] + +const menus = [ + { + name: 'Product', + child: [ + { + menu: 'Download', + path: '/download', + }, + { + menu: 'Changelog', + path: '/changelog', + }, + ], + }, + { + name: 'For Developers', + child: [ + { + menu: 'Documentation', + path: '/docs', + }, + ], + }, + { + name: 'Community', + child: [ + { + menu: 'Github', + path: 'https://github.com/janhq/jan', + external: true, + }, + { + menu: 'Discord', + path: 'https://discord.gg/FTk2MvZwJH', + external: true, + }, + { + menu: 'Twitter', + path: 'https://twitter.com/jandotai', + external: true, + }, + { + menu: 'LinkedIn', + path: 'https://www.linkedin.com/company/homebrewltd', + external: true, + }, + ], + }, + { + name: 'Company', + child: [ + { + menu: 'About', + path: '/about', + }, + { + menu: 'Blog', + path: '/blog', + }, + { + menu: 'Careers', + path: 'https://homebrew.bamboohr.com/careers', + external: true, + }, + ], + }, +] + +const getCurrentYear = new Date().getFullYear() + +export default function Footer() { + const { register, handleSubmit, reset } = useForm({ + defaultValues: { + email: '', + }, + }) + + const [formMessage, setFormMessage] = useState('') + + const onSubmit = (data: { email: string }) => { + const { email } = data + const options = { + method: 'POST', + + body: JSON.stringify({ + updateEnabled: false, + email, + listIds: [13], + }), + } + + if (email) { + fetch('https://brevo.jan.ai/', options) + .then((response) => response.json()) + .then((response) => { + if (response.id) { + setFormMessage('You have successfully joined our newsletter') + } else { + setFormMessage(response.message) + } + reset() + setTimeout(() => { + setFormMessage('') + }, 5000) + }) + .catch((err) => console.error(err)) + } + } + + return ( +
+
+
+
+ +

+ Jan +

+
+
+
+ The Soul of a New Machine +
+

+ Subscribe to our newsletter on AI  +
+ research and building Jan: +

+ +
+
+ + +
+ {formMessage &&

{formMessage}

} +
+
+
+ {menus.map((menu, i) => { + return ( +
+

+ {menu.name} +

+ +
+ ) + })} +
+
+
+
+ {socials.map((social, i) => { + return ( + + {social.icon} + + ) + })} +
+ ©{getCurrentYear} Homebrew Computer Company + +
+
+
+ ) +} diff --git a/docs/src/components/Home/APIStructure/index.tsx b/docs/src/components/Home/APIStructure/index.tsx new file mode 100644 index 0000000000..c926bb3981 --- /dev/null +++ b/docs/src/components/Home/APIStructure/index.tsx @@ -0,0 +1,99 @@ +import React from 'react' + +const endpoints = [ + { + name: '/threads', + status: '100% complete', + }, + { + name: '/messages', + status: '100% complete', + }, + { + name: '/models', + status: '90% complete', + }, + { + name: '/chat/completions', + status: '70% complete', + }, + { + name: '/assistants', + status: '30% complete', + }, + { + name: '/fine-tuning', + status: 'Coming soon', + }, + { + name: '/files', + status: 'Coming soon', + }, + { + name: '/...', + status: 'Coming soon', + }, +] + +const renderDot = (status: string) => { + switch (status) { + case 'Coming soon': + return
+ + case '100% complete': + return
+ + default: + return
+ } +} + +const APIStructure = () => { + return ( +
+
+

+ Fully OpenAI-Equivalent API +

+
+

+ Jan provides an OpenAI-equivalent API server at localhost:  + + 1337 + {' '} + that can be used as a drop-in replacement with compatible apps. +

+
+
+ +
+ {endpoints.map((item, i) => { + return ( +
+
+ {renderDot(item.status)} +
{item.name}
+
+

{item.status}

+
+ ) + })} +
+
+ ) +} + +export default APIStructure diff --git a/docs/src/components/Home/BuiltWithLove/index.tsx b/docs/src/components/Home/BuiltWithLove/index.tsx new file mode 100644 index 0000000000..b84fb36348 --- /dev/null +++ b/docs/src/components/Home/BuiltWithLove/index.tsx @@ -0,0 +1,142 @@ +import { IoMapOutline } from 'react-icons/io5' +import { FaGithub, FaDiscord } from 'react-icons/fa' +import { RiStarSFill } from 'react-icons/ri' +import { useDiscordWidget } from '@/hooks/useDiscordWidget' +import { useData } from 'nextra/data' +import { formatCompactNumber } from '@/utils/format' + +const BuiltWithLove = () => { + const { data: discordWidget } = useDiscordWidget() + const { stars } = useData() + + return ( +
+ + ) +} + +export default BuiltWithLove diff --git a/docs/src/components/Home/CTADownload/index.tsx b/docs/src/components/Home/CTADownload/index.tsx new file mode 100644 index 0000000000..c3562cd65f --- /dev/null +++ b/docs/src/components/Home/CTADownload/index.tsx @@ -0,0 +1,32 @@ +import DropdownDownload from '@/components/DropdownDownload' +import { totalDownload } from '@/utils/format' +import { useData } from 'nextra/data' + +const CTADownload = () => { + const { lastRelease, release } = useData() + + return ( +
+
+
+
+

+ Turn your computer
into an AI + computer +

+
+
+
+ +
+

+ {totalDownload(release)}+ Downloads | Free & Open Source +

+
+
+
+
+ ) +} + +export default CTADownload diff --git a/docs/src/components/Home/CTANewsletter/index.tsx b/docs/src/components/Home/CTANewsletter/index.tsx new file mode 100644 index 0000000000..09b193b419 --- /dev/null +++ b/docs/src/components/Home/CTANewsletter/index.tsx @@ -0,0 +1,93 @@ +import { useForm } from 'react-hook-form' +import ThemeImage from '@/components/ThemeImage' +import { useState } from 'react' + +const CTANewsletter = () => { + const { register, handleSubmit, reset } = useForm({ + defaultValues: { + email: '', + }, + }) + + const [formMessage, setFormMessage] = useState('') + + const onSubmit = (data: { email: string }) => { + const { email } = data + const options = { + method: 'POST', + + body: JSON.stringify({ + updateEnabled: false, + email, + listIds: [13], + }), + } + + if (email) { + fetch('https://brevo.jan.ai/', options) + .then((response) => response.json()) + .then((response) => { + if (response.id) { + setFormMessage('You have successfully joined our newsletter') + } else { + setFormMessage(response.message) + } + reset() + setTimeout(() => { + setFormMessage('') + }, 5000) + }) + .catch((err) => console.error(err)) + } + } + + return ( +
+
+
+
+
+ +

+ The Soul of a New Machine +

+

+ Follow our AI research and journey in building Jan +

+ +
+
+ + +
+ {formMessage &&

{formMessage}

} +
+
+
+
+
+
+ ) +} + +export default CTANewsletter diff --git a/docs/src/components/Home/Customizable/index.tsx b/docs/src/components/Home/Customizable/index.tsx new file mode 100644 index 0000000000..2b659bb550 --- /dev/null +++ b/docs/src/components/Home/Customizable/index.tsx @@ -0,0 +1,77 @@ +import ThemeImage from '@/components/ThemeImage' +import React from 'react' + +const Customizable = () => { + return ( +
+
+

+ Highly Customizable +

+
+

+ Customize Jan to match your needs and preferences. +

+
+
+ +
+
+
+
+

Assistants & Memory

+
+
+ Coming Soon +
+
+
+

+ Create personalized AI assistants that remember your conversations + and execute specific tasks across your systems. +

+
+ +
+ +
+
+
+
+

Extensions

+

+ Customize Jan with Extensions, that range from Cloud AI + connectors, tools, data connectors. +

+
+ +
+ +
+
+
+
+ ) +} + +export default Customizable diff --git a/docs/src/components/Home/Feature/index.tsx b/docs/src/components/Home/Feature/index.tsx new file mode 100644 index 0000000000..38c7c8fadf --- /dev/null +++ b/docs/src/components/Home/Feature/index.tsx @@ -0,0 +1,205 @@ +import ThemeImage from '@/components/ThemeImage' +import { useState } from 'react' +// import { BsArrowRight } from 'react-icons/bs' +import { twMerge } from 'tailwind-merge' + +const features = [ + { + title: 'Chat with AI', + experimantal: false, + description: + 'Ask your questions, brainstorm, and learn from the AI running on your device to be more productive.', + image: { + light: '/assets/images/homepage/features01.png', + dark: '/assets/images/homepage/features01dark.png', + }, + }, + { + title: 'Model Hub', + experimantal: false, + description: `Download and Run powerful models like Llama3, Gemma or Mistral on your computer.`, + image: { + light: '/assets/images/homepage/features02.png', + dark: '/assets/images/homepage/features02dark.png', + }, + }, + { + title: 'Connect to Cloud AIs', + experimantal: false, + description: `You can also route to more powerful cloud models, like OpenAI, Groq, Cohere etc., when needed.`, + image: { + light: '/assets/images/homepage/features03.png', + dark: '/assets/images/homepage/features03dark.png', + }, + }, + { + title: 'Local API Server', + experimantal: false, + description: `Set up and run your own OpenAI-compatible API server using local models with just one click.`, + image: { + light: '/assets/images/homepage/features04.png', + dark: '/assets/images/homepage/features04dark.png', + }, + }, + { + title: 'Chat with your files', + experimantal: true, + description: `Set up and run your own OpenAI-compatible API server using local models with just one click.`, + image: { + light: '/assets/images/homepage/features05.png', + dark: '/assets/images/homepage/features05dark.png', + }, + }, +] + +const Feature = () => { + const [activeFeature, setActiveFeature] = useState(0) + + return ( + <> +
+
+
+
+

+ Features +

+
+
+ +
+
+ {features.map((feature, i) => { + const isActive = activeFeature === i + return ( +
setActiveFeature(i)} + > +
+

+ 0{i + 1} +

+
+
+
{feature.title}
+ {feature.experimantal && ( +
+
+ Experimental +
+
+ )} +
+

+ {feature.description} +

+
+
+
+ +
+
+ ) + })} +
+ +
+ {activeFeature === 0 && ( + + )} + {activeFeature === 1 && ( + + )} + {activeFeature === 2 && ( + + )} + {activeFeature === 3 && ( + + )} + {activeFeature === 4 && ( + + )} +
+
+
+
+ + ) +} + +export default Feature diff --git a/docs/src/components/Home/Hero/index.tsx b/docs/src/components/Home/Hero/index.tsx new file mode 100644 index 0000000000..99d8c69953 --- /dev/null +++ b/docs/src/components/Home/Hero/index.tsx @@ -0,0 +1,124 @@ +import DropdownDownload from '@/components/DropdownDownload' +import ThemeImage from '@/components/ThemeImage' +import { totalDownload } from '@/utils/format' +import Link from 'next/link' +import { useData } from 'nextra/data' + +const QuoteIcon = () => { + return ( +
+ + + + + + + + + +
+ ) +} + +const Hero = () => { + const { lastVersion, lastRelease, release } = useData() + + return ( +
+
+
+ +
+
+ new +
+  ✨  {lastVersion} is now live on + GitHub. Check it out! +
+ +
+ +
+ +

+ Chat with AI
without privacy concerns +

+ +
+ {/* */} + +
+ +

+ Jan is an open source ChatGPT-alternative that runs 100% offline. +

+
+
+ +
+

+ + {totalDownload(release)}+ + +  downloads | Free & Open Source +

+
+ + +
+
+
+ ) +} + +export default Hero diff --git a/docs/src/components/Home/Principles/index.tsx b/docs/src/components/Home/Principles/index.tsx new file mode 100644 index 0000000000..a4db04df56 --- /dev/null +++ b/docs/src/components/Home/Principles/index.tsx @@ -0,0 +1,293 @@ +import LogoMark from '@/components/LogoMark' + +const Principles = () => { + return ( +
+
+
+

+ Our Principles +

+

+ Jan is opinionated software on what AI should be + + + + + + + + + + + + + + + + + + + +

+
+
+ + + + + + + + +
Local-first
+

+ {`We believe your conversations and files should remain yours + alone. That's why we prioritize local-first AI, running + open-source models directly on your computer.`} +

+
+
+ + + + + + + + + + + + + + +
User-owned
+

+ Your data, your rules. Jan stores everything on your device in + universal formats, giving you total freedom to move your data + without tricks or traps. +

+
+
+ + + + + + + + + + + + + + + + + + + + +
+ Fully Customizable +
+

+ You can endlessly customize the experience with 3rd party + extensions. You can adjust alignment, moderation, and censorship + levels to your needs. +

+
+
+
+
+
+ ) +} + +export default Principles diff --git a/docs/src/components/Home/Statistic/index.tsx b/docs/src/components/Home/Statistic/index.tsx new file mode 100644 index 0000000000..42a9e1893c --- /dev/null +++ b/docs/src/components/Home/Statistic/index.tsx @@ -0,0 +1,54 @@ +import ThemeImage from '@/components/ThemeImage' +import { useData } from 'nextra/data' +import { totalDownload } from '@/utils/format' + +const Statistic = () => { + const { release } = useData() + + return ( +
+
+
+
+
+

13

+

+ Core team +

+
+
+

46+

+

+ Contributors +

+
+
+

2800+

+

+ Pull Requests +

+
+
+

{totalDownload(release)}+

+

+ Downloads +

+
+
+
+ +
+
+ ) +} + +export default Statistic diff --git a/docs/src/components/Home/WallOfLove/ArrowButton.tsx b/docs/src/components/Home/WallOfLove/ArrowButton.tsx new file mode 100644 index 0000000000..83d6d6b438 --- /dev/null +++ b/docs/src/components/Home/WallOfLove/ArrowButton.tsx @@ -0,0 +1,98 @@ +import React, { + PropsWithChildren, + useCallback, + useEffect, + useState, +} from 'react' +import { EmblaCarouselType } from 'embla-carousel' + +type UsePrevNextButtonsType = { + prevBtnDisabled: boolean + nextBtnDisabled: boolean + onPrevButtonClick: () => void + onNextButtonClick: () => void +} + +export const usePrevNextButtons = ( + emblaApi: EmblaCarouselType | undefined +): UsePrevNextButtonsType => { + const [prevBtnDisabled, setPrevBtnDisabled] = useState(true) + const [nextBtnDisabled, setNextBtnDisabled] = useState(true) + + const onPrevButtonClick = useCallback(() => { + if (!emblaApi) return + emblaApi.scrollPrev() + }, [emblaApi]) + + const onNextButtonClick = useCallback(() => { + if (!emblaApi) return + emblaApi.scrollNext() + }, [emblaApi]) + + const onSelect = useCallback((emblaApi: EmblaCarouselType) => { + setPrevBtnDisabled(!emblaApi.canScrollPrev()) + setNextBtnDisabled(!emblaApi.canScrollNext()) + }, []) + + useEffect(() => { + if (!emblaApi) return + + onSelect(emblaApi) + emblaApi.on('reInit', onSelect) + emblaApi.on('select', onSelect) + }, [emblaApi, onSelect]) + + return { + prevBtnDisabled, + nextBtnDisabled, + onPrevButtonClick, + onNextButtonClick, + } +} + +type PropType = PropsWithChildren< + React.DetailedHTMLProps< + React.ButtonHTMLAttributes, + HTMLButtonElement + > +> + +export const PrevButton: React.FC = (props) => { + const { children, ...restProps } = props + + return ( + + ) +} + +export const NextButton: React.FC = (props) => { + const { children, ...restProps } = props + + return ( + + ) +} diff --git a/docs/src/components/Home/WallOfLove/ArrowButtonMobile.tsx b/docs/src/components/Home/WallOfLove/ArrowButtonMobile.tsx new file mode 100644 index 0000000000..df9f79355d --- /dev/null +++ b/docs/src/components/Home/WallOfLove/ArrowButtonMobile.tsx @@ -0,0 +1,97 @@ +import React, { + PropsWithChildren, + useCallback, + useEffect, + useState, +} from 'react' +import { EmblaCarouselType } from 'embla-carousel' + +type UsePrevNextButtonsType = { + prevBtnDisabled: boolean + nextBtnDisabled: boolean + onPrevButtonClick: () => void + onNextButtonClick: () => void +} + +export const usePrevNextButtons = ( + emblaApiMobile: EmblaCarouselType | undefined +): UsePrevNextButtonsType => { + const [prevBtnDisabled, setPrevBtnDisabled] = useState(true) + const [nextBtnDisabled, setNextBtnDisabled] = useState(true) + + const onPrevButtonClick = useCallback(() => { + if (!emblaApiMobile) return + emblaApiMobile.scrollPrev() + }, [emblaApiMobile]) + + const onNextButtonClick = useCallback(() => { + if (!emblaApiMobile) return + emblaApiMobile.scrollNext() + }, [emblaApiMobile]) + + const onSelect = useCallback((emblaApiMobile: EmblaCarouselType) => { + setPrevBtnDisabled(!emblaApiMobile.canScrollPrev()) + setNextBtnDisabled(!emblaApiMobile.canScrollNext()) + }, []) + + useEffect(() => { + if (!emblaApiMobile) return + onSelect(emblaApiMobile) + emblaApiMobile.on('reInit', onSelect) + emblaApiMobile.on('select', onSelect) + }, [emblaApiMobile, onSelect]) + + return { + prevBtnDisabled, + nextBtnDisabled, + onPrevButtonClick, + onNextButtonClick, + } +} + +type PropType = PropsWithChildren< + React.DetailedHTMLProps< + React.ButtonHTMLAttributes, + HTMLButtonElement + > +> + +export const PrevButton: React.FC = (props) => { + const { children, ...restProps } = props + + return ( + + ) +} + +export const NextButton: React.FC = (props) => { + const { children, ...restProps } = props + + return ( + + ) +} diff --git a/docs/src/components/Home/WallOfLove/SliderMobile.tsx b/docs/src/components/Home/WallOfLove/SliderMobile.tsx new file mode 100644 index 0000000000..10d4fdd8c9 --- /dev/null +++ b/docs/src/components/Home/WallOfLove/SliderMobile.tsx @@ -0,0 +1,120 @@ +import Autoplay from 'embla-carousel-autoplay' +import AutoScroll from 'embla-carousel-auto-scroll' +import AutoHeight from 'embla-carousel-auto-height' +import useEmblaCarousel from 'embla-carousel-react' +import { PrevButton, NextButton, usePrevNextButtons } from './ArrowButtonMobile' +import { Tweet } from 'react-tweet' + +const slideForMobile = [ + { + type: 'tweet', + id: '1742843063938994469', + }, + { + type: 'youtube', + id: 'zkafOIyQM8s', + }, + + { + type: 'youtube', + id: 'QpMQgJL4AZA', + }, + { + type: 'tweet', + id: '1744729548074459310', + }, + { + type: 'youtube', + id: '7JpzE-_cKo4', + }, + { + type: 'tweet', + id: '1757504717519749292', + }, + { + type: 'youtube', + id: 'ZCiEQVOjH5U', + }, + { + type: 'tweet', + id: '1757500111629025788', + }, + { + type: 'tweet', + id: '1742993414986068423', + }, + { + type: 'youtube', + id: '9ta2S425Zu8', + }, + + { + type: 'youtube', + id: 'ES021_sY6WQ', + }, + { + type: 'youtube', + id: 'CbJGxNmdWws', + }, +] + +const SliderMobile = () => { + const [emblaRefMobile, emblaApiMobile] = useEmblaCarousel( + { slidesToScroll: 'auto', loop: true }, + [AutoHeight(), Autoplay(), AutoScroll({ playOnInit: false })] + ) + + const { + prevBtnDisabled, + nextBtnDisabled, + onPrevButtonClick, + onNextButtonClick, + } = usePrevNextButtons(emblaApiMobile) + + return ( + <> +
+
+ + +
+
+
+
+ {slideForMobile.map((item, i) => { + return ( +
+ <> + {item.type === 'tweet' && ( +
+ +
+ )} + {item.type === 'youtube' && ( +
+