├── .chainlit ├── config.toml └── translations │ ├── en-US.json │ └── pt-BR.json ├── .env.example ├── .github └── FUNDING.yml ├── .gitignore ├── Dockerfile ├── LICENSE ├── README.md ├── agents ├── __init__.py ├── __pycache__ │ ├── __init__.cpython-311.pyc │ └── chainlit_agents.cpython-311.pyc └── chainlit_agents.py ├── app.py ├── asyncapp.py ├── chainlit.md ├── public ├── logo_dark.png └── logo_light.png └── requirements.txt /.chainlit/config.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | # Whether to enable telemetry (default: true). No personal data is collected. 3 | enable_telemetry = true 4 | 5 | 6 | # List of environment variables to be provided by each user to use the app. 7 | user_env = [] 8 | 9 | # Duration (in seconds) during which the session is saved when the connection is lost 10 | session_timeout = 3600 11 | 12 | # Enable third parties caching (e.g LangChain cache) 13 | cache = false 14 | 15 | # Authorized origins 16 | allow_origins = ["*"] 17 | 18 | # Follow symlink for asset mount (see https://github.com/Chainlit/chainlit/issues/317) 19 | # follow_symlink = false 20 | 21 | [features] 22 | # Show the prompt playground 23 | prompt_playground = true 24 | 25 | # Process and display HTML in messages. This can be a security risk (see https://stackoverflow.com/questions/19603097/why-is-it-dangerous-to-render-user-generated-html-or-javascript) 26 | unsafe_allow_html = false 27 | 28 | # Process and display mathematical expressions. This can clash with "$" characters in messages. 29 | latex = false 30 | 31 | # Authorize users to upload files with messages 32 | multi_modal = true 33 | 34 | # Allows user to use speech to text 35 | [features.speech_to_text] 36 | enabled = false 37 | # See all languages here https://github.com/JamesBrill/react-speech-recognition/blob/HEAD/docs/API.md#language-string 38 | # language = "en-US" 39 | 40 | [UI] 41 | # Name of the app and chatbot. 42 | name = "Chatbot" 43 | 44 | # Show the readme while the thread is empty. 45 | show_readme_as_default = true 46 | 47 | # Description of the app and chatbot. This is used for HTML tags. 48 | # description = "" 49 | 50 | # Large size content are by default collapsed for a cleaner ui 51 | default_collapse_content = true 52 | 53 | # The default value for the expand messages settings. 54 | default_expand_messages = false 55 | 56 | # Hide the chain of thought details from the user in the UI. 57 | hide_cot = false 58 | 59 | # Link to your github repo. This will add a github button in the UI's header. 60 | # github = "" 61 | 62 | # Specify a CSS file that can be used to customize the user interface. 63 | # The CSS file can be served from the public directory or via an external link. 64 | # custom_css = "/public/test.css" 65 | 66 | # Specify a custom font url. 67 | # custom_font = "https://fonts.googleapis.com/css2?family=Inter:wght@400;500;700&display=swap" 68 | 69 | # Override default MUI light theme. (Check theme.ts) 70 | [UI.theme] 71 | #font_family = "Inter, sans-serif" 72 | [UI.theme.light] 73 | #background = "#FAFAFA" 74 | #paper = "#FFFFFF" 75 | 76 | [UI.theme.light.primary] 77 | #main = "#F80061" 78 | #dark = "#980039" 79 | #light = "#FFE7EB" 80 | 81 | # Override default MUI dark theme. (Check theme.ts) 82 | [UI.theme.dark] 83 | #background = "#FAFAFA" 84 | #paper = "#FFFFFF" 85 | 86 | [UI.theme.dark.primary] 87 | #main = "#F80061" 88 | #dark = "#980039" 89 | #light = "#FFE7EB" 90 | 91 | 92 | [meta] 93 | generated_by = "1.0.200" 94 | -------------------------------------------------------------------------------- /.chainlit/translations/en-US.json: -------------------------------------------------------------------------------- 1 | { 2 | "components": { 3 | "atoms": { 4 | "buttons": { 5 | "userButton": { 6 | "menu": { 7 | "settings": "Settings", 8 | "settingsKey": "S", 9 | "APIKeys": "API Keys", 10 | "logout": "Logout" 11 | } 12 | } 13 | } 14 | }, 15 | "molecules": { 16 | "newChatButton": { 17 | "newChat": "New Chat" 18 | }, 19 | "tasklist": { 20 | "TaskList": { 21 | "title": "\ud83d\uddd2\ufe0f Task List", 22 | "loading": "Loading...", 23 | "error": "An error occured" 24 | } 25 | }, 26 | "attachments": { 27 | "cancelUpload": "Cancel upload", 28 | "removeAttachment": "Remove attachment" 29 | }, 30 | "newChatDialog": { 31 | "createNewChat": "Create new chat?", 32 | "clearChat": "This will clear the current messages and start a new chat.", 33 | "cancel": "Cancel", 34 | "confirm": "Confirm" 35 | }, 36 | "settingsModal": { 37 | "expandMessages": "Expand Messages", 38 | "hideChainOfThought": "Hide Chain of Thought", 39 | "darkMode": "Dark Mode" 40 | } 41 | }, 42 | "organisms": { 43 | "chat": { 44 | "history": { 45 | "index": { 46 | "lastInputs": "Last Inputs", 47 | "noInputs": "Such empty...", 48 | "loading": "Loading..." 49 | } 50 | }, 51 | "inputBox": { 52 | "input": { 53 | "placeholder": "Type your message here..." 54 | }, 55 | "speechButton": { 56 | "start": "Start recording", 57 | "stop": "Stop recording" 58 | }, 59 | "SubmitButton": { 60 | "sendMessage": "Send message", 61 | "stopTask": "Stop Task" 62 | }, 63 | "UploadButton": { 64 | "attachFiles": "Attach files" 65 | }, 66 | "waterMark": { 67 | "text": "Built with" 68 | } 69 | }, 70 | "Messages": { 71 | "index": { 72 | "running": "Running", 73 | "executedSuccessfully": "executed successfully", 74 | "failed": "failed", 75 | "feedbackUpdated": "Feedback updated", 76 | "updating": "Updating" 77 | } 78 | }, 79 | "dropScreen": { 80 | "dropYourFilesHere": "Drop your files here" 81 | }, 82 | "index": { 83 | "failedToUpload": "Failed to upload", 84 | "cancelledUploadOf": "Cancelled upload of", 85 | "couldNotReachServer": "Could not reach the server", 86 | "continuingChat": "Continuing previous chat" 87 | }, 88 | "settings": { 89 | "settingsPanel": "Settings panel", 90 | "reset": "Reset", 91 | "cancel": "Cancel", 92 | "confirm": "Confirm" 93 | } 94 | }, 95 | "threadHistory": { 96 | "sidebar": { 97 | "filters": { 98 | "FeedbackSelect": { 99 | "feedbackAll": "Feedback: All", 100 | "feedbackPositive": "Feedback: Positive", 101 | "feedbackNegative": "Feedback: Negative" 102 | }, 103 | "SearchBar": { 104 | "search": "Search" 105 | } 106 | }, 107 | "DeleteThreadButton": { 108 | "confirmMessage": "This will delete the thread as well as it's messages and elements.", 109 | "cancel": "Cancel", 110 | "confirm": "Confirm", 111 | "deletingChat": "Deleting chat", 112 | "chatDeleted": "Chat deleted" 113 | }, 114 | "index": { 115 | "pastChats": "Past Chats" 116 | }, 117 | "ThreadList": { 118 | "empty": "Empty..." 119 | }, 120 | "TriggerButton": { 121 | "closeSidebar": "Close sidebar", 122 | "openSidebar": "Open sidebar" 123 | } 124 | }, 125 | "Thread": { 126 | "backToChat": "Go back to chat", 127 | "chatCreatedOn": "This chat was created on" 128 | } 129 | }, 130 | "header": { 131 | "chat": "Chat", 132 | "readme": "Readme" 133 | } 134 | } 135 | }, 136 | "hooks": { 137 | "useLLMProviders": { 138 | "failedToFetchProviders": "Failed to fetch providers:" 139 | } 140 | }, 141 | "pages": { 142 | "Design": {}, 143 | "Env": { 144 | "savedSuccessfully": "Saved successfully", 145 | "requiredApiKeys": "Required API Keys", 146 | "requiredApiKeysInfo": "To use this app, the following API keys are required. The keys are stored on your device's local storage." 147 | }, 148 | "Page": { 149 | "notPartOfProject": "You are not part of this project." 150 | }, 151 | "ResumeButton": { 152 | "resumeChat": "Resume Chat" 153 | } 154 | } 155 | } -------------------------------------------------------------------------------- /.chainlit/translations/pt-BR.json: -------------------------------------------------------------------------------- 1 | { 2 | "components": { 3 | "atoms": { 4 | "buttons": { 5 | "userButton": { 6 | "menu": { 7 | "settings": "Configura\u00e7\u00f5es", 8 | "settingsKey": "S", 9 | "APIKeys": "Chaves de API", 10 | "logout": "Sair" 11 | } 12 | } 13 | } 14 | }, 15 | "molecules": { 16 | "newChatButton": { 17 | "newChat": "Nova Conversa" 18 | }, 19 | "tasklist": { 20 | "TaskList": { 21 | "title": "\ud83d\uddd2\ufe0f Lista de Tarefas", 22 | "loading": "Carregando...", 23 | "error": "Ocorreu um erro" 24 | } 25 | }, 26 | "attachments": { 27 | "cancelUpload": "Cancelar envio", 28 | "removeAttachment": "Remover anexo" 29 | }, 30 | "newChatDialog": { 31 | "createNewChat": "Criar novo chat?", 32 | "clearChat": "Isso limpar\u00e1 as mensagens atuais e iniciar\u00e1 uma nova conversa.", 33 | "cancel": "Cancelar", 34 | "confirm": "Confirmar" 35 | }, 36 | "settingsModal": { 37 | "expandMessages": "Expandir Mensagens", 38 | "hideChainOfThought": "Esconder Sequ\u00eancia de Pensamento", 39 | "darkMode": "Modo Escuro" 40 | } 41 | }, 42 | "organisms": { 43 | "chat": { 44 | "history": { 45 | "index": { 46 | "lastInputs": "\u00daltimas Entradas", 47 | "noInputs": "Vazio...", 48 | "loading": "Carregando..." 49 | } 50 | }, 51 | "inputBox": { 52 | "input": { 53 | "placeholder": "Digite sua mensagem aqui..." 54 | }, 55 | "speechButton": { 56 | "start": "Iniciar grava\u00e7\u00e3o", 57 | "stop": "Parar grava\u00e7\u00e3o" 58 | }, 59 | "SubmitButton": { 60 | "sendMessage": "Enviar mensagem", 61 | "stopTask": "Parar Tarefa" 62 | }, 63 | "UploadButton": { 64 | "attachFiles": "Anexar arquivos" 65 | }, 66 | "waterMark": { 67 | "text": "Constru\u00eddo com" 68 | } 69 | }, 70 | "Messages": { 71 | "index": { 72 | "running": "Executando", 73 | "executedSuccessfully": "executado com sucesso", 74 | "failed": "falhou", 75 | "feedbackUpdated": "Feedback atualizado", 76 | "updating": "Atualizando" 77 | } 78 | }, 79 | "dropScreen": { 80 | "dropYourFilesHere": "Solte seus arquivos aqui" 81 | }, 82 | "index": { 83 | "failedToUpload": "Falha ao enviar", 84 | "cancelledUploadOf": "Envio cancelado de", 85 | "couldNotReachServer": "N\u00e3o foi poss\u00edvel conectar ao servidor", 86 | "continuingChat": "Continuando o chat anterior" 87 | }, 88 | "settings": { 89 | "settingsPanel": "Painel de Configura\u00e7\u00f5es", 90 | "reset": "Redefinir", 91 | "cancel": "Cancelar", 92 | "confirm": "Confirmar" 93 | } 94 | }, 95 | "threadHistory": { 96 | "sidebar": { 97 | "filters": { 98 | "FeedbackSelect": { 99 | "feedbackAll": "Feedback: Todos", 100 | "feedbackPositive": "Feedback: Positivo", 101 | "feedbackNegative": "Feedback: Negativo" 102 | }, 103 | "SearchBar": { 104 | "search": "Buscar" 105 | } 106 | }, 107 | "DeleteThreadButton": { 108 | "confirmMessage": "Isso deletar\u00e1 a conversa, assim como suas mensagens e elementos.", 109 | "cancel": "Cancelar", 110 | "confirm": "Confirmar", 111 | "deletingChat": "Deletando conversa", 112 | "chatDeleted": "Conversa deletada" 113 | }, 114 | "index": { 115 | "pastChats": "Conversas Anteriores" 116 | }, 117 | "ThreadList": { 118 | "empty": "Vazio..." 119 | }, 120 | "TriggerButton": { 121 | "closeSidebar": "Fechar barra lateral", 122 | "openSidebar": "Abrir barra lateral" 123 | } 124 | }, 125 | "Thread": { 126 | "backToChat": "Voltar para a conversa", 127 | "chatCreatedOn": "Esta conversa foi criada em" 128 | } 129 | }, 130 | "header": { 131 | "chat": "Conversa", 132 | "readme": "Leia-me" 133 | } 134 | }, 135 | "hooks": { 136 | "useLLMProviders": { 137 | "failedToFetchProviders": "Falha ao buscar provedores:" 138 | } 139 | }, 140 | "pages": { 141 | "Design": {}, 142 | "Env": { 143 | "savedSuccessfully": "Salvo com sucesso", 144 | "requiredApiKeys": "Chaves de API necess\u00e1rias", 145 | "requiredApiKeysInfo": "Para usar este aplicativo, as seguintes chaves de API s\u00e3o necess\u00e1rias. As chaves s\u00e3o armazenadas localmente em seu dispositivo." 146 | }, 147 | "Page": { 148 | "notPartOfProject": "Voc\u00ea n\u00e3o faz parte deste projeto." 149 | }, 150 | "ResumeButton": { 151 | "resumeChat": "Continuar Conversa" 152 | } 153 | } 154 | } 155 | } -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | OPENAI_API_KEY= -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: antoineross 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | /.cache 3 | /__pycache__ -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.11 2 | 3 | # Create a non-root user 4 | RUN useradd -m -u 1000 user 5 | 6 | # Set user and environment variables 7 | USER user 8 | ENV HOME=/home/user \ 9 | PATH=/home/user/.local/bin:$PATH 10 | 11 | # Set the working directory in the container 12 | WORKDIR $HOME/app 13 | 14 | # Copy the requirements.txt file to the container 15 | COPY requirements.txt $HOME/app/ 16 | 17 | # Install Python dependencies from requirements.txt 18 | RUN pip install -r $HOME/app/requirements.txt 19 | 20 | # Copy the application files, including app.py 21 | COPY . $HOME/app/ 22 | 23 | # Specify the command to run your application 24 | CMD ["chainlit", "run", "app.py", "--port", "7860"] 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Autogen Template 3 | emoji: 🔥 4 | colorFrom: indigo 5 | colorTo: green 6 | sdk: docker 7 | pinned: false 8 | license: apache-2.0 9 | --- 10 | 11 | # Installation and Setup 12 | You will need Python, Conda, Docker (Optional for code-execution), Git, and a text editor installed. 13 | 14 | First install python=3.11 and other 3rd party dependencies. If you have conda installed, you can run the following commands: 15 | 16 | ```shell 17 | conda create --name demo python=3.11 -y 18 | conda activate demo 19 | 20 | pip install -r requirements.txt 21 | ``` 22 | 23 | If you do not have conda installed but have virtualenv installed, you can run the following commands: 24 | ```shell 25 | pip install virtualenv 26 | virtualenv demo -p python3. 27 | 28 | # on windows 29 | demo\Scripts\activate 30 | # on mac/linux 31 | source demo/bin/activate 32 | 33 | pip install -r requirements.txt 34 | ``` 35 | 36 | # Configure the environment variables 37 | Notion webpage for instructions: 38 | https://lopsided-zipper-e29.notion.site/ReviewGPT-57444b82eac643539e393b8fc34d2f38?pvs=4 39 | 40 | # Usage 41 | Run the following command to start the chat interface. Change the logo files on the /public folder to change the logo. 42 | 43 | ```shell 44 | chainlit run app.py 45 | ``` 46 | 47 | # File Structure 48 | 49 | This is an example of using the chainlit chat interface with multi-agent conversation between agents to complete a tasks. 50 | 51 | The tool was developed to grab SAP data online and then process it to easily digestible human language. 52 | 53 | `app.py` - Starts the chat interface. 54 | 55 | -------------------------------------------------------------------------------- /agents/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antoineross/Autogen-UI/52095fb0f6027ed2c9b046a400e5027f9ed3b3ac/agents/__init__.py -------------------------------------------------------------------------------- /agents/__pycache__/__init__.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antoineross/Autogen-UI/52095fb0f6027ed2c9b046a400e5027f9ed3b3ac/agents/__pycache__/__init__.cpython-311.pyc -------------------------------------------------------------------------------- /agents/__pycache__/chainlit_agents.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antoineross/Autogen-UI/52095fb0f6027ed2c9b046a400e5027f9ed3b3ac/agents/__pycache__/chainlit_agents.cpython-311.pyc -------------------------------------------------------------------------------- /agents/chainlit_agents.py: -------------------------------------------------------------------------------- 1 | from autogen.agentchat import Agent, AssistantAgent, UserProxyAgent 2 | from typing import Dict, Optional, Union, Callable 3 | import chainlit as cl 4 | 5 | async def ask_helper(func, **kwargs): 6 | res = await func(**kwargs).send() 7 | while not res: 8 | res = await func(**kwargs).send() 9 | return res 10 | 11 | class ChainlitAssistantAgent(AssistantAgent): 12 | """ 13 | Wrapper for AutoGens Assistant Agent 14 | """ 15 | def send( 16 | self, 17 | message: Union[Dict, str], 18 | recipient: Agent, 19 | request_reply: Optional[bool] = None, 20 | silent: Optional[bool] = False, 21 | ) -> bool: 22 | cl.run_sync( 23 | cl.Message( 24 | content=f'*Sending message to "{recipient.name}":*\n\n{message}', 25 | author=self.name, 26 | ).send() 27 | ) 28 | super(ChainlitAssistantAgent, self).send( 29 | message=message, 30 | recipient=recipient, 31 | request_reply=request_reply, 32 | silent=silent, 33 | ) 34 | 35 | class ChainlitUserProxyAgent(UserProxyAgent): 36 | """ 37 | Wrapper for AutoGens UserProxy Agent. Simplifies the UI by adding CL Actions. 38 | """ 39 | def get_human_input(self, prompt: str) -> str: 40 | if prompt.startswith( 41 | "Provide feedback to chat_manager. Press enter to skip and use auto-reply" 42 | ): 43 | res = cl.run_sync( 44 | ask_helper( 45 | cl.AskActionMessage, 46 | content="Continue or provide feedback?", 47 | actions=[ 48 | cl.Action( name="continue", value="continue", label="✅ Continue" ), 49 | cl.Action( name="feedback",value="feedback", label="💬 Provide feedback"), 50 | cl.Action( name="exit",value="exit", label="🔚 Exit Conversation" ) 51 | ], 52 | ) 53 | ) 54 | if res.get("value") == "continue": 55 | return "" 56 | if res.get("value") == "exit": 57 | return "exit" 58 | 59 | reply = cl.run_sync(ask_helper(cl.AskUserMessage, content=prompt, timeout=60)) 60 | 61 | return reply["output"].strip() 62 | 63 | def send( 64 | self, 65 | message: Union[Dict, str], 66 | recipient: Agent, 67 | request_reply: Optional[bool] = None, 68 | silent: Optional[bool] = False, 69 | ): 70 | cl.run_sync( 71 | cl.Message( 72 | content=f'*Sending message to "{recipient.name}"*:\n\n{message}', 73 | author=self.name, 74 | ).send() 75 | ) 76 | super(ChainlitUserProxyAgent, self).send( 77 | message=message, 78 | recipient=recipient, 79 | request_reply=request_reply, 80 | silent=silent, 81 | ) 82 | -------------------------------------------------------------------------------- /app.py: -------------------------------------------------------------------------------- 1 | """ 2 | This is the template for Autogen UI. 3 | Features: 4 | - Continuous messaging 5 | - Multithreading 6 | - MultiAgent LLM architecture 7 | Written by: Antoine Ross - October 2023. 8 | """ 9 | 10 | import os 11 | from typing import Dict, Optional, Union 12 | from dotenv import load_dotenv, find_dotenv 13 | 14 | import chainlit as cl 15 | from chainlit.types import AskFileResponse 16 | from langchain.document_loaders import PyPDFLoader, TextLoader 17 | from langchain.text_splitter import RecursiveCharacterTextSplitter 18 | from langchain.chains import ConversationalRetrievalChain 19 | 20 | import autogen 21 | from autogen import Agent, AssistantAgent, UserProxyAgent, config_list_from_json 22 | 23 | from agents.chainlit_agents import ChainlitAssistantAgent, ChainlitUserProxyAgent 24 | 25 | load_dotenv(find_dotenv()) 26 | 27 | # -------------------- GLOBAL VARIABLES AND AGENTS ----------------------------------- # 28 | USER_PROXY_NAME = "Query Agent" 29 | ASSISTANT = "Assistant" 30 | 31 | # -------------------- Config List. Edit to change your preferred model to use ----------------------------- # 32 | config_list = autogen.config_list_from_dotenv( 33 | dotenv_file_path = '.env', 34 | model_api_key_map={ 35 | "gpt-3.5-turbo-1106": "OPENAI_API_KEY", 36 | }, 37 | filter_dict={ 38 | "model": { 39 | "gpt-3.5-turbo-1106", 40 | } 41 | } 42 | ) 43 | OPENAI_API_KEY = os.getenv('OPENAI_API_KEY') 44 | llm_config = {"config_list": config_list, "api_key": OPENAI_API_KEY, "cache_seed": 42} 45 | 46 | # -------------------- Instantiate agents at the start of a new chat. Call functions and tools the agents will use. ---------------------------- # 47 | @cl.on_chat_start 48 | async def on_chat_start(): 49 | try: 50 | assistant = ChainlitAssistantAgent( 51 | name="Assistant", llm_config=llm_config, 52 | system_message="""Assistant. Assist the User Proxy in the task.""", 53 | description="Assistant Agent" 54 | ) 55 | 56 | user_proxy = ChainlitUserProxyAgent( 57 | name="User_Proxy", 58 | human_input_mode="ALWAYS", 59 | llm_config=llm_config, 60 | # max_consecutive_auto_reply=3, 61 | # is_termination_msg=lambda x: x.get("content", "").rstrip().endswith("TERMINATE"), 62 | code_execution_config=False, 63 | system_message="""Manager. Do the task. Collaborate with the Assistant to finish the task. 64 | """, 65 | description="User Proxy Agent" 66 | ) 67 | print("Set agents.") 68 | 69 | cl.user_session.set(USER_PROXY_NAME, user_proxy) 70 | cl.user_session.set(ASSISTANT, assistant) 71 | 72 | msg = cl.Message(content=f"""Hello! What task would you like to get done today? 73 | """, 74 | author="User_Proxy") 75 | await msg.send() 76 | 77 | print("Message sent.") 78 | 79 | except Exception as e: 80 | print("Error: ", e) 81 | pass 82 | 83 | # -------------------- Instantiate agents at the start of a new chat. Call functions and tools the agents will use. ---------------------------- # 84 | @cl.on_message 85 | async def run_conversation(message: cl.Message): 86 | #try: 87 | print("Running conversation") 88 | llm_config = {"config_list": config_list, "api_key": OPENAI_API_KEY, "cache_seed": 42} 89 | 90 | CONTEXT = message.content 91 | MAX_ITER = 10 92 | assistant = cl.user_session.get(ASSISTANT) 93 | user_proxy = cl.user_session.get(USER_PROXY_NAME) 94 | print("Setting grouipchat") 95 | groupchat = autogen.GroupChat(agents=[user_proxy, assistant], messages=[], max_round=MAX_ITER) 96 | manager = autogen.GroupChatManager(groupchat=groupchat,llm_config=llm_config) 97 | 98 | # -------------------- Conversation Logic. Edit to change your first message based on the Task you want to get done. ----------------------------- # 99 | if len(groupchat.messages) == 0: 100 | message = f"""Do the task based on the user input: {CONTEXT}.""" 101 | # user_proxy.initiate_chat(manager, message=message) 102 | await cl.Message(content=f"""Starting agents on task...""").send() 103 | await cl.make_async(user_proxy.initiate_chat)( manager, message=message, ) 104 | elif len(groupchat.messages) < MAX_ITER: 105 | await cl.make_async(user_proxy.send)( manager, message=CONTEXT, ) 106 | elif len(groupchat.messages) == MAX_ITER: 107 | await cl.make_async(user_proxy.send)( manager, message="exit", ) 108 | 109 | # except Exception as e: 110 | # print("Error: ", e) 111 | # pass -------------------------------------------------------------------------------- /asyncapp.py: -------------------------------------------------------------------------------- 1 | ########################################################################## 2 | # 3 | # 4 | # Waiting on https://github.com/microsoft/autogen/issues/527 to be solved 5 | # 6 | # 7 | ########################################################################## 8 | 9 | 10 | from typing import Dict, Optional, Union 11 | 12 | import autogen 13 | from autogen import Agent, AssistantAgent, UserProxyAgent, config_list_from_json 14 | import chainlit as cl 15 | 16 | from dotenv import load_dotenv, find_dotenv 17 | load_dotenv(find_dotenv()) 18 | import os 19 | 20 | TASK = "Find the date today." 21 | 22 | 23 | async def ask_helper(func, **kwargs): 24 | res = await func(**kwargs).send() 25 | while not res: 26 | res = await func(**kwargs).send() 27 | return res 28 | 29 | 30 | class ChainlitAssistantAgent(AssistantAgent): 31 | async def a_send( 32 | self, 33 | message: Union[Dict, str], 34 | recipient: Agent, 35 | request_reply: Optional[bool] = None, 36 | silent: Optional[bool] = False, 37 | ) -> bool: 38 | await cl.Message( 39 | content=f'*Sending message to "{recipient.name}":*\n\n{message}', 40 | author="AssistantAgent", 41 | ).send() 42 | await super(ChainlitAssistantAgent, self).a_send( 43 | message=message, 44 | recipient=recipient, 45 | request_reply=request_reply, 46 | silent=silent, 47 | ) 48 | 49 | 50 | class ChainlitUserProxyAgent(UserProxyAgent): 51 | async def get_human_input(self, prompt: str) -> str: 52 | if prompt.startswith( 53 | "Provide feedback to assistant. Press enter to skip and use auto-reply" 54 | ): 55 | res = await ask_helper( 56 | cl.AskActionMessage, 57 | content="Continue or provide feedback?", 58 | actions=[ 59 | cl.Action( 60 | name="continue", value="continue", label="✅ Continue" 61 | ), 62 | cl.Action( 63 | name="feedback", 64 | value="feedback", 65 | label="💬 Provide feedback", 66 | ), 67 | cl.Action( 68 | name="exit", 69 | value="exit", 70 | label="🔚 Exit Conversation" 71 | ), 72 | ], 73 | ) 74 | if res.get("value") == "continue": 75 | return "" 76 | if res.get("value") == "exit": 77 | return "exit" 78 | 79 | reply = await ask_helper( 80 | cl.AskUserMessage, content=prompt, timeout=60) 81 | 82 | return reply["content"].strip() 83 | 84 | async def a_send( 85 | self, 86 | message: Union[Dict, str], 87 | recipient: Agent, 88 | request_reply: Optional[bool] = None, 89 | silent: Optional[bool] = False, 90 | ): 91 | await cl.Message( 92 | content=f'*Sending message to "{recipient.name}"*:\n\n{message}', 93 | author="UserProxyAgent", 94 | ).send() 95 | await super(ChainlitUserProxyAgent, self).a_send( 96 | message=message, 97 | recipient=recipient, 98 | request_reply=request_reply, 99 | silent=silent, 100 | ) 101 | 102 | 103 | @cl.on_chat_start 104 | async def on_chat_start(): 105 | OPENAI_API_KEY = os.getenv('OPENAI_API_KEY') 106 | config_list = autogen.config_list_from_dotenv( 107 | dotenv_file_path = '.env', 108 | model_api_key_map={ 109 | "gpt-3.5-turbo": "OPENAI_API_KEY", 110 | }, 111 | filter_dict={ 112 | "model": { 113 | "gpt-3.5-turbo", 114 | } 115 | } 116 | ) 117 | assistant = ChainlitAssistantAgent( 118 | "assistant", llm_config={"config_list": config_list} 119 | ) 120 | user_proxy = ChainlitUserProxyAgent( 121 | "user_proxy", 122 | code_execution_config={ 123 | "work_dir": "workspace", 124 | "use_docker": False, 125 | }, 126 | ) 127 | await cl.Message(content=f"Starting agents on task: {TASK}...").send() 128 | await user_proxy.a_initiate_chat( 129 | assistant, 130 | message=TASK, 131 | ) -------------------------------------------------------------------------------- /chainlit.md: -------------------------------------------------------------------------------- 1 | # Welcome to Chainlit! 🚀🤖 2 | 3 | Hi there, Developer! 👋 We're excited to have you on board. Chainlit is a powerful tool designed to help you prototype, debug and share applications built on top of LLMs. 4 | 5 | ## Useful Links 🔗 6 | 7 | - **Documentation:** Get started with our comprehensive [Chainlit Documentation](https://docs.chainlit.io) 📚 8 | - **Discord Community:** Join our friendly [Chainlit Discord](https://discord.gg/k73SQ3FyUh) to ask questions, share your projects, and connect with other developers! 💬 9 | 10 | We can't wait to see what you create with Chainlit! Happy coding! 💻😊 11 | 12 | ## Welcome screen 13 | 14 | To modify the welcome screen, edit the `chainlit.md` file at the root of your project. If you do not want a welcome screen, just leave this file empty. 15 | -------------------------------------------------------------------------------- /public/logo_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antoineross/Autogen-UI/52095fb0f6027ed2c9b046a400e5027f9ed3b3ac/public/logo_dark.png -------------------------------------------------------------------------------- /public/logo_light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antoineross/Autogen-UI/52095fb0f6027ed2c9b046a400e5027f9ed3b3ac/public/logo_light.png -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | # Automatically generated by https://github.com/damnever/pigar. 2 | 3 | chainlit==1.0.200 4 | langchain==0.1.5 5 | pyautogen==0.2.10 6 | python-dotenv==1.0.1 7 | --------------------------------------------------------------------------------