Skip to content

Commit

Permalink
New OpenAI model. Minor tweaks.
Browse files Browse the repository at this point in the history
  • Loading branch information
pernifin committed May 29, 2024
1 parent 03e82dd commit 0ff1030
Show file tree
Hide file tree
Showing 17 changed files with 473 additions and 266 deletions.
10 changes: 6 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
{
"name": "gptitor",
"version": "1.3.3",
"version": "1.4.0",
"description": "",
"main": "src/index.ts",
"type": "module",
"scripts": {
"dev": "ts-node src/index.ts",
"dev:watch": "nodemon --exec ts-node src/index.ts",
"build": "tsc",
"lint": "tsc -noEmit && eslint src/**",
"test": "jest",
"start": "ts-node src/index.ts"
"start": "node --loader ts-node/esm ./src/index.ts"
},
"engines": {
"node": "18.x"
Expand All @@ -24,12 +25,13 @@
"fluent-ffmpeg": "^2.1.2",
"midjourney": "^4.0.98",
"node-fetch": "^2.6.11",
"openai": "^3.3.0",
"openai": "^4.24.1",
"redis": "^4.6.7",
"sharp": "^0.32.1",
"telegraf": "^4.12.2",
"ts-node": "^10.9.1",
"typescript": "^5.1.3"
"typescript": "^5.1.3",
"winston": "^3.11.0"
},
"devDependencies": {
"@jest/globals": "^29.5.0",
Expand Down
6 changes: 3 additions & 3 deletions src/bot.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Telegraf, Context, Scenes, session } from "telegraf";
import { Update, CallbackQuery } from 'typegram';
import { Update, CallbackQuery } from "telegraf/types";
import ffmpeg from "fluent-ffmpeg";

import { definitions } from "./scenes/dialog/commands";
Expand All @@ -8,8 +8,8 @@ import antispamScene from "./scenes/antispam";
import dialogScene, { DIALOG_SCENE_ID } from "./scenes/dialog";
import {
services,
Datastore, OpenAI, Quota, Settings, Translation, Conversation, Midjourney,
type UserQuota, type ChatSettings, type Translator
Datastore, OpenAI, Quota, Settings, Translation, Conversation,
type UserQuota, type ChatSettings, type Translator, type Midjourney,
} from "./services";

export type SceneState = Scenes.SceneSessionData & {
Expand Down
57 changes: 34 additions & 23 deletions src/config.ts
Original file line number Diff line number Diff line change
@@ -1,46 +1,57 @@
const prices = {
"gpt-3.5-turbo-16k-0613": 0.4,
"gpt-4-0613": 6,
"whisper-1": 0.6
"gpt-4o": 1.5,
"gpt-4-vision-preview": 3,
"whisper-1": 0.6,
"dall-e-3": 4,
} as const;

export type ModelName = keyof typeof prices;

const config = {
models: {
"gpt-3.5-turbo-16k-0613": "GPT-3.5 Turbo",
"gpt-4-0613": "GPT-4"
"gpt-4o": "GPT-4o"
} as Record<ModelName, string>,
prices,
modes: { "0.1": "Strict", "0.7": "Flexible", "1.2": "Creative", "1.7": "Extreme" },
systemMessage: [
"You are an AI assistant who has access to all the knowledge of mankind. The user asks you to explain something. Always politely and briefly answer his questions. If the answer requires clarification, ask a question. Communicate in a friendly tone, but always short and to the point.",
"You are an AI assistant who has access to all the knowledge of mankind.",
"The user asks you to explain something.",
"Always politely and briefly answer his questions.",
"Do not repeat user's question at the start of the answer.",
"If the answer requires clarification, ask a question.",
"Communicate in a friendly tone, but always short and to the point.",
"Generate code only if the user explicitly requested it, or if the code is an integral part of the explanation.",
"Always wrap code blocks with three backticks (`)"
"Always wrap code blocks with three backticks (`)",
"Use MarkdownV2 style for formatting messages.",
"To make bold text use single *asterisks*, to make italic use single _underscore_.",
"Don't make assumptions about what values to plug into functions. Ask for clarification if a user request is ambiguous.",
].join("\n"),
translationRequest: "Translate following user's message into English",
maxCompletions: 5,
defaultSettings: {
model: "gpt-3.5-turbo-16k-0613" as ModelName,
model: "gpt-4o" as ModelName,
temperature: 0.7,
completions: 1,
maxTokens: 4096
},
functions: [
// {
// name: "generateImage",
// description: "Generate an image from a user's prompt. Can be called only when user explicitly asks for an image",
// parameters: {
// type: "object",
// properties: {
// prompt: {
// type: "string",
// description: "Clear and concise prompt string in English language without verbs that describes the image to be generated"
// }
// },
// required: ["prompt"]
// },
// },
tools: [
{
type: "function" as const,
function: {
name: "generateImage",
description: "Generate an image from a user's prompt. Can be called only when user explicitly asks for an image",
parameters: {
type: "object",
properties: {
prompt: {
type: "string",
description: "Clear and concise prompt string in English language without verbs that describes the image to be generated"
}
},
required: ["prompt"]
},
}
},
// {
// name: "describeImage",
// description: "Describe in human readable format what is depicted on provided image",
Expand Down
30 changes: 23 additions & 7 deletions src/functions/index.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,33 @@
import { type Message } from "typegram";
import d from "debug";
import { Markup } from "telegraf";
import actions from "../scenes/dialog/actions";
import { callUntil } from "../utils";

import { type Message } from "telegraf/types";
import type { BotContext } from "../bot";
import actions from "../scenes/dialog/actions";

const debug = d("bot:functions");

export type BotFunction = (ctx: BotContext, args: object) => Promise<string | void>;

export async function generateImage(ctx: BotContext, { prompt }: { prompt: string }) {
const hasNonAscii = prompt.split("").some((char) => char.charCodeAt(0) > 127)
if (hasNonAscii) {
prompt = await ctx.openai.translateMessage(prompt);
try {
debug(`generateImage: ${prompt}`);
await callUntil(
() => ctx.sendChatAction("upload_photo"),
async () => {
const { url, revised_prompt } = await ctx.openai.generateImage(prompt);
return ctx.sendPhoto(url!, {
caption: revised_prompt,
// ...Markup.inlineKeyboard([
// Markup.button.callback(ctx.$t("action.fullsize"), `fullsize:${url}`)
// ])
});
}
);
} catch (error: any) {
await ctx.sendMessage(error.message ?? ctx.$t("error.noimage"));
}

await actions.generate(ctx, prompt);
}

export async function describeImage(ctx: BotContext) {
Expand Down
25 changes: 0 additions & 25 deletions src/index.test.ts

This file was deleted.

35 changes: 14 additions & 21 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,15 @@
import "dotenv/config";
import * as fs from "fs";
import express from "express";
import { type AxiosError } from 'axios';
import d from "debug";

import Bot from "./bot";
import routes from "./routes";

const { BOT_TOKEN, NODE_ENV, PORT, RAILWAY_STATIC_URL } = process.env;

const debug = d("bot:server");
const app = express();
const bot = new Bot(BOT_TOKEN!);
const host = RAILWAY_STATIC_URL || process.argv[2];
const log = fs.createWriteStream("./debug.log", { flags: "a" });

if (!host) {
throw new Error("Missing host. Provide '-- <host>' as the last argument");
Expand All @@ -25,28 +21,25 @@ app.post("/bot", async (request, response, next) => {
try {
await bot.handle(request, response, next);
} catch (error) {
debug(
"Error handle update: %s\n%s\n\n%o\n\n%o",
(error as Error).message,
(error as Error).stack,
request.body,
(error as AxiosError).response?.data
);
log.write(`Error: ${JSON.stringify(error, null, 2)}\nRequest: ${request.body}`, "utf-8");
console.error(`Error: ${JSON.stringify(error, null, 2)}\nRequest: ${request.body}`, "utf-8");
}
});

app.get("/file/:file.png", async (request, response) => {
const file = await bot.telegram.getFileLink(request.params.file);
const buffer = await fetch(file.href).then((result) => result.arrayBuffer());

response.setHeader('Cache-Control', 'public, max-age=31536000, immutable');
response.setHeader('Content-Type', 'image/png');
response.setHeader('Content-Length', buffer.byteLength);
response.send(Buffer.from(buffer));
app.use((request, response, next) => {
if (request.query.bot !== process.env.BOT_TOKEN) {
return response.status(418).json({ error: "I'm a teabot!" });
}
next();
});

app.use(routes(bot));
app.get("/check", async (request, response) => {
response.status(200).json({
env: process.env,
memory: process.memoryUsage(),
bot: await bot.telegram.getMe(),
webhook: await bot.telegram.getWebhookInfo()
});
});

app.listen(PORT || 3000, async () => {
await bot.run({
Expand Down
2 changes: 2 additions & 0 deletions src/lang/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@ export default {

"balance.message": "You have {{tokens}} tokens left. You receive {{dailyTokens}} tokens once in a day if your balance is less than {{startTokens}}.",

"error.chat": "An error occurred while generating the answer:\n{{error}}",
"error.noimage": "No image provided",
"error.image-not-found": "Image not found",
"error.process-image-failed": "Failed to process image",
"error.generate-image-failed": "Failed to generate image",

"action.fullsize": "🖼️ Full size",
"action.split": "🔢 Split",
"action.regenerate": "🔁 Regenerate",
"action.variate": "🔄 Variate",
Expand Down
2 changes: 2 additions & 0 deletions src/lang/ru.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@ export default {

"balance.message": "У вас осталось {{tokens}} токенов. Каждый день вы получете {{dailyTokens}} токенов если ваш баланс меньше чем {{startTokens}}.",

"error.chat": "Произошла ошибка при генерации ответа:\n{{error}}",
"error.noimage": "Изображение не загружено",
"error.image-not-found": "Изображение не найдено",
"error.process-image-failed": "Ошибка при обработке изображения",
"error.generate-image-failed": "Ошибка при генерации изображения",

"action.fullsize": "🖼️ Полный размер",
"action.split": "🔢 Разделить",
"action.regenerate": "🔁 Перерисовать",
"action.variate": "🔄 Варианты",
Expand Down
30 changes: 0 additions & 30 deletions src/routes.ts

This file was deleted.

25 changes: 17 additions & 8 deletions src/scenes/dialog/actions.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Markup } from "telegraf";
import { type Message, type CallbackQuery, type InlineKeyboardMarkup, type InlineKeyboardButton } from "typegram";

import { type Message, type CallbackQuery, type InlineKeyboardMarkup, type InlineKeyboardButton } from "telegraf/types";
import { type GeneratedImage } from "../../services/Midjourney";
import type { BotContext } from "../../bot";
import { format, callUntil } from "../../utils";
Expand Down Expand Up @@ -80,15 +80,24 @@ const trackProgress = async (ctx: BotContext, callback: (tracker: (progress: num
};

export default {
async fullsize(ctx: BotContext, imageUrl: string) {
await callUntil(
() => ctx.sendChatAction("upload_photo"),
ctx.sendDocument(imageUrl)
);
},
async generate(ctx: BotContext, prompt: string) {
await trackProgress(ctx, (setProgress) => {
const message = (ctx.message || ctx.callbackQuery?.message) as Message.PhotoMessage & Message.TextMessage;
if (message.photo) {
prompt = `${ctx.host}/file/${message.photo[0].file_id}.png ${prompt}`;
}
// await trackProgress(ctx, (setProgress) => {
// const message = (ctx.message || ctx.callbackQuery?.message) as Message.PhotoMessage & Message.TextMessage;
// if (message.photo) {
// prompt = `${ctx.host}/file/${message.photo[0].file_id}.png ${prompt}`;
// }

return sendImage(ctx, ctx.midjourney.generate(prompt, setProgress));
});
// return sendImage(ctx, ctx.midjourney.generate(prompt, setProgress));
// });
const message = (ctx.message || ctx.callbackQuery?.message) as Message.TextMessage;

return sendImage(ctx, ctx.midjourney.generate(prompt));
},

async upscale(ctx: BotContext, payload: string) {
Expand Down
Loading

0 comments on commit 0ff1030

Please sign in to comment.