Любой программист, часто работающий с API, может сэкономить массу времени, если использует ChatGPT для автоматизации преобразования JSON в интерфейсы Typescript. 

Зачем это нужно

API — удобный и универсальный способ наладить взаимодействие с сайтом или другим веб-приложением. Основная проблема при написании кода обычно заключается в том, он должен быть уведомлен об ответе. Но в результате обращения к API вы не получаете завершения.

У этой проблемы есть два основных варианта решения:

  1. Отправить запрос, получить результат и отобразить его в интерфейсах.

  2. Найти результат в документации веб-сайта (если она есть) и отобразить его в интерфейсах.

Но гораздо более простое решение — отправить данные в формате JSON и вернуть интерфейс в Typescript.

Это можно сделать с помощью специальных библиотек преобразования JSON в Typescript, но я собираюсь использовать для этой операции ChatGPT, потому что так гораздо интереснее. Я создал репозиторий с полным кодом для преобразования JSON в Typescript — не стесняйтесь клонировать и использовать его.

Что такое ChatGPT

ChatGPT — это языковая модель искусственного интеллекта, обученная OpenAI для генерации текста и взаимодействия с пользователями в разговорной манере, похожей на человеческую. Пользователи могут отправлять запросы на естественном языке и получать краткую информацию или развернутые ответы по широкому кругу тем всего за несколько секунд.

ChatGPT также помогает писать, отлаживать и объяснять фрагменты кода. В настоящее время сервис ChatGPT открыт для публичного использования. Поэтому в этом руководстве, мы будем использовать его API для создания конвертера JSON в Typescript.

Во сколько это обойдется

Если брать за основу стоимость одного запроса к API обычного Chat GPT (gpt-3.5-turbo), то, согласно данным TechCrunch, она составит 0.002 доллара за 1 000 токенов или 750 слов. Месячная подписка на коммерческий вариант ChatGPT Plus, включающая «безлимит» обойдется уже в 20 долларов.

Настройка проекта

Для начала я расскажу вам, как создать среду проекта для веб-приложения. Мы будем использовать React.js для внешнего интерфейса и Node.js для внутреннего сервера.

Создайте папку проекта для веб-приложения, выполнив приведенный ниже код:

mkdir json-to-typescript
cd json-to-typescript
mkdir client server

Настройка сервера Node.js

Перейдите в папку сервера и создайте файл «package.json».

cd server & npm init -y

Установите Express, Nodemon и библиотеку CORS:

  • ExpressJS — быстрая минималистичная среда, предоставляющая несколько функций для создания веб-приложений на Node.js.

  • CORS — это пакет Node.js, который обеспечивает связь между различными доменами.

  • Nodemon — инструмент Node.js, который автоматически перезапускает сервер после обнаружения изменений файлов.

npm install express cors nodemon

Создайте файл «index.js» — точку входа на веб-сервер.

touch index.js

Настройте сервер Node.js с помощью Express.js. Приведенный ниже фрагмент кода возвращает объект JSON при посещении «http://localhost:4000/api» в браузере.

//????????index.js
const express = require("express");
const cors = require("cors");
const app = express();
const PORT = 4000;

app.use(express.urlencoded({ extended: true }));
app.use(express.json());
app.use(cors());

app.get("/api", (req, res) => {
    res.json({
        message: "Hello world",
    });
});

app.listen(PORT, () => {
    console.log(`Server listening on ${PORT}`);
});

Настройте Nodemon, добавив команду start в список скриптов в файле «package.json». Приведенный ниже фрагмент кода запускает сервер с помощью Nodemon.

//In server/package.json

"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "nodemon index.js"
  },

Поздравляем! Теперь вы можете запустить сервер, используя команду ниже.

npm start

Настройка приложения React

Перейдите в соответствующий клиент через терминал и создайте новый проект React.js.

cd client
npx create-react-app ./

Установите 2 библиотеки: 

  • Monaco Editor for React — простой пакет для добавления редакторов кода в приложения React.

  • React Copy to Clipboard — пакет, который позволяет нам копировать и вставлять содержимое одним нажатием кнопки.

npm install @monaco-editor/react react-copy-to-clipboard

