Алиса ПРО — для мобильного разработчика

Всем привет! Меня зовут Сергей, моё основное направление — мобильные приложения, но помимо этого я пристально наблюдаю за тем, что происходит с ИИ.

Недавно мы все увидели новость:

10 апреля «Яндекс» представил «Алису нового поколения» —  и про-подписку,  где собраны продвинутые функции.

Не задумываясь, я сразу оформил подписку и решил попробовать, что же это такое.

В своей работе я часто использую сервис ChatGPT, но это не всегда удобно, особенно из-за необходимости включать VPN. Давайте попробуем ответить на вопрос: может ли разработчик мобильных приложений, например на платформе iOS, использовать Yandex GPT в своей ежедневной работе?

Небольшое отступление. Как я понимаю, в этом году все компании по всему миру в срочном порядке ищут способы монетизации ИИ-сервисов, так как все понимают, что это «круто», но пока неясно, где деньги =)

Итак, заходим на https://a.ya.ru

Помощь с кодом

Представим, что мы мобильные разработчики, которые каждый день пишут на языке Swift. Мы хотим использовать YaGPT ежедневно в своей работе. Для этого проверим его компетентность по сравнению с GPT 4o от компании OpenAI.

Наше собеседование на роль AI-ассистента будет проходить в три этапа:

  1. Алгоритмическая сессия. Дадим несколько задачек с leetcode.

  2. Исправление кода. Дадим небольшой кусочек кода и попросим его улучшить.

  3. Теоретические вопросы. Попробуем задать несколько теоретических вопросов.

Берем первую задачку с уровнем «просто» с leetcode 

leetcode

leetcode

Переводим текст задачи на русский, чтобы было честно, все же работаем с YaGPT

Текст промпта

Задача
Дан массив целых чисел nums и целое число target. Верните индексы двух чисел таким образом, чтобы их сумма была равна target.
Вы можете предполагать, что каждый ввод имеет ровно одно решение, и вы не можете использовать один и тот же элемент дважды.
Вы можете вернуть ответ в любом порядке.

Пример 1:

Ввод: nums = [2,7,11,15], target = 9
Вывод: [0,1]
Пояснение: Поскольку nums[0] + nums[1] == 9, мы возвращаем [0, 1].
Пример 2:

Ввод: nums = [3,2,4], target = 6
Вывод: [1,2]
Пример 3:

Ввод: nums = [3,3], target = 6
Вывод: [0,1]

Ограничения:
2 <= длина массива nums <= 104
-109 <= nums[i] <= 109
-109 <= target <= 109
Существует только один правильный ответ.

Начальный код

class Solution {
func twoSum (_ nums: [Int], _ target: Int) → [Int] {}

}

Получаем результаты

YaGPT

84cea4601d39a0b875c3a10c96e9efba.png

Проверяем ответ в leetcode 

1091cdd871f9feb515e2c2033005d86a.png

А теперь сравним с решением ChatGPT 4o

f842b7149cb9738666f6e29332d21303.png

Ответ от GPT 4o оказался более оптимизированным, но в целом обе сети справились с решением. 

Давайте возьмем еще одну задачку для проверки

Текст промпта

Дано целое число x. Вернуть true, если x является палиндромом, и false в противном случае. Целое число является палиндромом, когда оно читается одинаково как слева направо, так и справа налево. Например, 121 является палиндромом, в то время как 123 не является палиндромом.

Пример 1: Ввод: x = 121 Вывод: true

Пояснение: 121 читается одинаково слева направо и справа налево.

Пример 2: Ввод: x = -121 Вывод: false

Пояснение: Слева направо оно читается как -121. Справа налево оно становится 121-. Поэтому это не палиндром.

Пример 3: Ввод: x = 10 Вывод: false

Пояснение: Справа налево оно читается как 01. Поэтому это не палиндром.

Ограничения: -2^31 <= x <= 2^31 - 1

Начальный код class Solution { func isPalindrome (_ x: Int) → Bool { } }

Пробуем

013653ad7d3f555e1df374c091c5ce9d.png

