├── .github └── workflows │ └── ci.yml ├── .gitignore ├── LICENSE ├── MANIFEST.in ├── README.md ├── doppio_bot ├── __init__.py ├── api.py ├── config │ └── __init__.py ├── frappe_chatgpt_integration │ ├── __init__.py │ ├── doctype │ │ ├── __init__.py │ │ └── doppiobot_settings │ │ │ ├── __init__.py │ │ │ ├── doppiobot_settings.js │ │ │ ├── doppiobot_settings.json │ │ │ ├── doppiobot_settings.py │ │ │ └── test_doppiobot_settings.py │ └── page │ │ ├── __init__.py │ │ └── doppio_bot │ │ ├── __init__.py │ │ ├── doppio_bot.js │ │ └── doppio_bot.json ├── hooks.py ├── modules.txt ├── patches.txt ├── public │ ├── .gitkeep │ └── js │ │ ├── App.jsx │ │ ├── ChatView.jsx │ │ ├── app_customizations.js │ │ ├── components │ │ └── message │ │ │ ├── CopyToClipboardButton.jsx │ │ │ ├── Message.jsx │ │ │ ├── MessageBubble.jsx │ │ │ ├── MessageLoadingSkeletonText.jsx │ │ │ └── MessageRenderer.jsx │ │ └── doppiobot_ui.bundle.jsx ├── templates │ ├── __init__.py │ └── pages │ │ └── __init__.py └── www │ └── __init__.py ├── package.json ├── requirements.txt ├── setup.py └── yarn.lock /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | 2 | name: CI 3 | 4 | on: 5 | push: 6 | branches: 7 | - develop 8 | pull_request: 9 | 10 | concurrency: 11 | group: develop-doppio_bot-${{ github.event.number }} 12 | cancel-in-progress: true 13 | 14 | jobs: 15 | tests: 16 | runs-on: ubuntu-latest 17 | strategy: 18 | fail-fast: false 19 | name: Server 20 | 21 | services: 22 | redis-cache: 23 | image: redis:alpine 24 | ports: 25 | - 13000:6379 26 | redis-queue: 27 | image: redis:alpine 28 | ports: 29 | - 11000:6379 30 | redis-socketio: 31 | image: redis:alpine 32 | ports: 33 | - 12000:6379 34 | mariadb: 35 | image: mariadb:10.6 36 | env: 37 | MYSQL_ROOT_PASSWORD: root 38 | ports: 39 | - 3306:3306 40 | options: --health-cmd="mysqladmin ping" --health-interval=5s --health-timeout=2s --health-retries=3 41 | 42 | steps: 43 | - name: Clone 44 | uses: actions/checkout@v3 45 | 46 | - name: Setup Python 47 | uses: actions/setup-python@v4 48 | with: 49 | python-version: '3.10' 50 | 51 | - name: Setup Node 52 | uses: actions/setup-node@v3 53 | with: 54 | node-version: 16 55 | check-latest: true 56 | 57 | - name: Cache pip 58 | uses: actions/cache@v2 59 | with: 60 | path: ~/.cache/pip 61 | key: ${{ runner.os }}-pip-${{ hashFiles('**/*requirements.txt', '**/pyproject.toml', '**/setup.py', '**/setup.cfg') }} 62 | restore-keys: | 63 | ${{ runner.os }}-pip- 64 | ${{ runner.os }}- 65 | 66 | - name: Get yarn cache directory path 67 | id: yarn-cache-dir-path 68 | run: 'echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT' 69 | 70 | - uses: actions/cache@v3 71 | id: yarn-cache 72 | with: 73 | path: ${{ steps.yarn-cache-dir-path.outputs.dir }} 74 | key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} 75 | restore-keys: | 76 | ${{ runner.os }}-yarn- 77 | 78 | - name: Setup 79 | run: | 80 | pip install frappe-bench 81 | bench init --skip-redis-config-generation --skip-assets --python "$(which python)" ~/frappe-bench 82 | mysql --host 127.0.0.1 --port 3306 -u root -proot -e "SET GLOBAL character_set_server = 'utf8mb4'" 83 | mysql --host 127.0.0.1 --port 3306 -u root -proot -e "SET GLOBAL collation_server = 'utf8mb4_unicode_ci'" 84 | 85 | - name: Install 86 | working-directory: /home/runner/frappe-bench 87 | run: | 88 | bench get-app doppio_bot $GITHUB_WORKSPACE 89 | bench setup requirements --dev 90 | bench new-site --db-root-password root --admin-password admin test_site 91 | bench --site test_site install-app doppio_bot 92 | bench build 93 | env: 94 | CI: 'Yes' 95 | 96 | - name: Run Tests 97 | working-directory: /home/runner/frappe-bench 98 | run: | 99 | bench --site test_site set-config allow_tests true 100 | bench --site test_site run-tests --app doppio_bot 101 | env: 102 | TYPE: server 103 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.pyc 3 | *.egg-info 4 | *.swp 5 | tags 6 | node_modules 7 | doppio_bot/public/dist/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Mohammad Hussain Nagaria 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include MANIFEST.in 2 | include requirements.txt 3 | include *.json 4 | include *.md 5 | include *.py 6 | include *.txt 7 | recursive-include doppio_bot *.css 8 | recursive-include doppio_bot *.csv 9 | recursive-include doppio_bot *.html 10 | recursive-include doppio_bot *.ico 11 | recursive-include doppio_bot *.js 12 | recursive-include doppio_bot *.json 13 | recursive-include doppio_bot *.md 14 | recursive-include doppio_bot *.png 15 | recursive-include doppio_bot *.py 16 | recursive-include doppio_bot *.svg 17 | recursive-include doppio_bot *.txt 18 | recursive-exclude doppio_bot *.pyc -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DoppioBot 2 | 3 | 4 | 5 | Use. Play. Extend. ChatGPT experience, built right into Frappe's desk interface. 6 | 7 | ## Announcement Blog Post 8 | 9 | You can read more on how DoppioBot is built, how to use it and how to extend it for your own applications in [this](https://frappe.io/blog/engineering/introducing-doppiobot-template) blog post. 10 | 11 | ## Tech Stack 12 | 13 | - [Frappe Framework](https://frappeframework.com) 14 | - Python & JavaScript 15 | - MariaDB 16 | - Redis 17 | - [LangChain](https://python.langchain.com/en/latest/) 18 | - [OpenAI API](https://openai.com/blog/openai-api) 19 | - [ReactJS](https://reactjs.org) 20 | - [ChakraUI](https://chakra-ui.com) 21 | 22 | ## Installation & Usage 23 | 24 | Just like any other Frappe app, if you have bench installed, you can execute the following commands to install the **DoppioBot** app on your Frappe site: 25 | 26 | ```bash 27 | bench get-app NagariaHussain/doppio_bot 28 | bench --site install-app doppio_bot 29 | ``` 30 | 31 | Then add your OpenAI API key to the `site_config.json` (of the site you have installed the app on): 32 | 33 | ```json 34 | "openai_api_key": "sk-your-secret-api-key" 35 | ``` 36 | 37 | Then navigate to your site, use the awesome bar for **Ask DoppioBot**, and enjoy! 38 | 39 | ### Chat Interface 40 | 41 | ![doppio_bot_cover_image](https://user-images.githubusercontent.com/34810212/233837411-68359b1d-8a5a-4f7e-bf13-45f534cb6d64.png) 42 | 43 | The Chat page is built using Frappe's Custom Pages feature, React, and ChakraUI. 44 | 45 | ## Features 46 | 47 | ![DoppioBot Feature Sneak](https://user-images.githubusercontent.com/34810212/233836622-eac2011c-f84d-476d-926f-2e08da2b396d.png) 48 | 49 | - Session Chat history management with Redis 50 | - Formatting of markdown responses including tables and lists 51 | - Code block responses are syntax-highlighted and have a click to copy button! 52 | - A sleek loading skeleton is shown while the message is being fetched 53 | - The prompt can be submitted through mouse as well as keyboard (`Cmd + Enter`) 54 | 55 | 56 | ### API 57 | 58 | ![bot_fun_chat](https://user-images.githubusercontent.com/34810212/233836619-7d8eca87-a177-4659-bef1-7dbbf699cca7.png) 59 | 60 | The API that powers the chat page is built using the LangChain Python package. 61 | 62 | ## Advanced Example: Agent with Custom Tool 63 | 64 | Here is an example of an conversational agent that uses a custom tool that creates a ToDo document in the Frappe backend: 65 | 66 | ```python 67 | from langchain import OpenAI 68 | from langchain.agents import tool 69 | from langchain.agents import AgentType 70 | from langchain.memory import ConversationBufferMemory 71 | from langchain.agents import initialize_agent 72 | 73 | llm = OpenAI(temperature=0) 74 | memory = ConversationBufferMemory(memory_key="chat_history") 75 | tools = [create_todo] 76 | 77 | agent_chain = initialize_agent( 78 | tools, 79 | llm, 80 | agent=AgentType.CONVERSATIONAL_REACT_DESCRIPTION, 81 | verbose=True, 82 | memory=memory, 83 | ) 84 | 85 | # Will call the tool with proper JSON and voila, magic! 86 | agent.run("I have to create a college report before May 17, 2023, can you set a task for me?") 87 | ``` 88 | 89 | The tool that creates new `ToDo` documents in Frappe: 90 | 91 | ```python 92 | @tool 93 | def create_todo(todo: str) -> str: 94 | """ 95 | Create a new ToDo document, can be used when you need to store a note or todo or task for the user. 96 | It takes a json string as input and requires at least the `description`. Returns "done" if the 97 | todo was created and "failed" if the creation failed. Optionally it could contain a `date` 98 | field (in the JSON) which is the due date or reminder date for the task or todo. The `date` must follow 99 | the "YYYY-MM-DD" format. You don't need to add timezone to the date. 100 | """ 101 | try: 102 | data = frappe.parse_json(todo) 103 | todo = frappe.new_doc("ToDo") 104 | todo.update(data) 105 | todo.save() 106 | return "done" 107 | except Exception: 108 | return "failed" 109 | ``` 110 | 111 | Learn more about creating custom tools [here](https://python.langchain.com/en/latest/modules/agents/tools/custom_tools.html). 112 | 113 | #### License 114 | 115 | MIT 116 | -------------------------------------------------------------------------------- /doppio_bot/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | __version__ = '0.0.1' 3 | 4 | -------------------------------------------------------------------------------- /doppio_bot/api.py: -------------------------------------------------------------------------------- 1 | import frappe 2 | 3 | from langchain.llms import OpenAI 4 | from langchain.memory import RedisChatMessageHistory, ConversationBufferMemory 5 | from langchain.chains import ConversationChain 6 | from langchain.prompts import PromptTemplate 7 | 8 | 9 | # Note: Copied the default template and added extra instructions for code output 10 | prompt_template = PromptTemplate( 11 | input_variables=["history", "input"], 12 | output_parser=None, 13 | partial_variables={}, 14 | template=""" 15 | The following is a friendly conversation between a human and an AI. 16 | The AI is talkative and provides lots of specific details from its context. The AI's name is DoppioBot and it's birth date it 24th April, 2023. 17 | If the AI does not know the answer to a question, it truthfully says it does not know. 18 | Any programming code should be output in a github flavored markdown code block mentioning the programming language. 19 | 20 | 21 | Current conversation: 22 | {history} 23 | Human: {input} 24 | AI:""", 25 | template_format="f-string", 26 | validate_template=True, 27 | ) 28 | 29 | 30 | @frappe.whitelist() 31 | def get_chatbot_response(session_id: str, prompt_message: str) -> str: 32 | # Throw if no key in site_config 33 | # Maybe extract and cache this (site cache) 34 | opeai_api_key = frappe.conf.get("openai_api_key") 35 | openai_model = get_model_from_settings() 36 | 37 | if not opeai_api_key: 38 | frappe.throw("Please set `openai_api_key` in site config") 39 | 40 | llm = OpenAI(model_name=openai_model, temperature=0, openai_api_key=opeai_api_key) 41 | message_history = RedisChatMessageHistory( 42 | session_id=session_id, 43 | url=frappe.conf.get("redis_cache") or "redis://localhost:6379/0", 44 | ) 45 | memory = ConversationBufferMemory(memory_key="history", chat_memory=message_history) 46 | conversation_chain = ConversationChain(llm=llm, memory=memory, prompt=prompt_template) 47 | 48 | response = conversation_chain.run(prompt_message) 49 | return response 50 | 51 | 52 | def get_model_from_settings(): 53 | return ( 54 | frappe.db.get_single_value("DoppioBot Settings", "openai_model") or "gpt-3.5-turbo" 55 | ) 56 | -------------------------------------------------------------------------------- /doppio_bot/config/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NagariaHussain/doppio_bot/e063dc943d1ec6a483818a962031a0a6d28e519a/doppio_bot/config/__init__.py -------------------------------------------------------------------------------- /doppio_bot/frappe_chatgpt_integration/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NagariaHussain/doppio_bot/e063dc943d1ec6a483818a962031a0a6d28e519a/doppio_bot/frappe_chatgpt_integration/__init__.py -------------------------------------------------------------------------------- /doppio_bot/frappe_chatgpt_integration/doctype/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NagariaHussain/doppio_bot/e063dc943d1ec6a483818a962031a0a6d28e519a/doppio_bot/frappe_chatgpt_integration/doctype/__init__.py -------------------------------------------------------------------------------- /doppio_bot/frappe_chatgpt_integration/doctype/doppiobot_settings/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NagariaHussain/doppio_bot/e063dc943d1ec6a483818a962031a0a6d28e519a/doppio_bot/frappe_chatgpt_integration/doctype/doppiobot_settings/__init__.py -------------------------------------------------------------------------------- /doppio_bot/frappe_chatgpt_integration/doctype/doppiobot_settings/doppiobot_settings.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, Hussain Nagaria and contributors 2 | // For license information, please see license.txt 3 | 4 | // frappe.ui.form.on("DoppioBot Settings", { 5 | // refresh(frm) { 6 | 7 | // }, 8 | // }); 9 | -------------------------------------------------------------------------------- /doppio_bot/frappe_chatgpt_integration/doctype/doppiobot_settings/doppiobot_settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "actions": [], 3 | "allow_rename": 1, 4 | "creation": "2023-06-21 13:00:34.366049", 5 | "doctype": "DocType", 6 | "engine": "InnoDB", 7 | "field_order": [ 8 | "openai_model" 9 | ], 10 | "fields": [ 11 | { 12 | "default": "gpt-3.5-turbo", 13 | "fieldname": "openai_model", 14 | "fieldtype": "Select", 15 | "label": "OpenAI Model", 16 | "options": "gpt-3.5-turbo\ngpt-3.5-turbo-16k\ntext-davinci-003\ngpt-4\ngpt-4-32k" 17 | } 18 | ], 19 | "index_web_pages_for_search": 1, 20 | "issingle": 1, 21 | "links": [], 22 | "modified": "2023-06-21 13:06:09.895694", 23 | "modified_by": "Administrator", 24 | "module": "Frappe ChatGPT Integration", 25 | "name": "DoppioBot Settings", 26 | "owner": "Administrator", 27 | "permissions": [ 28 | { 29 | "create": 1, 30 | "delete": 1, 31 | "email": 1, 32 | "print": 1, 33 | "read": 1, 34 | "role": "System Manager", 35 | "share": 1, 36 | "write": 1 37 | } 38 | ], 39 | "sort_field": "modified", 40 | "sort_order": "DESC", 41 | "states": [] 42 | } -------------------------------------------------------------------------------- /doppio_bot/frappe_chatgpt_integration/doctype/doppiobot_settings/doppiobot_settings.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023, Hussain Nagaria and contributors 2 | # For license information, please see license.txt 3 | 4 | # import frappe 5 | from frappe.model.document import Document 6 | 7 | 8 | class DoppioBotSettings(Document): 9 | pass 10 | -------------------------------------------------------------------------------- /doppio_bot/frappe_chatgpt_integration/doctype/doppiobot_settings/test_doppiobot_settings.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023, Hussain Nagaria and Contributors 2 | # See license.txt 3 | 4 | # import frappe 5 | from frappe.tests.utils import FrappeTestCase 6 | 7 | 8 | class TestDoppioBotSettings(FrappeTestCase): 9 | pass 10 | -------------------------------------------------------------------------------- /doppio_bot/frappe_chatgpt_integration/page/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NagariaHussain/doppio_bot/e063dc943d1ec6a483818a962031a0a6d28e519a/doppio_bot/frappe_chatgpt_integration/page/__init__.py -------------------------------------------------------------------------------- /doppio_bot/frappe_chatgpt_integration/page/doppio_bot/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NagariaHussain/doppio_bot/e063dc943d1ec6a483818a962031a0a6d28e519a/doppio_bot/frappe_chatgpt_integration/page/doppio_bot/__init__.py -------------------------------------------------------------------------------- /doppio_bot/frappe_chatgpt_integration/page/doppio_bot/doppio_bot.js: -------------------------------------------------------------------------------- 1 | frappe.pages["doppio-bot"].on_page_load = function (wrapper) { 2 | frappe.ui.make_app_page({ 3 | parent: wrapper, 4 | single_column: true, 5 | }); 6 | }; 7 | 8 | frappe.pages["doppio-bot"].on_page_show = function (wrapper) { 9 | load_doppiobot_ui(wrapper); 10 | }; 11 | 12 | function load_doppiobot_ui(wrapper) { 13 | let $parent = $(wrapper).find(".layout-main-section"); 14 | $parent.empty(); 15 | 16 | frappe.require("doppiobot_ui.bundle.jsx").then(() => { 17 | new doppiobot.ui.DoppioBotUI({ 18 | wrapper: $parent, 19 | page: wrapper.page, 20 | }); 21 | }); 22 | } 23 | -------------------------------------------------------------------------------- /doppio_bot/frappe_chatgpt_integration/page/doppio_bot/doppio_bot.json: -------------------------------------------------------------------------------- 1 | { 2 | "content": null, 3 | "creation": "2023-03-19 12:19:57.679706", 4 | "docstatus": 0, 5 | "doctype": "Page", 6 | "idx": 0, 7 | "modified": "2023-04-10 12:23:49.022908", 8 | "modified_by": "Administrator", 9 | "module": "Frappe ChatGPT Integration", 10 | "name": "doppio-bot", 11 | "owner": "Administrator", 12 | "page_name": "doppio-bot", 13 | "roles": [ 14 | { 15 | "role": "System Manager" 16 | } 17 | ], 18 | "script": null, 19 | "standard": "Yes", 20 | "style": null, 21 | "system_page": 0, 22 | "title": "Ask DoppioBot" 23 | } -------------------------------------------------------------------------------- /doppio_bot/hooks.py: -------------------------------------------------------------------------------- 1 | from . import __version__ as app_version 2 | 3 | app_name = "doppio_bot" 4 | app_title = "DoppioBot" 5 | app_publisher = "Hussain Nagaria" 6 | app_description = "ChatGPT in the Desk, powered by React, LangChain & OpenAI API" 7 | app_email = "hussain@frappe.io" 8 | app_license = "AGPL-3.0" 9 | 10 | # Includes in 11 | # ------------------ 12 | 13 | # include js, css files in header of desk.html 14 | # app_include_css = "/assets/doppio_bot/css/doppio_bot.css" 15 | app_include_js = "/assets/doppio_bot/js/app_customizations.js" 16 | 17 | # include js, css files in header of web template 18 | # web_include_css = "/assets/doppio_bot/css/doppio_bot.css" 19 | # web_include_js = "/assets/doppio_bot/js/doppio_bot.js" 20 | 21 | # include custom scss in every website theme (without file extension ".scss") 22 | # website_theme_scss = "doppio_bot/public/scss/website" 23 | 24 | # include js, css files in header of web form 25 | # webform_include_js = {"doctype": "public/js/doctype.js"} 26 | # webform_include_css = {"doctype": "public/css/doctype.css"} 27 | 28 | # include js in page 29 | # page_js = {"page" : "public/js/file.js"} 30 | 31 | # include js in doctype views 32 | # doctype_js = {"doctype" : "public/js/doctype.js"} 33 | # doctype_list_js = {"doctype" : "public/js/doctype_list.js"} 34 | # doctype_tree_js = {"doctype" : "public/js/doctype_tree.js"} 35 | # doctype_calendar_js = {"doctype" : "public/js/doctype_calendar.js"} 36 | 37 | # Home Pages 38 | # ---------- 39 | 40 | # application home page (will override Website Settings) 41 | # home_page = "login" 42 | 43 | # website user home page (by Role) 44 | # role_home_page = { 45 | # "Role": "home_page" 46 | # } 47 | 48 | # Generators 49 | # ---------- 50 | 51 | # automatically create page for each record of this doctype 52 | # website_generators = ["Web Page"] 53 | 54 | # Jinja 55 | # ---------- 56 | 57 | # add methods and filters to jinja environment 58 | # jinja = { 59 | # "methods": "doppio_bot.utils.jinja_methods", 60 | # "filters": "doppio_bot.utils.jinja_filters" 61 | # } 62 | 63 | # Installation 64 | # ------------ 65 | 66 | # before_install = "doppio_bot.install.before_install" 67 | # after_install = "doppio_bot.install.after_install" 68 | 69 | # Uninstallation 70 | # ------------ 71 | 72 | # before_uninstall = "doppio_bot.uninstall.before_uninstall" 73 | # after_uninstall = "doppio_bot.uninstall.after_uninstall" 74 | 75 | # Desk Notifications 76 | # ------------------ 77 | # See frappe.core.notifications.get_notification_config 78 | 79 | # notification_config = "doppio_bot.notifications.get_notification_config" 80 | 81 | # Permissions 82 | # ----------- 83 | # Permissions evaluated in scripted ways 84 | 85 | # permission_query_conditions = { 86 | # "Event": "frappe.desk.doctype.event.event.get_permission_query_conditions", 87 | # } 88 | # 89 | # has_permission = { 90 | # "Event": "frappe.desk.doctype.event.event.has_permission", 91 | # } 92 | 93 | # DocType Class 94 | # --------------- 95 | # Override standard doctype classes 96 | 97 | # override_doctype_class = { 98 | # "ToDo": "custom_app.overrides.CustomToDo" 99 | # } 100 | 101 | # Document Events 102 | # --------------- 103 | # Hook on document methods and events 104 | 105 | # doc_events = { 106 | # "*": { 107 | # "on_update": "method", 108 | # "on_cancel": "method", 109 | # "on_trash": "method" 110 | # } 111 | # } 112 | 113 | # Scheduled Tasks 114 | # --------------- 115 | 116 | # scheduler_events = { 117 | # "all": [ 118 | # "doppio_bot.tasks.all" 119 | # ], 120 | # "daily": [ 121 | # "doppio_bot.tasks.daily" 122 | # ], 123 | # "hourly": [ 124 | # "doppio_bot.tasks.hourly" 125 | # ], 126 | # "weekly": [ 127 | # "doppio_bot.tasks.weekly" 128 | # ], 129 | # "monthly": [ 130 | # "doppio_bot.tasks.monthly" 131 | # ], 132 | # } 133 | 134 | # Testing 135 | # ------- 136 | 137 | # before_tests = "doppio_bot.install.before_tests" 138 | 139 | # Overriding Methods 140 | # ------------------------------ 141 | # 142 | # override_whitelisted_methods = { 143 | # "frappe.desk.doctype.event.event.get_events": "doppio_bot.event.get_events" 144 | # } 145 | # 146 | # each overriding function accepts a `data` argument; 147 | # generated from the base implementation of the doctype dashboard, 148 | # along with any modifications made in other Frappe apps 149 | # override_doctype_dashboards = { 150 | # "Task": "doppio_bot.task.get_dashboard_data" 151 | # } 152 | 153 | # exempt linked doctypes from being automatically cancelled 154 | # 155 | # auto_cancel_exempted_doctypes = ["Auto Repeat"] 156 | 157 | # Ignore links to specified DocTypes when deleting documents 158 | # ----------------------------------------------------------- 159 | 160 | # ignore_links_on_delete = ["Communication", "ToDo"] 161 | 162 | # Request Events 163 | # ---------------- 164 | # before_request = ["doppio_bot.utils.before_request"] 165 | # after_request = ["doppio_bot.utils.after_request"] 166 | 167 | # Job Events 168 | # ---------- 169 | # before_job = ["doppio_bot.utils.before_job"] 170 | # after_job = ["doppio_bot.utils.after_job"] 171 | 172 | # User Data Protection 173 | # -------------------- 174 | 175 | # user_data_fields = [ 176 | # { 177 | # "doctype": "{doctype_1}", 178 | # "filter_by": "{filter_by}", 179 | # "redact_fields": ["{field_1}", "{field_2}"], 180 | # "partial": 1, 181 | # }, 182 | # { 183 | # "doctype": "{doctype_2}", 184 | # "filter_by": "{filter_by}", 185 | # "partial": 1, 186 | # }, 187 | # { 188 | # "doctype": "{doctype_3}", 189 | # "strict": False, 190 | # }, 191 | # { 192 | # "doctype": "{doctype_4}" 193 | # } 194 | # ] 195 | 196 | # Authentication and authorization 197 | # -------------------------------- 198 | 199 | # auth_hooks = [ 200 | # "doppio_bot.auth.validate" 201 | # ] 202 | -------------------------------------------------------------------------------- /doppio_bot/modules.txt: -------------------------------------------------------------------------------- 1 | Frappe ChatGPT Integration -------------------------------------------------------------------------------- /doppio_bot/patches.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NagariaHussain/doppio_bot/e063dc943d1ec6a483818a962031a0a6d28e519a/doppio_bot/patches.txt -------------------------------------------------------------------------------- /doppio_bot/public/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NagariaHussain/doppio_bot/e063dc943d1ec6a483818a962031a0a6d28e519a/doppio_bot/public/.gitkeep -------------------------------------------------------------------------------- /doppio_bot/public/js/App.jsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { nanoid } from 'nanoid' 3 | 4 | import ChatView from "./ChatView"; 5 | 6 | export function App() { 7 | // Unique sessionID for chat memory/history 8 | return ; 9 | } 10 | -------------------------------------------------------------------------------- /doppio_bot/public/js/ChatView.jsx: -------------------------------------------------------------------------------- 1 | import { 2 | Flex, 3 | IconButton, 4 | VStack, 5 | Box, 6 | Card, 7 | CardBody, 8 | Avatar, 9 | useToast, 10 | Textarea, 11 | Text, 12 | } from "@chakra-ui/react"; 13 | import { SendIcon } from "lucide-react"; 14 | import React, { useState } from "react"; 15 | import Message from "./components/message/Message"; 16 | 17 | const ChatView = ({ sessionID }) => { 18 | // from Frappe! 19 | const userImageURL = frappe.user.image(); 20 | const userFullname = frappe.user.full_name(); 21 | 22 | const toast = useToast(); 23 | const [promptMessage, setPromptMessage] = useState(""); 24 | 25 | const [messages, setMessages] = useState([ 26 | { 27 | from: "ai", 28 | isLoading: false, 29 | content: "How can I help you?", 30 | }, 31 | ]); 32 | 33 | const handleSendMessage = () => { 34 | if (!promptMessage.trim().length) { 35 | return; 36 | } 37 | 38 | setMessages((old) => [ 39 | ...old, 40 | { from: "human", content: promptMessage, isLoading: false }, 41 | { from: "ai", content: "", isLoading: true }, 42 | ]); 43 | setPromptMessage(""); 44 | 45 | frappe 46 | .call("doppio_bot.api.get_chatbot_response", { 47 | prompt_message: promptMessage, 48 | session_id: sessionID, 49 | }) 50 | .then((response) => { 51 | setMessages((old) => { 52 | old.splice(old.length - 1, 1, { 53 | from: "ai", 54 | content: response.message, 55 | isLoading: false, 56 | }); 57 | return [...old]; 58 | }); 59 | }) 60 | .catch((e) => { 61 | console.error(e); 62 | toast({ 63 | title: "Something went wrong, check console", 64 | status: "error", 65 | position: "bottom-right", 66 | }); 67 | }); 68 | }; 69 | 70 | return ( 71 | 78 | Ask DoppioBot 79 | {/* Chat Area */} 80 | 88 | 89 | {messages.map((message) => { 90 | return ; 91 | })} 92 | 93 | 94 | 95 | {/* Prompt Area */} 96 | 97 | 98 | 99 | 100 | {/* Input Box */} 101 |