Удалите избыточные файлы (например, логотип и тестовые файлы) из приложения React и обновите файл «App.js», чтобы он отображал «Hello World», как показано ниже.

function App() {
    return (
        <div>
            <p>Hello World!</p>
        </div>
    );
}
export default App;

Перейдите в файл «src/index.css» и скопируйте приведенный ниже код. Он содержит весь код CSS, необходимый для описания внешнего вида веб-страниц в этом проекте.

@import url("https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300;400;500;600;700&display=swap");

* {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
    font-family: "Space Grotesk", sans-serif;
}
.app {
    width: 100%;
    min-height: 100vh;
}
.loading {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 100vh;
}
.header__container {
    width: 100%;
    display: flex;
    align-items: center;
    height: 10vh;
    background-color: #e0f2fe;
}
.header__right {
    display: flex;
    align-items: center;
}
.runBtn {
    padding: 10px 5px;
    width: 100px;
    margin-right: 10px;
    cursor: pointer;
    border: none;
    border-radius: 3px;
    box-shadow: 0 0 1px 1px #e0e0ea;
    background-color: #065f46;
    outline: none;
    color: #fff;
}
.header {
    border: 1px solid #ddd;
    padding: 10px 20px;
    border: 1px solid #e8e2e2;
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex: 0.5;
    height: 100%;
}
.code__container {
    display: flex;
    height: 95vh;
    width: 100%;
    align-items: flex-start;
}
.minimap {
    display: none;
}
.editor {
    padding: 10px 0px;
    width: 100%;
}
.code,
.output {
    width: 50vw;
}
.deleteIcon {
    height: 25px;
    color: #cf0a0a;
    cursor: pointer;
}
.copyIcon {
    height: 25px;
    color: #3e54ac;
    cursor: pointer;
}

Создание пользовательского интерфейса приложения

Здесь мы создадим пользовательский интерфейс для конвертера JSON в Typescript, чтобы пользователи могли добавлять объекты JSON в левой части экрана и просматривать результаты в Typescript в правой части экрана, как это показано ниже.

Для начала создайте папку иконок «icons» в папке «client/src». Папка будет содержать иконки удаления и копирования, как показано выше.

cd client/src
mkdir icons
cd icons
touch Copy.js Delete.js

Обновите файл «Copy.js», чтобы в нем начал отображаться значок SVG из Heroicons.

import React from "react";

const Copy = () => {
    return (
        <svg
            xmlns='http://www.w3.org/2000/svg'
            viewBox='0 0 24 24'
            fill='currentColor'
            className='w-6 h-6 copyIcon'
        >
            <path d='M7.5 3.375c0-1.036.84-1.875 1.875-1.875h.375a3.75 3.75 0 013.75 3.75v1.875C13.5 8.161 14.34 9 15.375 9h1.875A3.75 3.75 0 0121 12.75v3.375C21 17.16 20.16 18 19.125 18h-9.75A1.875 1.875 0 017.5 16.125V3.375z' />
            <path d='M15 5.25a5.23 5.23 0 00-1.279-3.434 9.768 9.768 0 016.963 6.963A5.23 5.23 0 0017.25 7.5h-1.875A.375.375 0 0115 7.125V5.25zM4.875 6H6v10.125A3.375 3.375 0 009.375 19.5H16.5v1.125c0 1.035-.84 1.875-1.875 1.875h-9.75A1.875 1.875 0 013 20.625V7.875C3 6.839 3.84 6 4.875 6z' />
        </svg>
    );
};

export default Copy;

Скопируйте приведенный ниже код в файл «Delete.js». Он отображает SVG-иконку кнопки удаления.

import React from "react";

