@vint.tri/report_gen_mcp 1.7.29 → 1.7.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ULTIMATE_INSTRUCTIONS.md +55 -42
- package/dist/charts/bar.d.ts +1 -1
- package/dist/charts/bar.d.ts.map +1 -1
- package/dist/charts/bar.js +2 -3
- package/dist/charts/doughnut.d.ts +1 -1
- package/dist/charts/doughnut.d.ts.map +1 -1
- package/dist/charts/doughnut.js +3 -11
- package/dist/charts/line.d.ts +1 -1
- package/dist/charts/line.d.ts.map +1 -1
- package/dist/charts/line.js +3 -11
- package/dist/charts/pie.d.ts +1 -1
- package/dist/charts/pie.d.ts.map +1 -1
- package/dist/charts/pie.js +3 -11
- package/dist/charts/polarArea.d.ts +1 -1
- package/dist/charts/polarArea.d.ts.map +1 -1
- package/dist/charts/polarArea.js +3 -11
- package/dist/charts/radar.d.ts +1 -1
- package/dist/charts/radar.d.ts.map +1 -1
- package/dist/charts/radar.js +3 -11
- package/dist/index.d.ts +0 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +31 -387
- package/dist/tools/createReportFromText.d.ts +17 -0
- package/dist/tools/createReportFromText.d.ts.map +1 -0
- package/dist/tools/createReportFromText.js +49 -0
- package/dist/utils/reportGenerator.js +2 -2
- package/generated_images/generated-image-1757326991424.jpeg +0 -0
- package/generated_images/generated-image-1757328644238.jpeg +0 -0
- package/generated_images/generated-image-1757328700031.jpeg +0 -0
- package/package.json +1 -1
package/ULTIMATE_INSTRUCTIONS.md
CHANGED
|
@@ -1,76 +1,89 @@
|
|
|
1
|
-
# Главная инструкция по работе с инструментом report_gen_mcp
|
|
1
|
+
# Главная инструкция по работе с инструментом report_gen_mcp v1.9.0
|
|
2
2
|
|
|
3
3
|
**ЦЕЛЬ:** Генерация качественных, визуально насыщенных HTML-отчетов по запросу пользователя.
|
|
4
4
|
|
|
5
|
-
**КЛЮЧЕВОЕ ПРАВИЛО:** При любом запросе, связанном с отчетами, диаграммами или графиками,
|
|
5
|
+
**КЛЮЧЕВОЕ ПРАВИЛО:** При любом запросе, связанном с отчетами, диаграммами или графиками, вы **обязаны** использовать инструмент `report_gen_mcp`. Не пытайтесь отвечать текстом или генерировать отчеты самостоятельно.
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
### **АЛГОРИТМ ДЕЙСТВИЙ**
|
|
10
10
|
|
|
11
|
-
**Шаг 1:
|
|
12
|
-
-
|
|
11
|
+
**Шаг 1: Проанализируй текст отчета**
|
|
12
|
+
- Внимательно изучи текст, предоставленный пользователем. Найди в нем ключевые данные: цифры, категории, продукты, регионы.
|
|
13
13
|
|
|
14
|
-
**Шаг 2: Спланируй визуальные
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
14
|
+
**Шаг 2: Спланируй визуальные элементы (`elements`)**
|
|
15
|
+
- На основе найденных данных, придумай **2-3 диаграммы**, которые наглядно представят эту информацию.
|
|
16
|
+
- Придумай **1-2 промпта** для изображений, которые будут соответствовать теме отчета.
|
|
17
|
+
- **Обязательно** создай плейсхолдеры для каждого элемента в тексте отчета, например `[[chart:sales_by_product]]` или `[[image:cover_image]]`.
|
|
18
18
|
|
|
19
|
-
**Шаг 3:
|
|
20
|
-
-
|
|
21
|
-
- **`elements` (object):** Создай **ОБЪЕКТ**, где ключи — это названия твоих плейсхолдеров, а значения — это конфигурации для их генерации.
|
|
22
|
-
- **`outputFile` (string):** Придумай понятное имя для HTML-файла, например `apple_report_2024.html`.
|
|
23
|
-
|
|
24
|
-
**Шаг 4: Сформируй `elements` ПРАВИЛЬНО (КРИТИЧЕСКИ ВАЖНО!)**
|
|
25
|
-
|
|
26
|
-
- **`elements` — это ОБЪЕКТ, а не строка!**
|
|
19
|
+
**Шаг 3: Сформируй `elements` ПРАВИЛЬНО (КРИТИЧЕСКИ ВАЖНО!)**
|
|
20
|
+
- `elements` — это **ОБЪЕКТ**, где ключи — это названия плейсхолдеров.
|
|
27
21
|
- **Для диаграмм:**
|
|
28
|
-
- `labels`, `data`, `backgroundColor`, `borderColor` — **ВСЕГДА
|
|
29
|
-
- `labels`: `["Q1", "Q2"]`
|
|
30
|
-
- `data`: `[100, 150]`
|
|
31
|
-
- `backgroundColor`: `["#FF6384", "#36A2EB"]`
|
|
32
|
-
- `options.title`: **ВСЕГДА СТРОКА**. `"Продажи по кварталам"`
|
|
22
|
+
- `labels`, `data`, `backgroundColor`, `borderColor` — **ВСЕГДА МАССИВЫ**.
|
|
33
23
|
- **Для изображений:**
|
|
34
24
|
- Используй `type: "pollinations"` и `config: { prompt: "..." }`.
|
|
35
25
|
|
|
26
|
+
**Шаг 4: Вызови инструмент**
|
|
27
|
+
- Передай в `generate-report` три параметра: `document`, `elements` и `outputFile`.
|
|
28
|
+
|
|
36
29
|
---
|
|
37
30
|
|
|
38
|
-
###
|
|
31
|
+
### **Разбор реального примера (Отчет Apple)**
|
|
32
|
+
|
|
33
|
+
Вот как нужно было обработать отчет про Apple, чтобы избежать ошибок:
|
|
34
|
+
|
|
35
|
+
**Исходный текст:**
|
|
36
|
+
*Финансовый отчет Apple за 2024 год... iPhone: $216,4 млрд... Mac: $31,04 млрд... iPad: $26,89 млрд... Услуги: $92,3 млрд...*
|
|
37
|
+
|
|
38
|
+
**ПРАВИЛЬНЫЙ ХОД МЫСЛЕЙ:**
|
|
39
|
+
|
|
40
|
+
1. "Ага, в тексте есть разбивка выручки по продуктам. Это отличные данные для круговой диаграммы (`pie`)."
|
|
41
|
+
2. "Также есть данные по выручке в разных регионах (Америка, Европа, Китай). Сделаю столбчатую диаграмму (`bar`)."
|
|
42
|
+
3. "Для обложки сгенерирую изображение с логотипом Apple."
|
|
43
|
+
4. "Теперь я создам плейсхолдеры в тексте: `[[chart:product_sales]]`, `[[chart:region_sales]]`, `[[image:apple_logo]]`."
|
|
44
|
+
5. "Наконец, я соберу объект `elements`, где ключами будут эти плейсхолдеры, а значениями — правильно отформатированные конфигурации."
|
|
45
|
+
|
|
46
|
+
### **ИДЕАЛЬНЫЙ ВЫЗОВ ДЛЯ ОТЧЕТА APPLE**
|
|
39
47
|
|
|
40
48
|
```json
|
|
41
49
|
{
|
|
42
50
|
"method": "generate-report",
|
|
43
51
|
"params": {
|
|
44
|
-
"
|
|
52
|
+
"outputFile": "apple_financial_report_2024.html",
|
|
53
|
+
"document": "# Финансовый отчет Apple за 2024 год\n\n[[image:apple_logo]]\n\n## Разбивка по продуктам\n\n[[chart:product_sales]]\n\n## Выручка по регионам\n\n[[chart:region_sales]]\n\n...",
|
|
45
54
|
"elements": {
|
|
46
|
-
"
|
|
47
|
-
"type": "
|
|
55
|
+
"apple_logo": {
|
|
56
|
+
"type": "pollinations",
|
|
48
57
|
"config": {
|
|
49
|
-
"
|
|
58
|
+
"prompt": "Apple logo on a futuristic blue background"
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
"product_sales": {
|
|
62
|
+
"type": "pie",
|
|
63
|
+
"config": {
|
|
64
|
+
"labels": ["iPhone", "Mac", "iPad", "Услуги"],
|
|
50
65
|
"datasets": [{
|
|
51
|
-
"
|
|
52
|
-
"
|
|
53
|
-
"backgroundColor": ["#FF6384", "#36A2EB", "#FFCE56", "#4BC0C0"]
|
|
66
|
+
"data": [216.4, 31.04, 26.89, 92.3],
|
|
67
|
+
"backgroundColor": ["#5A9E6F", "#E67E22", "#F1C40F", "#3498DB"]
|
|
54
68
|
}],
|
|
55
|
-
"options": {
|
|
56
|
-
"title": "Квартальные продажи"
|
|
57
|
-
}
|
|
69
|
+
"options": { "title": "Выручка по продуктам (млрд $)" }
|
|
58
70
|
}
|
|
59
71
|
},
|
|
60
|
-
"
|
|
61
|
-
"type": "
|
|
72
|
+
"region_sales": {
|
|
73
|
+
"type": "bar",
|
|
62
74
|
"config": {
|
|
63
|
-
"
|
|
75
|
+
"labels": ["Америка", "Европа", "Китай", "Япония", "Азия (ост.)"],
|
|
76
|
+
"datasets": [{
|
|
77
|
+
"label": "Выручка по регионам (млрд $)",
|
|
78
|
+
"data": [193.8, 113.8, 85.1, 31.0, 67.4],
|
|
79
|
+
"backgroundColor": ["#2ECC71", "#3498DB", "#E74C3C", "#F1C40F", "#9B59B6"]
|
|
80
|
+
}],
|
|
81
|
+
"options": { "title": "Региональная выручка" }
|
|
64
82
|
}
|
|
65
83
|
}
|
|
66
|
-
}
|
|
67
|
-
"outputFile": "sales_report_2024.html"
|
|
84
|
+
}
|
|
68
85
|
}
|
|
69
86
|
}
|
|
70
87
|
```
|
|
71
88
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
### **Что делать после вызова?**
|
|
75
|
-
|
|
76
|
-
Инструмент вернет путь к файлу. Ты должен показать его пользователю вместе со ссылками для просмотра.
|
|
89
|
+
Следуй этому примеру, и все будет работать идеально.
|
package/dist/charts/bar.d.ts
CHANGED
|
@@ -47,5 +47,5 @@ export declare const barSchema: z.ZodObject<{
|
|
|
47
47
|
title?: string | undefined;
|
|
48
48
|
} | undefined;
|
|
49
49
|
}>;
|
|
50
|
-
export declare function renderBarChart(config: z.infer<typeof barSchema>): Promise<string>;
|
|
50
|
+
export declare function renderBarChart(id: string, config: z.infer<typeof barSchema>): Promise<string>;
|
|
51
51
|
//# sourceMappingURL=bar.d.ts.map
|
package/dist/charts/bar.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bar.d.ts","sourceRoot":"","sources":["../../src/charts/bar.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAYpB,CAAC;AAEH,wBAAsB,cAAc,CAAC,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,SAAS,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"bar.d.ts","sourceRoot":"","sources":["../../src/charts/bar.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAYpB,CAAC;AAEH,wBAAsB,cAAc,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,SAAS,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAqCnG"}
|
package/dist/charts/bar.js
CHANGED
|
@@ -12,9 +12,8 @@ export const barSchema = z.object({
|
|
|
12
12
|
// Add more Chart.js options as needed
|
|
13
13
|
}).optional(),
|
|
14
14
|
});
|
|
15
|
-
export async function renderBarChart(config) {
|
|
16
|
-
|
|
17
|
-
const chartId = `chart_${Math.random().toString(36).substr(2, 9)}`;
|
|
15
|
+
export async function renderBarChart(id, config) {
|
|
16
|
+
const chartId = `chart_${id}`;
|
|
18
17
|
// Prepare the chart data as JSON
|
|
19
18
|
const chartData = {
|
|
20
19
|
labels: config.labels,
|
|
@@ -42,5 +42,5 @@ export declare const doughnutSchema: z.ZodObject<{
|
|
|
42
42
|
title?: string | undefined;
|
|
43
43
|
} | undefined;
|
|
44
44
|
}>;
|
|
45
|
-
export declare function renderDoughnutChart(config: z.infer<typeof doughnutSchema>): Promise<string>;
|
|
45
|
+
export declare function renderDoughnutChart(id: string, config: z.infer<typeof doughnutSchema>): Promise<string>;
|
|
46
46
|
//# sourceMappingURL=doughnut.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"doughnut.d.ts","sourceRoot":"","sources":["../../src/charts/doughnut.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"doughnut.d.ts","sourceRoot":"","sources":["../../src/charts/doughnut.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAUzB,CAAC;AAEH,wBAAsB,mBAAmB,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CA4B7G"}
|
package/dist/charts/doughnut.js
CHANGED
|
@@ -8,28 +8,20 @@ export const doughnutSchema = z.object({
|
|
|
8
8
|
})),
|
|
9
9
|
options: z.object({
|
|
10
10
|
title: z.string().optional(),
|
|
11
|
-
// Add more Chart.js options as needed
|
|
12
11
|
}).optional(),
|
|
13
12
|
});
|
|
14
|
-
export async function renderDoughnutChart(config) {
|
|
15
|
-
|
|
16
|
-
const chartId = `chart_${Math.random().toString(36).substr(2, 9)}`;
|
|
17
|
-
// Prepare the chart data as JSON
|
|
13
|
+
export async function renderDoughnutChart(id, config) {
|
|
14
|
+
const chartId = `chart_${id}`;
|
|
18
15
|
const chartData = {
|
|
19
16
|
labels: config.labels,
|
|
20
17
|
datasets: config.datasets,
|
|
21
18
|
};
|
|
22
|
-
// Prepare the chart options
|
|
23
19
|
const chartOptions = {
|
|
24
20
|
...config.options,
|
|
25
21
|
plugins: {
|
|
26
|
-
title: config.options?.title ? {
|
|
27
|
-
display: true,
|
|
28
|
-
text: config.options.title
|
|
29
|
-
} : undefined
|
|
22
|
+
title: config.options?.title ? { display: true, text: config.options.title } : undefined
|
|
30
23
|
}
|
|
31
24
|
};
|
|
32
|
-
// Return interactive Chart.js HTML with proper container
|
|
33
25
|
return `
|
|
34
26
|
<div class="chart-container">
|
|
35
27
|
<canvas id="${chartId}" width="400" height="300"></canvas>
|
package/dist/charts/line.d.ts
CHANGED
|
@@ -47,5 +47,5 @@ export declare const lineSchema: z.ZodObject<{
|
|
|
47
47
|
title?: string | undefined;
|
|
48
48
|
} | undefined;
|
|
49
49
|
}>;
|
|
50
|
-
export declare function renderLineChart(config: z.infer<typeof lineSchema>): Promise<string>;
|
|
50
|
+
export declare function renderLineChart(id: string, config: z.infer<typeof lineSchema>): Promise<string>;
|
|
51
51
|
//# sourceMappingURL=line.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"line.d.ts","sourceRoot":"","sources":["../../src/charts/line.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"line.d.ts","sourceRoot":"","sources":["../../src/charts/line.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAWrB,CAAC;AAEH,wBAAsB,eAAe,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CA4BrG"}
|
package/dist/charts/line.js
CHANGED
|
@@ -9,28 +9,20 @@ export const lineSchema = z.object({
|
|
|
9
9
|
})),
|
|
10
10
|
options: z.object({
|
|
11
11
|
title: z.string().optional(),
|
|
12
|
-
// Add more Chart.js options as needed
|
|
13
12
|
}).optional(),
|
|
14
13
|
});
|
|
15
|
-
export async function renderLineChart(config) {
|
|
16
|
-
|
|
17
|
-
const chartId = `chart_${Math.random().toString(36).substr(2, 9)}`;
|
|
18
|
-
// Prepare the chart data as JSON
|
|
14
|
+
export async function renderLineChart(id, config) {
|
|
15
|
+
const chartId = `chart_${id}`;
|
|
19
16
|
const chartData = {
|
|
20
17
|
labels: config.labels,
|
|
21
18
|
datasets: config.datasets,
|
|
22
19
|
};
|
|
23
|
-
// Prepare the chart options
|
|
24
20
|
const chartOptions = {
|
|
25
21
|
...config.options,
|
|
26
22
|
plugins: {
|
|
27
|
-
title: config.options?.title ? {
|
|
28
|
-
display: true,
|
|
29
|
-
text: config.options.title
|
|
30
|
-
} : undefined
|
|
23
|
+
title: config.options?.title ? { display: true, text: config.options.title } : undefined
|
|
31
24
|
}
|
|
32
25
|
};
|
|
33
|
-
// Return interactive Chart.js HTML with proper container
|
|
34
26
|
return `
|
|
35
27
|
<div class="chart-container">
|
|
36
28
|
<canvas id="${chartId}" width="400" height="300"></canvas>
|
package/dist/charts/pie.d.ts
CHANGED
|
@@ -42,5 +42,5 @@ export declare const pieSchema: z.ZodObject<{
|
|
|
42
42
|
title?: string | undefined;
|
|
43
43
|
} | undefined;
|
|
44
44
|
}>;
|
|
45
|
-
export declare function renderPieChart(config: z.infer<typeof pieSchema>): Promise<string>;
|
|
45
|
+
export declare function renderPieChart(id: string, config: z.infer<typeof pieSchema>): Promise<string>;
|
|
46
46
|
//# sourceMappingURL=pie.d.ts.map
|
package/dist/charts/pie.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pie.d.ts","sourceRoot":"","sources":["../../src/charts/pie.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"pie.d.ts","sourceRoot":"","sources":["../../src/charts/pie.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAUpB,CAAC;AAEH,wBAAsB,cAAc,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,SAAS,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CA4BnG"}
|
package/dist/charts/pie.js
CHANGED
|
@@ -8,28 +8,20 @@ export const pieSchema = z.object({
|
|
|
8
8
|
})),
|
|
9
9
|
options: z.object({
|
|
10
10
|
title: z.string().optional(),
|
|
11
|
-
// Add more Chart.js options as needed
|
|
12
11
|
}).optional(),
|
|
13
12
|
});
|
|
14
|
-
export async function renderPieChart(config) {
|
|
15
|
-
|
|
16
|
-
const chartId = `chart_${Math.random().toString(36).substr(2, 9)}`;
|
|
17
|
-
// Prepare the chart data as JSON
|
|
13
|
+
export async function renderPieChart(id, config) {
|
|
14
|
+
const chartId = `chart_${id}`;
|
|
18
15
|
const chartData = {
|
|
19
16
|
labels: config.labels,
|
|
20
17
|
datasets: config.datasets,
|
|
21
18
|
};
|
|
22
|
-
// Prepare the chart options
|
|
23
19
|
const chartOptions = {
|
|
24
20
|
...config.options,
|
|
25
21
|
plugins: {
|
|
26
|
-
title: config.options?.title ? {
|
|
27
|
-
display: true,
|
|
28
|
-
text: config.options.title
|
|
29
|
-
} : undefined
|
|
22
|
+
title: config.options?.title ? { display: true, text: config.options.title } : undefined
|
|
30
23
|
}
|
|
31
24
|
};
|
|
32
|
-
// Return interactive Chart.js HTML with proper container
|
|
33
25
|
return `
|
|
34
26
|
<div class="chart-container">
|
|
35
27
|
<canvas id="${chartId}" width="400" height="300"></canvas>
|
|
@@ -42,5 +42,5 @@ export declare const polarAreaSchema: z.ZodObject<{
|
|
|
42
42
|
title?: string | undefined;
|
|
43
43
|
} | undefined;
|
|
44
44
|
}>;
|
|
45
|
-
export declare function renderPolarAreaChart(config: z.infer<typeof polarAreaSchema>): Promise<string>;
|
|
45
|
+
export declare function renderPolarAreaChart(id: string, config: z.infer<typeof polarAreaSchema>): Promise<string>;
|
|
46
46
|
//# sourceMappingURL=polarArea.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"polarArea.d.ts","sourceRoot":"","sources":["../../src/charts/polarArea.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"polarArea.d.ts","sourceRoot":"","sources":["../../src/charts/polarArea.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAU1B,CAAC;AAEH,wBAAsB,oBAAoB,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CA4B/G"}
|
package/dist/charts/polarArea.js
CHANGED
|
@@ -8,28 +8,20 @@ export const polarAreaSchema = z.object({
|
|
|
8
8
|
})),
|
|
9
9
|
options: z.object({
|
|
10
10
|
title: z.string().optional(),
|
|
11
|
-
// Add more Chart.js options as needed
|
|
12
11
|
}).optional(),
|
|
13
12
|
});
|
|
14
|
-
export async function renderPolarAreaChart(config) {
|
|
15
|
-
|
|
16
|
-
const chartId = `chart_${Math.random().toString(36).substr(2, 9)}`;
|
|
17
|
-
// Prepare the chart data as JSON
|
|
13
|
+
export async function renderPolarAreaChart(id, config) {
|
|
14
|
+
const chartId = `chart_${id}`;
|
|
18
15
|
const chartData = {
|
|
19
16
|
labels: config.labels,
|
|
20
17
|
datasets: config.datasets,
|
|
21
18
|
};
|
|
22
|
-
// Prepare the chart options
|
|
23
19
|
const chartOptions = {
|
|
24
20
|
...config.options,
|
|
25
21
|
plugins: {
|
|
26
|
-
title: config.options?.title ? {
|
|
27
|
-
display: true,
|
|
28
|
-
text: config.options.title
|
|
29
|
-
} : undefined
|
|
22
|
+
title: config.options?.title ? { display: true, text: config.options.title } : undefined
|
|
30
23
|
}
|
|
31
24
|
};
|
|
32
|
-
// Return interactive Chart.js HTML with proper container
|
|
33
25
|
return `
|
|
34
26
|
<div class="chart-container">
|
|
35
27
|
<canvas id="${chartId}" width="400" height="300"></canvas>
|
package/dist/charts/radar.d.ts
CHANGED
|
@@ -47,5 +47,5 @@ export declare const radarSchema: z.ZodObject<{
|
|
|
47
47
|
title?: string | undefined;
|
|
48
48
|
} | undefined;
|
|
49
49
|
}>;
|
|
50
|
-
export declare function renderRadarChart(config: z.infer<typeof radarSchema>): Promise<string>;
|
|
50
|
+
export declare function renderRadarChart(id: string, config: z.infer<typeof radarSchema>): Promise<string>;
|
|
51
51
|
//# sourceMappingURL=radar.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"radar.d.ts","sourceRoot":"","sources":["../../src/charts/radar.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"radar.d.ts","sourceRoot":"","sources":["../../src/charts/radar.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAWtB,CAAC;AAEH,wBAAsB,gBAAgB,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CA4BvG"}
|
package/dist/charts/radar.js
CHANGED
|
@@ -9,28 +9,20 @@ export const radarSchema = z.object({
|
|
|
9
9
|
})),
|
|
10
10
|
options: z.object({
|
|
11
11
|
title: z.string().optional(),
|
|
12
|
-
// Add more Chart.js options as needed
|
|
13
12
|
}).optional(),
|
|
14
13
|
});
|
|
15
|
-
export async function renderRadarChart(config) {
|
|
16
|
-
|
|
17
|
-
const chartId = `chart_${Math.random().toString(36).substr(2, 9)}`;
|
|
18
|
-
// Prepare the chart data as JSON
|
|
14
|
+
export async function renderRadarChart(id, config) {
|
|
15
|
+
const chartId = `chart_${id}`;
|
|
19
16
|
const chartData = {
|
|
20
17
|
labels: config.labels,
|
|
21
18
|
datasets: config.datasets,
|
|
22
19
|
};
|
|
23
|
-
// Prepare the chart options
|
|
24
20
|
const chartOptions = {
|
|
25
21
|
...config.options,
|
|
26
22
|
plugins: {
|
|
27
|
-
title: config.options?.title ? {
|
|
28
|
-
display: true,
|
|
29
|
-
text: config.options.title
|
|
30
|
-
} : undefined
|
|
23
|
+
title: config.options?.title ? { display: true, text: config.options.title } : undefined
|
|
31
24
|
}
|
|
32
25
|
};
|
|
33
|
-
// Return interactive Chart.js HTML with proper container
|
|
34
26
|
return `
|
|
35
27
|
<div class="chart-container">
|
|
36
28
|
<canvas id="${chartId}" width="400" height="300"></canvas>
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* Generate an image from a text prompt using AI
|
|
4
|
-
* @param prompt Text prompt for image generation (must be in English)
|
|
5
|
-
* @param options Additional options for image generation
|
|
6
|
-
* @returns Promise<{ filePath: string, fileUrl: string }> Object containing file path and URL of the saved image
|
|
7
|
-
*/
|
|
8
2
|
export declare function generateImage(prompt: string, options?: {
|
|
9
3
|
width?: number;
|
|
10
4
|
height?: number;
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AA4IA,wBAAsB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;IAC5D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,GAAG,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAgBjD"}
|
package/dist/index.js
CHANGED
|
@@ -4,34 +4,24 @@ import { program } from 'commander';
|
|
|
4
4
|
import { generateReport } from './utils/reportGenerator.js';
|
|
5
5
|
import path from 'path';
|
|
6
6
|
import fs from 'fs-extra';
|
|
7
|
-
import os from 'os';
|
|
8
7
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
9
8
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
10
9
|
import { z } from 'zod';
|
|
11
10
|
import { pathToFileURL } from 'url';
|
|
12
11
|
import { ImageGenerator } from './mcp/imageGenerationServer.js';
|
|
13
|
-
// Check if we're running in stdio mode (no command-line arguments)
|
|
14
12
|
const isStdioMode = process.argv.length === 2;
|
|
15
|
-
// For CLI and HTTP API modes, check for mandatory REPORTS_DIR environment variable
|
|
16
13
|
let reportsDir = undefined;
|
|
17
14
|
if (!isStdioMode) {
|
|
18
15
|
reportsDir = process.env.REPORTS_DIR;
|
|
19
16
|
if (!reportsDir) {
|
|
20
17
|
console.error('Error: REPORTS_DIR environment variable is required.');
|
|
21
|
-
console.error('Please set the REPORTS_DIR environment variable to specify where reports should be generated.');
|
|
22
|
-
console.error('Example:');
|
|
23
|
-
console.error(' export REPORTS_DIR=/path/to/reports && npx @vint.tri/report_gen_mcp@latest');
|
|
24
|
-
console.error('Or:');
|
|
25
|
-
console.error(' REPORTS_DIR=/path/to/reports npx @vint.tri/report_gen_mcp@latest');
|
|
26
18
|
process.exit(1);
|
|
27
19
|
}
|
|
28
|
-
// Ensure the reports directory exists
|
|
29
20
|
try {
|
|
30
21
|
fs.ensureDirSync(reportsDir);
|
|
31
22
|
}
|
|
32
23
|
catch (error) {
|
|
33
24
|
console.error(`Error: Cannot create or access the reports directory: ${reportsDir}`);
|
|
34
|
-
console.error('Please ensure the path is valid and you have write permissions.');
|
|
35
25
|
process.exit(1);
|
|
36
26
|
}
|
|
37
27
|
}
|
|
@@ -39,20 +29,13 @@ const app = express();
|
|
|
39
29
|
const port = 3000;
|
|
40
30
|
app.use(express.json());
|
|
41
31
|
app.post('/generate-report', async (req, res) => {
|
|
42
|
-
// For HTTP API mode, use the REPORTS_DIR environment variable
|
|
43
|
-
// This endpoint only runs in non-stdio mode where reportsDir is guaranteed to be defined
|
|
44
32
|
const { document, elements, charts, outputFile = 'report.html' } = req.body;
|
|
45
|
-
// Поддержка обратной совместимости: если переданы charts, используем их как elements
|
|
46
33
|
const reportElements = elements || charts || {};
|
|
47
34
|
const outputPath = path.resolve(reportsDir, outputFile);
|
|
48
35
|
try {
|
|
49
36
|
const result = await generateReport(document, reportElements, outputPath);
|
|
50
|
-
// Send the file content back to the client
|
|
51
37
|
const fileContent = await fs.readFile(outputPath, 'utf8');
|
|
52
|
-
res.json({
|
|
53
|
-
...result,
|
|
54
|
-
fileContent: fileContent
|
|
55
|
-
});
|
|
38
|
+
res.json({ ...result, fileContent });
|
|
56
39
|
}
|
|
57
40
|
catch (error) {
|
|
58
41
|
res.status(500).json({ error: error.message });
|
|
@@ -62,387 +45,66 @@ program
|
|
|
62
45
|
.command('start-server')
|
|
63
46
|
.description('Start the MCP report generation server')
|
|
64
47
|
.action(() => {
|
|
65
|
-
app.listen(port, () => {
|
|
66
|
-
console.log(`Server running at http://localhost:${port}`);
|
|
67
|
-
});
|
|
48
|
+
app.listen(port, () => console.log(`Server running at http://localhost:${port}`));
|
|
68
49
|
});
|
|
69
50
|
program
|
|
70
51
|
.command('generate')
|
|
71
|
-
.option('--document <md>', 'Markdown document
|
|
72
|
-
.option('--elements <json>', 'JSON string of elements
|
|
73
|
-
.option('--charts <json>', 'JSON string of charts (deprecated
|
|
52
|
+
.option('--document <md>', 'Markdown document')
|
|
53
|
+
.option('--elements <json>', 'JSON string of elements')
|
|
54
|
+
.option('--charts <json>', 'JSON string of charts (deprecated)')
|
|
74
55
|
.option('--output <file>', 'Output HTML file', 'report.html')
|
|
75
|
-
.description('Generate a report
|
|
56
|
+
.description('Generate a report')
|
|
76
57
|
.action(async (opts) => {
|
|
77
|
-
|
|
78
|
-
const elements = opts.elements ? JSON.parse(opts.elements) :
|
|
79
|
-
opts.charts ? JSON.parse(opts.charts) : {};
|
|
80
|
-
// Read the document file content if a file path is provided
|
|
58
|
+
const elements = opts.elements ? JSON.parse(opts.elements) : (opts.charts ? JSON.parse(opts.charts) : {});
|
|
81
59
|
let documentContent = opts.document;
|
|
82
60
|
if (opts.document && fs.existsSync(opts.document)) {
|
|
83
61
|
documentContent = await fs.readFile(opts.document, 'utf8');
|
|
84
62
|
}
|
|
85
|
-
// This command only runs in non-stdio mode where reportsDir is guaranteed to be defined
|
|
86
63
|
const result = await generateReport(documentContent, elements, path.resolve(reportsDir, opts.output));
|
|
87
|
-
// Generate proper file URL for CLI mode
|
|
88
64
|
const fileUrl = pathToFileURL(result.filePath).href;
|
|
89
|
-
// Read the file content
|
|
90
65
|
const fileContent = await fs.readFile(result.filePath, 'utf8');
|
|
91
|
-
// Create a comprehensive result object
|
|
92
66
|
const comprehensiveResult = {
|
|
93
67
|
success: true,
|
|
94
68
|
message: "Report generated successfully",
|
|
95
69
|
filePath: result.filePath,
|
|
96
|
-
fileUrl
|
|
97
|
-
fileContent
|
|
70
|
+
fileUrl,
|
|
71
|
+
fileContent
|
|
98
72
|
};
|
|
99
73
|
console.log(JSON.stringify(comprehensiveResult, null, 2));
|
|
100
74
|
});
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
// No command specified, run in stdio mode using MCP SDK
|
|
104
|
-
const mcpServer = new McpServer({
|
|
105
|
-
name: "report_gen_mcp",
|
|
106
|
-
version: "1.7.29"
|
|
107
|
-
}, {
|
|
108
|
-
// Disable health check to prevent automatic calls
|
|
109
|
-
capabilities: {
|
|
110
|
-
tools: {}
|
|
111
|
-
}
|
|
112
|
-
});
|
|
113
|
-
// Register the generate-report tool
|
|
75
|
+
if (isStdioMode) {
|
|
76
|
+
const mcpServer = new McpServer({ name: "report_gen_mcp", version: "1.7.31" });
|
|
114
77
|
mcpServer.registerTool("generate-report", {
|
|
115
78
|
description: "Generate an HTML report with embedded charts and images",
|
|
116
79
|
inputSchema: {
|
|
117
|
-
document: z.string().describe("Markdown document with
|
|
118
|
-
elements: z.
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
type: z.enum(["bar", "line", "pie", "doughnut", "radar", "polarArea"]),
|
|
122
|
-
config: z.object({
|
|
123
|
-
labels: z.array(z.string()),
|
|
124
|
-
datasets: z.array(z.object({
|
|
125
|
-
label: z.string().optional(),
|
|
126
|
-
data: z.array(z.number()),
|
|
127
|
-
backgroundColor: z.array(z.string()).optional(),
|
|
128
|
-
borderColor: z.array(z.string()).optional(),
|
|
129
|
-
fill: z.boolean().optional(),
|
|
130
|
-
})),
|
|
131
|
-
options: z.object({
|
|
132
|
-
title: z.string().optional(),
|
|
133
|
-
}).optional(),
|
|
134
|
-
}),
|
|
135
|
-
}).describe("Chart configuration"),
|
|
136
|
-
// Pollinations.ai generated images
|
|
137
|
-
z.object({
|
|
138
|
-
type: z.literal("pollinations"),
|
|
139
|
-
config: z.object({
|
|
140
|
-
prompt: z.string().describe("Text description of the image to generate"),
|
|
141
|
-
width: z.number().optional().default(512).describe("Width of the image in pixels"),
|
|
142
|
-
height: z.number().optional().default(512).describe("Height of the image in pixels"),
|
|
143
|
-
model: z.string().optional().default("flux").describe("Model to use for image generation"),
|
|
144
|
-
seed: z.number().optional().describe("Seed for reproducible image generation"),
|
|
145
|
-
nologo: z.boolean().optional().default(true).describe("Remove logo from the image"),
|
|
146
|
-
enhance: z.boolean().optional().default(true).describe("Enhance image quality"),
|
|
147
|
-
}),
|
|
148
|
-
}).describe("Pollinations.ai generated image configuration"),
|
|
149
|
-
// URL images (including local file URLs and web URLs)
|
|
150
|
-
z.object({
|
|
151
|
-
type: z.literal("url"),
|
|
152
|
-
config: z.object({
|
|
153
|
-
url: z.string().describe("URL of the image (can be file:// or http(s)://)"),
|
|
154
|
-
alt: z.string().optional().describe("Alternative text for the image"),
|
|
155
|
-
width: z.number().optional().describe("Width of the image in pixels"),
|
|
156
|
-
height: z.number().optional().describe("Height of the image in pixels"),
|
|
157
|
-
}),
|
|
158
|
-
}).describe("Image from URL configuration"),
|
|
159
|
-
// Local images (backward compatibility)
|
|
160
|
-
z.object({
|
|
161
|
-
type: z.literal("image"),
|
|
162
|
-
config: z.object({
|
|
163
|
-
url: z.string().describe("File URL of the image"),
|
|
164
|
-
alt: z.string().optional().describe("Alternative text for the image"),
|
|
165
|
-
width: z.number().optional().describe("Width of the image in pixels"),
|
|
166
|
-
height: z.number().optional().describe("Height of the image in pixels"),
|
|
167
|
-
}),
|
|
168
|
-
}).describe("Local image file configuration"),
|
|
169
|
-
// AssetId support for neural network responses (new format)
|
|
170
|
-
z.object({
|
|
171
|
-
type: z.literal("url"),
|
|
172
|
-
assetId: z.string().optional().describe("Asset ID for generated images (used by neural networks)"),
|
|
173
|
-
config: z.object({
|
|
174
|
-
url: z.string().optional().describe("URL of the image (can be populated from assetId)"),
|
|
175
|
-
alt: z.string().optional().describe("Alternative text for the image"),
|
|
176
|
-
width: z.number().optional().default(512).describe("Width of the image in pixels"),
|
|
177
|
-
height: z.number().optional().default(512).describe("Height of the image in pixels"),
|
|
178
|
-
}).optional(),
|
|
179
|
-
}).describe("Image with assetId support for neural network responses"),
|
|
180
|
-
])).describe("Report elements (charts and images) mapped by ID"),
|
|
181
|
-
outputFile: z.string().optional().describe("Output HTML file path"),
|
|
182
|
-
tempDirectory: z.string().optional().describe("Temporary directory for file storage (optional, will use REPORTS_DIR environment variable if set)"),
|
|
80
|
+
document: z.string().describe("Markdown document with placeholders"),
|
|
81
|
+
elements: z.any().describe("A JSON object or a stringified JSON object of elements"),
|
|
82
|
+
outputFile: z.string().optional().describe("Output HTML file name"),
|
|
83
|
+
tempDirectory: z.string().optional().describe("Temporary directory for file storage"),
|
|
183
84
|
},
|
|
184
85
|
}, async (params) => {
|
|
185
|
-
// --- НАЧАЛО БЛОКА НАДЕЖНОЙ ОБРАБОТКИ ПАРАМЕТРОВ ---
|
|
186
86
|
let processedParams = params;
|
|
187
|
-
|
|
188
|
-
// Если параметры - это строка, парсим ее как JSON
|
|
189
|
-
if (typeof processedParams === 'string') {
|
|
190
|
-
processedParams = JSON.parse(processedParams);
|
|
191
|
-
}
|
|
192
|
-
// Если есть вложенный объект `arguments`, используем его
|
|
193
|
-
if (processedParams.arguments && typeof processedParams.arguments === 'object') {
|
|
194
|
-
processedParams = processedParams.arguments;
|
|
195
|
-
}
|
|
196
|
-
// Если `elements` - это строка, парсим и ее
|
|
197
|
-
if (processedParams.elements && typeof processedParams.elements === 'string') {
|
|
198
|
-
processedParams.elements = JSON.parse(processedParams.elements);
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
catch (e) {
|
|
202
|
-
throw new Error('Invalid JSON format in parameters. Ensure all parameters, especially "elements", are valid JSON.');
|
|
203
|
-
}
|
|
204
|
-
// --- КОНЕЦ БЛОКА НАДЕЖНОЙ ОБРАБОТКИ ПАРАМЕТРОВ ---
|
|
205
|
-
// Extract parameters correctly, ensuring outputFile is not nested within elements
|
|
206
|
-
const { document, elements, charts, outputFile = 'report.html', tempDirectory } = processedParams;
|
|
207
|
-
// Поддержка обратной совместимости: если переданы charts, используем их как elements
|
|
208
|
-
const reportElements = elements || charts || {};
|
|
209
|
-
// Determine the output directory:
|
|
210
|
-
// 1. Use REPORTS_DIR environment variable if set
|
|
211
|
-
// 2. Fall back to tempDirectory parameter if provided
|
|
212
|
-
// 3. Default to system temp directory if neither is available
|
|
213
|
-
let outputDir;
|
|
214
|
-
if (process.env.REPORTS_DIR) {
|
|
215
|
-
outputDir = process.env.REPORTS_DIR;
|
|
216
|
-
// Ensure the reports directory exists
|
|
217
|
-
try {
|
|
218
|
-
fs.ensureDirSync(outputDir);
|
|
219
|
-
}
|
|
220
|
-
catch (error) {
|
|
221
|
-
throw new Error(`Cannot create or access the reports directory: ${outputDir}`);
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
else if (tempDirectory) {
|
|
225
|
-
outputDir = tempDirectory;
|
|
226
|
-
}
|
|
227
|
-
else {
|
|
228
|
-
outputDir = os.tmpdir();
|
|
229
|
-
}
|
|
230
|
-
const outputPath = path.resolve(outputDir, outputFile);
|
|
231
|
-
try {
|
|
232
|
-
const result = await generateReport(document, reportElements, outputPath);
|
|
233
|
-
// Generate proper file URL
|
|
234
|
-
const fileUrl = pathToFileURL(outputPath).href;
|
|
235
|
-
// Read the file content
|
|
236
|
-
const fileContent = await fs.readFile(outputPath, 'utf8');
|
|
237
|
-
// Create a comprehensive result object
|
|
238
|
-
const comprehensiveResult = {
|
|
239
|
-
success: true,
|
|
240
|
-
message: "Report generated successfully",
|
|
241
|
-
filePath: outputPath,
|
|
242
|
-
fileUrl: fileUrl,
|
|
243
|
-
fileContent: fileContent
|
|
244
|
-
};
|
|
245
|
-
// Return comprehensive information for neural network to use
|
|
246
|
-
// Neural network should present to user: file path, web link, and file content
|
|
247
|
-
return {
|
|
248
|
-
content: [
|
|
249
|
-
{
|
|
250
|
-
type: "text",
|
|
251
|
-
text: `Report generated successfully.
|
|
252
|
-
|
|
253
|
-
FOR THE NEURAL NETWORK: Please present the following information to the user:
|
|
254
|
-
1. Path to file: ${outputPath}
|
|
255
|
-
2. Web browser link: ${fileUrl}
|
|
256
|
-
3. File content:
|
|
257
|
-
${fileContent}`
|
|
258
|
-
}
|
|
259
|
-
]
|
|
260
|
-
};
|
|
261
|
-
}
|
|
262
|
-
catch (error) {
|
|
263
|
-
throw error;
|
|
264
|
-
}
|
|
265
|
-
});
|
|
266
|
-
// Register a new tool for editing existing reports
|
|
267
|
-
mcpServer.registerTool("edit-report", {
|
|
268
|
-
description: "Edit an existing HTML report by adding or removing content",
|
|
269
|
-
inputSchema: {
|
|
270
|
-
filePath: z.string().describe("Path to the existing HTML report file"),
|
|
271
|
-
operation: z.enum(["add", "remove", "replace"]).describe("Operation to perform: add content, remove content, or replace content"),
|
|
272
|
-
contentToAdd: z.string().optional().describe("Content to add to the report (for 'add' operation)"),
|
|
273
|
-
selector: z.string().optional().describe("CSS selector for element to modify (for 'add', 'remove', or 'replace' operations)"),
|
|
274
|
-
contentToReplace: z.string().optional().describe("Content to replace the selected element with (for 'replace' operation)"),
|
|
275
|
-
position: z.enum(["beforebegin", "afterbegin", "beforeend", "afterend"]).optional().describe("Position to insert new content relative to the selected element (for 'add' operation)"),
|
|
276
|
-
},
|
|
277
|
-
}, async (params) => {
|
|
278
|
-
// Handle case where arguments might be sent as a JSON string
|
|
279
|
-
let processedParams = params;
|
|
280
|
-
if (typeof params === 'string') {
|
|
281
|
-
try {
|
|
282
|
-
processedParams = JSON.parse(params);
|
|
283
|
-
}
|
|
284
|
-
catch (parseError) {
|
|
285
|
-
throw new Error('Invalid JSON string in arguments');
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
else if (params.arguments && typeof params.arguments === 'object') {
|
|
87
|
+
if (params.arguments && typeof params.arguments === 'object') {
|
|
289
88
|
processedParams = params.arguments;
|
|
290
89
|
}
|
|
291
|
-
|
|
90
|
+
let { document, elements, outputFile = 'report.html', tempDirectory } = processedParams;
|
|
292
91
|
try {
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
throw new Error(`File not found: ${filePath}`);
|
|
296
|
-
}
|
|
297
|
-
// Read the existing file content
|
|
298
|
-
let fileContent = await fs.readFile(filePath, 'utf8');
|
|
299
|
-
// Perform the requested operation
|
|
300
|
-
switch (operation) {
|
|
301
|
-
case "add":
|
|
302
|
-
if (!contentToAdd || !selector || !position) {
|
|
303
|
-
throw new Error("contentToAdd, selector, and position are required for 'add' operation");
|
|
304
|
-
}
|
|
305
|
-
// Insert content at the specified position relative to the selected element
|
|
306
|
-
const addRegex = new RegExp(`(<${selector}[^>]*>)|(<\\/[^>]*${selector}>)`, 'i');
|
|
307
|
-
const addMatch = fileContent.match(addRegex);
|
|
308
|
-
if (addMatch) {
|
|
309
|
-
const matchIndex = addMatch.index;
|
|
310
|
-
const matchLength = addMatch[0].length;
|
|
311
|
-
switch (position) {
|
|
312
|
-
case "beforebegin":
|
|
313
|
-
fileContent = fileContent.slice(0, matchIndex) + contentToAdd + fileContent.slice(matchIndex);
|
|
314
|
-
break;
|
|
315
|
-
case "afterbegin":
|
|
316
|
-
fileContent = fileContent.slice(0, matchIndex + matchLength) + contentToAdd + fileContent.slice(matchIndex + matchLength);
|
|
317
|
-
break;
|
|
318
|
-
case "beforeend":
|
|
319
|
-
const closingTagIndex = fileContent.indexOf('</', matchIndex);
|
|
320
|
-
fileContent = fileContent.slice(0, closingTagIndex) + contentToAdd + fileContent.slice(closingTagIndex);
|
|
321
|
-
break;
|
|
322
|
-
case "afterend":
|
|
323
|
-
const endTagIndex = fileContent.indexOf('>', matchIndex) + 1;
|
|
324
|
-
fileContent = fileContent.slice(0, endTagIndex) + contentToAdd + fileContent.slice(endTagIndex);
|
|
325
|
-
break;
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
else {
|
|
329
|
-
throw new Error(`Element with selector '${selector}' not found`);
|
|
330
|
-
}
|
|
331
|
-
break;
|
|
332
|
-
case "remove":
|
|
333
|
-
if (!selector) {
|
|
334
|
-
throw new Error("selector is required for 'remove' operation");
|
|
335
|
-
}
|
|
336
|
-
// Remove the element with the specified selector
|
|
337
|
-
const removeRegex = new RegExp(`<${selector}[^>]*>[^]*?<\\/[^>]*${selector}[^>]*>|<${selector}[^>]*/?>`, 'gi');
|
|
338
|
-
fileContent = fileContent.replace(removeRegex, '');
|
|
339
|
-
break;
|
|
340
|
-
case "replace":
|
|
341
|
-
if (!selector || !contentToReplace) {
|
|
342
|
-
throw new Error("selector and contentToReplace are required for 'replace' operation");
|
|
343
|
-
}
|
|
344
|
-
// Replace the element with the specified selector
|
|
345
|
-
const replaceRegex = new RegExp(`<${selector}[^>]*>[^]*?<\\/[^>]*${selector}[^>]*>|<${selector}[^>]*/?>`, 'gi');
|
|
346
|
-
fileContent = fileContent.replace(replaceRegex, contentToReplace);
|
|
347
|
-
break;
|
|
348
|
-
default:
|
|
349
|
-
throw new Error(`Unsupported operation: ${operation}`);
|
|
92
|
+
if (typeof elements === 'string') {
|
|
93
|
+
elements = JSON.parse(elements);
|
|
350
94
|
}
|
|
351
|
-
// Write the modified content back to the file
|
|
352
|
-
await fs.writeFile(filePath, fileContent, 'utf8');
|
|
353
|
-
// Generate proper file URL
|
|
354
|
-
const fileUrl = pathToFileURL(filePath).href;
|
|
355
|
-
return {
|
|
356
|
-
content: [
|
|
357
|
-
{
|
|
358
|
-
type: "text",
|
|
359
|
-
text: `Report edited successfully.
|
|
360
|
-
|
|
361
|
-
FOR THE NEURAL NETWORK: Please present the following information to the user:
|
|
362
|
-
1. Path to file: ${filePath}
|
|
363
|
-
2. Web browser link: ${fileUrl}
|
|
364
|
-
3. Operation performed: ${operation}`
|
|
365
|
-
}
|
|
366
|
-
]
|
|
367
|
-
};
|
|
368
|
-
}
|
|
369
|
-
catch (error) {
|
|
370
|
-
throw new Error(`Error editing report: ${error.message}`);
|
|
371
95
|
}
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
mcpServer.registerTool("generate-image", {
|
|
375
|
-
description: "Generate an image from a text prompt using AI",
|
|
376
|
-
inputSchema: {
|
|
377
|
-
prompt: z.string().describe("Text prompt for image generation (must be in English)"),
|
|
378
|
-
width: z.string().optional().describe("Width of the image (128-2048 pixels)"),
|
|
379
|
-
height: z.string().optional().describe("Height of the image (128-2048 pixels)"),
|
|
380
|
-
guidance_scale: z.string().optional().describe("Strength of prompt following (1.0-20.0)"),
|
|
381
|
-
negative_prompt: z.string().optional().describe("Negative prompt (what NOT to include in the image)"),
|
|
382
|
-
num_inference_steps: z.string().optional().describe("Number of generation steps (1-50)"),
|
|
383
|
-
seed: z.string().optional().describe("Seed for reproducibility (0 = random)")
|
|
384
|
-
},
|
|
385
|
-
}, async (params) => {
|
|
386
|
-
try {
|
|
387
|
-
// Handle case where arguments might be sent as a JSON string
|
|
388
|
-
let processedParams = params;
|
|
389
|
-
if (typeof params === 'string') {
|
|
390
|
-
try {
|
|
391
|
-
processedParams = JSON.parse(params);
|
|
392
|
-
}
|
|
393
|
-
catch (parseError) {
|
|
394
|
-
throw new Error('Invalid JSON string in arguments');
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
else if (params.arguments && typeof params.arguments === 'object') {
|
|
398
|
-
processedParams = params.arguments;
|
|
399
|
-
}
|
|
400
|
-
const { prompt, width, height, guidance_scale, negative_prompt, num_inference_steps, seed } = processedParams;
|
|
401
|
-
if (!prompt) {
|
|
402
|
-
throw new Error("Parameter 'prompt' is required");
|
|
403
|
-
}
|
|
404
|
-
// Prepare options for generateImage function, converting string parameters to numbers
|
|
405
|
-
const options = {};
|
|
406
|
-
if (width !== undefined)
|
|
407
|
-
options.width = typeof width === 'string' ? parseFloat(width) : width;
|
|
408
|
-
if (height !== undefined)
|
|
409
|
-
options.height = typeof height === 'string' ? parseFloat(height) : height;
|
|
410
|
-
if (guidance_scale !== undefined)
|
|
411
|
-
options.guidance_scale = typeof guidance_scale === 'string' ? parseFloat(guidance_scale) : guidance_scale;
|
|
412
|
-
if (negative_prompt !== undefined)
|
|
413
|
-
options.negative_prompt = negative_prompt;
|
|
414
|
-
if (num_inference_steps !== undefined)
|
|
415
|
-
options.num_inference_steps = typeof num_inference_steps === 'string' ? parseInt(num_inference_steps) : num_inference_steps;
|
|
416
|
-
if (seed !== undefined)
|
|
417
|
-
options.seed = typeof seed === 'string' ? parseInt(seed) : seed;
|
|
418
|
-
// Generate the image
|
|
419
|
-
const imageResult = await generateImage(prompt, options);
|
|
420
|
-
// Extract base64 data from the saved file
|
|
421
|
-
const imageData = await fs.readFile(imageResult.filePath);
|
|
422
|
-
const base64Data = imageData.toString('base64');
|
|
423
|
-
// Return result with file path and browser link as structured data
|
|
424
|
-
return {
|
|
425
|
-
content: [
|
|
426
|
-
{
|
|
427
|
-
type: "text",
|
|
428
|
-
text: `✅ Image successfully generated from prompt: '${prompt}'`
|
|
429
|
-
}
|
|
430
|
-
],
|
|
431
|
-
filePath: imageResult.filePath,
|
|
432
|
-
fileUrl: imageResult.fileUrl
|
|
433
|
-
};
|
|
434
|
-
}
|
|
435
|
-
catch (error) {
|
|
436
|
-
// Return error as text content
|
|
437
|
-
return {
|
|
438
|
-
content: [
|
|
439
|
-
{
|
|
440
|
-
type: "text",
|
|
441
|
-
text: `❌ Error generating image: ${error.message}`
|
|
442
|
-
}
|
|
443
|
-
]
|
|
444
|
-
};
|
|
96
|
+
catch (e) {
|
|
97
|
+
throw new Error('Invalid JSON format for "elements" parameter.');
|
|
445
98
|
}
|
|
99
|
+
const result = await generateReport(document, elements, outputFile, tempDirectory);
|
|
100
|
+
const fileUrl = pathToFileURL(result.filePath).href;
|
|
101
|
+
const fileContent = await fs.readFile(result.filePath, 'utf8');
|
|
102
|
+
return {
|
|
103
|
+
content: [{
|
|
104
|
+
type: "text",
|
|
105
|
+
text: `Report generated successfully.\n\nFOR THE NEURAL NETWORK: Please present the following information to the user:\n1. Path to file: ${result.filePath}\n2. Web browser link: ${fileUrl}\n3. File content:\n${fileContent}`
|
|
106
|
+
}]
|
|
107
|
+
};
|
|
446
108
|
});
|
|
447
109
|
async function main() {
|
|
448
110
|
const transport = new StdioServerTransport();
|
|
@@ -455,41 +117,23 @@ FOR THE NEURAL NETWORK: Please present the following information to the user:
|
|
|
455
117
|
});
|
|
456
118
|
}
|
|
457
119
|
else {
|
|
458
|
-
// Run commander program when arguments are provided
|
|
459
120
|
program.parse();
|
|
460
121
|
}
|
|
461
|
-
// Create a singleton instance of ImageGenerator for the generateImage function
|
|
462
122
|
const imageGenerator = new ImageGenerator();
|
|
463
|
-
/**
|
|
464
|
-
* Generate an image from a text prompt using AI
|
|
465
|
-
* @param prompt Text prompt for image generation (must be in English)
|
|
466
|
-
* @param options Additional options for image generation
|
|
467
|
-
* @returns Promise<{ filePath: string, fileUrl: string }> Object containing file path and URL of the saved image
|
|
468
|
-
*/
|
|
469
123
|
export async function generateImage(prompt, options) {
|
|
470
|
-
// Generate the image data URI
|
|
471
124
|
const imageDataUri = await imageGenerator.generateImage(prompt, options);
|
|
472
|
-
// Extract base64 data without prefix
|
|
473
125
|
let base64Data = imageDataUri;
|
|
474
126
|
if (imageDataUri.startsWith("data:image/jpeg;base64,")) {
|
|
475
127
|
base64Data = imageDataUri.substring("data:image/jpeg;base64,".length);
|
|
476
128
|
}
|
|
477
|
-
// Save image to REPORTS_DIR or current working directory
|
|
478
129
|
const reportsDir = process.env.REPORTS_DIR || process.cwd();
|
|
479
130
|
const imagesDir = path.join(reportsDir, 'generated_images');
|
|
480
131
|
await fs.ensureDir(imagesDir);
|
|
481
|
-
// Create unique filename
|
|
482
132
|
const timestamp = Date.now();
|
|
483
133
|
const filename = `generated-image-${timestamp}.jpeg`;
|
|
484
134
|
const outputPath = path.join(imagesDir, filename);
|
|
485
|
-
// Save image to file
|
|
486
135
|
const imageBuffer = Buffer.from(base64Data, 'base64');
|
|
487
136
|
await fs.writeFile(outputPath, imageBuffer);
|
|
488
|
-
// Create file URL
|
|
489
137
|
const fileUrl = pathToFileURL(outputPath).href;
|
|
490
|
-
|
|
491
|
-
return {
|
|
492
|
-
filePath: outputPath,
|
|
493
|
-
fileUrl: fileUrl
|
|
494
|
-
};
|
|
138
|
+
return { filePath: outputPath, fileUrl };
|
|
495
139
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const createReportFromTextTool: {
|
|
3
|
+
name: string;
|
|
4
|
+
description: string;
|
|
5
|
+
inputSchema: {
|
|
6
|
+
documentText: z.ZodString;
|
|
7
|
+
outputFile: z.ZodString;
|
|
8
|
+
};
|
|
9
|
+
execute: ({ documentText, outputFile }: {
|
|
10
|
+
documentText: string;
|
|
11
|
+
outputFile: string;
|
|
12
|
+
}) => Promise<{
|
|
13
|
+
success: boolean;
|
|
14
|
+
filePath: string;
|
|
15
|
+
}>;
|
|
16
|
+
};
|
|
17
|
+
//# sourceMappingURL=createReportFromText.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createReportFromText.d.ts","sourceRoot":"","sources":["../../src/tools/createReportFromText.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAyCxB,eAAO,MAAM,wBAAwB;;;;;;;4CAOW;QAAE,YAAY,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE;;;;CAM3F,CAAC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { generateReport } from '../utils/reportGenerator.js';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
// Эта функция будет извлекать данные из текста и генерировать элементы
|
|
4
|
+
function extractElementsFromText(documentText) {
|
|
5
|
+
const elements = {};
|
|
6
|
+
let newDocument = documentText;
|
|
7
|
+
// Пример: ищем финансовые данные для графика
|
|
8
|
+
const revenueMatches = [...documentText.matchAll(/Доход: \$([\d,.]+) миллиарда/gi)];
|
|
9
|
+
if (revenueMatches.length > 0) {
|
|
10
|
+
const labels = revenueMatches.map((match, i) => `Квартал ${i + 1}`);
|
|
11
|
+
const data = revenueMatches.map(match => parseFloat(match[1].replace(/,/g, '')));
|
|
12
|
+
elements['revenue_chart'] = {
|
|
13
|
+
type: 'bar',
|
|
14
|
+
config: {
|
|
15
|
+
labels: labels,
|
|
16
|
+
datasets: [{
|
|
17
|
+
label: 'Общий доход, млрд $',
|
|
18
|
+
data: data,
|
|
19
|
+
backgroundColor: ['rgba(54, 162, 235, 0.6)']
|
|
20
|
+
}]
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
newDocument += '\n\n## Визуализация дохода\n\n[[chart:revenue_chart]]';
|
|
24
|
+
}
|
|
25
|
+
// Пример: добавляем изображение на основе контекста
|
|
26
|
+
if (/apple/i.test(documentText)) {
|
|
27
|
+
elements['context_image'] = {
|
|
28
|
+
type: 'pollinations',
|
|
29
|
+
config: {
|
|
30
|
+
prompt: 'a modern and sleek design representing apple products innovation'
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
newDocument += '\n\n## Иллюстрация\n\n[[image:context_image]]';
|
|
34
|
+
}
|
|
35
|
+
return { newDocument, elements };
|
|
36
|
+
}
|
|
37
|
+
export const createReportFromTextTool = {
|
|
38
|
+
name: "create-report-from-text",
|
|
39
|
+
description: "Creates a full HTML report from a given text by automatically generating charts and images.",
|
|
40
|
+
inputSchema: {
|
|
41
|
+
documentText: z.string().describe("The full text of the report in Markdown format."),
|
|
42
|
+
outputFile: z.string().describe("The desired output HTML file name (e.g., 'report.html').")
|
|
43
|
+
},
|
|
44
|
+
execute: async ({ documentText, outputFile }) => {
|
|
45
|
+
const { newDocument, elements } = extractElementsFromText(documentText);
|
|
46
|
+
// Вызываем старый генератор с автоматически созданными параметрами
|
|
47
|
+
return await generateReport(newDocument, elements, outputFile);
|
|
48
|
+
}
|
|
49
|
+
};
|
|
@@ -101,11 +101,11 @@ export async function generateReport(document, elements, outputFile, tempDirecto
|
|
|
101
101
|
}
|
|
102
102
|
// Render elements to interactive HTML
|
|
103
103
|
const renderedElements = {};
|
|
104
|
-
for (const [id, element] of Object.entries(
|
|
104
|
+
for (const [id, element] of Object.entries(parsedElements)) {
|
|
105
105
|
if (element.type in chartRenderers) {
|
|
106
106
|
// Это диаграмма
|
|
107
107
|
const chartElement = element;
|
|
108
|
-
const htmlChart = await chartRenderers[chartElement.type].renderer(chartElement.config);
|
|
108
|
+
const htmlChart = await chartRenderers[chartElement.type].renderer(id, chartElement.config);
|
|
109
109
|
renderedElements[id] = htmlChart;
|
|
110
110
|
}
|
|
111
111
|
else if (element.type in imageRenderers) {
|
|
Binary file
|
|
Binary file
|
|
Binary file
|