mirror of
https://github.com/matrixgpt/matrix-chatgpt-bot.git
synced 2024-06-26 14:42:14 +00:00
Merge pull request #78 from max298/main
Update chatgpt-api to use proper api
This commit is contained in:
commit
1f0b7733e7
12
.env.example
12
.env.example
|
@ -1,13 +1,11 @@
|
|||
# ChatGPT Settings (required)
|
||||
OPENAI_EMAIL=
|
||||
OPENAI_PASSWORD=
|
||||
# What type of Login it is, possibility's are google, openai, microsoft
|
||||
OPENAI_LOGIN_TYPE=google
|
||||
# Set the next line to true if you are using a ChatGPT pro account.
|
||||
OPENAI_PRO=false
|
||||
# Set the API Key from OpenAI
|
||||
OPENAI_API_KEY=
|
||||
|
||||
# Set the ChatGPT conversation context to 'thread', 'room' or 'both'.
|
||||
CHATGPT_CONTEXT=thread
|
||||
# (Optional) Explicitly set the ChatGPT model to be used by the API.
|
||||
#CHATGPT_MODEL=text-chat-davinci-002-20221122
|
||||
|
||||
# Matrix Static Settings (required, see notes)
|
||||
# Defaults to "https://matrix.org"
|
||||
|
@ -36,4 +34,4 @@ MATRIX_ENCRYPTION=true
|
|||
# If you turn threads off you will have problems if you don't set CHATGPT_CONTEXT=room
|
||||
MATRIX_THREADS=true
|
||||
MATRIX_PREFIX_DM=false
|
||||
MATRIX_RICH_TEXT=true
|
||||
MATRIX_RICH_TEXT=true
|
||||
|
|
20
Dockerfile
20
Dockerfile
|
@ -1,22 +1,7 @@
|
|||
FROM satantime/puppeteer-node:19-slim
|
||||
FROM node:19-slim
|
||||
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true
|
||||
ENV PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium
|
||||
ENV CHROME_PATH=/usr/bin/chromium
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
RUN apt update -qq \
|
||||
&& apt install -qq -y --no-install-recommends \
|
||||
chromium \
|
||||
dumb-init \
|
||||
# To run Headful mode we just need to install Xvfb and Puppeteer related dependencies.
|
||||
xfonts-100dpi xfonts-75dpi xfonts-scalable xfonts-cyrillic \
|
||||
xvfb xauth\
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& rm -rf /src/*.deb
|
||||
|
||||
COPY package*.json ./
|
||||
RUN yarn install --frozen-lockfile --production && yarn cache clean
|
||||
|
||||
|
@ -27,5 +12,4 @@ RUN yarn build
|
|||
VOLUME /storage
|
||||
ENV DATA_PATH="/storage"
|
||||
|
||||
# We run a fake display and run our script using Xvfb
|
||||
CMD xvfb-run --server-args="-screen 0 1024x768x16" yarn start
|
||||
CMD yarn start
|
||||
|
|
19
README.md
19
README.md
|
@ -35,12 +35,8 @@ You must adjust all required settings in the `.env` file according to your needs
|
|||
Per default, whoever knows the name of your bot can add it to their rooms and start chatting. Access can be restricted by setting `MATRIX_BLACKLIST` or `MATRIX_WHISTLIST` in your `.env` file. When using a self-hosted setup, you could wildcard all your user by adding `MATRIX_WHITELIST=:anotherhomeserver.example` and change it to your homeserver address.
|
||||
|
||||
### OpenAI / ChatGPT
|
||||
- You need to have an account at [openai.com. ](https://openai.com/) Its recommended to use an google account without 2FA for set up the account to avoid unsolvable captchas. Then, set `OPENAI_LOGIN_TYPE` to `google` in your `.env` file
|
||||
|
||||
You must read the [authentication instructions](https://www.npmjs.com/package/chatgpt#usage) for chatgpt-api if you get stuck.
|
||||
Using the same account at [chat.openai.com](https://chat.openai.com) may refresh tokens invalidating the bot's session.
|
||||
|
||||
**If the Google account uses 2FA it will fail** but there is [a workaround](https://github.com/transitive-bullshit/chatgpt-api/issues/169#issuecomment-1362206780)
|
||||
- You need to have an account at [openai.com. ](https://openai.com/). Create a [API Key](https://platform.openai.com/account/api-keys). Then, set `OPENAI_API_KEY` in your `.env` file
|
||||
- You might want to change to chat-model by setting the `CHATGPT_MODEL` in your `.env` file. The model currently defaults to `text-chat-davinci-002-20221122`. Check the [node-chatgpt-api](https://github.com/waylaidwanderer/node-chatgpt-api) repository for keeping track of the models.
|
||||
|
||||
## Setup
|
||||
|
||||
|
@ -52,7 +48,7 @@ You no longer need `MATRIX_BOT_PASSWORD` set but you can leave it if you want.
|
|||
|
||||
# Run
|
||||
|
||||
There are multiple ways to run this bot. The easiest way is to run it within docker. You need to be logged into your OpenAi account from the same network your bot machine is. When you are logged in, you can safely close the window, just make sure you do not log out because this would make your session token invalid.
|
||||
There are multiple ways to run this bot. The easiest way is to run it within docker.
|
||||
|
||||
## with Docker
|
||||
|
||||
|
@ -114,10 +110,6 @@ You only need to do this if you want to contribute code to this package.
|
|||
|
||||
# FAQ
|
||||
|
||||
## What do I do if a login fails?
|
||||
- Its strongly suggested to use google as the prefererred login method to avoid being not abled to solve the required captchas
|
||||
- Make sure that 2FA is deactivated (E.g. use the above mentioned workaroud or create a fresh google account)
|
||||
|
||||
## How do I handle "[Error: decryption failed because the room key is missing]"
|
||||
Encryption works great with this package but can sometimes be a bit sensitive. Following steps can help to solve the "encryption" error
|
||||
|
||||
|
@ -134,11 +126,6 @@ Encryption works great with this package but can sometimes be a bit sensitive. F
|
|||
4) Log into your bot account (e.g. via Element) and log out of all sessions
|
||||
5) Verify the correctness of your `env` file and then run the bot setup again (e.g. via `docker-compose up` if you use docker-compose).
|
||||
|
||||
- If you experience this error after adding the bot to a new room but it was working before, you can try to use the command `/discardsession` in the element app to drop the session and trigger a new one. In this error case, the error only appears on a specific device, so using another client should work eitherway.
|
||||
|
||||
## What to do if I get an error saying I'm not logged in?
|
||||
- If the bot can't log into your OpenAI account, your session token might not been valid anymore (e.g. you logged out of your OpenAI account through your browser). Re-login to your OpenAI account using a machine in the same network as the machine your bot is using. Then restart the bot.
|
||||
|
||||
## I just want to chat with the bot and don't want to deal with encryption problems
|
||||
- Set `MATRIX_ENCRYPTION=false` in your env-file and restart the bot. If it previously was running with encryption switched on, you need to create a new room with the bot as encryption can't be switched off once it was activated.
|
||||
|
||||
|
|
3435
package-lock.json
generated
3435
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
|
@ -15,11 +15,10 @@
|
|||
"typecheck": "npx tsc"
|
||||
},
|
||||
"dependencies": {
|
||||
"chatgpt": "^3.5.1",
|
||||
"chatgpt": "^4.1.1",
|
||||
"dotenv": "^16.0.3",
|
||||
"markdown-it": "^13.0.1",
|
||||
"matrix-bot-sdk": "^0.6.3",
|
||||
"puppeteer": "^19.4.1",
|
||||
"typescript": "^4.9.4",
|
||||
"znv": "^0.3.2",
|
||||
"zod": "^3.20.2"
|
||||
|
|
16
src/env.ts
16
src/env.ts
|
@ -23,12 +23,10 @@ export const {
|
|||
MATRIX_DEFAULT_PREFIX,
|
||||
MATRIX_DEFAULT_PREFIX_REPLY,
|
||||
/** ChatGPT Settings */
|
||||
OPENAI_EMAIL,
|
||||
OPENAI_PASSWORD,
|
||||
OPENAI_LOGIN_TYPE,
|
||||
OPENAI_PRO,
|
||||
OPENAI_API_KEY,
|
||||
CHATGPT_CONTEXT,
|
||||
CHATGPT_TIMEOUT
|
||||
CHATGPT_TIMEOUT,
|
||||
CHATGPT_MODEL
|
||||
} = parseEnv(process.env, {
|
||||
DATA_PATH: { schema: z.string().default("./storage"), description: "Set to /storage/ if using docker, ./storage if running without" },
|
||||
/** Matrix Bot Settings */
|
||||
|
@ -49,10 +47,8 @@ export const {
|
|||
MATRIX_DEFAULT_PREFIX: { schema: z.string().default(""), description: "Set to a string if you want the bot to respond only when messages start with this prefix. Trailing space matters. Empty for no prefix." },
|
||||
MATRIX_DEFAULT_PREFIX_REPLY: { schema: z.boolean().default(false), description: "Set to false if you want the bot to answer to all messages in a thread/conversation" },
|
||||
/** ChatGPT Settings */
|
||||
OPENAI_EMAIL: { schema: z.string().min(3), description: "Set full username of OpenAI's account" },
|
||||
OPENAI_PASSWORD: { schema: z.string().min(1), description: "Set password of OpenAI's account" },
|
||||
OPENAI_LOGIN_TYPE: { schema: z.enum(["google", "openai", "microsoft"]).default("google"), description: "Set authentication provider to 'google', 'openai' or 'microsoft'" },
|
||||
OPENAI_PRO: { schema: z.boolean().default(false), description: "Set to true if you have a paid ChatGPT subscription." },
|
||||
OPENAI_API_KEY: { schema: z.string().default(""), description: "Set to the API key from https://platform.openai.com/account/api-keys"},
|
||||
CHATGPT_TIMEOUT: { schema: z.number().default(2 * 60 * 1000), description: "Set number of milliseconds to wait for ChatGPT responses" },
|
||||
CHATGPT_CONTEXT: { schema: z.enum(["thread", "room", "both"]).default("thread"), description: "Set the ChatGPT conversation context to 'thread', 'room' or 'both'" }
|
||||
CHATGPT_CONTEXT: { schema: z.enum(["thread", "room", "both"]).default("thread"), description: "Set the ChatGPT conversation context to 'thread', 'room' or 'both'" },
|
||||
CHATGPT_MODEL: { schema: z.string().default("text-chat-davinci-002-20221122"), description: "The model for the ChatGPT-API to use" }
|
||||
});
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { ChatGPTAPIBrowser } from "chatgpt";
|
||||
import { ChatGPTAPI } from "chatgpt";
|
||||
import { LogService, MatrixClient, UserID } from "matrix-bot-sdk";
|
||||
import { CHATGPT_CONTEXT, CHATGPT_TIMEOUT, MATRIX_DEFAULT_PREFIX_REPLY, MATRIX_DEFAULT_PREFIX, MATRIX_BLACKLIST, MATRIX_WHITELIST, MATRIX_RICH_TEXT, MATRIX_PREFIX_DM, MATRIX_THREADS } from "./env.js";
|
||||
import { RelatesTo, MessageEvent, StoredConversation, StoredConversationConfig } from "./interfaces.js";
|
||||
|
@ -11,7 +11,7 @@ export default class CommandHandler {
|
|||
private userId: string;
|
||||
private localpart: string;
|
||||
|
||||
constructor(private client: MatrixClient, private chatGPT: ChatGPTAPIBrowser) { }
|
||||
constructor(private client: MatrixClient, private chatGPT: ChatGPTAPI) { }
|
||||
|
||||
public async start() {
|
||||
await this.prepareProfile(); // Populate the variables above (async)
|
||||
|
@ -124,11 +124,11 @@ export default class CommandHandler {
|
|||
const result = await sendChatGPTMessage(this.chatGPT, await bodyWithoutPrefix, storedConversation);
|
||||
await Promise.all([
|
||||
this.client.setTyping(roomId, false, 500),
|
||||
sendReply(this.client, roomId, this.getRootEventId(event), `${result.response}`, MATRIX_THREADS, MATRIX_RICH_TEXT)
|
||||
sendReply(this.client, roomId, this.getRootEventId(event), `${result.text}`, MATRIX_THREADS, MATRIX_RICH_TEXT)
|
||||
]);
|
||||
|
||||
const storedConfig = ((storedConversation !== undefined && storedConversation.config !== undefined) ? storedConversation.config : {})
|
||||
const configString: string = JSON.stringify({conversationId: result.conversationId, messageId: result.messageId, config: storedConfig})
|
||||
const configString: string = JSON.stringify({conversationId: result.conversationId, messageId: result.id, config: storedConfig})
|
||||
await this.client.storageProvider.storeValue('gpt-' + storageKey, configString);
|
||||
if ((storageKey === roomId) && (CHATGPT_CONTEXT === "both")) await this.client.storageProvider.storeValue('gpt-' + event.event_id, configString);
|
||||
} catch (err) {
|
||||
|
|
21
src/index.ts
21
src/index.ts
|
@ -7,10 +7,10 @@ import {
|
|||
} from "matrix-bot-sdk";
|
||||
|
||||
import * as path from "path";
|
||||
import { DATA_PATH, OPENAI_EMAIL, OPENAI_PASSWORD, OPENAI_LOGIN_TYPE, OPENAI_PRO, MATRIX_HOMESERVER_URL, MATRIX_ACCESS_TOKEN, MATRIX_AUTOJOIN, MATRIX_BOT_PASSWORD, MATRIX_BOT_USERNAME, MATRIX_ENCRYPTION, MATRIX_THREADS, CHATGPT_CONTEXT } from './env.js'
|
||||
import { DATA_PATH, OPENAI_API_KEY, MATRIX_HOMESERVER_URL, MATRIX_ACCESS_TOKEN, MATRIX_AUTOJOIN, MATRIX_BOT_PASSWORD, MATRIX_BOT_USERNAME, MATRIX_ENCRYPTION, MATRIX_THREADS, CHATGPT_CONTEXT, CHATGPT_MODEL } from './env.js'
|
||||
import { parseMatrixUsernamePretty } from './utils.js';
|
||||
import CommandHandler from "./handlers.js"
|
||||
import { ChatGPTAPIBrowser } from 'chatgpt'
|
||||
import { ChatGPTAPI } from 'chatgpt'
|
||||
|
||||
LogService.setLogger(new RichConsoleLogger());
|
||||
|
||||
|
@ -42,18 +42,13 @@ async function main() {
|
|||
const client: MatrixClient = new MatrixClient(MATRIX_HOMESERVER_URL, MATRIX_ACCESS_TOKEN, storage, cryptoStore);
|
||||
|
||||
// use puppeteer to bypass cloudflare (headful because of captchas)
|
||||
const chatGPT: ChatGPTAPIBrowser = new ChatGPTAPIBrowser({
|
||||
email: OPENAI_EMAIL,
|
||||
password: OPENAI_PASSWORD,
|
||||
isGoogleLogin: (OPENAI_LOGIN_TYPE == "google"),
|
||||
isMicrosoftLogin: (OPENAI_LOGIN_TYPE == "microsoft"),
|
||||
isProAccount: OPENAI_PRO
|
||||
const chatGPT: ChatGPTAPI = new ChatGPTAPI({
|
||||
apiKey: OPENAI_API_KEY,
|
||||
completionParams: {
|
||||
model: CHATGPT_MODEL
|
||||
}
|
||||
})
|
||||
|
||||
chatGPT.initSession().then(() => {
|
||||
LogService.info('ChatGPT session initialized');
|
||||
});
|
||||
|
||||
// // call `api.refreshSession()` every hour to refresh the session
|
||||
// setInterval(() => {
|
||||
// chatGPT.refreshSession().then(() => {
|
||||
|
@ -91,7 +86,7 @@ async function main() {
|
|||
const commands = new CommandHandler(client, chatGPT);
|
||||
await commands.start();
|
||||
|
||||
LogService.info("index", "Starting bot...");
|
||||
LogService.info("index", `Starting bot using ChatGPT model ${CHATGPT_MODEL}`);
|
||||
await client.start()
|
||||
LogService.info("index", "Bot started!");
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { ChatGPTAPIBrowser, ChatResponse } from "chatgpt";
|
||||
import { ChatGPTAPI, ChatMessage } from "chatgpt";
|
||||
import Markdown from 'markdown-it';
|
||||
import { MatrixClient } from "matrix-bot-sdk";
|
||||
import { MessageEvent, StoredConversation } from "./interfaces.js";
|
||||
|
@ -76,8 +76,8 @@ export async function sendReply(client: MatrixClient, roomId: string, rootEventI
|
|||
await client.sendEvent(roomId, "m.room.message", finalContent);
|
||||
}
|
||||
|
||||
export async function sendChatGPTMessage(chatGPT: ChatGPTAPIBrowser, question: string, storedConversation: StoredConversation) {
|
||||
let result: ChatResponse
|
||||
export async function sendChatGPTMessage(chatGPT: ChatGPTAPI, question: string, storedConversation: StoredConversation) {
|
||||
let result: ChatMessage
|
||||
if (storedConversation !== undefined) {
|
||||
result = await chatGPT.sendMessage(question, {
|
||||
timeoutMs: CHATGPT_TIMEOUT,
|
||||
|
|
Loading…
Reference in New Issue
Block a user