const Delete = () => {
    return (
        <svg
            xmlns='http://www.w3.org/2000/svg'
            viewBox='0 0 24 24'
            fill='currentColor'
            className='w-6 h-6 deleteIcon'
        >
            <path
                fillRule='evenodd'
                d='M16.5 4.478v.227a48.816 48.816 0 013.878.512.75.75 0 11-.256 1.478l-.209-.035-1.005 13.07a3 3 0 01-2.991 2.77H8.084a3 3 0 01-2.991-2.77L4.087 6.66l-.209.035a.75.75 0 01-.256-1.478A48.567 48.567 0 017.5 4.705v-.227c0-1.564 1.213-2.9 2.816-2.951a52.662 52.662 0 013.369 0c1.603.051 2.815 1.387 2.815 2.951zm-6.136-1.452a51.196 51.196 0 013.273 0C14.39 3.05 15 3.684 15 4.478v.113a49.488 49.488 0 00-6 0v-.113c0-.794.609-1.428 1.364-1.452zm-.355 5.945a.75.75 0 10-1.5.058l.347 9a.75.75 0 101.499-.058l-.346-9zm5.48.058a.75.75 0 10-1.498-.058l-.347 9a.75.75 0 001.5.058l.345-9z'
                clipRule='evenodd'
            />
        </svg>
    );
};

export default Delete;

Обновите файл «App.js», как показано ниже, чтобы отобразить элементы заголовка веб-приложения.

import React from "react";
import Delete from "./icons/Delete";
import Copy from "./icons/Copy";

const App = () => {
    const handleSubmit = () => {
        console.log("Run Button Clicked");
    };

    return (
        <main className='app'>
            <header className='header__container'>
                <div className='header'>
                    <h3>JSON</h3>
                    <div className='header__right'>
                        <button className='runBtn' onClick={handleSubmit}>
                            RUN
                        </button>
                        <Delete />
                    </div>
                </div>

                <div className='header'>
                    <h3>Typescript</h3>
                    <Copy />
                </div>
            </header>

            <div className='code__container'></div>
        </main>
    );
};

export default App;

Добавление редактора кода Monaco в приложение React

Monaco — это популярный редактор кода на основе веб-технологий, который поддерживает VS Code. Для поддержки нескольких языков программирования в этом инструменте требуется всего лишь однострочная интеграция.

Импортируйте библиотеку, которую мы уже установили библиотеку в предыдущем разделе в файл «App.js», как показано ниже.

import React, { useState } from "react";
import Delete from "./icons/Delete";
import Copy from "./icons/Copy";
import Editor from "@monaco-editor/react";

const App = () => {
    const [value, setValue] = useState("");
    const [output, setOutput] = useState("");
    const handleSubmit = () => {
        console.log("Run Button Clicked");
    };

    return (
        <main className='app'>
            <header className='header__container'>
                <div className='header'>
                    <h3>JSON</h3>
                    <div className='header__right'>
                        <button className='runBtn' onClick={handleSubmit}>
                            RUN
                        </button>
                        <Delete />
                    </div>
                </div>

                <div>
                    <h3>Typescript</h3>
                    <Copy />
                </div>
            </header>

            <div className='code__container'>
                <div className='code'>
                    <Editor
                        height='90vh'
                        className='editor'
                        defaultLanguage='json'
                        defaultValue='{ }'
                        value={value}
                        onChange={(value) => setValue(value)}
                    />
                </div>
                <div className='output'>
                    <Editor
                        height='90vh'
                        className='editor'
                        defaultLanguage='typescript'
                        options={{
                            domReadOnly: true,
                            readOnly: true,
                        }}
                        defaultValue=''
                        value={output}
                        onChange={(value) => setOutput(value)}
                    />
                </div>
            </div>
        </main>
    );
};

export default App;

Последовательность действий в приведенном выше коде:

  • Импортирован компонент «Editor» из пакета Monaco Editor.

  • Первый компонент редактора принимает такие реквизиты, как высота, значение, язык и свойство события «onChange».

  • Второй компонент редактора принимает те же реквизиты, что и первый, но с дополнительным реквизитом, называемым «options», который не позволяет пользователям редактировать его значения, поскольку он доступен только для чтения.

Как общаться с ChatGPT в Node.js

В этом разделе вы узнаете, как взаимодействовать с ChatGPT через его API на сервере Node.js. Мы отправим код JSON, предоставленный пользователем, в API, чтобы преобразовать его в эквивалент в Typescript. Для этого следует выполнить приведенный ниже пошаговый алгоритм.

Для начала, установите библиотеку Node.js «OpenAI API», выполнив приведенный ниже код.

npm install openai

Войдите или создайте учетную запись OpenAI здесь.

