Всем привет! С вами Анна Жаркова, руководитель группы разработки в компании Usetech. Сегодня я вам принесла необычный материал. 27 июня 2024 года для сторонних разработчиков открыли и презентовали российскую среду разработки Giga IDE со встроенным ИИ-ассистентом от «Сбера» и «СберТеха». Заявлено, что встроенный в среду ИИ-ассистент GigaCode анализирует контекст, предлагает полные конструкции функций, циклов и других элементов, что позволяет писать код в среднем на 25% быстрее. Ассистент поддерживает как автокомплит кода, так и интеллектуальные подсказки для ввода, генерацию кода для поддерживаемых язык. Также его можно использовать для выполнения разных команд.

Мы посмотрим, как подключить, настроить и применить GigaCode AI к мобильной разработке.
Для начала нам потребуется скачать специальную IDE GigaCode . Нам предложит перейти на ресурс GitVerse (аналоги GitHub, полностью совместим с Git), где потребуется создать аккаунт и авторизоваться через СберID:



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


Также здесь мы можем скачать установочный файл IDE под свою версию ОС:


Если у вас Mac, как у меня, вы можете столкнуться с проблемой:


Не пугайтесь. На самом деле, это просто Mac OS блокирует установку из неизвестного источника. Для разблокировки приложения введем в терминале команду:
sudo xattr -rd com.apple.quarantine /Applications/GIGA\ IDE\ CE\ 2024.1.1.app


После этого мы можем спокойно запустить IDE. Т.к GigaCode IDE базируется на PyChar и JB Idea, то окно приложения очень похоже на оригинал:

Без дополнительных плагинов мы можем создавать и работать с теми же проектами на тех же технологиях, что в Intelij Idea:


А вот чтобы работать с Android проектами, нам потребуется активировать GigaChat AI-ассистента и подключить его к Android. Для этого переходим по ссылке и выбираем нужную IDE.

Попадаем на страницу активации расширения на GitVerse. В процессе может снова потребоваться снова авторизоваться через СберID.
Далее мы попадаем на страницу подробных инструкций для подключения.
Для начала нужно зайти в настройки Android Studio и добавить в разделе управления репозиториями плагинов ссылку на хранилище плагинов GigaCode:

https://gigacode.ru/jarvis/updatePlugins.xml

Во вкладке Marketplace выберите GigaCode и нажмите «Install»:

Перезапускаем IDE и открываем, либо создаем проект. Наш плагин активирован.
Внизу окна появится кнопка GigaCode. Нажав попадаем снова на GitVerse, где наш экземпляр IDE добавляется в список активированных устройств:

Снова перезапускаем IDE. Теперь мы, наконец, можем использовать AI-ассистента Giga в работе.
Давайте посмотрим, что он умеет делать. Тапаем на иконку чата и открываем его:

Визуально это похоже на Gemini AI, который встроен в Koala Preview версию Android Studio. Только работает без впн, и активировать в Gemini нужно не под экземпляр IDE, а под каждый проект с помощью ключа.

Что же нам предлагается:
— создать тест для выделенного блока кода
— объяснить блок кода
— сгенерировать документацию.
Для этого есть готовые команды, которые мы можем ввести в поле ввода.

Что ж. Начнем с генерации теста.
Итак, у нас есть код:
class MainTestConfig : IConfigurator {

    override fun create(view: IView): IInteractor? {
        val presenter = MainTestPresenter(view = view)
        val router = MainTestRouter(view = view)
        val interactor: IMainTestInteractor = MainTestInteractor(
            presenter = presenter,
            router = router
        )

        view.interactor = interactor

        return interactor
    }
}

Просто выделим его и вобьем в поле чата /test. Нам сгенерирует сэмпл теста:


При повторном вызове для того же блока кода сэмпл усложняется и даже становится похожим на настоящий с импортами:
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito.verify
import org.mockito.junit.MockitoJUnitRunner

@RunWith(MockitoJUnitRunner::class)
class MainTestConfigTest {

    @Mock
    lateinit var view: IView

    lateinit var config: MainTestConfig

