From 90edd986135a2638dc6aa1d8d6633d6b37ca1ae6 Mon Sep 17 00:00:00 2001 From: ItzCrazyKns Date: Wed, 17 Apr 2024 11:27:05 +0530 Subject: [PATCH 1/4] feat(messageHandler): add new emitter event handling --- src/agents/wolframAlphaSearchAgent.ts | 2 +- src/websocket/messageHandler.ts | 236 ++++++-------------------- 2 files changed, 51 insertions(+), 187 deletions(-) diff --git a/src/agents/wolframAlphaSearchAgent.ts b/src/agents/wolframAlphaSearchAgent.ts index a9a3202..c071ef0 100644 --- a/src/agents/wolframAlphaSearchAgent.ts +++ b/src/agents/wolframAlphaSearchAgent.ts @@ -9,7 +9,7 @@ import { RunnableMap, RunnableLambda, } from '@langchain/core/runnables'; -import { ChatOpenAI, OpenAI, OpenAIEmbeddings } from '@langchain/openai'; +import { ChatOpenAI, OpenAI } from '@langchain/openai'; import { StringOutputParser } from '@langchain/core/output_parsers'; import { Document } from '@langchain/core/documents'; import { searchSearxng } from '../core/searxng'; diff --git a/src/websocket/messageHandler.ts b/src/websocket/messageHandler.ts index 08bb4c4..83fa50d 100644 --- a/src/websocket/messageHandler.ts +++ b/src/websocket/messageHandler.ts @@ -1,4 +1,4 @@ -import { WebSocket } from 'ws'; +import { EventEmitter, WebSocket } from 'ws'; import { BaseMessage, AIMessage, HumanMessage } from '@langchain/core/messages'; import handleWebSearch from '../agents/webSearchAgent'; import handleAcademicSearch from '../agents/academicSearchAgent'; @@ -15,6 +15,49 @@ type Message = { history: Array<[string, string]>; }; +const searchHandlers = { + webSearch: handleWebSearch, + academicSearch: handleAcademicSearch, + writingAssistant: handleWritingAssistant, + wolframAlphaSearch: handleWolframAlphaSearch, + youtubeSearch: handleYoutubeSearch, + redditSearch: handleRedditSearch, +}; + +const handleEmitterEvents = ( + emitter: EventEmitter, + ws: WebSocket, + id: string, +) => { + emitter.on('data', (data) => { + const parsedData = JSON.parse(data); + if (parsedData.type === 'response') { + ws.send( + JSON.stringify({ + type: 'message', + data: parsedData.data, + messageId: id, + }), + ); + } else if (parsedData.type === 'sources') { + ws.send( + JSON.stringify({ + type: 'sources', + data: parsedData.data, + messageId: id, + }), + ); + } + }); + emitter.on('end', () => { + ws.send(JSON.stringify({ type: 'messageEnd', messageId: id })); + }); + emitter.on('error', (data) => { + const parsedData = JSON.parse(data); + ws.send(JSON.stringify({ type: 'error', data: parsedData.data })); + }); +}; + export const handleMessage = async (message: string, ws: WebSocket) => { try { const parsedMessage = JSON.parse(message) as Message; @@ -38,191 +81,12 @@ export const handleMessage = async (message: string, ws: WebSocket) => { }); if (parsedMessage.type === 'message') { - switch (parsedMessage.focusMode) { - case 'webSearch': { - const emitter = handleWebSearch(parsedMessage.content, history); - emitter.on('data', (data) => { - const parsedData = JSON.parse(data); - if (parsedData.type === 'response') { - ws.send( - JSON.stringify({ - type: 'message', - data: parsedData.data, - messageId: id, - }), - ); - } else if (parsedData.type === 'sources') { - ws.send( - JSON.stringify({ - type: 'sources', - data: parsedData.data, - messageId: id, - }), - ); - } - }); - emitter.on('end', () => { - ws.send(JSON.stringify({ type: 'messageEnd', messageId: id })); - }); - emitter.on('error', (data) => { - const parsedData = JSON.parse(data); - ws.send(JSON.stringify({ type: 'error', data: parsedData.data })); - }); - break; - } - case 'academicSearch': { - const emitter = handleAcademicSearch(parsedMessage.content, history); - emitter.on('data', (data) => { - const parsedData = JSON.parse(data); - if (parsedData.type === 'response') { - ws.send( - JSON.stringify({ - type: 'message', - data: parsedData.data, - messageId: id, - }), - ); - } else if (parsedData.type === 'sources') { - ws.send( - JSON.stringify({ - type: 'sources', - data: parsedData.data, - messageId: id, - }), - ); - } - }); - emitter.on('end', () => { - ws.send(JSON.stringify({ type: 'messageEnd', messageId: id })); - }); - emitter.on('error', (data) => { - const parsedData = JSON.parse(data); - ws.send(JSON.stringify({ type: 'error', data: parsedData.data })); - }); - break; - } - case 'writingAssistant': { - const emitter = handleWritingAssistant( - parsedMessage.content, - history, - ); - emitter.on('data', (data) => { - const parsedData = JSON.parse(data); - if (parsedData.type === 'response') { - ws.send( - JSON.stringify({ - type: 'message', - data: parsedData.data, - messageId: id, - }), - ); - } - }); - emitter.on('end', () => { - ws.send(JSON.stringify({ type: 'messageEnd', messageId: id })); - }); - emitter.on('error', (data) => { - const parsedData = JSON.parse(data); - ws.send(JSON.stringify({ type: 'error', data: parsedData.data })); - }); - break; - } - case 'wolframAlphaSearch': { - const emitter = handleWolframAlphaSearch( - parsedMessage.content, - history, - ); - emitter.on('data', (data) => { - const parsedData = JSON.parse(data); - if (parsedData.type === 'response') { - ws.send( - JSON.stringify({ - type: 'message', - data: parsedData.data, - messageId: id, - }), - ); - } else if (parsedData.type === 'sources') { - ws.send( - JSON.stringify({ - type: 'sources', - data: parsedData.data, - messageId: id, - }), - ); - } - }); - emitter.on('end', () => { - ws.send(JSON.stringify({ type: 'messageEnd', messageId: id })); - }); - emitter.on('error', (data) => { - const parsedData = JSON.parse(data); - ws.send(JSON.stringify({ type: 'error', data: parsedData.data })); - }); - break; - } - case 'youtubeSearch': { - const emitter = handleYoutubeSearch(parsedMessage.content, history); - emitter.on('data', (data) => { - const parsedData = JSON.parse(data); - if (parsedData.type === 'response') { - ws.send( - JSON.stringify({ - type: 'message', - data: parsedData.data, - messageId: id, - }), - ); - } else if (parsedData.type === 'sources') { - ws.send( - JSON.stringify({ - type: 'sources', - data: parsedData.data, - messageId: id, - }), - ); - } - }); - emitter.on('end', () => { - ws.send(JSON.stringify({ type: 'messageEnd', messageId: id })); - }); - emitter.on('error', (data) => { - const parsedData = JSON.parse(data); - ws.send(JSON.stringify({ type: 'error', data: parsedData.data })); - }); - break; - } - case 'redditSearch': { - const emitter = handleRedditSearch(parsedMessage.content, history); - emitter.on('data', (data) => { - const parsedData = JSON.parse(data); - if (parsedData.type === 'response') { - ws.send( - JSON.stringify({ - type: 'message', - data: parsedData.data, - messageId: id, - }), - ); - } else if (parsedData.type === 'sources') { - ws.send( - JSON.stringify({ - type: 'sources', - data: parsedData.data, - messageId: id, - }), - ); - } - }); - emitter.on('end', () => { - ws.send(JSON.stringify({ type: 'messageEnd', messageId: id })); - }); - emitter.on('error', (data) => { - const parsedData = JSON.parse(data); - ws.send(JSON.stringify({ type: 'error', data: parsedData.data })); - }); - break; - } + const handler = searchHandlers[parsedMessage.focusMode]; + if (handler) { + const emitter = handler(parsedMessage.content, history); + handleEmitterEvents(emitter, ws, id); + } else { + ws.send(JSON.stringify({ type: 'error', data: 'Invalid focus mode' })); } } } catch (error) { From 30d544cb362ceb7603fb06928eaedba278edca19 Mon Sep 17 00:00:00 2001 From: ItzCrazyKns <95534749+ItzCrazyKns@users.noreply.github.com> Date: Wed, 17 Apr 2024 11:40:00 +0530 Subject: [PATCH 2/4] Update issue templates --- .github/ISSUE_TEMPLATE/bug_report.md | 27 +++++++++++++++++++++++ .github/ISSUE_TEMPLATE/custom.md | 10 +++++++++ .github/ISSUE_TEMPLATE/feature_request.md | 20 +++++++++++++++++ 3 files changed, 57 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/custom.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..e065bb4 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,27 @@ +--- +name: Bug report +about: Create an issue to help us fix bugs +title: '' +labels: bug +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/custom.md b/.github/ISSUE_TEMPLATE/custom.md new file mode 100644 index 0000000..48d5f81 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/custom.md @@ -0,0 +1,10 @@ +--- +name: Custom issue template +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 new file mode 100644 index 0000000..11fc491 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: enhancement +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. From 0b18877fb8fe00f2765aa4e7e713c5b1a5474c60 Mon Sep 17 00:00:00 2001 From: ItzCrazyKns <95534749+ItzCrazyKns@users.noreply.github.com> Date: Wed, 17 Apr 2024 11:53:55 +0530 Subject: [PATCH 3/4] Create CONTRIBUTING.md --- CONTRIBUTING.md | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..af43ae1 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,41 @@ +# 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. + +## Project Structure + +Perplexica's design consists of two main domains: + +- **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. + +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. + +## 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`. + +**Please note**: Docker configurations are present for setting up production environments, whereas `npm run dev` is used for development purposes. + +## Coding and Contribution Practices + +Before committing changes: + +1. Ensure that your code functions correctly by thorough testing. +2. Always run `npm run format:write` to format your code according to the project's coding standards. This helps maintain consistency and code quality. +3. We currently do not have a code of conduct, but it is in the works. In the meantime, please be mindful of how you engage with the project and its community. + +Following these steps will help maintain the integrity of Perplexica's codebase and facilitate a smoother integration of your valuable contributions. Thank you for your support and commitment to improving Perplexica. From d14042d62140b95eae26500d902b6900f91d9803 Mon Sep 17 00:00:00 2001 From: ItzCrazyKns Date: Wed, 17 Apr 2024 11:57:45 +0530 Subject: [PATCH 4/4] feat(readme): Add contributing file --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 227e7c9..9d26fae 100644 --- a/README.md +++ b/README.md @@ -94,7 +94,7 @@ If you find Perplexica useful, consider giving us a star on GitHub. This helps m ## Contribution -Perplexica is built on the idea that AI and large language models should be easy for everyone to use. If you find bugs or have ideas, please share them in via GitHub Issues. Details on how to contribute will be shared soon. +Perplexica is built on the idea that AI and large language models should be easy for everyone to use. If you find bugs or have ideas, please share them in via GitHub Issues. For more information on contributing to Perplexica you can read the [CONTRIBUTING.md](CONTRIBUTING.md) file to learn more about Perplexica and how you can contribute to it. ## Acknowledgements