Нажмите «Личный» (Personal) на панели навигации и выберите «Просмотреть ключи API» (View API keys) в строке меню, чтобы создать новый секретный ключ.

Скопируйте ключ API в безопасное место на своем компьютере — мы воспользуемся им в ближайшее время.

Для настройки API, скопируйте приведенный ниже код в файл «index.js». Замените в скопированном фрагменте значение «apiKey» своим ключом API.

Создайте на сервере маршрут POST, который будет принимать код JSON из внешнего интерфейса и включать его Typescript эквивалент.

app.post("/convert", async (req, res) => {
	let { value } = req.body;

	const prompt = `Convert the JSON object into Typescript interfaces \n ${value} Please, I need the only the code, I don't need any explanations.`;
	const completion = await openai.createChatCompletion({
		model: "gpt-3.5-turbo",
		messages: [{ role: "user", content: prompt }],
	});
	res.json({
		message: "Successful",
		response: completion.data.choices[0].message.content,
	});
});

Обновите функцию «handleSubmit» в файле «App.js», чтобы отправить объект JSON, предоставленный пользователем, в эндпойнт «/convert» на сервере.

const handleSubmit = () => {
    fetch("http://localhost:4000/convert", {
        method: "POST",
        body: JSON.stringify({
            value,
        }),
        headers: {
            "Content-Type": "application/json",
        },
    })
        .then((res) => res.json())
        .then((data) => {
            setOutput(data.response);
        })
        .catch((err) => console.error(err));
};

Обновите эндпойнт «/convert», как показано ниже.

Приведенный выше фрагмент кода выполняет несколько действий: 

  1. принимает объект JSON из приложения React; 

  2. создает приглашение с кодом JSON;

  3. отправляет его в API ChatGPT. 

Ответ, содержащий эквивалент кода Typescript, отправляется обратно клиенту.

Поскольку мы получили ответ от сервера Node.js, добавьте в приложение состояние загрузки, чтобы уведомлять пользователей о том, что их запрос находится на рассмотрении. Для этого создайте файл «Loading.js» и скопируйте в него приведенный ниже код.

import React from "react";

const Loading = () => {
    return (
        <div className='loading'>
            <h2>Loading...</h2>
        </div>
    );
};

export default Loading;

Добавьте состояние загрузки в файл «App.js».

const [loading, setLoading] = useState(false);

Обновите функцию «handleSubmit», чтобы обновлять состояние загрузки, когда пользователь нажимает кнопку «Выполнить» (Run) или когда запрос успешен.

const handleSubmit = () => {
    //???????? sets to true
    setLoading(true);
    fetch("http://localhost:4000/convert", {
        method: "POST",
        body: JSON.stringify({
            value,
        }),
        headers: {
            "Content-Type": "application/json",
        },
    })
        .then((res) => res.json())
        .then((data) => {
            //???????? sets to false
            setLoading(false);
            setOutput(data.response);
        })
        .catch((err) => console.error(err));
};

Проведите условный рендеринг второго редактора кода, содержащего выходные данные, как показано ниже.

return (
    <main className='app'>
        {/* -- other UI components --*/}
        <div className='code__container'>
            <div className='code'>
                <Editor
                    height='90vh'
                    className='editor'
                    defaultLanguage='json'
                    defaultValue='{ }'
                    value={value}
                    onChange={(value) => setValue(value)}
                />
            </div>

            <div className='output'>
                {loading ? (
                    <Loading />
                ) : (
                    <Editor
                        height='90vh'
                        className='editor'
                        defaultLanguage='typescript'
                        options={{
                            domReadOnly: true,
                            readOnly: true,
                        }}
                        defaultValue=''
                        value={output}
                        onChange={(value) => setOutput(value)}
                    />
                )}
            </div>
        </div>
    </main>
);

Когда пользователь отправляет объект JSON для преобразования, компонент «Загрузка» (Loading) отображается сразу до тех пор, пока запрос не будет успешно выполнен, а затем результат отображается в редакторе кода.

Поздравляем!  Приложение почти готово. 

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

Как скопировать код Typescript одним кликом

Из этого раздела вы узнаете, как копировать и вставлять контент  в один клик, используя библиотеку «React-copy-to-clipboard».