    @Before
    fun setup() {
        config = MainTestConfig()
    }

    @Test
    fun testCreate() {
        val interactor = config.create(view)

        assert(interactor is MainTestInteractor)
    }

    @Test
    fun testCreate_Presenter() {
        val interactor = config.create(view)

        verify(view).interactor = interactor

        assert(view.interactor is MainTestInteractor)
    }

    @Test
    fun testCreate_Presenter_Router() {
        val interactor = config.create(view)

        assert(view.interactor is MainTestInteractor)
        assert((view.interactor as MainTestInteractor).presenter is MainTestPresenter)
        assert((view.interactor as MainTestInteractor).router is MainTestRouter)
    }
}


Бонусом получаем объяснение:


Попробуем сгенерировать документацию для того же блока кода с помощью команды /doc:
class MainTestConfig : IConfigurator {

    /**
     * This method creates an instance of `MainTestInteractor` and sets it on the `view`.
     *
     * @param view The view to set the interactor on.
     * @return The created `MainTestInteractor` instance.
     */
    override fun create(view: IView): IInteractor? {
        // Create an instance of MainTestPresenter and MainTestRouter.
        val presenter = MainTestPresenter(view = view)
        val router = MainTestRouter(view = view)

        // Create an instance of MainTestInteractor and set it on the view.
        val interactor: IMainTestInter


Вот тут получается довольно хорошо.
Теперь перейдем на сэмплы для Android. Попросим нам создать composable функцию для Image с плейсхолдером:

Получим вменяемый код:
@Composable
fun ImagePlaceholder(
    modifier: Modifier = Modifier,
    contentDescription: String? = null,
    placeholder: Painter = painterResource(id = R.drawable.ic_placeholder),
) {
    Image(
        painter = placeholder,
        contentDescription = contentDescription,
        contentScale = ContentScale.Crop,
        modifier = modifier
    )
}

Поменяем наш промпт: Create a composable function for image placeholder. Also add all needed imports to support Material 3
Получим тот же код, но с добавленными импортами под Material3:

Попробуем пример посложнее. Возьмем Json для SDUI и попросим нам его распарсить:
длинный json
{
            "data": [
                {
                    "type": "SCAFFOLD",
                    "top_bar": [
                        {
                            "type": "CENTER_ALIGNED_TOP_APP_BAR",
                            "children": [
                                {
                                    "type": "TEXT",
                                    "value": "Server Driven Ui"
                                }
                            ]
                        }
                    ],
                    "children": [
                        {
                            "type": "VERTICAL_LIST",
                            "children": [
                                {
                                    "type": "ROW",
                                    "children": [
                                        {
                                            "type": "TEXT",
                                            "value": "Hi 1"
                                        },
                                        {
                                            "type": "IMAGE",
                                            "value": "https://www.fonstola.ru/images/201510/fonstola.ru_209312.jpg"
                                        }
                                    ]
                                },
                                {
                                    "type": "ROW",
                                    "children": [
                                        {
                                            "type": "TEXT",
                                            "value": "Hi 2"
                                        },
                                        {
                                            "type": "IMAGE",
                                            "value": "https://fanibani.ru/wp-content/uploads/2022/12/1617975830_18-p-kotyata-milie-i-pushistie-18.jpg"
                                        }
                                    ]
                                },
                                {
                                    "type": "ROW",
                                    "children": [
                                        {
                                            "type": "TEXT",
                                            "value": "Hi 3"
                                        },
                                        {
                                            "type": "IMAGE",
                                            "value": "https://fanibani.ru/wp-content/uploads/2022/12/pushistye-lapki-na-krasnom-barzate.jpg"
                                        }
                                    ]
                                }
                            ]
                        }
                    ]
                }
            ]
        }


Если в качестве промпта используем что-то типа: «Parse selected text to composable», то получим вот такой код с сэмплом использования:
@Composable
fun Scaffold() {
    val scaffold = remember { Scaffold() }
    val topBar = remember { CenterAlignedTopAppBar() }
    val text = remember { Text("Server Driven Ui") }
    val verticalList = remember { VerticalList() }
    val row1 = remember { Row() }
    val text1 = remember { Text("Hi 1") }
    val image1 = remember { Image("https://www.fonstola.ru/images/201510/fonstola.ru_209312.jpg") }
    val row2 = remember { Row() }
    val text2 = remember { Text("Hi 2") }
    val image2 = remember { Image("https://fanibani.ru/wp-content/uploads/2022/12/1617975830_18-p-kotyata-milie-i-pushistie-18.jpg") }
    val row3 = remember { Row() }
    val text3 = remember { Text("Hi 3") }
    val image3 = remember { Image("https://fanibani.ru/wp-content/uploads/2022/12/pushistye-lapki-na-krasnom-barzate.jpg") }

    Scaffold(topBar = { topBar { text } }) {
        verticalList {
            row1 {
                text1
                image1
            }
            row2 {
                text2
                image2
            }
            row3 {
                text3
                image3
            }
        }
    }
}


Да, он странный, с претензией на DSL и неправильный. Работать это не будет.

Попробуем добавить деталей:

Получаем более осмысленную реализацию:

Тут у нас и импорты, и модели данных, и даже корректная комбинация элементов экрана:
много кода
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.CenterAlignedTopAppBar
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.unit.dp
import coil.compose.rememberImagePainter
import kotlinx.serialization.json.Json

@Composable
fun ImagePlaceholder(
    modifier: Modifier = Modifier,
    contentDescription: String? = null,
    imageUrl: String? = null,
) {
    val painter = rememberImagePainter(
        data = imageUrl,
        builder = {
            crossfade(true)
        }
    )

    Image(
        painter = painter,
        contentDescription = contentDescription,
        contentScale = ContentScale.Crop,
        modifier = modifier
    )
}

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun ServerDrivenUi(json: String) {
    val ui = Json.decodeFromString<Ui>(json)
    Scaffold(
        topBar = {
            CenterAlignedTopAppBar(
                title = { Text(text = ui.topBar.title) }
            )
        }
    ) { padding ->
        LazyColumn(
            modifier = Modifier.padding(padding)
        ) {
            items(ui.children) { child ->
                Row {
                    Text(text = child.text)
                    ImagePlaceholder(
                        modifier = Modifier
                            .fillMaxWidth()
                            .height(200.dp),
                        contentDescription = "Placeholder image",
                        imageUrl = child.image
                    )
                }
            }
        }
    }
}

data class Ui(
    val topBar: TopBar,
    val children: List<Child>
)

data class TopBar(
    val title: String
)

data class Child(
    val text: String,
    val image: String?
)


Добавляем сами в gradle Kotlinx.serialization и Coil (версию Jetpack Compose).

Также нам вывело и объяснение с кратким примером использования:


Только десериализовало нам неверно, и работать это не будет. Дубль еще раз. Указываем, что нужна правильная иерархия и имена полей:


Получаем верные модели данных:
import kotlinx.serialization.Serializable

@Serializable
data class ServerDrivenUi(
    val data: List<Data>
)

@Serializable
data class Data(
    val type: String,
    @SerialName("top_bar")
    val topBar: List<TopBar>,
    val children: List<Children>
)

@Serializable
data class TopBar(
    val type: String,
    val children: List<Children>
)

@Serializable
data class Children(
    val type: String,
    val value: String? = null,
    val children: List<Children>? = null
)


Уже ближе, но все равно не то. Нам еще нужен enum типов, правильный маппинг и соединение всего вместе.
Через какое-то время AI начинает лениться:

Постепенно качество ответов снижается, а ошибок увеличивается. Будто бы AI становится невменяемым.
В итоге нам придется собирать код по частям из сниппетов, чтобы получилось то, что мы хотим:


Времени ушло у меня много. Полностью код для примера сгенерировать у меня так и не удалось, поэтому финальную версию сюда приводить не буду.
Через 30 промптов примерно AI устал, перестал слушаться и стал генерировать какую-то кодовую кашу. Также он перестал учиться.
Если сравнивать с аналогами, то Gemini он местами уступает по качеству. О подробностях работы с Gemini будет в одной из следующих статей.

Для начала, конечно, неплохо. Но хотелось бы большей устойчивости. При этом количество промптов не сказывается на заготовленных командах и автокомплите. Также подойдет для решения маленьких атомарных задач.
Но попробовать свою IDE (пусть и на базе JB IDEA, хотя многие технологии рождались из форков, а не с нуля) точно стоит.

gigacode.ru
И полезные статьи на тему:
habr.com/ru/companies/sberbank/articles/816107

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


  1. Denis_Andreevich
    29.06.2024 03:35

    После анонса, загрузил на свой Mac M2. Операционка при запуске упорно пишет, что пакет сломан и предлагает его удалить. На Windows 11 запускается тааааак медленно, что я дальше создания проекта никуда не ушёл.


    1. anioutka Автор
      29.06.2024 03:35
      +4

      У меня M2 Max. Помогло: sudo xattr -rd com.apple.quarantine <путь к аппу>


    1. JerryI
      29.06.2024 03:35

      Опять за Apple Developer подписку никто платить не хочет ;)


