mistral ai vision for single image

This commit is contained in:
2026-01-16 15:54:10 +03:00
parent 326cfcafc8
commit 38b312ae41
2 changed files with 58 additions and 10 deletions
+44 -10
View File
@@ -6,6 +6,7 @@ import {
collectReplyChainText, collectReplyChainText,
editMessageText, editMessageText,
escapeMarkdownV2Text, escapeMarkdownV2Text,
getPhotoMaxSize,
logError, logError,
replyToMessage, replyToMessage,
startIntervalEditor startIntervalEditor
@@ -14,6 +15,9 @@ import {Environment} from "../common/environment";
import {bot} from "../index"; import {bot} from "../index";
import {MessageStore} from "../common/message-store"; import {MessageStore} from "../common/message-store";
import {Mistral} from "@mistralai/mistralai"; import {Mistral} from "@mistralai/mistralai";
import path from "node:path";
import fs from "node:fs";
import axios from "axios";
export class MistralChat extends ChatCommand { export class MistralChat extends ChatCommand {
regexp = /^\/mistral\s([^]+)/i; regexp = /^\/mistral\s([^]+)/i;
@@ -34,24 +38,54 @@ export class MistralChat extends ChatCommand {
const chatId = msg.chat.id; const chatId = msg.chat.id;
let imageFilePath: string | null = null;
const maxSize = await getPhotoMaxSize(msg.photo);
if (maxSize) {
const imagePath = path.join(Environment.DATA_PATH, "temp");
if (!fs.existsSync(imagePath)) {
fs.mkdirSync(imagePath);
}
imageFilePath = path.join(imagePath, maxSize.unique_file_id + ".jpg");
if (!fs.existsSync(imageFilePath)) {
const res = await axios.get<ArrayBuffer>(maxSize.url, {responseType: "arraybuffer"});
const src = Buffer.from(res.data);
try {
fs.writeFileSync(imageFilePath, src);
} catch (e) {
console.error(e);
imageFilePath = null;
}
}
}
const messageParts = await collectReplyChainText(msg, "/mistral"); const messageParts = await collectReplyChainText(msg, "/mistral");
console.log("MESSAGE PARTS", messageParts); console.log("MESSAGE PARTS", messageParts);
const chatMessages = messageParts.map(part => { const chatMessages = messageParts.map((part, i) => {
const content = [];
content.push({
type: "text",
text: part.content
});
if (imageFilePath && i === 0) {
const base64Image = Buffer.from(fs.readFileSync(imageFilePath)).toString("base64");
content.push({
type: "image_url",
imageUrl: "data:image/jpeg;base64," + base64Image
});
}
return { return {
role: part.bot ? "assistant" : "user", role: part.bot ? "assistant" : "user",
content: part.content content: content,
}; };
}); });
chatMessages.reverse(); chatMessages.reverse();
chatMessages.unshift({role: "system", content: Environment.SYSTEM_PROMPT}); chatMessages.unshift({role: "system", content: [{type: "text", text: Environment.SYSTEM_PROMPT}]});
// let chatContent = "";
// for (const part of chatMessages) {
// chatContent += `${part.role.toUpperCase()}:\n${part.content}\n\n`;
// }
// chatContent = chatContent.trim();
let waitMessage: Message; let waitMessage: Message;
+14
View File
@@ -13,6 +13,7 @@ import sharp from "sharp";
import {UserStore} from "../common/user-store"; import {UserStore} from "../common/user-store";
import * as orm from "drizzle-orm"; import * as orm from "drizzle-orm";
import {sql, type SQL} from "drizzle-orm"; import {sql, type SQL} from "drizzle-orm";
import fs from "node:fs";
export const ignore = () => { export const ignore = () => {
}; };
@@ -784,4 +785,17 @@ export async function mapPhotoSizeToMax(size: PhotoSize): Promise<PhotoMaxSize |
url: await getFileUrl(size.file_id), url: await getFileUrl(size.file_id),
unique_file_id: size.file_unique_id unique_file_id: size.file_unique_id
}; };
}
export async function imageToBase64(filePath: string): Promise<string> {
return new Promise((resolve, reject) => {
fs.readFile(filePath, (err, data) => {
if (err) {
return reject(err);
}
const base64Image = Buffer.from(data).toString("base64");
const dataUrl = `data:image/jpeg;base64,${base64Image}`;
resolve(dataUrl);
});
});
} }