+ {message.content} +
++ Sources +
++ Answer +
+Related
++ {suggestion} +
+diff --git a/.assets/manifest.json b/.assets/manifest.json new file mode 100644 index 0000000..e69de29 diff --git a/.assets/perplexica-screenshot.png b/.assets/perplexica-screenshot.png index c47a544..fc7a697 100644 Binary files a/.assets/perplexica-screenshot.png and b/.assets/perplexica-screenshot.png differ diff --git a/.env.example b/.env.example deleted file mode 100644 index bc67919..0000000 --- a/.env.example +++ /dev/null @@ -1,5 +0,0 @@ -PORT=3001 -OPENAI_API_KEY= -SIMILARITY_MEASURE=cosine # cosine or dot -SEARXNG_API_URL= # no need to fill this if using docker -MODEL_NAME=gpt-3.5-turbo \ No newline at end of file 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/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index e065bb4..1de1177 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -4,7 +4,6 @@ about: Create an issue to help us fix bugs title: '' labels: bug assignees: '' - --- **Describe the bug** @@ -12,6 +11,7 @@ A clear and concise description of what the bug is. **To Reproduce** Steps to reproduce the behavior: + 1. Go to '...' 2. Click on '....' 3. Scroll down to '....' diff --git a/.github/ISSUE_TEMPLATE/custom.md b/.github/ISSUE_TEMPLATE/custom.md index 48d5f81..96a4735 100644 --- a/.github/ISSUE_TEMPLATE/custom.md +++ b/.github/ISSUE_TEMPLATE/custom.md @@ -4,7 +4,4 @@ about: Describe this issue template's purpose here. title: '' labels: '' assignees: '' - --- - - diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 11fc491..5f0a04c 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -4,7 +4,6 @@ about: Suggest an idea for this project title: '' labels: enhancement assignees: '' - --- **Is your feature request related to a problem? Please describe.** diff --git a/.github/workflows/docker-build.yaml b/.github/workflows/docker-build.yaml new file mode 100644 index 0000000..29f7987 --- /dev/null +++ b/.github/workflows/docker-build.yaml @@ -0,0 +1,138 @@ +name: Build & Push Docker Images + +on: + push: + branches: + - master + release: + types: [published] + +jobs: + build-amd64: + runs-on: ubuntu-latest + 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 AMD64 Docker image + if: github.ref == 'refs/heads/master' && github.event_name == 'push' + run: | + 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}:amd64 \ + --push . + + - name: Build and push AMD64 release Docker image + if: github.event_name == 'release' + run: | + 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 }}-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 0f857e0..9fb5e4c 100644 --- a/.gitignore +++ b/.gitignore @@ -4,8 +4,9 @@ npm-debug.log yarn-error.log # Build output -/.next/ -/out/ +.next/ +out/ +dist/ # IDE/Editor specific .vscode/ @@ -19,6 +20,9 @@ yarn-error.log .env.test.local .env.production.local +# Config files +config.toml + # Log files logs/ *.log @@ -28,4 +32,10 @@ logs/ # Miscellaneous .DS_Store -Thumbs.db \ No newline at end of file +Thumbs.db + +# Db +db.sqlite +/searxng + +certificates \ No newline at end of file diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..55d3c7c --- /dev/null +++ b/.prettierignore @@ -0,0 +1,41 @@ +# Ignore all files in the node_modules directory +node_modules + +# Ignore all files in the .next directory (Next.js build output) +.next + +# Ignore all files in the .out directory (TypeScript build output) +.out + +# Ignore all files in the .cache directory (Prettier cache) +.cache + +# Ignore all files in the .vscode directory (Visual Studio Code settings) +.vscode + +# Ignore all files in the .idea directory (IntelliJ IDEA settings) +.idea + +# Ignore all files in the dist directory (build output) +dist + +# Ignore all files in the build directory (build output) +build + +# Ignore all files in the coverage directory (test coverage reports) +coverage + +# Ignore all files with the .log extension +*.log + +# Ignore all files with the .tmp extension +*.tmp + +# Ignore all files with the .swp extension +*.swp + +# Ignore all files with the .DS_Store extension (macOS specific) +.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 af43ae1..7bbb280 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,32 +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. -Both the root directory (for backend configurations outside `src`) and the `ui` folder come with an `.env.example` file. These are templates for environment variables that you need to set up manually for the application to run correctly. +## 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 `.env.example` file. -2. Rename it to `.env` and fill in the necessary environment variables specific to the backend. -3. Run `npm install` to install dependencies. -4. 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`. +1. In the root directory, locate the `sample.config.toml` file. +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 9d26fae..5eb0713 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,24 @@ # 🚀 Perplexica - An AI-powered search engine 🔎 - +
+ {item.content.slice(0, 100)}... +
++ No chats found. +
++ {formatTimeDifference(new Date(), chat.createdAt)} Ago +
++ 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. +
++ {suggestion} +
+