Подключаем GigaCode к мобильной разработке

от автора

Всем привет! С вами Анна Жаркова, руководитель группы разработки в компании 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


ссылка на оригинал статьи https://habr.com/ru/articles/825470/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *