Практическое применение ИИ в платформе Aggregate

Всем привет. Меня зовут Сергей, я основатель независимого сообщества разработчиков на Low-code платформе Tibbo Aggregate (Платформа).

В этой статье я покажу как на практике можно применить генеративные ИИ для создания Java скриптов и встроить их Платформу.

Постановка задачи

Решим задачу определения вхождения точки на поверхности земли в круглую геозону, заданную координатой центра и радиусом в метрах.

Для визуализации и ручного тестирования функции создадим:

  • абсолютную модель geoUtils, в которой реализуем функцию checkPointInCircle
  • дашборд geoTest, в котором будет карта, кнопка генерации круга случайного радиуса, и лейбл в который будет записанаинформация о вхождении произвольной точки в зону

Реализация контекстов

Java код функции users.admin.models.geoUtils.checkPointInCircle() пока реализуем в виде заглушки следующего вида:

import com.tibbo.aggregate.common.context.*; import com.tibbo.aggregate.common.datatable.*; import com.tibbo.aggregate.common.server.*; import com.tibbo.linkserver.*; import com.tibbo.linkserver.context.*; //Дополнительный импорт класса Math import java.lang.Math; public class %ScriptClassNamePattern% implements FunctionImplementation { public DataTable execute(Context con, FunctionDefinition def, CallerController caller, RequestController request, DataTable parameters) throws ContextException { //Чтение параметров из входной таблицы double latitudeC = parameters.rec().getDouble("latitudeC"); double longitudeC = parameters.rec().getDouble("longitudeC"); double radius = parameters.rec().getDouble("radius"); double latitudeP = parameters.rec().getDouble("latitudeP"); double longitudeP = parameters.rec().getDouble("longitudeP"); //Генерация случайного значение TRUE / FALSE boolean inside = Math.random() > 0.5; //Создаём "пустой" формат выходной таблицы TableFormat resultFormat = new TableFormat(); //Добавляем в выходной формат поле <inside><B> resultFormat.addField(FieldFormat.create("inside", 'B')); //Создаём выходную таблицу заданного формама DataTable resultTable = new SimpleDataTable(resultFormat); //Добавляем в таблицу строку с результатом resultTable.addRecord().addBoolean(inside); return resultTable; } }

Создаём дашборд users.admin.dashboards.geoTest и добавляем на него карту, кнопку и лейбл.

Тестовый дашборд
Тестовый дашборд

Привязка генерации круглой зоны произвольного радиуса

Цель:

form/map0:circleAreas

Выражение:

table( "<<id><S><F=K><A=><D=ID>><<description><S><F=N><A=<NULL>><D=Description>><<latitude><E><F=N><A=0.0><D=Latitude>><<longitude><E><F=N><A=0.0><D=Longitude>><<radius><I><F=N><A=100><D=Radius>><<layerId><S><A=><D=Layer>><<circleAreaStyleId><S><A=><D=Style>><V=<K=>>" ,0 ,"Круглая зона" ,56 ,38 ,1000 + random()*1000 )

Активатор:

form/button0:mouseClicked@

Отображение маркера при клике

Цель:

form/map0:markers

Выражение:

table( "<<id><S><F=K><A=><D=ID>><<layerId><S><A=><D=Layer>><<latitude><E><F=N><A=0.0><D=Latitude>><<longitude><E><F=N><A=0.0><D=Longitude>><<riseOnHover><B><F=N><A=0><D=Rise On Hover>><<riseOffset><I><F=N><A=250><D=Z-index Rise Offset>><<draggable><B><F=N><A=0><D=Draggable>><<popupOptions><T><F=N><A=<F=<<popupContent><S><A=><D=Content><E=code><O=html>><<className><S><F=N><A=<NULL>><D=Class Name>><<activationEvent><S><F=N><A=click><D=Activation Event><S=<Click=click><Hover=hover>>><<closeButton><B><F=N><A=1><D=Close Button>><<autoClose><B><F=N><A=1><D=Auto Close>><<closeOnEscapeKey><B><F=N><A=1><D=Close On Escape>><<closeOnClick><B><F=N><A=0><D=Close On Click>><X=1>>><D=Popup Options>><<tooltipOptions><T><F=N><A=<F=<<tooltipContent><S><F=N><A=<NULL>><D=Content><E=code><O=html>><<className><S><F=N><A=<NULL>><D=Class Name>><<direction><S><F=N><A=auto><D=Direction><S=<Auto=auto><Right=right><Left=left><Top=top><Bottom=bottom><Center=center>>><<permanent><B><F=N><A=0><D=Permanent Visible>><<sticky><B><F=N><A=0><D=Stick>><X=1>>><D=Tooltip Options>><<markerStyleId><S><A=><D=Style>><V=<K=>>" ,0 ,"" ,cell({env/value},"latitude") ,cell({env/value},"longitude") )

Активатор:

form/map0:mouseClicked@

Запись результата вычисления users.admin.models.geoUtils.checkPointInCircle() в label0

Цель:

form/label0:text

Выражение:

