From 8090de8031bd4bcf8ec0cb24bd99813d9b0810bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B5=D0=B2=20=D0=9C?= =?UTF-8?q?=D0=B0=D0=BA=D1=81=D0=B8=D0=BC=20=D0=A1=D0=B5=D1=80=D0=B3=D0=B5?= =?UTF-8?q?=D0=B5=D0=B2=D0=B8=D1=87?= Date: Mon, 16 Jun 2025 14:02:19 +0300 Subject: [PATCH 1/3] remove initiatives folder --- .../sber_mobile/initiatives-ai-agents/llm.ts | 22 -------- .../initiatives-ai-agents/moderation.ts | 56 ------------------- .../initiatives-ai-agents/picture.ts | 38 ------------- 3 files changed, 116 deletions(-) delete mode 100644 server/routers/kfu-m-24-1/sber_mobile/initiatives-ai-agents/llm.ts delete mode 100644 server/routers/kfu-m-24-1/sber_mobile/initiatives-ai-agents/moderation.ts delete mode 100644 server/routers/kfu-m-24-1/sber_mobile/initiatives-ai-agents/picture.ts diff --git a/server/routers/kfu-m-24-1/sber_mobile/initiatives-ai-agents/llm.ts b/server/routers/kfu-m-24-1/sber_mobile/initiatives-ai-agents/llm.ts deleted file mode 100644 index a5a0e23..0000000 --- a/server/routers/kfu-m-24-1/sber_mobile/initiatives-ai-agents/llm.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { GigaChat as GigaChatLang} from 'langchain-gigachat'; -import { GigaChat } from 'gigachat'; -import { Agent } from 'node:https'; - -const httpsAgent = new Agent({ - rejectUnauthorized: false, -}); - -export const llm_mod = (GIGA_AUTH) => - new GigaChatLang({ - credentials: GIGA_AUTH, - temperature: 0.2, - model: 'GigaChat-2-Max', - httpsAgent, -}); - -export const llm_gen = (GIGA_AUTH) => - new GigaChat({ - credentials: GIGA_AUTH, - model: 'GigaChat-2', - httpsAgent, -}); \ No newline at end of file diff --git a/server/routers/kfu-m-24-1/sber_mobile/initiatives-ai-agents/moderation.ts b/server/routers/kfu-m-24-1/sber_mobile/initiatives-ai-agents/moderation.ts deleted file mode 100644 index 48162c0..0000000 --- a/server/routers/kfu-m-24-1/sber_mobile/initiatives-ai-agents/moderation.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { llm_mod } from './llm' -import { z } from "zod"; - - -// возвращаю комментарий + исправленное предложение + булево значение - -export const moderationText = async (title: string, description: string, GIGA_AUTH): Promise<[string, string | undefined, boolean]> => { - - const moderationLlm = llm_mod(GIGA_AUTH).withStructuredOutput(z.object({ - comment: z.string(), - fixedText: z.string().optional(), - isApproved: z.boolean(), - }) as any) - - const prompt = ` - Представь, что ты модерируешь предложения от жильцов многоквартирного дома (это личная инициатива по улучшения, - не имеющая отношения к Управляющей компании). - - Заголовок: ${title} - Основной текст: ${description} - - Твои задачи: - 1. Проверь предложение и заголовок на спам. - 2. Проверь, чтобы заголовок и текст были на одну тему. - 3. Проверь само предложение пользователя на отсутствие грубой лексики и пошлостей. - 4. Проверь грамматику. - 5. Проверь на бессмысленность предложения. Оно не должно содержать только случайные символы. - 6. Не должно быть рекламы, ссылок и т.д. - 7. Проверь предложение на информативность, предложение не может быть коротким, оно должно ясно отражжать суть инициативы. - 8. Предложение должно быть в вежливой форме. - - - Если все правила соблюдены, то предложение принимается! - - - Если предложение отклонено, всегда пиши комментарий и fixedText! - - Правила написания комментария: - - Если предложение отклоняется, пиши комментарий со следующей формулировкой: - "Предложение отклонено. Причина: (укажи проблему)" - - Правила написания fixedText: - - Если предложение отклонено, то верни в поле "fixedText" измененный текст, который будет соответствовать правилам. - - Если предложение отклонено и содержит запрещённый контент (рекламу, личные данные), удали всю информацию, - которая противоречит правилам, и верни в только подходящий фрагмент, сохраняя общий смысл. - - Если текст не представляет никакой ценности, возврати в поле "fixedText" правило, - по которому оно не прошло. - -Если предложение принимается, то ничего не возвращай в поле fixedText. - ` - - const result = await moderationLlm.invoke(prompt); - if(!result.isApproved && result.comment.trim() === '' && (!result.fixedText || result.fixedText.trim() === '')) { - result.comment = 'Предложение отклонено. Причина: несоблюдение требований к оформлению или содержанию.', - result.fixedText = description - } - - return [result.comment, result.fixedText, result.isApproved]; -}; \ No newline at end of file diff --git a/server/routers/kfu-m-24-1/sber_mobile/initiatives-ai-agents/picture.ts b/server/routers/kfu-m-24-1/sber_mobile/initiatives-ai-agents/picture.ts deleted file mode 100644 index d216c5d..0000000 --- a/server/routers/kfu-m-24-1/sber_mobile/initiatives-ai-agents/picture.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { llm_gen } from './llm' -import { detectImage } from 'gigachat'; - -export const generatePicture = async (prompt: string, GIGA_AUTH) => { - const resp = await llm_gen(GIGA_AUTH).chat({ - messages: [ - { - "role": "system", - "content": "Ты — Василий Кандинский для жильцов многоквартирного дома" - }, - { - role: "user", - content: `Старайся передать атмосферу уюта и безопасности. - Нарисуй картинку подходящую для такого события: ${prompt} - В картинке не должно быть текста, только изображение.`, - }, - ], - function_call: 'auto', - }); - - // Получение изображения по идентификатору - const detectedImage = detectImage(resp.choices[0]?.message.content ?? ''); - - if (!detectedImage?.uuid) { - throw new Error('Не удалось получить UUID изображения из ответа GigaChat'); - } - - const image = await llm_gen(GIGA_AUTH).getImage(detectedImage.uuid); - - // Возвращаем содержимое изображения, убеждаясь что это Buffer - if (Buffer.isBuffer(image.content)) { - return image.content; - } else if (typeof image.content === 'string') { - return Buffer.from(image.content, 'binary'); - } else { - throw new Error('Unexpected image content type: ' + typeof image.content); - } -} From f66114b22f5905db35f5e8e4f50f6af27a5bff19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B5=D0=B2=20=D0=9C?= =?UTF-8?q?=D0=B0=D0=BA=D1=81=D0=B8=D0=BC=20=D0=A1=D0=B5=D1=80=D0=B3=D0=B5?= =?UTF-8?q?=D0=B5=D0=B2=D0=B8=D1=87?= Date: Mon, 16 Jun 2025 14:03:13 +0300 Subject: [PATCH 2/3] add initiatives folder --- .../sber_mobile/initiatives-ai-agents/llm.ts | 22 ++++++++ .../initiatives-ai-agents/moderation.ts | 56 +++++++++++++++++++ .../initiatives-ai-agents/picture.ts | 38 +++++++++++++ 3 files changed, 116 insertions(+) create mode 100644 server/routers/kfu-m-24-1/sber_mobile/initiatives-ai-agents/llm.ts create mode 100644 server/routers/kfu-m-24-1/sber_mobile/initiatives-ai-agents/moderation.ts create mode 100644 server/routers/kfu-m-24-1/sber_mobile/initiatives-ai-agents/picture.ts diff --git a/server/routers/kfu-m-24-1/sber_mobile/initiatives-ai-agents/llm.ts b/server/routers/kfu-m-24-1/sber_mobile/initiatives-ai-agents/llm.ts new file mode 100644 index 0000000..a5a0e23 --- /dev/null +++ b/server/routers/kfu-m-24-1/sber_mobile/initiatives-ai-agents/llm.ts @@ -0,0 +1,22 @@ +import { GigaChat as GigaChatLang} from 'langchain-gigachat'; +import { GigaChat } from 'gigachat'; +import { Agent } from 'node:https'; + +const httpsAgent = new Agent({ + rejectUnauthorized: false, +}); + +export const llm_mod = (GIGA_AUTH) => + new GigaChatLang({ + credentials: GIGA_AUTH, + temperature: 0.2, + model: 'GigaChat-2-Max', + httpsAgent, +}); + +export const llm_gen = (GIGA_AUTH) => + new GigaChat({ + credentials: GIGA_AUTH, + model: 'GigaChat-2', + httpsAgent, +}); \ No newline at end of file diff --git a/server/routers/kfu-m-24-1/sber_mobile/initiatives-ai-agents/moderation.ts b/server/routers/kfu-m-24-1/sber_mobile/initiatives-ai-agents/moderation.ts new file mode 100644 index 0000000..48162c0 --- /dev/null +++ b/server/routers/kfu-m-24-1/sber_mobile/initiatives-ai-agents/moderation.ts @@ -0,0 +1,56 @@ +import { llm_mod } from './llm' +import { z } from "zod"; + + +// возвращаю комментарий + исправленное предложение + булево значение + +export const moderationText = async (title: string, description: string, GIGA_AUTH): Promise<[string, string | undefined, boolean]> => { + + const moderationLlm = llm_mod(GIGA_AUTH).withStructuredOutput(z.object({ + comment: z.string(), + fixedText: z.string().optional(), + isApproved: z.boolean(), + }) as any) + + const prompt = ` + Представь, что ты модерируешь предложения от жильцов многоквартирного дома (это личная инициатива по улучшения, + не имеющая отношения к Управляющей компании). + + Заголовок: ${title} + Основной текст: ${description} + + Твои задачи: + 1. Проверь предложение и заголовок на спам. + 2. Проверь, чтобы заголовок и текст были на одну тему. + 3. Проверь само предложение пользователя на отсутствие грубой лексики и пошлостей. + 4. Проверь грамматику. + 5. Проверь на бессмысленность предложения. Оно не должно содержать только случайные символы. + 6. Не должно быть рекламы, ссылок и т.д. + 7. Проверь предложение на информативность, предложение не может быть коротким, оно должно ясно отражжать суть инициативы. + 8. Предложение должно быть в вежливой форме. + + - Если все правила соблюдены, то предложение принимается! + + - Если предложение отклонено, всегда пиши комментарий и fixedText! + + Правила написания комментария: + - Если предложение отклоняется, пиши комментарий со следующей формулировкой: + "Предложение отклонено. Причина: (укажи проблему)" + + Правила написания fixedText: + - Если предложение отклонено, то верни в поле "fixedText" измененный текст, который будет соответствовать правилам. + - Если предложение отклонено и содержит запрещённый контент (рекламу, личные данные), удали всю информацию, + которая противоречит правилам, и верни в только подходящий фрагмент, сохраняя общий смысл. + - Если текст не представляет никакой ценности, возврати в поле "fixedText" правило, + по которому оно не прошло. + -Если предложение принимается, то ничего не возвращай в поле fixedText. + ` + + const result = await moderationLlm.invoke(prompt); + if(!result.isApproved && result.comment.trim() === '' && (!result.fixedText || result.fixedText.trim() === '')) { + result.comment = 'Предложение отклонено. Причина: несоблюдение требований к оформлению или содержанию.', + result.fixedText = description + } + + return [result.comment, result.fixedText, result.isApproved]; +}; \ No newline at end of file diff --git a/server/routers/kfu-m-24-1/sber_mobile/initiatives-ai-agents/picture.ts b/server/routers/kfu-m-24-1/sber_mobile/initiatives-ai-agents/picture.ts new file mode 100644 index 0000000..d216c5d --- /dev/null +++ b/server/routers/kfu-m-24-1/sber_mobile/initiatives-ai-agents/picture.ts @@ -0,0 +1,38 @@ +import { llm_gen } from './llm' +import { detectImage } from 'gigachat'; + +export const generatePicture = async (prompt: string, GIGA_AUTH) => { + const resp = await llm_gen(GIGA_AUTH).chat({ + messages: [ + { + "role": "system", + "content": "Ты — Василий Кандинский для жильцов многоквартирного дома" + }, + { + role: "user", + content: `Старайся передать атмосферу уюта и безопасности. + Нарисуй картинку подходящую для такого события: ${prompt} + В картинке не должно быть текста, только изображение.`, + }, + ], + function_call: 'auto', + }); + + // Получение изображения по идентификатору + const detectedImage = detectImage(resp.choices[0]?.message.content ?? ''); + + if (!detectedImage?.uuid) { + throw new Error('Не удалось получить UUID изображения из ответа GigaChat'); + } + + const image = await llm_gen(GIGA_AUTH).getImage(detectedImage.uuid); + + // Возвращаем содержимое изображения, убеждаясь что это Buffer + if (Buffer.isBuffer(image.content)) { + return image.content; + } else if (typeof image.content === 'string') { + return Buffer.from(image.content, 'binary'); + } else { + throw new Error('Unexpected image content type: ' + typeof image.content); + } +} From 3639524fc7717c8a4259149bf355c04c50e8a4b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B5=D0=B2=20=D0=9C?= =?UTF-8?q?=D0=B0=D0=BA=D1=81=D0=B8=D0=BC=20=D0=A1=D0=B5=D1=80=D0=B3=D0=B5?= =?UTF-8?q?=D0=B5=D0=B2=D0=B8=D1=87?= Date: Mon, 16 Jun 2025 14:04:48 +0300 Subject: [PATCH 3/3] remove console log --- server/routers/kfu-m-24-1/sber_mobile/moderate.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/server/routers/kfu-m-24-1/sber_mobile/moderate.js b/server/routers/kfu-m-24-1/sber_mobile/moderate.js index 0e8b3f8..96c9926 100644 --- a/server/routers/kfu-m-24-1/sber_mobile/moderate.js +++ b/server/routers/kfu-m-24-1/sber_mobile/moderate.js @@ -39,8 +39,6 @@ router.post('/moderate', async (req, res) => { // Модерация текста (передаем title и description как body) const [comment, fixedText, isApproved] = await moderationText(title, description, GIGA_AUTH); - console.log('Результат модерации получен:', { comment, fixedText: fixedText?.substring(0, 100), isApproved }); - // Если модерация не прошла, возвращаем undefined if (!isApproved) { if (!comment || comment.trim() === '') {