@vint.tri/report_gen_mcp 1.5.44 → 1.5.48

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.
@@ -0,0 +1,7 @@
1
+ export * from './bar.js';
2
+ export * from './doughnut.js';
3
+ export * from './line.js';
4
+ export * from './pie.js';
5
+ export * from './polarArea.js';
6
+ export * from './radar.js';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/charts/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,eAAe,CAAC;AAC9B,cAAc,WAAW,CAAC;AAC1B,cAAc,UAAU,CAAC;AACzB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC"}
@@ -0,0 +1,6 @@
1
+ export * from './bar.js';
2
+ export * from './doughnut.js';
3
+ export * from './line.js';
4
+ export * from './pie.js';
5
+ export * from './polarArea.js';
6
+ export * from './radar.js';
@@ -0,0 +1,4 @@
1
+ export * from './localImages.js';
2
+ export { generatedImageSchema, renderGeneratedImage, pollinationsImageSchema, renderPollinationsImage } from './pollinations.js';
3
+ export { urlImageSchema, renderUrlImage } from './urlImages.js';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/images/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,OAAO,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,uBAAuB,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AACjI,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,3 @@
1
+ export * from './localImages.js';
2
+ export { generatedImageSchema, renderGeneratedImage, pollinationsImageSchema, renderPollinationsImage } from './pollinations.js';
3
+ export { urlImageSchema, renderUrlImage } from './urlImages.js';
@@ -10,8 +10,8 @@ export declare const generatedImageSchema: z.ZodObject<{
10
10
  }, "strip", z.ZodTypeAny, {
11
11
  width: number;
12
12
  height: number;
13
- prompt: string;
14
13
  model: string;
14
+ prompt: string;
15
15
  nologo: boolean;
16
16
  enhance: boolean;
17
17
  seed?: number | undefined;
@@ -43,5 +43,5 @@ export declare const imageUrlSchema: z.ZodObject<{
43
43
  export declare function generateImageUrl(params: z.infer<typeof generatedImageSchema>): string;
44
44
  export declare function renderGeneratedImage(params: z.infer<typeof generatedImageSchema>): Promise<string>;
45
45
  export declare function renderImageUrl(params: z.infer<typeof imageUrlSchema>): Promise<string>;
46
- export { generatedImageSchema as pollinationsImageSchema, renderGeneratedImage as renderPollinationsImage, imageUrlSchema as urlImageSchema, renderImageUrl as renderUrlImage };
46
+ export { generatedImageSchema as pollinationsImageSchema, renderGeneratedImage as renderPollinationsImage };
47
47
  //# sourceMappingURL=pollinations.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"pollinations.d.ts","sourceRoot":"","sources":["../../src/images/pollinations.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;EAQ/B,CAAC;AAGH,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;EAKzB,CAAC;AAGH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,GAAG,MAAM,CAgBrF;AAGD,wBAAsB,oBAAoB,CAAC,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAUxG;AAGD,wBAAsB,cAAc,CAAC,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAc5F;AAED,OAAO,EACL,oBAAoB,IAAI,uBAAuB,EAC/C,oBAAoB,IAAI,uBAAuB,EAC/C,cAAc,IAAI,cAAc,EAChC,cAAc,IAAI,cAAc,EACjC,CAAC"}
1
+ {"version":3,"file":"pollinations.d.ts","sourceRoot":"","sources":["../../src/images/pollinations.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;EAQ/B,CAAC;AAGH,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;EAKzB,CAAC;AAGH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,GAAG,MAAM,CAgBrF;AAGD,wBAAsB,oBAAoB,CAAC,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAUxG;AAGD,wBAAsB,cAAc,CAAC,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAc5F;AAED,OAAO,EACL,oBAAoB,IAAI,uBAAuB,EAC/C,oBAAoB,IAAI,uBAAuB,EAChD,CAAC"}
@@ -62,4 +62,4 @@ export async function renderImageUrl(params) {
62
62
  </div>
63
63
  `;
64
64
  }
65
- export { generatedImageSchema as pollinationsImageSchema, renderGeneratedImage as renderPollinationsImage, imageUrlSchema as urlImageSchema, renderImageUrl as renderUrlImage };
65
+ export { generatedImageSchema as pollinationsImageSchema, renderGeneratedImage as renderPollinationsImage };
@@ -7,8 +7,8 @@ export declare const urlImageSchema: z.ZodObject<{
7
7
  embed: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
8
8
  outputPath: z.ZodOptional<z.ZodString>;
9
9
  }, "strip", z.ZodTypeAny, {
10
- embed: boolean;
11
10
  url: string;
11
+ embed: boolean;
12
12
  alt?: string | undefined;
13
13
  width?: number | undefined;
14
14
  height?: number | undefined;
package/dist/index.js CHANGED
@@ -109,7 +109,7 @@ if (process.argv.length === 2) {
109
109
  // No command specified, run in stdio mode using MCP SDK
110
110
  const mcpServer = new McpServer({
111
111
  name: "report_gen_mcp",
112
- version: "1.5.44"
112
+ version: "1.5.48"
113
113
  }, {
114
114
  // Disable health check to prevent automatic calls
115
115
  capabilities: {
@@ -1 +1 @@
1
- {"version":3,"file":"imageGenerationServer.d.ts","sourceRoot":"","sources":["../../src/mcp/imageGenerationServer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAeH,UAAU,uBAAuB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;IACxB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB;AAED,cAAM,cAAc;IAClB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,eAAe,CAA0B;;IAiBjD,OAAO,CAAC,aAAa;IAIf,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,gBAAgB,GAAE,OAAO,CAAC,uBAAuB,CAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CAuE9G;AA+ND,iBAAe,IAAI,kBASlB;AAOD,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC"}
1
+ {"version":3,"file":"imageGenerationServer.d.ts","sourceRoot":"","sources":["../../src/mcp/imageGenerationServer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAeH,UAAU,uBAAuB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;IACxB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB;AAED,cAAM,cAAc;IAClB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,eAAe,CAA0B;;IAiBjD,OAAO,CAAC,aAAa;IAIf,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,gBAAgB,GAAE,OAAO,CAAC,uBAAuB,CAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CAuE9G;AA8OD,iBAAe,IAAI,kBASlB;AAOD,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC"}
@@ -204,7 +204,8 @@ app.registerTool("generate_image_to_file", {
204
204
  guidance_scale: z.string().optional().describe("Сила следования промпту (1.0-20.0)"),
205
205
  negative_prompt: z.string().optional().describe("Негативный промпт (что НЕ включать в изображение)"),
206
206
  num_inference_steps: z.string().optional().describe("Количество шагов генерации (1-50)"),
207
- seed: z.string().optional().describe("Seed для воспроизводимости (0 = случайный)")
207
+ seed: z.string().optional().describe("Seed для воспроизводимости (0 = случайный)"),
208
+ reportsDir: z.string().optional().describe("Директория отчетов, если используется HTTP сервер (для формирования относительного пути)")
208
209
  },
209
210
  }, async (args) => {
210
211
  try {
@@ -212,6 +213,7 @@ app.registerTool("generate_image_to_file", {
212
213
  const prompt = args.prompt || "";
213
214
  const directory = args.directory || "";
214
215
  const filename = args.filename || "";
216
+ const reportsDir = args.reportsDir || ""; // reportsDir from report_gen_mcp
215
217
  if (!prompt) {
216
218
  throw new Error("Параметр 'prompt' обязателен");
217
219
  }
@@ -250,9 +252,13 @@ app.registerTool("generate_image_to_file", {
250
252
  }
251
253
  // Проверяем базовый каталог из переменной окружения
252
254
  const baseSaveDirectory = process.env.IMG_SAVE_BASE_DIR || "";
253
- const fullDirectory = baseSaveDirectory
255
+ let fullDirectory = baseSaveDirectory
254
256
  ? path.normalize(path.join(baseSaveDirectory, directory))
255
257
  : path.normalize(directory);
258
+ // If reportsDir is provided, save relative to it for HTTP serving
259
+ if (reportsDir) {
260
+ fullDirectory = path.join(reportsDir, directory);
261
+ }
256
262
  // Создаем каталог если не существует
257
263
  await fs.ensureDir(fullDirectory);
258
264
  // Формируем полный путь к файлу
@@ -260,14 +266,21 @@ app.registerTool("generate_image_to_file", {
260
266
  // Сохраняем изображение
261
267
  const imageBuffer = Buffer.from(base64Data, 'base64');
262
268
  await fs.writeFile(outputPath, imageBuffer);
263
- // Создаем file URI
264
- const fileUrl = new URL(`file://${path.resolve(outputPath)}`).href;
269
+ // Determine the URI to return
270
+ let finalUri = outputPath; // Default to local path
271
+ // If reportsDir was used, construct an HTTP-friendly relative path
272
+ if (reportsDir) {
273
+ const relativePath = path.relative(reportsDir, outputPath);
274
+ // Assuming the HTTP server serves reportsDir as its root for /reports
275
+ // The actual serverBaseUrl will be prepended by the caller (report_gen_mcp)
276
+ finalUri = `${directory.startsWith('/') ? '' : '/'}${path.join(directory, filename)}`;
277
+ }
265
278
  // Возвращаем результат
266
279
  return {
267
280
  content: [
268
281
  {
269
282
  type: "text",
270
- text: `✅ Изображение успешно сгенерировано и сохранено в '${outputPath}' (URI: ${fileUrl})`
283
+ text: `✅ Изображение успешно сгенерировано и сохранено в '${outputPath}' (URI: ${finalUri})`
271
284
  }
272
285
  ]
273
286
  };
@@ -0,0 +1,3 @@
1
+ export { main as startImageEditingServer, ImageEditor } from './imageEditingServer.js';
2
+ export { main as startImageGenerationServer, ImageGenerator } from './imageGenerationServer.js';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mcp/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,IAAI,uBAAuB,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACvF,OAAO,EAAE,IAAI,IAAI,0BAA0B,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { main as startImageEditingServer, ImageEditor } from './imageEditingServer.js';
2
+ export { main as startImageGenerationServer, ImageGenerator } from './imageGenerationServer.js';
@@ -0,0 +1,4 @@
1
+ export * from './createReportFromText.js';
2
+ export * from './simpleReport.js';
3
+ export * from './testReport.js';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA,cAAc,2BAA2B,CAAC;AAC1C,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC"}
@@ -0,0 +1,3 @@
1
+ export * from './createReportFromText.js';
2
+ export * from './simpleReport.js';
3
+ export * from './testReport.js';
@@ -0,0 +1,2 @@
1
+ export * from './reportGenerator.js';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC"}
@@ -0,0 +1 @@
1
+ export * from './reportGenerator.js';
@@ -1 +1 @@
1
- {"version":3,"file":"reportGenerator.d.ts","sourceRoot":"","sources":["../../src/utils/reportGenerator.ts"],"names":[],"mappings":"AAKA,wBAAsB,cAAc,CAClC,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,EAClB,aAAa,CAAC,EAAE,MAAM,GACrB,OAAO,CAAC;IAAE,OAAO,EAAE,IAAI,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAkJ9C"}
1
+ {"version":3,"file":"reportGenerator.d.ts","sourceRoot":"","sources":["../../src/utils/reportGenerator.ts"],"names":[],"mappings":"AAKA,wBAAsB,cAAc,CAClC,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,EAClB,aAAa,CAAC,EAAE,MAAM,GACrB,OAAO,CAAC;IAAE,OAAO,EAAE,IAAI,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAmQ9C"}
@@ -22,10 +22,71 @@ export async function generateReport(htmlDocument, outputFile, serverBaseUrl) {
22
22
  if (!head.querySelector('style')) {
23
23
  const style = document.createElement('style');
24
24
  style.textContent = `
25
- body { font-family: Arial, sans-serif; padding: 20px; }
26
- h1, h2 { color: #1a5276; }
27
- .chart-container { width: 80%; max-width: 600px; margin: 30px auto; }
28
- img { max-width: 100%; height: auto; display: block; margin: 20px auto; }
25
+ body {
26
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
27
+ line-height: 1.6;
28
+ color: #333;
29
+ margin: 0;
30
+ padding: 40px;
31
+ background-color: #f4f7f6;
32
+ }
33
+ h1, h2, h3, h4, h5, h6 {
34
+ color: #2c3e50;
35
+ margin-top: 1.5em;
36
+ margin-bottom: 0.5em;
37
+ line-height: 1.2;
38
+ }
39
+ h1 { font-size: 2.5em; border-bottom: 2px solid #3498db; padding-bottom: 10px; }
40
+ h2 { font-size: 2em; color: #3498db; }
41
+ p {
42
+ margin-bottom: 1em;
43
+ }
44
+ .container {
45
+ max-width: 900px;
46
+ margin: 0 auto;
47
+ background-color: #ffffff;
48
+ padding: 30px;
49
+ border-radius: 8px;
50
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
51
+ }
52
+ .chart-container {
53
+ width: 100%;
54
+ max-width: 700px;
55
+ margin: 40px auto;
56
+ padding: 20px;
57
+ background-color: #fdfdfd;
58
+ border-radius: 8px;
59
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
60
+ }
61
+ img {
62
+ max-width: 100%;
63
+ height: auto;
64
+ display: block;
65
+ margin: 20px auto;
66
+ border-radius: 8px;
67
+ box-shadow: 0 4px 8px rgba(0,0,0,0.1);
68
+ }
69
+ table {
70
+ width: 100%;
71
+ border-collapse: collapse;
72
+ margin: 20px 0;
73
+ }
74
+ th, td {
75
+ border: 1px solid #ddd;
76
+ padding: 10px;
77
+ text-align: left;
78
+ }
79
+ th {
80
+ background-color: #ecf0f1;
81
+ color: #2c3e50;
82
+ }
83
+ a {
84
+ color: #3498db;
85
+ text-decoration: none;
86
+ }
87
+ a:hover {
88
+ text-decoration: underline;
89
+ }
29
90
  `;
30
91
  head.appendChild(style);
31
92
  }
@@ -53,15 +114,65 @@ export async function generateReport(htmlDocument, outputFile, serverBaseUrl) {
53
114
  scriptTag.remove();
54
115
  }
55
116
  });
56
- // 4. Process all img elements to handle local images
117
+ // 4. Process all img elements to handle local images or generate them
57
118
  const images = document.querySelectorAll('img');
58
119
  for (const img of Array.from(images)) {
59
120
  const src = img.getAttribute('src');
60
- if (src) {
61
- // Check if it's a local file (not a URL)
121
+ const generatePrompt = img.getAttribute('data-generate-image'); // New attribute for AI generation
122
+ if (generatePrompt) {
123
+ // If data-generate-image attribute is present, try to generate image
124
+ try {
125
+ console.log(`Generating image for prompt: "${generatePrompt}"`);
126
+ // Use generate_image_to_file to get an HTTP link
127
+ const imageFileName = `generated-image-${Date.now()}.jpeg`; // Unique filename
128
+ const imageOutputDir = path.join(outputDirPath, 'generated_images'); // Save in a subfolder
129
+ const result = await use_mcp_tool('image-generator-ts', // The name of your image generation MCP server
130
+ 'generate_image_to_file', {
131
+ prompt: generatePrompt,
132
+ directory: imageOutputDir,
133
+ filename: imageFileName
134
+ });
135
+ if (result && result.content && result.content[0] && result.content[0].text) {
136
+ // Extract the URL from the success message
137
+ const match = result.content[0].text.match(/URI:\s*(https?:\/\/.+)/);
138
+ if (match && match[1]) {
139
+ const httpUrl = match[1];
140
+ img.setAttribute('src', httpUrl);
141
+ img.removeAttribute('data-generate-image'); // Remove attribute after processing
142
+ console.log(`✅ Successfully generated image for prompt: "${generatePrompt}" and set HTTP source: ${httpUrl}`);
143
+ }
144
+ else {
145
+ console.warn(`⚠️ Failed to extract HTTP URL from image generation result:`, result.content[0].text);
146
+ // Fallback to placeholder if URL extraction fails
147
+ const width = img.getAttribute('width') ? parseInt(img.getAttribute('width')) : 300;
148
+ const height = img.getAttribute('height') ? parseInt(img.getAttribute('height')) : 200;
149
+ const placeholderSvg = `<svg width="${width}" height="${height}" xmlns="http://www.w3.org/2000/svg"><rect width="100%" height="100%" fill="#f0f0f0"/><text x="50%" y="50%" font-family="Arial" font-size="16" fill="#666" text-anchor="middle" dy=".3em">Failed to get image URL</text></svg>`;
150
+ img.setAttribute('src', `data:image/svg+xml;base64,${Buffer.from(placeholderSvg).toString('base64')}`);
151
+ }
152
+ }
153
+ else {
154
+ console.warn(`⚠️ Failed to generate image for prompt: "${generatePrompt}". No valid result returned.`, JSON.stringify(result));
155
+ // Fallback to placeholder if generation fails or returns no data
156
+ const width = img.getAttribute('width') ? parseInt(img.getAttribute('width')) : 300;
157
+ const height = img.getAttribute('height') ? parseInt(img.getAttribute('height')) : 200;
158
+ const placeholderSvg = `<svg width="${width}" height="${height}" xmlns="http://www.w3.org/2000/svg"><rect width="100%" height="100%" fill="#f0f0f0"/><text x="50%" y="50%" font-family="Arial" font-size="16" fill="#666" text-anchor="middle" dy=".3em">Image generation failed</text></svg>`;
159
+ img.setAttribute('src', `data:image/svg+xml;base64,${Buffer.from(placeholderSvg).toString('base64')}`);
160
+ }
161
+ }
162
+ catch (error) {
163
+ console.error(`❌ Error generating image for prompt "${generatePrompt}":`, error);
164
+ // Fallback to placeholder if an error occurs during generation
165
+ const width = img.getAttribute('width') ? parseInt(img.getAttribute('width')) : 300;
166
+ const height = img.getAttribute('height') ? parseInt(img.getAttribute('height')) : 200;
167
+ const placeholderSvg = `<svg width="${width}" height="${height}" xmlns="http://www.w3.org/2000/svg"><rect width="100%" height="100%" fill="#f0f0f0"/><text x="50%" y="50%" font-family="Arial" font-size="16" fill="#666" text-anchor="middle" dy=".3em">Error during generation</text></svg>`;
168
+ img.setAttribute('src', `data:image/svg+xml;base64,${Buffer.from(placeholderSvg).toString('base64')}`);
169
+ }
170
+ }
171
+ else if (src) {
172
+ // Process existing local images if no generation prompt is given
173
+ // Check if it's a local file (not a URL or data URI)
62
174
  if (!src.startsWith('http://') && !src.startsWith('https://') && !src.startsWith('data:')) {
63
175
  try {
64
- // Try to read the image file first
65
176
  const imageSourcePath = path.resolve(process.cwd(), src);
66
177
  await fs.access(imageSourcePath); // This will throw if file doesn't exist
67
178
  // If file exists, process it normally
@@ -92,7 +203,7 @@ export async function generateReport(htmlDocument, outputFile, serverBaseUrl) {
92
203
  }
93
204
  }
94
205
  catch (error) {
95
- console.warn(`Failed to process local image ${src}:`, error);
206
+ console.warn(`⚠️ Failed to process local image ${src}:`, error);
96
207
  // If file doesn't exist or processing fails, keep original src
97
208
  // This allows the browser to potentially load the image if it becomes available
98
209
  // or handle it according to its own fallback mechanisms
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vint.tri/report_gen_mcp",
3
- "version": "1.5.44",
3
+ "version": "1.5.48",
4
4
  "description": "CLI tool for generating HTML reports with embedded charts and images",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -1,93 +0,0 @@
1
- import { generateReport } from './dist/utils/reportGenerator.js';
2
- import fs from 'fs-extra';
3
- import path from 'path';
4
-
5
- async function testAppleReportFix() {
6
- // Create a test HTML similar to your Apple report
7
- const htmlContent = `
8
- <!DOCTYPE html>
9
- <html>
10
- <head>
11
- <title>Отчет о прибылях Apple за 2024 год</title>
12
- <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
13
- <style>
14
- body { font-family: Arial, sans-serif; padding: 20px; }
15
- h1, h2 { color: #1a5276; }
16
- img { max-width: 100%; height: auto; display: block; margin: 20px auto; }
17
- </style>
18
- </head>
19
- <body>
20
- <h1>Отчет о прибылях Apple за 2024 год</h1>
21
- <p>В 2024 году компания Apple показала значительный рост прибыли по сравнению с предыдущими годами.</p>
22
-
23
- <h2>График прибыли</h2>
24
- <img src="profit_chart.png" alt="График прибыли">
25
-
26
- <h2>Данные по кварталам</h2>
27
- <canvas id="quarterlyChart" width="400" height="200"></canvas>
28
- <script>
29
- var ctx = document.getElementById('quarterlyChart').getContext('2d');
30
- var quarterlyChart = new Chart(ctx, {
31
- type: 'bar',
32
- data: {
33
- labels: ['Q1', 'Q2', 'Q3', 'Q4'],
34
- datasets: [{
35
- label: 'Прибыль (млрд $)',
36
- data: [25.2, 28.5, 32.1, 35.8],
37
- backgroundColor: 'rgba(54, 162, 235, 0.6)'
38
- }]
39
- },
40
- options: {
41
- scales: {
42
- y: {
43
- beginAtZero: true
44
- }
45
- }
46
- }
47
- });
48
- </script>
49
-
50
- <p>Как видно из графика, прибыль компании увеличилась на 15% по сравнению с 2023 годом.</p>
51
- </body>
52
- </html>`;
53
-
54
- // Generate report with server base URL (simulating MCP server mode)
55
- const outputPath = path.resolve('.', 'apple_report_fixed.html');
56
- const serverBaseUrl = 'http://localhost:55453/reports';
57
-
58
- console.log('Testing Apple report generation with missing image...');
59
- const result = await generateReport(htmlContent, outputPath, serverBaseUrl);
60
-
61
- // Read the generated report
62
- const generatedContent = fs.readFileSync(outputPath, 'utf8');
63
-
64
- console.log('Generated report saved to:', result.filePath);
65
- console.log('\nChecking results...');
66
-
67
- // Check if the report contains the expected elements
68
- if (generatedContent.includes('data:image/svg+xml;base64')) {
69
- console.log('✅ SUCCESS: Missing profit_chart.png converted to SVG placeholder');
70
- } else {
71
- console.log('❌ FAILED: Missing image not handled properly');
72
- }
73
-
74
- // Check if chart processing worked
75
- if (generatedContent.includes('data-chart-script')) {
76
- console.log('✅ SUCCESS: Quarterly chart processed correctly');
77
- } else {
78
- console.log('❌ FAILED: Charts not processed');
79
- }
80
-
81
- // Check if HTTP URL was generated for the report
82
- if (generatedContent.includes(serverBaseUrl)) {
83
- console.log('✅ SUCCESS: Server base URL applied correctly');
84
- } else {
85
- console.log('ℹ️ INFO: No HTTP URLs needed (using base64 fallback)');
86
- }
87
-
88
- console.log('\n✅ Test completed successfully!');
89
- console.log('Open the generated file in browser to verify:');
90
- console.log(result.filePath);
91
- }
92
-
93
- testAppleReportFix().catch(console.error);
@@ -1,44 +0,0 @@
1
- import { generateReport } from './dist/utils/reportGenerator.js';
2
- import fs from 'fs-extra';
3
- import path from 'path';
4
-
5
- async function testFix() {
6
- // Read the test HTML file with missing image
7
- const htmlContent = fs.readFileSync('test_missing_image.html', 'utf8');
8
-
9
- // Generate report with server base URL (simulating MCP server mode)
10
- const outputPath = path.resolve('.', 'test_fix_output.html');
11
- const serverBaseUrl = 'http://localhost:3000/reports';
12
-
13
- console.log('Testing report generation with missing image...');
14
- const result = await generateReport(htmlContent, outputPath, serverBaseUrl);
15
-
16
- // Read the generated report
17
- const generatedContent = fs.readFileSync(outputPath, 'utf8');
18
-
19
- console.log('Generated report saved to:', result.filePath);
20
- console.log('\nChecking results...');
21
-
22
- // Check if the report contains the expected elements
23
- if (generatedContent.includes('data:image')) {
24
- console.log('✅ SUCCESS: Missing image converted to base64 fallback');
25
- } else if (generatedContent.includes('nonexistent_image.png')) {
26
- console.log('❌ FAILED: Image still using original path');
27
- } else {
28
- console.log('⚠️ UNKNOWN: Image handling result unclear');
29
- }
30
-
31
- // Check if chart processing worked
32
- if (generatedContent.includes('data-chart-script')) {
33
- console.log('✅ SUCCESS: Charts processed correctly');
34
- } else {
35
- console.log('❌ FAILED: Charts not processed');
36
- }
37
-
38
- console.log('\nGenerated HTML preview:');
39
- console.log('======================');
40
- // Show first 1000 characters to avoid overwhelming output
41
- console.log(generatedContent.substring(0, 1000) + (generatedContent.length > 1000 ? '...' : ''));
42
- }
43
-
44
- testFix().catch(console.error);
@@ -1,45 +0,0 @@
1
- import { generateReport } from './dist/utils/reportGenerator.js';
2
- import fs from 'fs-extra';
3
- import path from 'path';
4
-
5
- async function testRealScenario() {
6
- // Read the real Apple report file
7
- const htmlContent = fs.readFileSync('Apple_Profit_Report_2024.html', 'utf8');
8
-
9
- // Generate report with server base URL (like in your real case)
10
- const outputPath = path.resolve('.', 'real_scenario_test.html');
11
- const serverBaseUrl = 'http://localhost:55453/reports';
12
-
13
- console.log('Testing real scenario with server base URL...');
14
- const result = await generateReport(htmlContent, outputPath, serverBaseUrl);
15
-
16
- // Read the generated report
17
- const generatedContent = fs.readFileSync(outputPath, 'utf8');
18
-
19
- console.log('Generated report saved to:', result.filePath);
20
- console.log('\nChecking results...');
21
-
22
- // Check if the report contains HTTP links
23
- if (generatedContent.includes(serverBaseUrl)) {
24
- console.log('✅ SUCCESS: Images converted to HTTP links');
25
- } else if (generatedContent.includes('profit_chart.png')) {
26
- console.log('ℹ️ INFO: Images kept original paths (file not found case)');
27
- } else {
28
- console.log('⚠️ UNKNOWN: Image handling result unclear');
29
- }
30
-
31
- // Check if chart processing worked
32
- if (generatedContent.includes('data-chart-script')) {
33
- console.log('✅ SUCCESS: Charts processed correctly');
34
- } else {
35
- console.log('❌ FAILED: Charts not processed');
36
- }
37
-
38
- console.log('\nGenerated HTML preview (first 800 chars):');
39
- console.log('===========================================');
40
- console.log(generatedContent.substring(0, 800) + (generatedContent.length > 800 ? '...' : ''));
41
-
42
- console.log('\n✅ Real scenario test completed!');
43
- }
44
-
45
- testRealScenario().catch(console.error);
@@ -1,77 +0,0 @@
1
- import { generateReport } from './dist/utils/reportGenerator.js';
2
- import fs from 'fs-extra';
3
- import path from 'path';
4
-
5
- async function testWithExistingImage() {
6
- // Create a test image file
7
- const testImagePath = 'test_image.png';
8
- try {
9
- // Try to copy an existing image or create a simple one
10
- if (fs.existsSync('apple_logo_chart.png')) {
11
- fs.copyFileSync('apple_logo_chart.png', testImagePath);
12
- console.log('✅ Copied existing image for test');
13
- } else {
14
- // Create a simple test image (1x1 pixel PNG)
15
- const testImageData = Buffer.from('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==', 'base64');
16
- fs.writeFileSync(testImagePath, testImageData);
17
- console.log('✅ Created simple test image');
18
- }
19
- } catch (error) {
20
- console.log('⚠️ Could not create test image:', error.message);
21
- return;
22
- }
23
-
24
- // Create HTML with existing image
25
- const htmlContent = `
26
- <!DOCTYPE html>
27
- <html>
28
- <head>
29
- <title>Test with existing image</title>
30
- <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
31
- </head>
32
- <body>
33
- <h1>Test Report with Existing Image</h1>
34
- <img src="${testImagePath}" alt="Test Image" width="100" height="100">
35
- <p>This image should be converted to base64 or HTTP link.</p>
36
- </body>
37
- </html>`;
38
-
39
- // Test 1: Without serverBaseUrl (should convert to base64)
40
- console.log('\n--- Test 1: Convert to base64 ---');
41
- const outputPath1 = path.resolve('.', 'test_base64.html');
42
- const result1 = await generateReport(htmlContent, outputPath1);
43
-
44
- const generatedContent1 = fs.readFileSync(outputPath1, 'utf8');
45
- if (generatedContent1.includes('data:image')) {
46
- console.log('✅ SUCCESS: Image converted to base64');
47
- } else {
48
- console.log('❌ FAILED: Image not converted to base64');
49
- }
50
-
51
- // Test 2: With serverBaseUrl (should create HTTP link)
52
- console.log('\n--- Test 2: Convert to HTTP link ---');
53
- const outputPath2 = path.resolve('.', 'test_http_link.html');
54
- const serverBaseUrl = 'http://localhost:3000/reports';
55
- const result2 = await generateReport(htmlContent, outputPath2, serverBaseUrl);
56
-
57
- const generatedContent2 = fs.readFileSync(outputPath2, 'utf8');
58
- if (generatedContent2.includes(serverBaseUrl)) {
59
- console.log('✅ SUCCESS: Image converted to HTTP link');
60
- } else if (generatedContent2.includes('data:image')) {
61
- console.log('ℹ️ INFO: Image converted to base64 (fallback)');
62
- } else {
63
- console.log('❌ FAILED: Image not processed correctly');
64
- }
65
-
66
- // Clean up test image
67
- try {
68
- fs.unlinkSync(testImagePath);
69
- console.log('✅ Cleaned up test image');
70
- } catch (error) {
71
- console.log('⚠️ Could not clean up test image:', error.message);
72
- }
73
-
74
- console.log('\n✅ All tests completed!');
75
- }
76
-
77
- testWithExistingImage().catch(console.error);