callFunction( "users." + substring({env/alias},6,index({env/alias}, ".dashboards.")) + ".models.geoUtils" ,"checkPointInCircle" ,{form/map0:circleAreas$latitude} ,{form/map0:circleAreas$longitude} ,{form/map0:circleAreas$radius} ,cell({env/value},"latitude") ,cell({env/value},"longitude") ) ? "Внутри" : "Снаружи"

Активатор:

form/map0:mouseClicked@

В результате получаем рабочих дашборд, со случайным ответом о вхождении точки.

Дашборд с заглушками

Генерация кода Java скрипта

В данном примере буду пользоваться Китайским чат ботом:

Результат в исходном виде:
Результат в исходном виде:
public class GeoZoneChecker { public static boolean isPointInGeoZone(double centerLat, double centerLon, double radiusMeters, double pointLat, double pointLon) { final double EARTH_RADIUS = 6371e3; // Радиус Земли в метрах // Конвертация градусов в радианы double lat1Rad = Math.toRadians(centerLat); double lon1Rad = Math.toRadians(centerLon); double lat2Rad = Math.toRadians(pointLat); double lon2Rad = Math.toRadians(pointLon); // Разница координат double deltaLat = lat2Rad - lat1Rad; double deltaLon = lon2Rad - lon1Rad; // Вычисление по формуле гаверсинусов double a = Math.sin(deltaLat / 2) * Math.sin(deltaLat / 2) + Math.cos(lat1Rad) * Math.cos(lat2Rad) * Math.sin(deltaLon / 2) * Math.sin(deltaLon / 2); double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); double distance = EARTH_RADIUS * c; return distance <= radiusMeters; } // Пример использования public static void main(String[] args) { double centerLat = 55.751244; // Широта центра double centerLon = 37.618423; // Долгота центра double radius = 1000; // Радиус 1 км double testLat = 55.751245; double testLon = 37.618424; boolean isInside = isPointInGeoZone(centerLat, centerLon, radius, testLat, testLon); System.out.println("Точка в геозоне: " + isInside); } }

Теперь вносим минимальные правки в исходный код с учётом наших входных и выходных форматов, и получаем реализацию функции checkPointInCircle() следующего вида:

import com.tibbo.aggregate.common.context.*; import com.tibbo.aggregate.common.datatable.*; import com.tibbo.aggregate.common.server.*; import com.tibbo.linkserver.*; import com.tibbo.linkserver.context.*; //Дополнительный импорт класса Math import java.lang.Math; public class %ScriptClassNamePattern% implements FunctionImplementation { public DataTable execute(Context con, FunctionDefinition def, CallerController caller, RequestController request, DataTable parameters) throws ContextException { final double EARTH_RADIUS = 6371e3; // Радиус Земли в метрах //Чтение параметров из входной таблицы double centerLat = parameters.rec().getDouble("latitudeC"); double centerLon = parameters.rec().getDouble("longitudeC"); double radius = parameters.rec().getDouble("radius"); double testLat = parameters.rec().getDouble("latitudeP"); double testLon = parameters.rec().getDouble("longitudeP"); //Генерация случайного значение TRUE / FALSE boolean inside = isPointInGeoZone(centerLat, centerLon, radius, testLat, testLon); //Создаём "пустой" формат выходной таблицы TableFormat resultFormat = new TableFormat(); //Добавляем в выходной формат поле <inside><B> resultFormat.addField(FieldFormat.create("inside", 'B')); //Создаём выходную таблицу заданного формама DataTable resultTable = new SimpleDataTable(resultFormat); //Добавляем в таблицу строку с результатом resultTable.addRecord().addBoolean(inside); return resultTable; } public static boolean isPointInGeoZone(double centerLat, double centerLon, double radiusMeters, double pointLat, double pointLon) { final double EARTH_RADIUS = 6371e3; // Радиус Земли в метрах // Конвертация градусов в радианы double lat1Rad = Math.toRadians(centerLat); double lon1Rad = Math.toRadians(centerLon); double lat2Rad = Math.toRadians(pointLat); double lon2Rad = Math.toRadians(pointLon); // Разница координат double deltaLat = lat2Rad - lat1Rad; double deltaLon = lon2Rad - lon1Rad; // Вычисление по формуле гаверсинусов double a = Math.sin(deltaLat / 2) * Math.sin(deltaLat / 2) + Math.cos(lat1Rad) * Math.cos(lat2Rad) * Math.sin(deltaLon / 2) * Math.sin(deltaLon / 2); double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); double distance = EARTH_RADIUS * c; return distance <= radiusMeters; } }

Как Вы можете видеть, правка фактически заключается только в замене имён переменных внутри функции.

Проверяем результат

Проверка вхождения точки в круглую зону

Заключение

По моему мнению сочетание Low-code + Генеративных ИИ это перспективное направление для создания B2C и B2B приложений "общего" назначения.

Разработка данной конфигуркации при наличии опыта работы на Платформе укладывается в 10 - 15 минут.

Желаю всем успехов в применении современных технологий в своей работе!

Начать дискуссию