├── .env.example
├── .gitignore
├── Dockerfile
├── LICENSE
├── README.en.md
├── README.md
├── demo
├── Get-Notion-SpaceId.png
├── Get-Notion-Token.png
├── NotionAI-Discord-Bot-Demo1.png
├── NotionAI-Discord-Bot-Demo2.png
├── NotionAI-Discord-Bot-En-Demo1.png
└── NotionAI-Discord-Bot-En-Demo2.png
├── docker-compose.yaml
├── main.py
├── notionai
├── __init__.py
├── enums.py
└── notionai.py
├── requirements.txt
└── src
├── __init__.py
├── discordBot.py
├── logger.py
└── server.py
/.env.example:
--------------------------------------------------------------------------------
1 | DISCORD_TOKEN =
2 | NOTION_TOKEN =
3 | NOTION_SPACE_ID =
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | .DS_Store
3 | */.DS_Store
4 | logs
5 | *.log
6 | npm-debug.log*
7 | yarn-debug.log*
8 | yarn-error.log*
9 | lerna-debug.log*
10 |
11 | # Diagnostic reports (https://nodejs.org/api/report.html)
12 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
13 |
14 | # Runtime data
15 | pids
16 | *.pid
17 | *.seed
18 | *.pid.lock
19 |
20 | # Directory for instrumented libs generated by jscoverage/JSCover
21 | lib-cov
22 |
23 | # Coverage directory used by tools like istanbul
24 | coverage
25 | *.lcov
26 |
27 | # nyc test coverage
28 | .nyc_output
29 |
30 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
31 | .grunt
32 |
33 | # Bower dependency directory (https://bower.io/)
34 | bower_components
35 |
36 | # node-waf configuration
37 | .lock-wscript
38 |
39 | # Compiled binary addons (https://nodejs.org/api/addons.html)
40 | build/Release
41 |
42 | # Dependency directories
43 | node_modules/
44 | jspm_packages/
45 |
46 | # Snowpack dependency directory (https://snowpack.dev/)
47 | web_modules/
48 |
49 | # TypeScript cache
50 | *.tsbuildinfo
51 |
52 | # Optional npm cache directory
53 | .npm
54 |
55 | # Optional eslint cache
56 | .eslintcache
57 |
58 | # Microbundle cache
59 | .rpt2_cache/
60 | .rts2_cache_cjs/
61 | .rts2_cache_es/
62 | .rts2_cache_umd/
63 |
64 | # Optional REPL history
65 | .node_repl_history
66 |
67 | # Output of 'npm pack'
68 | *.tgz
69 |
70 | # Yarn Integrity file
71 | .yarn-integrity
72 |
73 | # dotenv environment variables file
74 | .env
75 | .env.test
76 |
77 | # parcel-bundler cache (https://parceljs.org/)
78 | .cache
79 | .parcel-cache
80 |
81 | # Next.js build output
82 | .next
83 | out
84 |
85 | # Nuxt.js build / generate output
86 | .nuxt
87 | dist
88 |
89 | # Gatsby files
90 | .cache/
91 | # Comment in the public line in if your project uses Gatsby and not Next.js
92 | # https://nextjs.org/blog/next-9-1#public-directory-support
93 | # public
94 |
95 | # vuepress build output
96 | .vuepress/dist
97 |
98 | # Serverless directories
99 | .serverless/
100 |
101 | # FuseBox cache
102 | .fusebox/
103 |
104 | # DynamoDB Local files
105 | .dynamodb/
106 |
107 | # TernJS port file
108 | .tern-port
109 |
110 | # Stores VSCode versions used for testing VSCode extensions
111 | .vscode-test
112 |
113 | # yarn v2
114 | .yarn/cache
115 | .yarn/unplugged
116 | .yarn/build-state.yml
117 | .yarn/install-state.gz
118 | .pnp.*
119 |
120 |
121 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM python:3.9-alpine
2 |
3 |
4 | COPY ./ /DiscordBot
5 | WORKDIR /DiscordBot
6 |
7 | RUN pip3 install -r requirements.txt
8 |
9 | CMD ["python3", "main.py"]
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 ExplainThis
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.
--------------------------------------------------------------------------------
/README.en.md:
--------------------------------------------------------------------------------
1 | # NotionAI Discord Bot
2 |
3 | [中文](README.md) | English
4 |
5 | [](LICENSE) [](https://github.com/TheExplainthis/NotionAI-Discord-Bot/releases/)
6 |
7 |
8 | ## Introduction
9 | Notion, a note-taking software, has launched its own NotionAI service in recent months. How powerful is it? You can check out the video below:
10 |
11 | [](https://youtu.be/RDZ3mY10zY8)
12 |
13 | NotionAI is similar to ChatGPT, but it provides various functions, such as translation, itinerary planning, email writing, copywriting, brainstorming, etc. This article will teach you how to use NotionAI on Discord to enhance team collaboration.
14 |
15 | 
16 | 
17 |
18 | ## Installation Steps
19 | ### Token Retrieval
20 | 1. Obtain NotionAI Token:
21 | 1. Login to the web version of [Notion](https://www.notion.so/)
22 | 2. After logging in, right-click on the web page -> "Inspect" -> "Application" -> Token and then in Cookies, and SpaceId in LocalStorage, as shown below
23 | * 
24 | * 
25 | 2. Obtain Discord Token::
26 | 1. Login to [Discord Developer](https://discord.com/developers/applications)
27 | 2. Create a bot:
28 | 1. Enter `Applications` on the left
29 | 2. Click `New Application` in the upper right corner and enter the name of the bot > after confirmation, enter the new page.
30 | 3. Click `Bot` on the left
31 | 4. Click `Add Bot` on the right
32 | 5. The `MESSAGE CONTENT INTENT` below needs to be turned on
33 | 6. Click `Save Change`
34 | 7. The Token can be selected at the top by clicking `View Token` or if you have already applied, it will be the `Reset Token` button.
35 | 3. Set up OAuth2
36 | 1. Click `OAuth2` on the left
37 | 2. Click `URL Generator` on the left
38 | 3. On the right, select `bot` under `SCOPES` and `Administrator` under `BOT PERMISSIONS` at the bottom right
39 | 4. Copy the bottom URL to the browser
40 | 5. Select the server to join
41 | 6. Click `Continue` > `Authorize`
42 |
43 | ### Project Setup
44 | 1. Fork Github project:
45 | 1. Register/Login to [GitHub](https://github.com/)
46 | 2. Access [NotionAI-Discord-Bot](https://github.com/TheExplainthis/NotionAI-Discord-Bot)
47 | 3. Click `Star` to support the developer
48 | 4. Click `Fork` to copy all the code to your own repository
49 | 2. Deployment (free space):
50 | 1. Go to [replit](https://replit.com/)
51 | 2. Click `Sign Up` to log in directly with your Github account and authorize it -> click `Skip` to skip the initialization settings
52 | 3. After entering, click `Create` in the center of the main page -> a pop-up window will appear, click `Import from Github` in the upper right corner
53 | 4. If the Github repository has not been added, click the link `Connect GitHub to import your private repos.` -> check `Only select repositories` -> select `NotionAI-Discord-Bot`
54 | 5. Go back to step four, at this point the `Github URL` can choose the `NotionAI-Discord-Bot` project -> click `Import from Github`.
55 |
56 | ### Project Execution
57 | 1. Environment variable setting
58 | 1. After completing the previous step of `Import` in the Replit project management page, click `Secrets` in the lower left corner of `Tools`.
59 | 2. After clicking `Got it` on the right, you can add environment variables, and you need to add:
60 | 1. Discord Token:
61 | - key: `DISCORD_TOKEN`
62 | - value: `[obtained from step one above]`
63 | 2. Notion Token:
64 | - key: `NOTION_TOKEN`
65 | - value: `[obtained from step one above]`
66 | 3. Notion Space Id:
67 | - key: `NOTION_SPACE_ID`
68 | - value: `[obtained from step one above]`
69 | 2. Start running
70 | 1. Click `Run` above
71 | 2. After success, the right side of the screen will display `Hello World`, and copy the URL in the upper left of the screen, which will be used in the next step
72 | - Note: If there are no requests within an hour, the program will be interrupted, so the next step is required.
73 | 3. CronJob timing request
74 | 1. Register/Login to [cron-job.org](https://cron-job.org/en/)
75 | 2. Select `CREATE CRONJOB` in the upper right of the panel
76 | 3. Enter `NotionAI-Discord-Bot` in the `Title` and enter the URL from the previous step
77 | 4. Click every `5 minutes` below
78 | 5. Click `CREATE`
79 |
80 | ## Explanation
81 | | Command | Parameters + Explanation |
82 | | --- | ---------- |
83 | | `help_me_write` | prompt: The command for AI, context: The text to be edited, page_title(Optional): Title, rest_content(Optional): Other parts of the text |
84 | | `continue_write` | context: Text, page_title(Optional): Title, rest_content(Optional): Other parts of the text |
85 | | `help_me_edit` | prompt: The command for AI, context: The text to be edited, page_title(Optional): Title |
86 | | `translate` | language: The language to be translated, context: The text to be translated |
87 | | `change_tone` | context: The text to be converted, tone: The style of the text |
88 | | `summarize` | context: The text to be summarized, page_title(Optional): Title |
89 | | `improve_writing` | context: The text to be improved, page_title(Optional): Title |
90 | | `fix_spelling_grammar` | context: The text to be corrected, page_title(Optional): Title |
91 | | `explain_this` | context: The text to be explained, page_title(Optional): Title |
92 | | `make_longer` | context: The text to be lengthened, page_title(Optional): Title |
93 | | `make_shorter` | context: The text to be shortened, page_title(Optional): Title |
94 | | `find_action_items` | context: The text to be edited, page_title(Optional): Title |
95 | | `simplify_language` | context: The text to be edited, page_title(Optional): Title |
96 | | `blog_post` | prompt: The command for AI |
97 | | `brainstorm_ideas` | prompt: The command for AI |
98 | | `outline` | prompt: The command for AI |
99 | | `social_media_post` | prompt: The command for AI |
100 | | `creative_story` | prompt: The command for AI |
101 | | `poem` | prompt: The command for AI |
102 | | `essay` | prompt: The command for AI |
103 | | `meeting_agenda` | prompt: The command for AI |
104 | | `press_release` | prompt: The command for AI |
105 | | `job_description` | prompt: The command for AI |
106 | | `sales_email` | prompt: The command for AI |
107 | | `recruiting_email` | prompt: The command for AI |
108 | | `pros_cons_list` | prompt: The command for AI |
109 |
110 | ## Support Us
111 | Like this free project? Please consider [supporting us](https://www.buymeacoffee.com/explainthis) to keep it running.
112 |
113 | [
](https://www.buymeacoffee.com/explainthis)
114 |
115 | ## Related Projects
116 | [NotionAI](https://github.com/Vaayne/NotionAI)
117 |
118 | ## License
119 | [MIT](LICENSE)
120 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # NotionAI Discord Bot
2 |
3 | 中文 | [English](README.en.md)
4 |
5 | [](LICENSE) [](https://github.com/TheExplainthis/NotionAI-Discord-Bot/releases/)
6 |
7 |
8 | ## 介紹
9 | 近幾個月筆記軟體 Notion 也開始推出了自己的 [NotionAI 服務](https://www.notion.so/product/ai),功能有多強大呢?可以先看看下面的影片:
10 |
11 | [](https://youtu.be/RDZ3mY10zY8)
12 |
13 |
14 | NotionAI 和 ChatGPT 相似,但提供多種不同的功能,例如翻譯、行程規劃、Email 撰寫、文案發想、頭腦風暴等。本文將教你如何在 Discord 上使用 NotionAI,增強團隊協作。
15 |
16 | 
17 | 
18 |
19 |
20 |
21 | ## 安裝步驟
22 | ### Token 取得
23 | 1. 取得 NotionAI Token:
24 | 1. 登入網頁版 [Notion](https://www.notion.so/)
25 | 2. 登入後按網頁 `右鍵` -> `檢查` -> `應用程式` -> Token 再 Cookies 裡,而 SpaceId 在 LocalStorage 裡,如下圖所示
26 | * 
27 | * 
28 | 2. 取得 Discord Token:
29 | 1. 登入 [Discord Developer](https://discord.com/developers/applications)
30 | 2. 創建機器人:
31 | 1. 進入左方 `Applications`
32 | 2. 點擊右上方 `New Application` 並輸入 Bot 的名稱 > 確認後進入新頁面。
33 | 3. 點擊左方 `Bot`
34 | 4. 點擊右方 `Add Bot`
35 | 5. 下方 `MESSAGE CONTENT INTENT` 需打開
36 | 6. 按下 `Save Change`
37 | 7. Token 在上方選擇 `View Token` 或已申請過則會是 `Reset Token` 的按鈕。
38 | 3. 設定 OAuth2
39 | 1. 點擊左欄 `OAuth2`
40 | 2. 點擊左欄 `URL Generator`
41 | 3. 右欄 `SCOPES` 選擇 `bot`、右欄下方 `BOT PERMISSIONS` 選擇 `Administrator`
42 | 4. 複製最下方網址到瀏覽器中
43 | 5. 選擇欲加入的伺服器
44 | 6. 按下 `繼續` > `授權`
45 |
46 | ### 專案設置
47 | 1. Fork Github 專案:
48 | 1. 註冊/登入 [GitHub](https://github.com/)
49 | 2. 進入 [NotionAI-Discord-Bot](https://github.com/TheExplainthis/NotionAI-Discord-Bot)
50 | 3. 點選 `Star` 支持開發者
51 | 4. 點選 `Fork` 複製全部的程式碼到自己的倉庫
52 | 2. 部署(免費空間):
53 | 1. 進入 [replit](https://replit.com/)
54 | 2. 點選 `Sign Up` 直接用 `Github` 帳號登入並授權 -> 按下 `Skip` 跳過初始化設定
55 | 3. 進入後中間主頁的部分點選 `Create` -> 跳出框,點選右上角 `Import from Github`
56 | 4. 若尚未加入 Github 倉庫,則點選連結 `Connect GitHub to import your private repos.` -> 勾選 `Only select repositories` -> 選擇 `NotionAI-Discord-Bot`
57 | 5. 回到第四步,此時 `Github URL` 可以選擇 `NotionAI-Discord-Bot` 專案 -> 點擊 `Import from Github`。
58 |
59 | ### 專案執行
60 | 1. 環境變數設定
61 | 1. 接續上一步 `Import` 完成後在 `Replit` 的專案管理頁面左下方 `Tools` 點擊 `Secrets`。
62 | 2. 右方按下 `Got it` 後,即可新增環境變數,需新增:
63 | 1. Discord Token:
64 | - key: `DISCORD_TOKEN`
65 | - value: `[由上方步驟一取得]`
66 | 2. Notion Token:
67 | - key: `NOTION_TOKEN`
68 | - value: `[由上方步驟一取得]`
69 | 3. Notion Space Id:
70 | - key: `NOTION_SPACE_ID`
71 | - value: `[由上方步驟一取得]`
72 | 2. 開始執行
73 | 1. 點擊上方的 `Run`
74 | 2. 成功後右邊畫面會顯示 `Hello World`,並將畫面中上方的**網址複製**下來,下一步驟會用到
75 | - 注意:若一小時內沒有任何請求,則程式會中斷,因此需要下步驟
76 | 3. CronJob 定時發送請求
77 | 1. 註冊/登入 [cron-job.org](https://cron-job.org/en/)
78 | 2. 進入後面板右上方選擇 `CREATE CRONJOB`
79 | 3. `Title` 輸入 `NotionAI-Discord-Bot`,網址輸入上一步驟的網址
80 | 4. 下方則每 `5 分鐘` 打一次
81 | 5. 按下 `CREATE`
82 |
83 |
84 | ## 說明
85 | | 指令 | 參數 + 說明 |
86 | | --- | ---------- |
87 | | `help_me_write` | prompt: 給 AI 的指令, context: 欲編輯的內文, page_title(Optional): 標題, rest_content(Optional): 其他部分的內文 |
88 | | `continue_write` | context: 內文, page_title(Optional): 標題, rest_content(Optional): 其他部分的內文 |
89 | | `help_me_edit` | prompt: 給 AI 的指令, context: 欲編輯的內文, page_title(Optional): 標題 |
90 | | `translate` | language: 欲翻譯的語言, context: 欲翻譯的內文 |
91 | | `change_tone` | context: 欲轉換風格的內文, tone: 內文風格 |
92 | | `summarize` | context: 欲總結的內文, page_title(Optional): 標題 |
93 | | `improve_writing` | context: 欲改善的內文, page_title(Optional): 標題 |
94 | | `fix_spelling_grammar` | context: 欲修正的內文, page_title(Optional): 標題 |
95 | | `explain_this` | context: 欲解釋的內文, page_title(Optional): 標題 |
96 | | `make_longer` | context: 欲變長的內文, page_title(Optional): 標題 |
97 | | `make_shorter` | context: 欲變短的內文, page_title(Optional): 標題 |
98 | | `find_action_items` | context: 欲編輯的內文, page_title(Optional): 標題 |
99 | | `simplify_language` | context: 欲編輯的內文, page_title(Optional): 標題 |
100 | | `blog_post` | prompt: 給 AI 的指令 |
101 | | `brainstorm_ideas` | prompt: 給 AI 的指令 |
102 | | `outline` | prompt: 給 AI 的指令 |
103 | | `social_media_post` | prompt: 給 AI 的指令 |
104 | | `creative_story` | prompt: 給 AI 的指令 |
105 | | `poem` | prompt: 給 AI 的指令 |
106 | | `essay` | prompt: 給 AI 的指令 |
107 | | `meeting_agenda` | prompt: 給 AI 的指令 |
108 | | `press_release` | prompt: 給 AI 的指令 |
109 | | `job_description` | prompt: 給 AI 的指令 |
110 | | `sales_email` | prompt: 給 AI 的指令 |
111 | | `recruiting_email` | prompt: 給 AI 的指令 |
112 | | `pros_cons_list` | prompt: 給 AI 的指令 |
113 |
114 |
115 | ## 支持我們
116 | 如果你喜歡這個專案,願意[支持我們](https://www.buymeacoffee.com/explainthis),可以請我們喝一杯咖啡,這會成為我們繼續前進的動力!
117 |
118 | [
](https://www.buymeacoffee.com/explainthis)
119 |
120 | ## 相關專案
121 | [NotionAI](https://github.com/Vaayne/NotionAI)
122 |
123 | ## 授權
124 | [MIT](LICENSE)
125 |
--------------------------------------------------------------------------------
/demo/Get-Notion-SpaceId.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheExplainthis/NotionAI-Discord-Bot/1bf02ec7cb4c5513c17deeed1c5aa38e3a11fe6c/demo/Get-Notion-SpaceId.png
--------------------------------------------------------------------------------
/demo/Get-Notion-Token.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheExplainthis/NotionAI-Discord-Bot/1bf02ec7cb4c5513c17deeed1c5aa38e3a11fe6c/demo/Get-Notion-Token.png
--------------------------------------------------------------------------------
/demo/NotionAI-Discord-Bot-Demo1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheExplainthis/NotionAI-Discord-Bot/1bf02ec7cb4c5513c17deeed1c5aa38e3a11fe6c/demo/NotionAI-Discord-Bot-Demo1.png
--------------------------------------------------------------------------------
/demo/NotionAI-Discord-Bot-Demo2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheExplainthis/NotionAI-Discord-Bot/1bf02ec7cb4c5513c17deeed1c5aa38e3a11fe6c/demo/NotionAI-Discord-Bot-Demo2.png
--------------------------------------------------------------------------------
/demo/NotionAI-Discord-Bot-En-Demo1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheExplainthis/NotionAI-Discord-Bot/1bf02ec7cb4c5513c17deeed1c5aa38e3a11fe6c/demo/NotionAI-Discord-Bot-En-Demo1.png
--------------------------------------------------------------------------------
/demo/NotionAI-Discord-Bot-En-Demo2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheExplainthis/NotionAI-Discord-Bot/1bf02ec7cb4c5513c17deeed1c5aa38e3a11fe6c/demo/NotionAI-Discord-Bot-En-Demo2.png
--------------------------------------------------------------------------------
/docker-compose.yaml:
--------------------------------------------------------------------------------
1 | version: "3"
2 |
3 | services:
4 | app:
5 | container_name: discord-chatgpt-ai-assistant
6 | build: .
7 | restart: always
8 | ports:
9 | - "${APP_PORT}:${APP_PORT}"
--------------------------------------------------------------------------------
/main.py:
--------------------------------------------------------------------------------
1 |
2 | import os
3 |
4 | from dotenv import load_dotenv
5 | import discord
6 | from notionai import NotionAI, ToneEnum, TranslateLanguageEnum
7 | from src.discordBot import DiscordClient, Sender
8 | from src.logger import logger
9 | from src.server import keep_alive
10 | load_dotenv()
11 |
12 |
13 | def run():
14 | client = DiscordClient()
15 | sender = Sender()
16 | notion_ai = NotionAI(os.getenv('NOTION_TOKEN'), os.getenv('NOTION_SPACE_ID'))
17 |
18 | @client.tree.command(name="help_me_write", description="Help me write, ask AI to write for you")
19 | async def help_me_write(interaction: discord.Interaction, *, prompt: str, context: str, page_title: str = "", rest_content: str = ""):
20 | if interaction.user == client.user:
21 | return
22 | await interaction.response.defer()
23 | ai_response = notion_ai.help_me_write(prompt, context, page_title, rest_content)
24 | send_message = f"[help_me_write] prompt: {prompt} \n context: {context} \n page_title: {page_title} \n rest_content: {rest_content}"
25 | await sender.send_message(interaction, send_message, ai_response)
26 |
27 | @client.tree.command(name="continue_write", description="Continue writing, generating more")
28 | async def continue_write(interaction: discord.Interaction, *, context: str, page_title: str = "", rest_content: str = ""):
29 | if interaction.user == client.user:
30 | return
31 | await interaction.response.defer()
32 | ai_response = notion_ai.continue_write(context, page_title, rest_content)
33 | send_message = f"[continue_write] context: {context} \n page_title: {page_title} \n rest_content: {rest_content}"
34 | await sender.send_message(interaction, send_message, ai_response)
35 |
36 | @client.tree.command(name="help_me_edit", description="Help me edit somethings, it will change the current context")
37 | async def help_me_edit(interaction: discord.Interaction, *, prompt: str, context: str, page_title: str = ""):
38 | if interaction.user == client.user:
39 | return
40 | await interaction.response.defer()
41 | ai_response = notion_ai.help_me_edit(prompt, context, page_title)
42 | send_message = f"[help_me_edit] prompt: {prompt} \n context: {context} \n page_title: {page_title} "
43 | await sender.send_message(interaction, send_message, ai_response)
44 |
45 | @client.tree.command(name="translate", description="Use NotionAI to translate your context")
46 | async def translate(interaction: discord.Interaction, *, language: str, context: str):
47 | if interaction.user == client.user:
48 | return
49 | await interaction.response.defer()
50 | send_message = f"[translate] language: {language} \n context: {context}"
51 |
52 | language = language.lower()
53 | try:
54 | language = TranslateLanguageEnum(language)
55 | except Exception:
56 | error_message = "❌ Error: The language can only be: english, korean, chinese, japanese, spanish, russiab, french, german, italian, portuguese, dutch, indonesia, tagalog or vietnamese."
57 | await sender.send_message(interaction, send_message, error_message)
58 | ai_response = notion_ai.translate(language, context)
59 | await sender.send_message(interaction, send_message, ai_response)
60 |
61 | @client.tree.command(name="change_tone", description="Change the tone of your context")
62 | async def change_tone(interaction: discord.Interaction, *, context: str, tone: str):
63 | if interaction.user == client.user:
64 | return
65 | await interaction.response.defer()
66 |
67 | send_message = f"[change_tone] context: {context} \n tone: {tone}"
68 | try:
69 | tone = ToneEnum(tone)
70 | except Exception:
71 | error_message = "❌ Error: The tone can only be: professional, casual, straightforward, confident, or friendly."
72 | await sender.send_message(interaction, send_message, error_message)
73 | ai_response = notion_ai.change_tone(context, ToneEnum(tone))
74 | await sender.send_message(interaction, send_message, ai_response)
75 |
76 | @client.tree.command(name="summarize", description="Summarize context")
77 | async def summarize(interaction: discord.Interaction, *, context: str, page_title: str = ""):
78 | if interaction.user == client.user:
79 | return
80 | await interaction.response.defer()
81 | ai_response = notion_ai.summarize(context, page_title)
82 | send_message = f"[summarize] context: {context} \n page_title: {page_title}"
83 | await sender.send_message(interaction, send_message, ai_response)
84 |
85 | @client.tree.command(name="improve_writing", description="Improve context")
86 | async def improve_writing(interaction: discord.Interaction, *, context: str, page_title: str = ""):
87 | if interaction.user == client.user:
88 | return
89 | await interaction.response.defer()
90 | ai_response = notion_ai.improve_writing(context, page_title)
91 | send_message = f"[improve_writing] context: {context} \n page_title: {page_title}"
92 | await sender.send_message(interaction, send_message, ai_response)
93 |
94 | @client.tree.command(name="fix_spelling_grammar", description="Correcting grammar errors in context")
95 | async def fix_spelling_grammar(interaction: discord.Interaction, *, context: str, page_title: str = ""):
96 | if interaction.user == client.user:
97 | return
98 | await interaction.response.defer()
99 | ai_response = notion_ai.fix_spelling_grammar(context, page_title)
100 | send_message = f"[fix_spelling_grammar] context: {context} \n page_title: {page_title}"
101 | await sender.send_message(interaction, send_message, ai_response)
102 |
103 | @client.tree.command(name="explain_this", description="Explanation of Context")
104 | async def explain_this(interaction: discord.Interaction, *, context: str, page_title: str = ""):
105 | if interaction.user == client.user:
106 | return
107 | await interaction.response.defer()
108 | ai_response = notion_ai.explain_this(context, page_title)
109 | send_message = f"[explain_this] context: {context} \n page_title: {page_title}"
110 | await sender.send_message(interaction, send_message, ai_response)
111 |
112 | @client.tree.command(name="make_longer", description="Editing text to make the Context longer")
113 | async def make_longer(interaction: discord.Interaction, *, context: str, page_title: str = ""):
114 | if interaction.user == client.user:
115 | return
116 | await interaction.response.defer()
117 | ai_response = notion_ai.make_longer(context, page_title)
118 | send_message = f"[make_longer] context: {context} \n page_title: {page_title}"
119 | await sender.send_message(interaction, send_message, ai_response)
120 |
121 | @client.tree.command(name="make_shorter", description="Editing text to make the Context shorter")
122 | async def make_shorter(interaction: discord.Interaction, *, context: str, page_title: str = ""):
123 | if interaction.user == client.user:
124 | return
125 | await interaction.response.defer()
126 | ai_response = notion_ai.make_shorter(context, page_title)
127 | send_message = f"[make_shorter] context: {context} \n page_title: {page_title}"
128 | await sender.send_message(interaction, send_message, ai_response)
129 |
130 | @client.tree.command(name="find_action_items", description="Generate action items")
131 | async def find_action_items(interaction: discord.Interaction, *, context: str, page_title: str = ""):
132 | if interaction.user == client.user:
133 | return
134 | await interaction.response.defer()
135 | ai_response = notion_ai.find_action_items(context, page_title)
136 | send_message = f"[find_action_items] context: {context} \n page_title: {page_title}"
137 | await sender.send_message(interaction, send_message, ai_response)
138 |
139 | @client.tree.command(name="simplify_language", description="Simplify Context")
140 | async def simplify_language(interaction: discord.Interaction, *, context: str, page_title: str = ""):
141 | if interaction.user == client.user:
142 | return
143 | await interaction.response.defer()
144 | ai_response = notion_ai.simplify_language(context, page_title)
145 | send_message = f"[simplify_language] context: {context} \n page_title: {page_title}"
146 | await sender.send_message(interaction, send_message, ai_response)
147 |
148 | @client.tree.command(name="blog_post", description="Generate post")
149 | async def blog_post(interaction: discord.Interaction, *, prompt: str):
150 | if interaction.user == client.user:
151 | return
152 | await interaction.response.defer()
153 | ai_response = notion_ai.blog_post(prompt)
154 | send_message = f"[blog_post] prompt: {prompt}"
155 | await sender.send_message(interaction, send_message, ai_response)
156 |
157 | @client.tree.command(name="brainstorm_ideas", description="Generate ideas")
158 | async def brainstorm_ideas(interaction: discord.Interaction, *, prompt: str):
159 | if interaction.user == client.user:
160 | return
161 | await interaction.response.defer()
162 | ai_response = notion_ai.brainstorm_ideas(prompt)
163 | send_message = f"[brainstorm_ideas] prompt: {prompt}"
164 | await sender.send_message(interaction, send_message, ai_response)
165 |
166 | @client.tree.command(name="outline", description="Generate outline")
167 | async def outline(interaction: discord.Interaction, *, prompt: str):
168 | if interaction.user == client.user:
169 | return
170 | await interaction.response.defer()
171 | ai_response = notion_ai.outline(prompt)
172 | send_message = f"[outline] prompt: {prompt}"
173 | await sender.send_message(interaction, send_message, ai_response)
174 |
175 | @client.tree.command(name="social_media_post", description="Generate social media post")
176 | async def social_media_post(interaction: discord.Interaction, *, prompt: str):
177 | if interaction.user == client.user:
178 | return
179 | await interaction.response.defer()
180 | ai_response = notion_ai.social_media_post(prompt)
181 | send_message = f"[social_media_post] prompt: {prompt}"
182 | await sender.send_message(interaction, send_message, ai_response)
183 |
184 | @client.tree.command(name="creative_story", description="Generate creative story")
185 | async def creative_story(interaction: discord.Interaction, *, prompt: str):
186 | if interaction.user == client.user:
187 | return
188 | await interaction.response.defer()
189 | ai_response = notion_ai.creative_story(prompt)
190 | send_message = f"[creative_story] prompt: {prompt}"
191 | await sender.send_message(interaction, send_message, ai_response)
192 |
193 | @client.tree.command(name="poem", description="Generate poem")
194 | async def poem(interaction: discord.Interaction, *, prompt: str):
195 | if interaction.user == client.user:
196 | return
197 | await interaction.response.defer()
198 | ai_response = notion_ai.poem(prompt)
199 | send_message = f"[poem] prompt: {prompt}"
200 | await sender.send_message(interaction, send_message, ai_response)
201 |
202 | @client.tree.command(name="essay", description="Generate essay")
203 | async def essay(interaction: discord.Interaction, *, prompt: str):
204 | if interaction.user == client.user:
205 | return
206 | await interaction.response.defer()
207 | ai_response = notion_ai.essay(prompt)
208 | send_message = f"[essay] prompt: {prompt}"
209 | await sender.send_message(interaction, send_message, ai_response)
210 |
211 | @client.tree.command(name="meeting_agenda", description="Generate meeting agenda")
212 | async def meeting_agenda(interaction: discord.Interaction, *, prompt: str):
213 | if interaction.user == client.user:
214 | return
215 | await interaction.response.defer()
216 | ai_response = notion_ai.meeting_agenda(prompt)
217 | send_message = f"[meeting_agenda] prompt: {prompt}"
218 | await sender.send_message(interaction, send_message, ai_response)
219 |
220 | @client.tree.command(name="press_release", description="Generate press release")
221 | async def press_release(interaction: discord.Interaction, *, prompt: str):
222 | if interaction.user == client.user:
223 | return
224 | await interaction.response.defer()
225 | ai_response = notion_ai.press_release(prompt)
226 | send_message = f"[press_release] prompt: {prompt}"
227 | await sender.send_message(interaction, send_message, ai_response)
228 |
229 | @client.tree.command(name="job_description", description="Generate jon description")
230 | async def job_description(interaction: discord.Interaction, *, prompt: str):
231 | if interaction.user == client.user:
232 | return
233 | await interaction.response.defer()
234 | ai_response = notion_ai.job_description(prompt)
235 | send_message = f"[job_description] prompt: {prompt}"
236 | await sender.send_message(interaction, send_message, ai_response)
237 |
238 | @client.tree.command(name="sales_email", description="Generate sales email")
239 | async def sales_email(interaction: discord.Interaction, *, prompt: str):
240 | if interaction.user == client.user:
241 | return
242 | await interaction.response.defer()
243 | ai_response = notion_ai.sales_email(prompt)
244 | send_message = f"[sales_email] prompt: {prompt}"
245 | await sender.send_message(interaction, send_message, ai_response)
246 |
247 | @client.tree.command(name="recruiting_email", description="Generate recuiting email")
248 | async def recruiting_email(interaction: discord.Interaction, *, prompt: str):
249 | if interaction.user == client.user:
250 | return
251 | await interaction.response.defer()
252 | ai_response = notion_ai.recruiting_email(prompt)
253 | send_message = f"[recruiting_email] prompt: {prompt}"
254 | await sender.send_message(interaction, send_message, ai_response)
255 |
256 | @client.tree.command(name="pros_cons_list", description="Generate prons and cons list")
257 | async def pros_cons_list(interaction: discord.Interaction, *, prompt: str):
258 | if interaction.user == client.user:
259 | return
260 | await interaction.response.defer()
261 | ai_response = notion_ai.pros_cons_list(prompt)
262 | send_message = f"[pros_cons_list] prompt: {prompt}"
263 | await sender.send_message(interaction, send_message, ai_response)
264 |
265 | client.run(os.getenv('DISCORD_TOKEN'))
266 |
267 |
268 | if __name__ == '__main__':
269 | logger.info('Server Run')
270 | keep_alive()
271 | run()
272 |
--------------------------------------------------------------------------------
/notionai/__init__.py:
--------------------------------------------------------------------------------
1 | # ruff: noqa
2 | from .notionai import NotionAI, NotionAIStream
3 | from .enums import TopicEnum, TranslateLanguageEnum, PromptTypeEnum, ToneEnum
4 |
--------------------------------------------------------------------------------
/notionai/enums.py:
--------------------------------------------------------------------------------
1 | from enum import Enum
2 |
3 |
4 | class ExtendedEnum(Enum):
5 | @classmethod
6 | def list(cls):
7 | return list(map(lambda c: c.value, cls))
8 |
9 | @classmethod
10 | def list_name(cls):
11 | return list(map(lambda c: c.name, cls))
12 |
13 |
14 | class TopicEnum(ExtendedEnum):
15 | brainstorm_ideas = "brainstormIdeas"
16 | blog_post = "blogPost"
17 | outline = "outline"
18 | social_media_post = "socialMediaPost"
19 | press_release = "pressRelease"
20 | creative_story = "creativeStory"
21 | essay = "essay"
22 | poem = "poem"
23 | meeting_agenda = "meetingAgenda"
24 | pros_cons_list = "prosConsList"
25 | job_description = "jobDescription"
26 | sales_email = "salesEmail"
27 | recruiting_email = "recruitingEmail"
28 |
29 |
30 | class TranslateLanguageEnum(ExtendedEnum):
31 | english = "english"
32 | korean = "korean"
33 | chinese = "chinese"
34 | japanese = "japanese"
35 | spanish = "spanish"
36 | russiab = "russiab"
37 | french = "french"
38 | german = "german"
39 | italian = "italian"
40 | portuguese = "portuguese"
41 | dutch = "dutch"
42 | indonesia = "indonesia"
43 | tagalog = "tagalog"
44 | vietnamese = "vietnamese"
45 |
46 |
47 | class PromptTypeEnum(ExtendedEnum):
48 | help_me_write = "helpMeWrite"
49 | continue_writing = "continueWriting"
50 | change_tone = "changeTone"
51 | summarize = "summarize"
52 | improve_writing = "improveWriting"
53 | fix_spelling_grammar = "fixSpellingGrammar"
54 | translate = "translate"
55 | explain_this = "explainThis"
56 | make_longer = "makeLonger"
57 | make_shorter = "makeShorter"
58 | find_action_items = "findActionItems"
59 | simplify_language = "simplifyLanguage"
60 | help_me_edit = "helpMeEdit"
61 |
62 |
63 | class ToneEnum(ExtendedEnum):
64 | professional = "professional"
65 | casual = "casual"
66 | straight_forward = "straightforward"
67 | confident = "confident"
68 | friendly = "friendly"
--------------------------------------------------------------------------------
/notionai/notionai.py:
--------------------------------------------------------------------------------
1 | import json
2 | import uuid
3 |
4 | import requests
5 |
6 | from notionai.enums import PromptTypeEnum, ToneEnum, TopicEnum, TranslateLanguageEnum
7 |
8 | MODEL = "openai-3"
9 | URL = "https://www.notion.so/api/v3/getCompletion"
10 |
11 |
12 | class NotionAIBase(object):
13 | stream = False
14 |
15 | def __init__(
16 | self,
17 | token: str,
18 | space_id: str,
19 | model: str = MODEL,
20 | ) -> None:
21 | """Init NotionAI
22 | Args:
23 | token (str): Notion token_v2
24 | space_id (str): Notion workspace id
25 | model (str, optional): AI model. Default to openai-1.1
26 | stream (bool, optional): use stream result. Defaults to False.
27 | pageTitle (str, optional): Title for your content. Defaults to PAGE_TITLE.
28 | """
29 | self.token = token
30 | self.space_id = space_id
31 | self.model = model
32 | self.is_space_permission = False
33 | self.url = URL
34 |
35 | def _request(self, content: dict) -> str:
36 | payload = {
37 | "id": self._get_id(),
38 | "model": self.model,
39 | "spaceId": self.space_id,
40 | "isSpacePermission": self.is_space_permission,
41 | "context": content,
42 | }
43 |
44 | cookies = [
45 | "token_v2=" + self.token,
46 | ]
47 |
48 | headers = {
49 | "accept": "application/json",
50 | "Cookie": "; ".join(cookies),
51 | "Content-Type": "application/json",
52 | }
53 |
54 | return requests.post(
55 | self.url, json=payload, headers=headers, stream=self.stream
56 | )
57 |
58 | def _post(self, content: dict) -> str:
59 | r = self._request(content)
60 | data = r.text.split("\n")
61 | res = [self._parse_resp_line(d) for d in data]
62 | return "".join(res).strip("\n")
63 |
64 | def _parse_resp_line(self, line):
65 | if line:
66 | try:
67 | data = json.loads(line)
68 | if data["type"] == "success":
69 | return data["completion"]
70 | except Exception as e:
71 | print(f"data: {line}, error: {e}")
72 | return ""
73 |
74 | def _get_id(self) -> str:
75 | return str(uuid.uuid4())
76 |
77 |
78 | class NotionAI(NotionAIBase):
79 | def writing_with_topic(self, topic: TopicEnum, prompt: str) -> str:
80 | """Writing for special topic
81 | Args:
82 | topic (TopicEnum): the special topic
83 | prompt (str): prompt for writing
84 | Returns:
85 | str: Response from NotionAI
86 | """
87 | content = {"type": topic.value, "topic": prompt}
88 | return self._post(content)
89 |
90 | def writing_with_prompt(
91 | self,
92 | prompt_type: PromptTypeEnum,
93 | context: str,
94 | page_title: str = "",
95 | ) -> str:
96 | """Writing with special prompt, like summarize, explain_this, improve_writing
97 | Args:
98 | prompt_type (PromptTypeEnum): special prompt
99 | context (str): the context for your writing
100 | page_title (str, optional): I am not sure about this. Defaults to ""
101 | Returns:
102 | str: Response from NotionAI
103 | """
104 | if prompt_type == PromptTypeEnum.continue_writing:
105 | return self.continue_write(context, page_title)
106 |
107 | if prompt_type in {
108 | PromptTypeEnum.help_me_write,
109 | PromptTypeEnum.help_me_edit,
110 | PromptTypeEnum.translate,
111 | PromptTypeEnum.change_tone,
112 | }:
113 | raise ValueError("Please use the specific method for this prompt type")
114 | content = {
115 | "type": prompt_type.value,
116 | "pageTitle": page_title,
117 | "selectedText": context,
118 | }
119 | return self._post(content)
120 |
121 | def help_me_write(
122 | self, prompt: str, context: str, page_title: str = "", rest_content: str = ""
123 | ) -> str:
124 | """Help me write, ask AI to write for you
125 | Args:
126 | prompt (str): your prompt, could be anything
127 | context (str): context for your writing
128 | page_title (str, optional): not sure. Defaults to "".
129 | rest_content (str, optional): more context. Defaults to "".
130 | Returns:
131 | str: Response from NotionAI
132 | """
133 | content = {
134 | "type": PromptTypeEnum.help_me_write.value,
135 | "prompt": prompt,
136 | "pageTitle": page_title,
137 | "previousContent": context,
138 | "restContent": rest_content,
139 | }
140 | return self._post(content)
141 |
142 | def continue_write(
143 | self, context: str, page_title: str = "", rest_content: str = ""
144 | ) -> str:
145 | """Continue writing, generating more
146 | Args:
147 | context (str): context for continue
148 | page_title (str, optional): not sure. Defaults to "".
149 | rest_content (str, optional): more context. Defaults to "".
150 | Returns:
151 | str: Response from NotionAI
152 | """
153 | content = {
154 | "type": PromptTypeEnum.continue_writing.value,
155 | "pageTitle": page_title,
156 | "previousContent": context,
157 | "restContent": rest_content,
158 | }
159 | return self._post(content)
160 |
161 | def help_me_edit(self, prompt: str, context: str, page_title: str = "") -> str:
162 | """Help me edit somethings, it will change the current context
163 | Args:
164 | prompt (str): your prompt, could be anything
165 | context (str): context to edit
166 | page_title (str, optional): not sure. Defaults to "".
167 | Returns:
168 | str: Response from NotionAI
169 | """
170 |
171 | content = {
172 | "type": PromptTypeEnum.help_me_edit.value,
173 | "pageTitle": page_title,
174 | "prompt": prompt,
175 | "selectedText": context,
176 | }
177 | return self._post(content)
178 |
179 | def translate(self, language: TranslateLanguageEnum, context: str) -> str:
180 | """Use NotionAI to translate your context
181 | Args:
182 | language (TranslateLanguageEnum): target language
183 | context (str): context to translate
184 | Returns:
185 | str: translate result
186 | """
187 | content = {
188 | "type": PromptTypeEnum.translate.value,
189 | "text": context,
190 | "language": language.value,
191 | }
192 | return self._post(content)
193 |
194 | def change_tone(self, context: str, tone: ToneEnum) -> str:
195 | """Change the tone of your context
196 | Args:
197 | context (str): context to change
198 | tone (ToneEnum): target tone
199 | Returns:
200 | str: Response from NotionAI
201 | """
202 | content = {
203 | "type": "changeTone",
204 | "tone": tone.value,
205 | "text": context,
206 | }
207 | return self._post(content)
208 |
209 | def summarize(self, context: str, page_title: str = "") -> str:
210 | return self.writing_with_prompt(PromptTypeEnum.summarize, context)
211 |
212 | def improve_writing(self, context: str, page_title: str = "") -> str:
213 | return self.writing_with_prompt(PromptTypeEnum.improve_writing, context)
214 |
215 | def fix_spelling_grammar(self, context: str, page_title: str = "") -> str:
216 | return self.writing_with_prompt(
217 | PromptTypeEnum.fix_spelling_grammar,
218 | context,
219 | page_title=page_title,
220 | )
221 |
222 | def explain_this(self, context: str, page_title: str = "") -> str:
223 | return self.writing_with_prompt(
224 | PromptTypeEnum.explain_this, context, page_title=page_title
225 | )
226 |
227 | def make_longer(self, context: str, page_title: str = "") -> str:
228 | return self.writing_with_prompt(
229 | PromptTypeEnum.make_longer, context, page_title=page_title
230 | )
231 |
232 | def make_shorter(self, context: str, page_title: str = "") -> str:
233 | return self.writing_with_prompt(
234 | PromptTypeEnum.make_shorter, context, page_title=page_title
235 | )
236 |
237 | def find_action_items(self, context: str, page_title: str = "") -> str:
238 | return self.writing_with_prompt(
239 | PromptTypeEnum.find_action_items, context, page_title=page_title
240 | )
241 |
242 | def simplify_language(self, context: str, page_title: str = "") -> str:
243 | return self.writing_with_prompt(
244 | PromptTypeEnum.simplify_language, context, page_title=page_title
245 | )
246 |
247 | def blog_post(self, prompt: str) -> str:
248 | return self.writing_with_topic(TopicEnum.blog_post, prompt)
249 |
250 | def brainstorm_ideas(self, prompt: str) -> str:
251 | return self.writing_with_topic(TopicEnum.brainstorm_ideas, prompt)
252 |
253 | def outline(self, prompt: str) -> str:
254 | return self.writing_with_topic(TopicEnum.outline, prompt)
255 |
256 | def social_media_post(self, prompt: str) -> str:
257 | return self.writing_with_topic(TopicEnum.social_media_post, prompt)
258 |
259 | def creative_story(self, prompt: str) -> str:
260 | return self.writing_with_topic(TopicEnum.creative_story, prompt)
261 |
262 | def poem(self, prompt: str) -> str:
263 | return self.writing_with_topic(TopicEnum.poem, prompt)
264 |
265 | def essay(self, prompt: str) -> str:
266 | return self.writing_with_topic(TopicEnum.essay, prompt)
267 |
268 | def meeting_agenda(self, prompt: str) -> str:
269 | return self.writing_with_topic(TopicEnum.meeting_agenda, prompt)
270 |
271 | def press_release(self, prompt: str) -> str:
272 | return self.writing_with_topic(TopicEnum.press_release, prompt)
273 |
274 | def job_description(self, prompt: str) -> str:
275 | return self.writing_with_topic(TopicEnum.job_description, prompt)
276 |
277 | def sales_email(self, prompt: str) -> str:
278 | return self.writing_with_topic(TopicEnum.sales_email, prompt)
279 |
280 | def recruiting_email(self, prompt: str) -> str:
281 | return self.writing_with_topic(TopicEnum.recruiting_email, prompt)
282 |
283 | def pros_cons_list(self, prompt: str) -> str:
284 | self.writing_with_topic(TopicEnum.pros_cons_list, prompt)
285 |
286 |
287 | class NotionAIStream(NotionAI):
288 | stream = True
289 |
290 | def _post(self, content: dict) -> str:
291 | r = self._request(content)
292 | for line in r.text.splitlines():
293 | yield self._parse_resp_line(line)
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | discord.py==2.1.1
2 | python-dotenv==0.21.1
3 | Flask==2.2.3
--------------------------------------------------------------------------------
/src/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheExplainthis/NotionAI-Discord-Bot/1bf02ec7cb4c5513c17deeed1c5aa38e3a11fe6c/src/__init__.py
--------------------------------------------------------------------------------
/src/discordBot.py:
--------------------------------------------------------------------------------
1 | import discord
2 | from src.logger import logger
3 |
4 | intents = discord.Intents.default()
5 | intents.message_content = True
6 |
7 |
8 | class DiscordClient(discord.Client):
9 | def __init__(self) -> None:
10 | super().__init__(intents=intents)
11 | self.synced = False
12 | self.added = False
13 | self.tree = discord.app_commands.CommandTree(self)
14 | self.activity = discord.Activity(type=discord.ActivityType.watching, name="/chat | /reset | /imagine")
15 |
16 | async def on_ready(self):
17 | await self.wait_until_ready()
18 | logger.info("Syncing")
19 | if not self.synced:
20 | await self.tree.sync()
21 | self.synced = True
22 | if not self.added:
23 | self.added = True
24 | logger.info(f"Synced, {self.user} is running!")
25 |
26 |
27 | class Sender():
28 | async def send_message(self, interaction, send, receive):
29 | try:
30 | user_id = interaction.user.id
31 | response = f'> **{send}** - <@{str(user_id)}> \n\n {receive}'
32 | await interaction.followup.send(response)
33 | logger.info(f"{user_id} sent: {send}, response: {receive}")
34 | except Exception as e:
35 | await interaction.followup.send('> **Error: Something went wrong, please try again later!**')
36 | logger.exception(f"Error while sending:{send} in chatgpt model, error: {e}")
37 |
38 | async def send_image(self, interaction, send, receive):
39 | try:
40 | user_id = interaction.user.id
41 | response = f'> **{send}** - <@{str(user_id)}> \n\n'
42 | await interaction.followup.send(response)
43 | await interaction.followup.send(receive)
44 | logger.info(f"{user_id} sent: {send}, response: {receive}")
45 | except Exception as e:
46 | await interaction.followup.send('> **Error: Something went wrong, please try again later!**')
47 | logger.exception(f"Error while sending:{send} in dalle model, error: {e}")
48 |
--------------------------------------------------------------------------------
/src/logger.py:
--------------------------------------------------------------------------------
1 | import os
2 | import logging
3 | import logging.handlers
4 |
5 |
6 | class CustomFormatter(logging.Formatter):
7 | __LEVEL_COLORS = [
8 | (logging.DEBUG, '\x1b[40;1m'),
9 | (logging.INFO, '\x1b[34;1m'),
10 | (logging.WARNING, '\x1b[33;1m'),
11 | (logging.ERROR, '\x1b[31m'),
12 | (logging.CRITICAL, '\x1b[41m'),
13 | ]
14 | __FORMATS = None
15 |
16 | @classmethod
17 | def get_formats(cls):
18 | if cls.__FORMATS is None:
19 | cls.__FORMATS = {
20 | level: logging.Formatter(
21 | f'\x1b[30;1m%(asctime)s\x1b[0m {color}%(levelname)-8s\x1b[0m \x1b[35m%(name)s\x1b[0m -> %(message)s',
22 | '%Y-%m-%d %H:%M:%S'
23 | )
24 | for level, color in cls.__LEVEL_COLORS
25 | }
26 | return cls.__FORMATS
27 |
28 | def format(self, record):
29 | formatter = self.get_formats().get(record.levelno)
30 | if formatter is None:
31 | formatter = self.get_formats()[logging.DEBUG]
32 | if record.exc_info:
33 | text = formatter.formatException(record.exc_info)
34 | record.exc_text = f'\x1b[31m{text}\x1b[0m'
35 |
36 | output = formatter.format(record)
37 | record.exc_text = None
38 | return output
39 |
40 |
41 | class LoggerFactory:
42 | @staticmethod
43 | def create_logger(formatter, handlers):
44 | logger = logging.getLogger('chatgpt_logger')
45 | logger.setLevel(logging.INFO)
46 | for handler in handlers:
47 | handler.setLevel(logging.DEBUG)
48 | handler.setFormatter(formatter)
49 | logger.addHandler(handler)
50 | return logger
51 |
52 |
53 | class FileHandler(logging.FileHandler):
54 | def __init__(self, log_file):
55 | os.makedirs(os.path.dirname(log_file), exist_ok=True)
56 | super().__init__(log_file)
57 |
58 |
59 | class ConsoleHandler(logging.StreamHandler):
60 | pass
61 |
62 |
63 | formatter = CustomFormatter()
64 | file_handler = FileHandler('./logs')
65 | console_handler = ConsoleHandler()
66 | logger = LoggerFactory.create_logger(formatter, [file_handler, console_handler])
67 |
--------------------------------------------------------------------------------
/src/server.py:
--------------------------------------------------------------------------------
1 | from threading import Thread
2 | from flask import Flask
3 |
4 | app = Flask('NotionAI-Discord-Bot')
5 |
6 |
7 | @app.route('/')
8 | def home():
9 | return "Hello World"
10 |
11 |
12 | def server_run():
13 | app.run(host='0.0.0.0', port=8080)
14 |
15 |
16 | def keep_alive():
17 | t = Thread(target=server_run)
18 | t.start()
19 |
--------------------------------------------------------------------------------