Пробуем отправить код на проверку и видим ошибку к сожалению =(

f41903c42bb01d4a32d5d3284b3340d0.png

Проверяем код, который отдает GPT 4o. Результаты говорят сами за себя

9f8a1f46eaacede4e40e7ec954118843.png

Исправление кода

Дадим небольшой кусочек кода и попросим его улучшить. 

Примечание

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

Давайте предположим что у вас есть вот такой экран в приложении

d759e92b45b1c2e3c9dfd6e5073ef839.png

И тут к вам приходят, и говорят, а нужно заменить текст. Вы говорите, конечно, задачка на две минуты. И заменяете текст и видите следующее. 

152ce7489a2ed555df4af827b1c9984b.png

Экран поехал, никто не предполагал, что там будет столько текста. Скролла, конечно же, нет. Что нужно сделать? Правильно, нужно добавить скролл на данный экран, чтобы все элементы могли скролиться, но кнопку «Поделиться» давайте оставим фиксированной за пределами скролла. Итак, попробуем отправить эту задачку в Алису и в GPT.

Текст промпта

import UIKit
import SnapKit

class ViewController: UIViewController {
    
    let headerBlockView: UIView = {
        let view = UIView()
        view.backgroundColor = .lightGray
        return view
    }()
    
    let linkContainerView: UIView = {
        let view = UIView()
        view.backgroundColor = .lightGray
        view.layer.cornerRadius = 10
        return view
    }()
    
    let referralLinkLabel: UILabel = {
        let label = UILabel()
        label.text = "https://google.com"
        label.textColor = .systemBlue
        label.numberOfLines = 1
        label.textAlignment = .center
        return label
    }()
    
    let copyButton: UIButton = {
        let button = UIButton(type: .system)
        button.setTitle("Copy", for: .normal)
        button.addTarget(self, action: #selector(copyLink), for: .touchUpInside)
        return button
    }()
    
    let shareButton: UIButton = {
        let button = UIButton(type: .system)
        button.setTitle("Поделиться", for: .normal)
        button.setTitleColor(.white, for: .normal)
        button.backgroundColor = .red
        button.layer.cornerRadius = 10
        button.addTarget(self, action: #selector(shareLink), for: .touchUpInside)
        return button
    }()
    
    let descriptionLabel: UILabel = {
        let label = UILabel()
        label.text = """
        Искусственный интеллект (ИИ) о потенциал уже сейчас меняет мир, открывая новые возможности во всех сферах нашей жизни. ИИ способен анализировать огромные объемы данных за считанные секунды, находя в них закономерности и выводы, которые были бы недоступны человеку. Это приводит к улучшению решений в медицине, финансах, производстве и других областях.
        """
        label.numberOfLines = 0
        label.textAlignment = .center
        label.font = UIFont.systemFont(ofSize: 14)
        return label
    }()
    
    let agreementLabel: UILabel = {
        let label = UILabel()
        label.text = """
        Нажимая "Поделиться", ты соглашаешься с правилами программы.
        """
        label.numberOfLines = 0
        label.textAlignment = .center
        label.font = UIFont.systemFont(ofSize: 12)
        label.textColor = .gray
        return label
    }()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.backgroundColor = .white
        
        setupUI()
    }
    
    func setupUI() {
        view.addSubview(headerBlockView)
        view.addSubview(linkContainerView)
        linkContainerView.addSubview(referralLinkLabel)
        linkContainerView.addSubview(copyButton)
        view.addSubview(descriptionLabel)
        view.addSubview(shareButton)
        view.addSubview(agreementLabel)
        
        headerBlockView.snp.makeConstraints { make in
            make.top.equalTo(view.safeAreaLayoutGuide.snp.top)
            make.leading.trailing.equalToSuperview()
            make.height.equalTo(200)
        }
        
        linkContainerView.snp.makeConstraints { make in
            make.top.equalTo(headerBlockView.snp.bottom).offset(16)
            make.leading.trailing.equalToSuperview().inset(16)
            make.height.equalTo(50)
        }
        
        referralLinkLabel.snp.makeConstraints { make in
            make.centerY.equalTo(linkContainerView.snp.centerY)
            make.leading.equalTo(linkContainerView.snp.leading).offset(16)
        }
        
        copyButton.snp.makeConstraints { make in
            make.centerY.equalTo(linkContainerView.snp.centerY)
            make.leading.equalTo(referralLinkLabel.snp.trailing).offset(8)
            make.trailing.equalTo(linkContainerView.snp.trailing).inset(16)
        }
        
        descriptionLabel.snp.makeConstraints { make in
            make.top.equalTo(linkContainerView.snp.bottom).offset(16)
            make.leading.trailing.equalToSuperview().inset(16)
        }
        
        shareButton.snp.makeConstraints { make in
            make.bottom.equalTo(view.safeAreaLayoutGuide.snp.bottom).offset(-16)
            make.leading.trailing.equalToSuperview().inset(16)
            make.height.equalTo(50)
        }
        
        agreementLabel.snp.makeConstraints { make in
            make.bottom.equalTo(shareButton.snp.top).offset(-8)
            make.leading.trailing.equalToSuperview().inset(16)
        }
    }
    
    @objc func copyLink() {
        UIPasteboard.general.string = referralLinkLabel.text
        let alert = UIAlertController(title: "Copied", message: "Referral link copied to clipboard.", preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
        present(alert, animated: true, completion: nil)
    }
    
    @objc func shareLink() {
        let activityVC = UIActivityViewController(activityItems: [referralLinkLabel.text ?? ""], applicationActivities: nil)
        present(activityVC, animated: true, completion: nil)
    }
}


Положи все объекты на скрол вью, чтобы все элементы скролились так как в label может быть много текста
Кнопка поделится должна быть над scollview чтобы она не скролилась

Что у нас получилось с GPT 4o

Пробуем использовать YaGPT, и к сожалению видим ограничению по вводимому тексту, и весь экран у нас не помещается в ответ (даже половина)

Ничего, подумал я. Давайте попрбуем зайти в Yandex Cloud, возможно там нет такого ограничения на ввод. Но нет, к сожалению мы видим такое же ограничение.

674c58e4115f606530bfcb180a01a5c3.png

По итоге в этом тесте ставим YaGPT минус.

Теоретический вопрос

Попробуем задать базовый вопрос про работу с памятью в swift ИИ

Вопрос

Расскажи как в swift работать с памятью

YaGPT

В Swift управление памятью осуществляется через два основных механизма: 
Automatic Reference Counting (ARC) и Manual Memory Management.Automatic Reference Counting (ARC)ARC является предпочтительным 
и дефолтным механизмом управления памятью в Swift.
Он автоматизирует процесс выделения и освобождения памяти, упрощая работу 
разработчика. 

ARC отслеживает количество сильных ссылок на объекты и освобождает память,
когда количество ссылок становится равным нулю.Manual Memory ManagementНесмотря на то, 
что ARC является основным механизмом управления памятью в Swift, иногда требуется более точный контроль над выделением и освобождением памяти.
Для этого используются технологии вроде UnsafeMutablePointer и UnsafeBufferPointer, 
которые позволяют напрямую управлять памятью.

Пример работы с памятью в SwiftРассмотрим пример использования
ARC:class 

University {
 var title: String
 init(title: String) {
 self.title = title
 print("\(title) has been initialized.")
 }
 deinit {
 print("\(title) has been deallocated.")
 }
}

func assignTitle() {
 _ = University(title: "Cambridge")
}

assignTitle()

В этом примере создается класс University с одним свойством title типа String. При создании экземпляра класса University с помощью метода init печатается сообщение о инициализации объекта. После того как экземпляр выходит из области видимости, вызывается метод deinit, который печатает сообщение о деинициализации объекта.Этот пример демонстрирует, как ARC автоматически управляет памятью, освобождая ее после того, как экземпляр класса University выходит из области видимости.

GPT 4o

Работа с памятью в Swift в основном управляется автоматически с помощью механизма ARC (Automatic Reference Counting). Однако, чтобы эффективно использовать память и избегать проблем, таких как утечки памяти и циклические ссылки, важно понимать, как ARC работает и как управлять ссылками на объекты. Вот подробное руководство по работе с памятью в Swift:

### Основные концепции ARC

#### Сильные ссылки (Strong References)

По умолчанию все ссылки на объекты являются сильными. Это означает, что объект будет удерживаться в памяти до тех пор, пока на него существует хотя бы одна сильная ссылка.

```swift
class Person {
    var name: String
    
    init(name: String) {
        self.name = name
    }
}

var john: Person? = Person(name: "John") // Сильная ссылка на объект Person
```

#### Слабые ссылки (Weak References)

Слабые ссылки не удерживают объект в памяти. Они используются, чтобы избежать циклических ссылок. Слабые ссылки объявляются с помощью ключевого слова `weak`.

```swift
class Apartment {
    weak var tenant: Person?
}

class Person {
    var name: String
    var apartment: Apartment?
    
    init(name: String) {
        self.name = name
    }
}

var john: Person? = Person(name: "John")
var unit4A: Apartment? = Apartment()

john?.apartment = unit4A
unit4A?.tenant = john

john = nil // Объект Person освобождается, так как единственная сильная ссылка на него установлена в nil
```

#### Несоблюдающие ссылки (Unowned References)

Несоблюдающие ссылки (`unowned`) также не удерживают объект в памяти, но в отличие от слабых ссылок они предполагают, что объект всегда будет существовать при обращении к нему. Несоблюдающие ссылки используются, когда обе стороны взаимосвязи всегда существуют одновременно.

```swift
class Customer {
    var creditCard: CreditCard?
    
    init() {
        self.creditCard = CreditCard(customer: self)
    }
}

class CreditCard {
    unowned let customer: Customer
    
    init(customer: Customer) {
        self.customer = customer
    }
}

var customer = Customer()
// customer имеет сильную ссылку на creditCard, а creditCard имеет несоблюдающую ссылку на customer
```

### Избегание циклических ссылок

Циклические ссылки возникают, когда два объекта удерживают друг друга, создавая цикл. Это приводит к утечкам памяти, так как ARC не может освободить такие объекты. Использование слабых и несоблюдающих ссылок помогает избежать циклических ссылок.

#### Пример циклической ссылки

```swift
class Person {
    var name: String
    var apartment: Apartment?
    
    init(name: String) {
        self.name = name
    }
}

class Apartment {
    var tenant: Person?
}

var john: Person? = Person(name: "John")
var unit4A: Apartment? = Apartment()

john?.apartment = unit4A
unit4A?.tenant = john

john = nil // john и unit4A не освобождаются из памяти из-за циклической ссылки
```

#### Исправление циклической ссылки с использованием слабых ссылок

```swift
class Apartment {
    weak var tenant: Person?
}

// Остальная часть кода остается без изменений
```

### Управление памятью с помощью замыканий (Closures)

Замыкания в Swift захватывают ссылки на любые переменные и объекты, которые они используют внутри себя. Это может привести к циклическим ссылкам, если замыкание и захваченные объекты ссылаются друг на друга.

#### Пример замыкания, создающего циклическую ссылку

```swift
class HTMLElement {
    let name: String
    let text: String?
    
    lazy var asHTML: () -> String = {
        if let text = self.text {
            return "<\(self.name)>\(text)"
        } else {
            return "<\(self.name) />"
        }
    }
    
    init(name: String, text: String? = nil) {
        self.name = name
        self.text = text
    }
    
    deinit {
        print("\(name) is being deinitialized")
    }
}

var heading: HTMLElement? = HTMLElement(name: "h1", text: "Hello, world!")
print(heading!.asHTML())
heading = nil // HTMLElement не освобождается из памяти
```

#### Использование захватывающих списков (Capture Lists) для предотвращения циклических ссылок

```swift
lazy var asHTML: () -> String = { [weak self] in
    guard let self = self else { return "" }
    if let text = self.text {
        return "<\(self.name)>\(text)"
    } else {
        return "<\(self.name) />"
    }
}
```

### Вывод

Работа с памятью в Swift с помощью ARC позволяет автоматизировать управление памятью и уменьшить количество ошибок, связанных с ручным управлением памятью. Однако важно понимать, как работают сильные, слабые и несоблюдающие ссылки, чтобы эффективно предотвращать утечки памяти и избегать циклических ссылок.

Выводы делайте сами =)

Итог

Очень круто, что у нас создаются такие продукты, как YandexGPT и Gigachat. Они определенно движутся в правильном направлении. Но, к сожалению, как инструменты для разработчиков, которые можно использовать уже сейчас, они пока не подходят.

А используете ли вы ИИ в своей работе?

Если вам интересно больше узнать об ИИ, подписывайтесь на мой телеграм‑канал.

© Habrahabr.ru