From 9df4c6799d352eabe9d4242c72e9fe6da8eba141 Mon Sep 17 00:00:00 2001
From: Ivan <8611739+IRBorisov@users.noreply.github.com>
Date: Wed, 16 Apr 2025 21:02:53 +0300
Subject: [PATCH] F: Add LLM prompt generator
---
rsconcept/frontend/package-lock.json | 6 +--
rsconcept/frontend/src/components/icons.tsx | 1 +
.../features/help/items/ui/help-rsmenu.tsx | 8 ++++
.../src/features/rsform/models/rslang-api.ts | 44 ++++++++++---------
.../rsform/pages/rsform-page/menu-main.tsx | 21 ++++++++-
rsconcept/frontend/src/utils/labels.ts | 1 +
6 files changed, 56 insertions(+), 25 deletions(-)
diff --git a/rsconcept/frontend/package-lock.json b/rsconcept/frontend/package-lock.json
index b047aa09..76c83a7d 100644
--- a/rsconcept/frontend/package-lock.json
+++ b/rsconcept/frontend/package-lock.json
@@ -1387,9 +1387,9 @@
}
},
"node_modules/@eslint-community/eslint-utils": {
- "version": "4.6.0",
- "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.6.0.tgz",
- "integrity": "sha512-WhCn7Z7TauhBtmzhvKpoQs0Wwb/kBcy4CwpuI0/eEIr2Lx2auxmulAzLr91wVZJaz47iUZdkXOK7WlAfxGKCnA==",
+ "version": "4.6.1",
+ "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.6.1.tgz",
+ "integrity": "sha512-KTsJMmobmbrFLe3LDh0PC2FXpcSYJt/MLjlkh/9LEnmKYLSYmT/0EW9JWANjeoemiuZrmogti0tW5Ch+qNUYDw==",
"dev": true,
"license": "MIT",
"dependencies": {
diff --git a/rsconcept/frontend/src/components/icons.tsx b/rsconcept/frontend/src/components/icons.tsx
index f3375f6f..3c08ae7d 100644
--- a/rsconcept/frontend/src/components/icons.tsx
+++ b/rsconcept/frontend/src/components/icons.tsx
@@ -68,6 +68,7 @@ export { LuGlasses as IconReader } from 'react-icons/lu';
// ===== Domain entities =======
export { TbBriefcase as IconBusiness } from 'react-icons/tb';
export { VscLibrary as IconLibrary } from 'react-icons/vsc';
+export { BiBot as IconRobot } from 'react-icons/bi';
export { IoLibrary as IconLibrary2 } from 'react-icons/io5';
export { BiDiamond as IconTemplates } from 'react-icons/bi';
export { TbHexagons as IconOSS } from 'react-icons/tb';
diff --git a/rsconcept/frontend/src/features/help/items/ui/help-rsmenu.tsx b/rsconcept/frontend/src/features/help/items/ui/help-rsmenu.tsx
index 97ffcfb4..eac1e1fe 100644
--- a/rsconcept/frontend/src/features/help/items/ui/help-rsmenu.tsx
+++ b/rsconcept/frontend/src/features/help/items/ui/help-rsmenu.tsx
@@ -10,7 +10,9 @@ import {
IconEditor,
IconMenu,
IconOwner,
+ IconQR,
IconReader,
+ IconRobot,
IconShare,
IconUpload
} from '@/components/icons';
@@ -51,6 +53,12 @@ export function HelpRSMenu() {
Поделиться – скопировать ссылку на схему
+
+ Отобразить QR-код схемы
+
+
+ Генерировать запрос для LLM
+
Клонировать – создать копию схемы
diff --git a/rsconcept/frontend/src/features/rsform/models/rslang-api.ts b/rsconcept/frontend/src/features/rsform/models/rslang-api.ts
index 1afba909..4e6f6623 100644
--- a/rsconcept/frontend/src/features/rsform/models/rslang-api.ts
+++ b/rsconcept/frontend/src/features/rsform/models/rslang-api.ts
@@ -9,6 +9,7 @@ import { PARAMETER } from '@/utils/constants';
import { CstType, type IRSErrorDescription, type RSErrorType } from '../backend/types';
+import { type IRSForm } from './rsform';
import { type AliasMapping, type IArgumentValue, RSErrorClass, type SyntaxTree } from './rslang';
// cspell:disable
@@ -18,30 +19,22 @@ const COMPLEX_SYMBOLS_REGEXP = /[∀∃×ℬ;|:]/g;
const TYPIFICATION_SET = /^ℬ+\([ℬ\(X\d+\)×]*\)$/g;
// cspell:enable
-/**
- * Extracts global variable names from a given expression.
- */
+/** Extracts global variable names from a given expression. */
export function extractGlobals(expression: string): Set {
return new Set(expression.match(GLOBALS_REGEXP) ?? []);
}
-/**
- * Check if expression is simple derivation.
- */
+/** Check if expression is simple derivation. */
export function isSimpleExpression(text: string): boolean {
return !text.match(COMPLEX_SYMBOLS_REGEXP);
}
-/**
- * Check if expression is set typification.
- */
+/** Check if expression is set typification. */
export function isSetTypification(text: string): boolean {
return !!text.match(TYPIFICATION_SET);
}
-/**
- * Infers type of constituent for a given template and arguments.
- */
+/** Infers type of constituent for a given template and arguments. */
export function inferTemplatedType(templateType: CstType, args: IArgumentValue[]): CstType {
if (args.length === 0 || args.some(arg => !arg.value)) {
return templateType;
@@ -138,16 +131,12 @@ export function getRSErrorPrefix(error: IRSErrorDescription): string {
}
}
-/**
- * Apply alias mapping.
- */
+/** Apply alias mapping. */
export function applyAliasMapping(target: string, mapping: AliasMapping): string {
return applyPattern(target, mapping, GLOBALS_REGEXP);
}
-/**
- * Apply alias typification mapping.
- */
+/** Apply alias typification mapping. */
export function applyTypificationMapping(target: string, mapping: AliasMapping): string {
const modified = applyAliasMapping(target, mapping);
if (modified === target) {
@@ -202,9 +191,7 @@ export function applyTypificationMapping(target: string, mapping: AliasMapping):
return result;
}
-/**
- * Transform Tree to {@link SyntaxTree}.
- */
+/** Transform Tree to {@link SyntaxTree}. */
export function transformAST(tree: Tree): SyntaxTree {
const result: SyntaxTree = [];
const parents: number[] = [];
@@ -252,6 +239,21 @@ export function transformAST(tree: Tree): SyntaxTree {
return result;
}
+export function generatePrompt(schema: IRSForm): string {
+ const intro =
+ 'Концептуальная схема — это формализованная модель предметной области, выраженная с помощью языка родов структур, основанного на аппарате формальной логики и теории множеств, и дополненная естественно-языковыми пояснениями. Она представляет собой систему взаимосвязанных определений, где каждое понятие или утверждение задаётся в строгом формате Обозначение - "Типизация" - "Термин" - "Определение в языке родов структур" - "Определение в естественном языке" - "Конвенция или комментарий".\nОбозначение — уникальный идентификатор понятия (например, X1, S3, F14).\nТипизация — структура элементов множества, моделирующего данное понятие (например, ℬ(X1) для подмножества индивидов или ℬ(X1×X1) для бинарных отношений).\nТермин — название понятия в естественном языке.\nКонвенция описывает неопределяемые понятия предметным языком, включая уточнения, ограничения или примеры, включая ссылки на внешние данные (например, документы).\n------------\nДалее приведена концептуальная схема, описывающая некоторую предметную область.\n';
+ const outro =
+ '\n------\nПри ответе на следующий вопрос используй представленные в концептуальной схеме понятия и определения.\n';
+
+ let body = `Название концептуальной схемы: ${schema.title}\n`;
+ body += `[${schema.alias}] Описание: "${schema.description}"\n\n`;
+ body += 'Понятия:\n';
+ schema.items.forEach(item => {
+ body += `${item.alias} - "${item.parse.typification}" - "${item.term_resolved}" - "${item.definition_formal}" - "${item.definition_resolved}" - "${item.convention}"\n`;
+ });
+ return `${intro} ${body} ${outro}`;
+}
+
// ====== Internals =========
/** Text substitution guided by mapping and regular expression. */
function applyPattern(text: string, mapping: AliasMapping, pattern: RegExp): string {
diff --git a/rsconcept/frontend/src/features/rsform/pages/rsform-page/menu-main.tsx b/rsconcept/frontend/src/features/rsform/pages/rsform-page/menu-main.tsx
index 73506e39..94bc99be 100644
--- a/rsconcept/frontend/src/features/rsform/pages/rsform-page/menu-main.tsx
+++ b/rsconcept/frontend/src/features/rsform/pages/rsform-page/menu-main.tsx
@@ -1,3 +1,4 @@
+import { toast } from 'react-toastify';
import fileDownload from 'js-file-download';
import { urls, useConceptNavigation } from '@/app';
@@ -17,17 +18,19 @@ import {
IconNewItem,
IconOSS,
IconQR,
+ IconRobot,
IconShare,
IconUpload
} from '@/components/icons';
import { useDialogsStore } from '@/stores/dialogs';
import { useModificationStore } from '@/stores/modification';
import { EXTEOR_TRS_FILE } from '@/utils/constants';
-import { tooltipText } from '@/utils/labels';
+import { infoMsg, tooltipText } from '@/utils/labels';
import { generatePageQR, promptUnsaved, sharePage } from '@/utils/utils';
import { useDownloadRSForm } from '../../backend/use-download-rsform';
import { useMutatingRSForm } from '../../backend/use-mutating-rsform';
+import { generatePrompt } from '../../models/rslang-api';
import { useRSEdit } from './rsedit-context';
@@ -107,6 +110,16 @@ export function MenuMain() {
sharePage();
}
+ function handleCopyPrompt() {
+ menu.hide();
+
+ const prompt = generatePrompt(schema);
+ navigator.clipboard
+ .writeText(prompt)
+ .then(() => toast.success(infoMsg.promptReady))
+ .catch(console.error);
+ }
+
function handleShowQR() {
menu.hide();
showQR({ target: generatePageQR() });
@@ -139,6 +152,12 @@ export function MenuMain() {
icon={}
onClick={handleShowQR}
/>
+ }
+ onClick={handleCopyPrompt}
+ />
{!isAnonymous ? (
`Копия создана: ${alias}`,