      1. Borz
        29.06.2024 03:35

        а сбер может официально её оплатить нынче? Не думаю, что они пожадничали бы ...
        Тем более, что это не для простого люда, а для разрабов и тут изгаляться, как с банковским ПО, не надо особо - комманду "доверия" ввёл и работай с продуктом


  1. alek0585
    29.06.2024 03:35

    Заявлено, что встроенный в среду ИИ-ассистент GigaCode анализирует контекст, предлагает полные конструкции функций, циклов и других элементов, что позволяет писать код в среднем на 25% быстрее.

    Времени ушло у меня много. Полностью код для примера сгенерировать у меня так и не удалось, поэтому финальную версию сюда приводить не буду.

    Улыбнуло


    1. anioutka Автор
      29.06.2024 03:35

      Ну так это ж был краш-тест на сложной комплексной таске) с простыми (тест, генерация частей задачи) ИИ очень быстро справляется)


  1. Borz
    29.06.2024 03:35

    было бы интересно увидеть его в сравнении с другими AI инструментами


  1. Ales_Ivanov
    29.06.2024 03:35
    +1

    Спасибо, очень полезно почитать от опытного разработчика, что могут и чего не могут ИИ-инструменты на данном этапе.

    А ты вообще в работе ИИ-инструменты используешь на постоянной основе?


    1. anioutka Автор
      29.06.2024 03:35

      Я пробовала Gemini, но им ежедневно пользоваться сложно из-за IP и региона. На рабочем коде я не использую, но этот инструмент подходит для точечных задачек на пет-проектах.


  1. JekaBut
    29.06.2024 03:35

    @anioutka а был опыт работы с копайлот? Который в гит хабе. Интересно было бы почитать о реальном опыте использования "месяц спустя, хочу поделиться как его использую и как нет" что то такое.


    1. anioutka Автор
      29.06.2024 03:35

      Copilot я пока использовала в связке с плагином для Xcode https://github.com/intitni/CopilotForXcode.
      Спасибо за идею) У меня была мысль, сравнить с готовой реализацией AI под новый Xcode, но, похоже, быстрее будет сделать свое решение или попробовать что-то с просторов гитхаба


  1. Nikitakanunov
    29.06.2024 03:35

    Для каких целей была выпущена это IDE?


    1. anioutka Автор
      29.06.2024 03:35

      Альтернатива для импортозамещения. Для тех, кому достаточно community версии IDEA или пользователей Android Studio, профит пока не заметен. Но вот для тех же питонистов - хороший задел на будущее


  1. GriNAME
    29.06.2024 03:35

    А нейронка сливает код всего проекта на сервер? Можно как-то ограничивать что можно читать, а что нет, какой-то аналоги .gitignore? Или он анализирует только выделенный блок кода? А то у нас безопасники вряд ли разрешат им пользоваться


    1. anioutka Автор
      29.06.2024 03:35

      Код всего проекта не сливает. По отдельным кускам, которые передаются плагину, вполне может быть. Но это надо проверить. Пока я запросы через Proxyman не отследила