This commit is contained in:
root
2025-10-13 18:05:00 +05:00
parent 49befe21e4
commit 89ab124664
2 changed files with 102 additions and 16 deletions
@@ -185,24 +185,32 @@ public class OpenAiChartService {
return "Ты — эксперт по визуализации данных. На основе следующего JSON, сгенерируй полный и валидный SVG-код для диаграммы. "
+
"SVG должен быть стильным и читаемым, с подписями на русском языке. \n" +
"ВАЖНЫЕ ПРАВИЛА:\n" +
"1. Все значения атрибутов width, height, x, y, r должны быть ПОЛОЖИТЕЛЬНЫМИ числами (>= 0).\n" +
"2. Не добавляй никаких комментариев или объяснений.\n" +
"3. Верни ТОЛЬКО SVG-код, начиная с тега <svg> и заканчивая </svg>.\n\n" +
"КРИТИЧЕСКИ ВАЖНЫЕ ПРАВИЛА:\n" +
"1. ВСЕ значения атрибутов width, height, x, y, r ДОЛЖНЫ быть СТРОГО ПОЛОЖИТЕЛЬНЫМИ числами (> 0).\n"
+
"2. НИКОГДА не используй отрицательные значения в атрибутах элементов <rect>, <circle>, <ellipse> и других.\n"
+
"3. Для столбчатых диаграмм: y-координата = (высота_диаграммы - высота_столбца), высота столбца всегда > 0.\n"
+
"4. Проверь каждый элемент перед отправкой - отрицательные значения приведут к ошибке конвертации.\n"
+
"5. Не добавляй никаких комментариев или объяснений.\n" +
"6. Верни ТОЛЬКО SVG-код, начиная с тега <svg> и заканчивая </svg>.\n\n" +
"JSON с данными:\n---\n" +
json + "\n---";
} else {
return "You are a data visualization expert that generates clean, valid SVG code.\n" +
"Based on the following JSON, generate a complete and valid SVG code for a bar chart.\n\n" +
"IMPORTANT RULES:\n" +
"CRITICAL RULES - FOLLOW EXACTLY:\n" +
"1. The SVG coordinate system starts with (0,0) in the TOP-LEFT corner. The Y-axis points DOWN.\n" +
"2. Therefore, to draw a bar upwards from the bottom, the 'y' attribute of the <rect> must be calculated as (chart_height - bar_height), and the 'height' attribute must ALWAYS be a POSITIVE number.\n"
"2. For bar charts: y-coordinate = (chart_height - bar_height), height attribute must ALWAYS be POSITIVE (> 0).\n"
+
"3. All dimensional attributes (width, height, x, y, r) MUST be POSITIVE numbers (>= 0).\n" +
"4. The chart must be visually appealing, with appropriate padding, colors, and English labels.\n" +
"5. Double-check your final SVG code to ensure no height or width attributes are negative.\n" +
"6. Return ONLY the raw SVG code, starting with <svg> and ending with </svg>. Do not include any explanations or markdown.\n\n"
"3. ALL dimensional attributes (width, height, x, y, r) MUST be POSITIVE numbers (> 0).\n" +
"4. NEVER use negative values in any element attributes - this will cause conversion errors.\n" +
"5. Double-check every <rect>, <circle>, <ellipse> element for positive values.\n" +
"6. The chart must be visually appealing, with appropriate padding, colors, and English labels.\n" +
"7. Return ONLY the raw SVG code, starting with <svg> and ending with </svg>. No explanations or markdown.\n\n"
+
"JSON data:\n---\n" +
@@ -3,6 +3,8 @@ package kz.konturai.parser.util;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.nio.charset.StandardCharsets;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.batik.transcoder.TranscoderInput;
import org.apache.batik.transcoder.TranscoderOutput;
@@ -12,6 +14,13 @@ import java.io.InputStream;
public class SvgToPngConverter {
// Регулярные выражения для поиска и исправления отрицательных значений
private static final Pattern HEIGHT_PATTERN = Pattern.compile("height\\s*=\\s*[\"']([^\"']*)[\"']");
private static final Pattern WIDTH_PATTERN = Pattern.compile("width\\s*=\\s*[\"']([^\"']*)[\"']");
private static final Pattern Y_PATTERN = Pattern.compile("y\\s*=\\s*[\"']([^\"']*)[\"']");
private static final Pattern X_PATTERN = Pattern.compile("x\\s*=\\s*[\"']([^\"']*)[\"']");
private static final Pattern R_PATTERN = Pattern.compile("r\\s*=\\s*[\"']([^\"']*)[\"']");
/**
* Преобразует строку с SVG-кодом в массив байт PNG-изображения.
*
@@ -24,21 +33,24 @@ public class SvgToPngConverter {
}
try {
// 1. Создаем транскодер для PNG
// 1. Санитизируем SVG код перед конвертацией
String sanitizedSvg = sanitizeSvg(svgCode);
// 2. Создаем транскодер для PNG
PNGTranscoder transcoder = new PNGTranscoder();
// 2. Устанавливаем входные данные (наш SVG-код)
InputStream inputStream = new ByteArrayInputStream(svgCode.getBytes(StandardCharsets.UTF_8));
// 3. Устанавливаем входные данные (наш SVG-код)
InputStream inputStream = new ByteArrayInputStream(sanitizedSvg.getBytes(StandardCharsets.UTF_8));
TranscoderInput input = new TranscoderInput(inputStream);
// 3. Устанавливаем, куда будет записан результат (в байтовый массив в памяти)
// 4. Устанавливаем, куда будет записан результат (в байтовый массив в памяти)
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
TranscoderOutput output = new TranscoderOutput(outputStream);
// 4. Запускаем процесс конвертации
// 5. Запускаем процесс конвертации
transcoder.transcode(input, output);
// 5. Получаем результат
// 6. Получаем результат
outputStream.flush();
return outputStream.toByteArray();
@@ -48,4 +60,70 @@ public class SvgToPngConverter {
return null;
}
}
/**
* Санитизирует SVG код, исправляя отрицательные значения в атрибутах.
*
* @param svgCode Исходный SVG код
* @return Санитизированный SVG код
*/
private static String sanitizeSvg(String svgCode) {
if (svgCode == null || svgCode.isBlank()) {
return svgCode;
}
String result = svgCode;
// Исправляем отрицательные значения height
result = fixNegativeValues(result, HEIGHT_PATTERN, "height");
// Исправляем отрицательные значения width
result = fixNegativeValues(result, WIDTH_PATTERN, "width");
// Исправляем отрицательные значения y
result = fixNegativeValues(result, Y_PATTERN, "y");
// Исправляем отрицательные значения x
result = fixNegativeValues(result, X_PATTERN, "x");
// Исправляем отрицательные значения r (радиус)
result = fixNegativeValues(result, R_PATTERN, "r");
return result;
}
/**
* Исправляет отрицательные значения в указанном атрибуте.
*
* @param svgCode SVG код
* @param pattern Регулярное выражение для поиска атрибута
* @param attributeName Название атрибута для логирования
* @return Исправленный SVG код
*/
private static String fixNegativeValues(String svgCode, Pattern pattern, String attributeName) {
Matcher matcher = pattern.matcher(svgCode);
StringBuffer result = new StringBuffer();
while (matcher.find()) {
String value = matcher.group(1);
try {
// Пытаемся распарсить значение как число
double numValue = Double.parseDouble(value.trim());
if (numValue < 0) {
// Заменяем отрицательное значение на 0
String replacement = matcher.group(0).replace(value, "0");
matcher.appendReplacement(result, replacement);
System.out.println("Исправлено отрицательное значение " + attributeName + ": " + value + " -> 0");
} else {
matcher.appendReplacement(result, matcher.group(0));
}
} catch (NumberFormatException e) {
// Если не удается распарсить как число, оставляем как есть
matcher.appendReplacement(result, matcher.group(0));
}
}
matcher.appendTail(result);
return result.toString();
}
}