.
This commit is contained in:
@@ -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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user