diff --git a/.assets/manifest.json b/.assets/manifest.json new file mode 100644 index 0000000..e69de29 diff --git a/ui/.eslintrc.json b/.eslintrc.json similarity index 100% rename from ui/.eslintrc.json rename to .eslintrc.json diff --git a/.github/workflows/docker-build.yaml b/.github/workflows/docker-build.yaml index f658c29..29f7987 100644 --- a/.github/workflows/docker-build.yaml +++ b/.github/workflows/docker-build.yaml @@ -8,18 +8,12 @@ on: types: [published] jobs: - build-and-push: + build-amd64: runs-on: ubuntu-latest - strategy: - matrix: - service: [backend, app] steps: - name: Checkout code uses: actions/checkout@v3 - - name: Set up QEMU - uses: docker/setup-qemu-action@v2 - - name: Set up Docker Buildx uses: docker/setup-buildx-action@v2 with: @@ -36,38 +30,109 @@ jobs: id: version run: echo "RELEASE_VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV - - name: Build and push Docker image for ${{ matrix.service }} + - name: Build and push AMD64 Docker image if: github.ref == 'refs/heads/master' && github.event_name == 'push' run: | - docker buildx create --use - if [[ "${{ matrix.service }}" == "backend" ]]; then \ - DOCKERFILE=backend.dockerfile; \ - IMAGE_NAME=perplexica-backend; \ - else \ - DOCKERFILE=app.dockerfile; \ - IMAGE_NAME=perplexica-frontend; \ - fi - docker buildx build --platform linux/amd64,linux/arm64 \ - --cache-from=type=registry,ref=itzcrazykns1337/${IMAGE_NAME}:main \ + DOCKERFILE=app.dockerfile + IMAGE_NAME=perplexica + docker buildx build --platform linux/amd64 \ + --cache-from=type=registry,ref=itzcrazykns1337/${IMAGE_NAME}:amd64 \ --cache-to=type=inline \ + --provenance false \ -f $DOCKERFILE \ - -t itzcrazykns1337/${IMAGE_NAME}:main \ + -t itzcrazykns1337/${IMAGE_NAME}:amd64 \ --push . - - name: Build and push release Docker image for ${{ matrix.service }} + - name: Build and push AMD64 release Docker image if: github.event_name == 'release' run: | - docker buildx create --use - if [[ "${{ matrix.service }}" == "backend" ]]; then \ - DOCKERFILE=backend.dockerfile; \ - IMAGE_NAME=perplexica-backend; \ - else \ - DOCKERFILE=app.dockerfile; \ - IMAGE_NAME=perplexica-frontend; \ - fi - docker buildx build --platform linux/amd64,linux/arm64 \ - --cache-from=type=registry,ref=itzcrazykns1337/${IMAGE_NAME}:${{ env.RELEASE_VERSION }} \ + DOCKERFILE=app.dockerfile + IMAGE_NAME=perplexica + docker buildx build --platform linux/amd64 \ + --cache-from=type=registry,ref=itzcrazykns1337/${IMAGE_NAME}:${{ env.RELEASE_VERSION }}-amd64 \ --cache-to=type=inline \ + --provenance false \ -f $DOCKERFILE \ - -t itzcrazykns1337/${IMAGE_NAME}:${{ env.RELEASE_VERSION }} \ + -t itzcrazykns1337/${IMAGE_NAME}:${{ env.RELEASE_VERSION }}-amd64 \ --push . + + build-arm64: + runs-on: ubuntu-24.04-arm + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + with: + install: true + + - name: Log in to DockerHub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Extract version from release tag + if: github.event_name == 'release' + id: version + run: echo "RELEASE_VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV + + - name: Build and push ARM64 Docker image + if: github.ref == 'refs/heads/master' && github.event_name == 'push' + run: | + DOCKERFILE=app.dockerfile + IMAGE_NAME=perplexica + docker buildx build --platform linux/arm64 \ + --cache-from=type=registry,ref=itzcrazykns1337/${IMAGE_NAME}:arm64 \ + --cache-to=type=inline \ + --provenance false \ + -f $DOCKERFILE \ + -t itzcrazykns1337/${IMAGE_NAME}:arm64 \ + --push . + + - name: Build and push ARM64 release Docker image + if: github.event_name == 'release' + run: | + DOCKERFILE=app.dockerfile + IMAGE_NAME=perplexica + docker buildx build --platform linux/arm64 \ + --cache-from=type=registry,ref=itzcrazykns1337/${IMAGE_NAME}:${{ env.RELEASE_VERSION }}-arm64 \ + --cache-to=type=inline \ + --provenance false \ + -f $DOCKERFILE \ + -t itzcrazykns1337/${IMAGE_NAME}:${{ env.RELEASE_VERSION }}-arm64 \ + --push . + + manifest: + needs: [build-amd64, build-arm64] + runs-on: ubuntu-latest + steps: + - name: Log in to DockerHub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Extract version from release tag + if: github.event_name == 'release' + id: version + run: echo "RELEASE_VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV + + - name: Create and push multi-arch manifest for main + if: github.ref == 'refs/heads/master' && github.event_name == 'push' + run: | + IMAGE_NAME=perplexica + docker manifest create itzcrazykns1337/${IMAGE_NAME}:main \ + --amend itzcrazykns1337/${IMAGE_NAME}:amd64 \ + --amend itzcrazykns1337/${IMAGE_NAME}:arm64 + docker manifest push itzcrazykns1337/${IMAGE_NAME}:main + + - name: Create and push multi-arch manifest for releases + if: github.event_name == 'release' + run: | + IMAGE_NAME=perplexica + docker manifest create itzcrazykns1337/${IMAGE_NAME}:${{ env.RELEASE_VERSION }} \ + --amend itzcrazykns1337/${IMAGE_NAME}:${{ env.RELEASE_VERSION }}-amd64 \ + --amend itzcrazykns1337/${IMAGE_NAME}:${{ env.RELEASE_VERSION }}-arm64 + docker manifest push itzcrazykns1337/${IMAGE_NAME}:${{ env.RELEASE_VERSION }} diff --git a/.gitignore b/.gitignore index 8391d19..9fb5e4c 100644 --- a/.gitignore +++ b/.gitignore @@ -4,9 +4,9 @@ npm-debug.log yarn-error.log # Build output -/.next/ -/out/ -/dist/ +.next/ +out/ +dist/ # IDE/Editor specific .vscode/ @@ -37,3 +37,5 @@ Thumbs.db # Db db.sqlite /searxng + +certificates \ No newline at end of file diff --git a/.prettierignore b/.prettierignore index c184fdb..55d3c7c 100644 --- a/.prettierignore +++ b/.prettierignore @@ -35,4 +35,7 @@ coverage *.swp # Ignore all files with the .DS_Store extension (macOS specific) -.DS_Store \ No newline at end of file +.DS_Store + +# Ignore all files in uploads directory +uploads \ No newline at end of file diff --git a/.prettierrc.js b/.prettierrc.js index 1937ff1..8ca480f 100644 --- a/.prettierrc.js +++ b/.prettierrc.js @@ -6,7 +6,6 @@ const config = { endOfLine: 'auto', singleQuote: true, tabWidth: 2, - semi: true, }; module.exports = config; diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 73256bd..7bbb280 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,31 +1,43 @@ # How to Contribute to Perplexica -Hey there, thanks for deciding to contribute to Perplexica. Anything you help with will support the development of Perplexica and will make it better. Let's walk you through the key aspects to ensure your contributions are effective and in harmony with the project's setup. +Thanks for your interest in contributing to Perplexica! Your help makes this project better. This guide explains how to contribute effectively. + +Perplexica is a modern AI chat application with advanced search capabilities. ## Project Structure -Perplexica's design consists of two main domains: +Perplexica's codebase is organized as follows: -- **Frontend (`ui` directory)**: This is a Next.js application holding all user interface components. It's a self-contained environment that manages everything the user interacts with. -- **Backend (root and `src` directory)**: The backend logic is situated in the `src` folder, but the root directory holds the main `package.json` for backend dependency management. +- **UI Components and Pages**: + - **Components (`src/components`)**: Reusable UI components. + - **Pages and Routes (`src/app`)**: Next.js app directory structure with page components. + - Main app routes include: home (`/`), chat (`/c`), discover (`/discover`), library (`/library`), and settings (`/settings`). + - **API Routes (`src/app/api`)**: API endpoints implemented with Next.js API routes. + - `/api/chat`: Handles chat interactions. + - `/api/search`: Provides direct access to Perplexica's search capabilities. + - Other endpoints for models, files, and suggestions. +- **Backend Logic (`src/lib`)**: Contains all the backend functionality including search, database, and API logic. + - The search functionality is present inside `src/lib/search` directory. + - All of the focus modes are implemented using the Meta Search Agent class in `src/lib/search/metaSearchAgent.ts`. + - Database functionality is in `src/lib/db`. + - Chat model and embedding model providers are managed in `src/lib/providers`. + - Prompt templates and LLM chain definitions are in `src/lib/prompts` and `src/lib/chains` respectively. + +## API Documentation + +Perplexica exposes several API endpoints for programmatic access, including: + +- **Search API**: Access Perplexica's advanced search capabilities directly via the `/api/search` endpoint. For detailed documentation, see `docs/api/search.md`. ## Setting Up Your Environment Before diving into coding, setting up your local environment is key. Here's what you need to do: -### Backend - 1. In the root directory, locate the `sample.config.toml` file. -2. Rename it to `config.toml` and fill in the necessary configuration fields specific to the backend. -3. Run `npm install` to install dependencies. -4. Run `npm run db:push` to set up the local sqlite. -5. Use `npm run dev` to start the backend in development mode. - -### Frontend - -1. Navigate to the `ui` folder and repeat the process of renaming `.env.example` to `.env`, making sure to provide the frontend-specific variables. -2. Execute `npm install` within the `ui` directory to get the frontend dependencies ready. -3. Launch the frontend development server with `npm run dev`. +2. Rename it to `config.toml` and fill in the necessary configuration fields. +3. Run `npm install` to install all dependencies. +4. Run `npm run db:push` to set up the local sqlite database. +5. Use `npm run dev` to start the application in development mode. **Please note**: Docker configurations are present for setting up production environments, whereas `npm run dev` is used for development purposes. diff --git a/README.md b/README.md index 721d41c..5eb0713 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,23 @@ # 🚀 Perplexica - An AI-powered search engine 🔎 +
+ {item.content.slice(0, 100)}... +
++ Theme +
++ Measurement Units +
++ Automatic Image Search +
++ Automatically search for relevant images in chat + responses +
++ Automatic Video Search +
++ Automatically search for relevant videos in chat + responses +
++ Chat Model Provider +
++ Chat Model +
++ Model Name +
+ ) => { + setConfig((prev) => ({ + ...prev!, + customOpenaiModelName: e.target.value, + })); + }} + onSave={(value) => + saveConfig('customOpenaiModelName', value) + } + /> ++ Custom OpenAI API Key +
+ ) => { + setConfig((prev) => ({ + ...prev!, + customOpenaiApiKey: e.target.value, + })); + }} + onSave={(value) => + saveConfig('customOpenaiApiKey', value) + } + /> ++ Custom OpenAI Base URL +
+ ) => { + setConfig((prev) => ({ + ...prev!, + customOpenaiApiUrl: e.target.value, + })); + }} + onSave={(value) => + saveConfig('customOpenaiApiUrl', value) + } + /> ++ Embedding Model Provider +
++ Embedding Model +
++ OpenAI API Key +
+ { + setConfig((prev) => ({ + ...prev!, + openaiApiKey: e.target.value, + })); + }} + onSave={(value) => saveConfig('openaiApiKey', value)} + /> ++ Ollama API URL +
+ { + setConfig((prev) => ({ + ...prev!, + ollamaApiUrl: e.target.value, + })); + }} + onSave={(value) => saveConfig('ollamaApiUrl', value)} + /> ++ Ollama API Key (Can be left blank) +
+ { + setConfig((prev) => ({ + ...prev!, + ollamaApiKey: e.target.value, + })); + }} + onSave={(value) => saveConfig('ollamaApiKey', value)} + /> ++ GROQ API Key +
+ { + setConfig((prev) => ({ + ...prev!, + groqApiKey: e.target.value, + })); + }} + onSave={(value) => saveConfig('groqApiKey', value)} + /> ++ Anthropic API Key +
+ { + setConfig((prev) => ({ + ...prev!, + anthropicApiKey: e.target.value, + })); + }} + onSave={(value) => saveConfig('anthropicApiKey', value)} + /> ++ Gemini API Key +
+ { + setConfig((prev) => ({ + ...prev!, + geminiApiKey: e.target.value, + })); + }} + onSave={(value) => saveConfig('geminiApiKey', value)} + /> ++ Deepseek API Key +
+ { + setConfig((prev) => ({ + ...prev!, + deepseekApiKey: e.target.value, + })); + }} + onSave={(value) => saveConfig('deepseekApiKey', value)} + /> ++ AI/ML API Key +
+ { + setConfig((prev) => ({ + ...prev!, + aimlApiKey: e.target.value, + })); + }} + onSave={(value) => saveConfig('aimlApiKey', value)} + /> ++ LM Studio API URL +
+ { + setConfig((prev) => ({ + ...prev!, + lmStudioApiUrl: e.target.value, + })); + }} + onSave={(value) => saveConfig('lmStudioApiUrl', value)} + /> ++ Failed to connect to the server. Please try again later. +
+