Вы уже установили нужный пакет в начале этого руководства. Теперь импортируйте его в файл «App.js», как показано ниже.

import { CopyToClipboard } from "react-copy-to-clipboard";

Создайте функцию, которая запускается после успешного копирования содержимого, в файле «App.js».

const copyToClipBoard = () => alert(`Copied ✅`);

Оберните компонент «CopyToClipboard» из пакета вокруг значка SVG, как показано ниже.

<CopyToClipboard text={output} onCopy={copyToClipBoard}>
    <span>
        <Copy />
    </span>
</CopyToClipboard>

Компонент «CopyToClipboard» принимает текстовый реквизит, содержащий копируемый контент, и реквизит «onCopy» — функцию, которая запускается при копировании содержимого.

Удаление всех введенных данных пользователя одним кликом

Чтобы удалить все введенные пользователем данные, передайте состояние значения в качестве свойства в компонент «<Delete/>».

<Delete setValue={setValue} />

Обновите состояние значения, когда пользователь щелкнет на значок удаления (Delete).

import React from "react";

const Delete = ({ setValue }) => {
    return (
        <svg
            xmlns='http://www.w3.org/2000/svg'
            viewBox='0 0 24 24'
            fill='currentColor'
            className='w-6 h-6 deleteIcon'
            onClick={() => setValue("{ }")}
        >
            <path
                fillRule='evenodd'
                d='M16.5 4.478v.227a48.816 48.816 0 013.878.512.75.75 0 11-.256 1.478l-.209-.035-1.005 13.07a3 3 0 01-2.991 2.77H8.084a3 3 0 01-2.991-2.77L4.087 6.66l-.209.035a.75.75 0 01-.256-1.478A48.567 48.567 0 017.5 4.705v-.227c0-1.564 1.213-2.9 2.816-2.951a52.662 52.662 0 013.369 0c1.603.051 2.815 1.387 2.815 2.951zm-6.136-1.452a51.196 51.196 0 013.273 0C14.39 3.05 15 3.684 15 4.478v.113a49.488 49.488 0 00-6 0v-.113c0-.794.609-1.428 1.364-1.452zm-.355 5.945a.75.75 0 10-1.5.058l.347 9a.75.75 0 101.499-.058l-.346-9zm5.48.058a.75.75 0 10-1.498-.058l-.347 9a.75.75 0 001.5.058l.345-9z'
                clipRule='evenodd'
            />
        </svg>
    );
};

export default Delete;

Заключение

В этом руководстве рассматривается пример приложения, которое можно создать с помощью API ChatGPT. Этот же инструмент можно использовать для создания мощных приложений, которые будут полезны в различных областях: перевод текста, Q&A, объяснение или генерация кода и других.

Исходный код этого проекта доступен здесь.

Спасибо за чтение!


НЛО прилетело и оставило здесь промокод для читателей нашего блога:
-15% на заказ любого VDS (кроме тарифа Прогрев) — HABRFIRSTVDS.

Комментарии (4)


  1. yarkov
    20.09.2023 08:49
    -1

    Если это пример работы с ChatGPT программно, то ОК. Если это попытка сделать конвертер, то 100500 онлайн сервисов, найденных по запросу "json2ts", это могут.


  1. shai_hulud
    20.09.2023 08:49
    +1

    В статье вместо реализации метода /convert заглушка. Вот метод из исходников на гитхабе:

    app.post("/convert", async (req, res) => {
    	let { value } = req.body;
    
    	const prompt = `Convert the JSON object into Typescript interfaces \n ${value} Please, I need the only the code, I don't need any explanations.`;
    	const completion = await openai.createChatCompletion({
    		model: "gpt-3.5-turbo",
    		messages: [{ role: "user", content: prompt }],
    	});
    	res.json({
    		message: "Successful",
    		response: completion.data.choices[0].message.content,
    	});
    });


    1. UprightMan Автор
      20.09.2023 08:49

      Большое спасибо! Добавили полный вариант в текст статьи.


  1. Gippsland
    20.09.2023 08:49
    +2

    А всмысле тратить драгоценные токены на такое, легче тогда уж самому написать конвертер.