Всем привет, я Григорий Тумаков, CTO в Моризо Диджитал.
Недавно рассказал, как мы в компании «потрогали» нейросети для прикладных задач разработки. Но там никаких серьезных выводов сделать не удалось.
Поэтому решил на этом не останавливаться. Если есть инструменты — их надо протестировать на какой-то реальной задаче.
Далее в статье мой опыт сравнения для прикладной задачи трех AI-инструментов: Phind, ChatGPT, Machinet.
Идея и промпт
Создай страницу с использованием JS и html для получения погоды по названию города. На странице должна быть форма заполнения названия города, кнопка "Узнать погоду". Не забудь учесть проблемы с CORS.
Работать это должно таким образом:
Пользователь вводит название города.
По названию города нужно запросить долготу и широту по этому API
curl -X POST
-H "Content-Type: application/json"
-H "Accept: application/json"
-H "Authorization: Token {API_TOKEN}"
-H "X-Secret: {SECRET_TOKEN}"
-d '[ "{Название города}" ]'
https://cleaner.dadata.ru/api/v1/clean/address
Далее долготу и широту необходимо подставить в запрос - https://api.openweathermap.org/data/2.5/weather?lat={lat}&lon={lon}&appid={API key}
Вывести результат обращения к API.
Для сравнения я загрузил промпт в каждую из трех нейросетей.
Рассказываю, что получилось.
ChatGPT
*Вот пример кода HTML и JavaScript, который реализует описанную вами функциональность:*
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Получить погоду</title> </head> <body> <h2>Узнать погоду</h2> <form id="weatherForm"> <label for="cityInput">Введите название города:</label><br> <input type="text" id="cityInput" name="cityInput"><br> <button type="submit">Узнать погоду</button> </form> <div id="weatherResult"></div>
<script> document.getElementById('weatherForm').addEventListener('submit', function(event) { event.preventDefault(); // Prevent default form submission var city = document.getElementById('cityInput').value.trim(); if (city === '') { alert('Пожалуйста, введите название города.'); return; } fetchCoordinates(city) .then(function(coordinates) { return fetchWeather(coordinates.lat, coordinates.lon); }) .then(function(weather) { displayWeather(weather); }) .catch(function(error) { console.error('Произошла ошибка:', error); }); });
function fetchCoordinates(city) { var apiToken = '{API_TOKEN}'; var secretToken = '{SECRET_TOKEN}'; return fetch('https://cleaner.dadata.ru/api/v1/clean/address', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', 'Authorization': 'Token ' + apiToken, 'X-Secret': secretToken }, body: JSON.stringify([city]) }) .then(function(response) { if (!response.ok) { throw new Error('Ошибка при получении координат города.'); } return response.json(); }) .then(function(data) { var coordinates = data[0].geo_lat && data[0].geo_lon ? { lat: data[0].geo_lat, lon: data[0].geo_lon } : null; if (!coordinates) { throw new Error('Координаты для указанного города не найдены.'); } return coordinates; }); }
function fetchWeather(lat, lon) { var apiKey = '{API_KEY}'; return fetch(`https://api.openweathermap.org/data/2.5/weather?lat=${lat}&lon=${lon}&appid=${apiKey}`) .then(function(response) { if (!response.ok) { throw new Error('Ошибка при получении данных о погоде.'); } return response.json(); }); }
function displayWeather(weather) { var weatherResultDiv = document.getElementById('weatherResult'); weatherResultDiv.innerHTML = ''; var cityName = weather.name; var weatherDescription = weather.weather && weather.weather[0] ? weather.weather[0].description : ''; var temperature = weather.main && weather.main.temp ? Math.round(weather.main.temp - 273.15) : ''; var weatherInfo = document.createElement('p'); weatherInfo.textContent = `Погода в городе ${cityName}: ${weatherDescription}, Температура: ${temperature}°C`; weatherResultDiv.appendChild(weatherInfo); } </script> </body> </html> |
*Пожалуйста, обратите внимание, что вы должны заменить `{API_TOKEN}`, `{SECRET_TOKEN}` и `{API_KEY}` на свои реальные значения. Кроме того, помните, что без использования сервера для обхода CORS вы можете столкнуться с проблемами безопасности при попытке выполнить этот код в браузере.*
Очевидно, что этот код не выведет нам результат, мы получим ошибку CORS.
Поэтому я попросил придумать решение этой проблемы.
Вот, что предложил ChatGPT
*Чтобы обойти ошибку CORS при обращении к API с клиентской стороны, можно воспользоваться серверной прокси. Например, можно создать простой сервер с использованием Node.js, который будет проксировать запросы к API `cleaner.dadata.ru` и передавать результат обратно на клиент.*
*Вот пример кода для сервера на Node.js:*
const express = require('express'); const fetch = require('node-fetch'); const cors = require('cors');
const app = express(); const PORT = process.env.PORT || 3000;
app.use(cors());
app.post('/getCoordinates', async (req, res) => { try { const cityName = req.body.cityName; const response = await fetch('https://cleaner.dadata.ru/api/v1/clean/address', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', 'Authorization': 'Token {API_TOKEN}', 'X-Secret': '{SECRET_TOKEN}' }, body: JSON.stringify([cityName]) });
const data = await response.json(); const coordinates = data[0].geo_lat && data[0].geo_lon ? { lat: data[0].geo_lat, lon: data[0].geo_lon } : null;
if (coordinates) { res.json(coordinates); } else { res.status(404).json({ error: 'Coordinates not found for the provided city name' }); } } catch (error) { console.error('Error:', error); res.status(500).json({ error: 'Internal Server Error' }); } });
app.listen(PORT, () => { console.log(`Server is running on port ${PORT}`); }); |
*Изменения в коде:*
1. *Добавлена библиотека `express` для создания сервера.*
2. *Добавлена библиотека `node-fetch` для выполнения HTTP запросов на сервере.*
3. *Добавлена библиотека `cors` для обработки CORS политики.*
4. *Создан маршрут `/getCoordinates`, который принимает POST запрос с именем города, отправляет запрос к API `cleaner.dadata.ru` через сервер, получает координаты города и отправляет их обратно клиенту.*
*На стороне клиента теперь нужно обратиться к серверу для получения координат города, затем использовать полученные координаты для запроса погоды к API `api.openweathermap.org`.*
<html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Weather App</title> </head> <body> <h1>Weather App</h1> <form id="cityForm"> <label for="cityName">Enter city name:</label> <input type="text" id="cityName" name="cityName"> <button type="submit">Get Weather</button> </form> <div id="weatherData"></div>
<script> document.getElementById('cityForm').addEventListener('submit', async (event) => { event.preventDefault(); const cityName = document.getElementById('cityName').value; const response = await fetch('http://localhost:3000/getCoordinates', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ cityName }) });
const data = await response.json();
if (data.error) { document.getElementById('weatherData').textContent = data.error; } else { const weatherResponse = await fetch(`https://api.openweathermap.org/data/2.5/weather?lat=${data.lat}&lon=${data.lon}&appid={API key}`); const weatherData = await weatherResponse.json(); document.getElementById('weatherData').textContent = JSON.stringify(weatherData, null, 2); } }); </script> </body> </html> |
*Теперь клиентский JavaScript делает запрос к серверу для получения координат города, затем использует эти координаты для запроса погоды к API `api.openweathermap.org`.*
К сожалению, снова получаю ошибку.
Error [ERR_REQUIRE_ESM]: require() of ES Module .../ai/chat-gpt/node_modules/node-fetch/src/index.js from .../ai/chat-gpt/server.js not supported. Instead change the require of index.js in .../ai/chat-gpt/server.js to a dynamic import() which is available in all CommonJS modules. at Object.<anonymous> (.../ai/chat-gpt/server.js:50:15) { code: 'ERR_REQUIRE_ESM' }
Прошу поправить и получаю новый блок кода, с указанием необходимости установки axios.
const express = require('express'); const axios = require('axios'); const cors = require('cors');
const app = express(); const PORT = process.env.PORT || 3000;
app.use(cors()); app.use(express.json());
app.post('/getCoordinates', async (req, res) => { try { const cityName = req.body.cityName; const response = await axios.post('https://cleaner.dadata.ru/api/v1/clean/address', [cityName], { headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', 'Authorization': 'Token {API_TOKEN}', 'X-Secret': '{SECRET_TOKEN}' } });
const data = response.data; const coordinates = data[0].geo_lat && data[0].geo_lon ? { lat: data[0].geo_lat, lon: data[0].geo_lon } : null;
if (coordinates) { res.json(coordinates); } else { res.status(404).json({ error: 'Coordinates not found for the provided city name' }); } } catch (error) { console.error('Error:', error); res.status(500).json({ error: 'Internal Server Error' }); } });
app.listen(PORT, () => { console.log(`Server is running on port ${PORT}`); }); |
И наконец получаю нужный результат, приложение работает
Попрошу отформатировать полученный ответ от API.
*Выведи красиво ответ от API, чтобы было понятно какая сейчас погода, скорость ветра и так далее*
Phind
Загружаю промпт и сразу вижу различия в результате. Phind предпочел разделить html и js код в разные файлы, что радует.
К сожалению, не получаю работающую программу с первого запроса, поэтому прошу добавить веб-сервер для обхода проблемы с CORS. Вижу, что Phind дает более развернутые ответы и предлагает несколько вариантов.
Пробую сначала первый вариант. Спрашиваю, как его использовать, и получаю достаточно подробную инструкцию.
После изменения кода пробую запустить сервер, но получаю уже знакомую ошибку.
```
Error [ERR_REQUIRE_ESM]: require() of ES Module .../ai/chat-gpt/node_modules/node-fetch/src/index.js from .../ai/chat-gpt/server.js not supported. Instead change the require of index.js in .../ai/chat-gpt/server.js to a dynamic import() which is available in all CommonJS modules. at Object.<anonymous> (.../ai/chat-gpt/server.js:50:15) { code: 'ERR_REQUIRE_ESM' }
```
Прошу исправить ошибку и получаю ответ, который значительно лучше по сравнению с ChatGPT, он подробный и в нем объясняется проблема.
Пробую использовать предложенное решение — все работает.
Прошу красиво вывести ответ от апи, чтобы было понятно, какая погода, ветер и т.д.
Правлю код и пробую получить данные.
Теперь тестирую второй предложенный вариант. Применяю изменения, запускаю.
Но выходит ошибка — прошу ее исправить.
Снова получаю развернутый ответ с объяснением ошибки и несколькими решениями, но теперь уже знаю, что первое решение поможет, поэтому не продолжаю.
Machinet
Загружаю промпт, получаю ответ:
*Хорошо, я могу помочь вам создать страницу для получения погоды по названию города с использованием JavaScript и HTML. Для начала, вам понадобится создать HTML-разметку для страницы. Вот пример кода:*
<!DOCTYPE html> <html> <head> <title>Получение погоды</title> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> </head> <body> <h1>Получение погоды по названию города</h1> <form id="weatherForm"> <label for="cityInput">Введите название города:</label> <input type="text" id="cityInput" required> <button type="submit">Узнать погоду</button> </form> <div id="weatherResult"></div>
<script> // Обработчик события отправки формы $("#weatherForm").submit(function(event) { event.preventDefault(); // Предотвращаем отправку формы
var city = $("#cityInput").val(); // Получаем значение поля ввода
// Запрос для получения долготы и широты $.ajax({ url: "https://cleaner.dadata.ru/api/v1/clean/address", type: "POST", headers: { "Content-Type": "application/json", "Accept": "application/json", "Authorization": "Token {API_TOKEN}", "X-Secret": "{SECRET_TOKEN}" }, data: JSON.stringify([city]), success: function(response) { var latitude = response[0].geo_lat; var longitude = response[0].geo_lon;
// Запрос для получения погоды $.ajax({ url: "https://api.openweathermap.org/data/2.5/weather", type: "GET", data: { lat: latitude, lon: longitude, appid: "{API key}" }, success: function(weatherData) { // Выводим результат обращения к API $("#weatherResult").html("Текущая погода в городе " + city + ": " + weatherData.weather[0].description); }, error: function() { $("#weatherResult").html("Ошибка при получении погоды"); } }); }, error: function() { $("#weatherResult").html("Ошибка при получении координат города"); } }); }); </script> </body> </html> |
*В этом примере мы используем jQuery для упрощения работы с AJAX-запросами. При отправке формы, мы сначала отправляем запрос на получение долготы и широты города с помощью API от Dadata, а затем используем полученные координаты для запроса погоды с помощью API от OpenWeatherMap. Результат выводится в элементе с id "weatherResult".*
*Обратите внимание, что вам нужно будет заменить {API_TOKEN}, {SECRET_TOKEN} и {API key} на соответствующие значения, полученные при регистрации на соответствующих сервисах.*
Пробую запустить код и выполнить запрос. Снова получаю ошибку CORS, прошу исправить, используя тот же текст, что и в предыдущих нейросетях — и получаю интересный ответ.
Выбираю второй подход.
Пробую запустить сервер и получаю ошибку.
app.use(corsAnywhere({ ^ TypeError: corsAnywhere is not a function |
Прошу исправить.
После исправлений сервер действительно запустился. Но при выполнении запроса получаю новую ошибку, снова прошу ее исправить.
Применяю изменения и пробую выполнить запрос еще раз, но снова получаю ошибку.
Пробую дать больше информации об ошибке.
К сожалению, не получаю никакого решения, только рекомендации. Здесь нет смысла дальше продолжать.
Результаты
Хуже всех с поставленной задачей справилась Machinet, ей не удалось выдать работающего решения. Возможно, на более простых задачах она сможет помочь.
Если же выбирать из ChatGPT и Phind, то я бы предпочел Phind, поскольку она давала более развернутые ответы и предлагала больше вариантов решения задач.