Всем привет! Меня зовут Сергей, моё основное направление — мобильные приложения, но помимо этого я пристально наблюдаю за тем, что происходит с ИИ.
Недавно мы все увидели новость:
10 апреля «Яндекс» представил «Алису нового поколения» — и про-подписку, где собраны продвинутые функции.
Не задумываясь, я сразу оформил подписку и решил попробовать, что же это такое.
В своей работе я часто использую сервис ChatGPT, но это не всегда удобно, особенно из-за необходимости включать VPN. Давайте попробуем ответить на вопрос: может ли разработчик мобильных приложений, например на платформе iOS, использовать Yandex GPT в своей ежедневной работе?
Небольшое отступление. Как я понимаю, в этом году все компании по всему миру в срочном порядке ищут способы монетизации ИИ-сервисов, так как все понимают, что это "круто", но пока неясно, где деньги =)
Итак, заходим на https://a.ya.ru
Помощь с кодом
Представим, что мы мобильные разработчики, которые каждый день пишут на языке Swift. Мы хотим использовать YaGPT ежедневно в своей работе. Для этого проверим его компетентность по сравнению с GPT 4o от компании OpenAI.
Наше собеседование на роль AI-ассистента будет проходить в три этапа:
Алгоритмическая сессия. Дадим несколько задачек с leetcode.
Исправление кода. Дадим небольшой кусочек кода и попросим его улучшить.
Теоретические вопросы. Попробуем задать несколько теоретических вопросов.
Берем первую задачку с уровнем "просто" с leetcode
![leetcode leetcode](https://habrastorage.org/getpro/habr/upload_files/357/60f/deb/35760fdebf53f3480a7dc9b7b692bcd2.png)
Переводим текст задачи на русский, чтобы было честно, все же работаем с 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
![](https://habrastorage.org/getpro/habr/upload_files/84c/ea4/601/84cea4601d39a0b875c3a10c96e9efba.png)
Проверяем ответ в leetcode
![](https://habrastorage.org/getpro/habr/upload_files/109/1cd/d87/1091cdd871f9feb515e2c2033005d86a.png)
А теперь сравним с решением ChatGPT 4o
![](https://habrastorage.org/getpro/habr/upload_files/f84/2b7/149/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 { } }
Пробуем
![](https://habrastorage.org/getpro/habr/upload_files/013/653/ad7/013653ad7d3f555e1df374c091c5ce9d.png)
Пробуем отправить код на проверку и видим ошибку к сожалению =(
![](https://habrastorage.org/getpro/habr/upload_files/f41/903/c42/f41903c42bb01d4a32d5d3284b3340d0.png)
Проверяем код, который отдает GPT 4o. Результаты говорят сами за себя
![](https://habrastorage.org/getpro/habr/upload_files/9f8/a1f/46e/9f8a1f46eaacede4e40e7ec954118843.png)
Исправление кода
Дадим небольшой кусочек кода и попросим его улучшить.
Примечание
Изначально я не знал, что у YaGPT есть ограничение на количество символов. Когда я начал проверять его, я подумал, что можно заменить задачу на более простую. Но задача с версткой очень базовая, и действительно ИИ может помочь в этом. Поэтому я решил не менять задачу и оставить ее как есть.
Давайте предположим что у вас есть вот такой экран в приложении
![](https://habrastorage.org/getpro/habr/upload_files/d75/9e9/2b4/d759e92b45b1c2e3c9dfd6e5073ef839.png)
И тут к вам приходят, и говорят а нужно заменить текст. Вы говорите, конечно, задачка на две минуты. И заменяете текст и видите следующее.
![](https://habrastorage.org/getpro/habr/upload_files/152/ce7/489/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, возможно там нет такого ограничения на ввод. Но нет, к сожалению мы видим такое же ограничение.
![](https://habrastorage.org/getpro/habr/upload_files/674/c58/e41/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)</\(self.name)>"
} 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)</\(self.name)>"
} else {
return "<\(self.name) />"
}
}
```
### Вывод
Работа с памятью в Swift с помощью ARC позволяет автоматизировать управление памятью и уменьшить количество ошибок, связанных с ручным управлением памятью. Однако важно понимать, как работают сильные, слабые и несоблюдающие ссылки, чтобы эффективно предотвращать утечки памяти и избегать циклических ссылок.
Выводы делайте сами =)
Итог
Очень круто, что у нас создаются такие продукты, как YandexGPT и Gigachat. Они определенно движутся в правильном направлении. Но, к сожалению, как инструменты для разработчиков, которые можно использовать уже сейчас, они пока не подходят.
А используете ли вы ИИ в своей работе?
Если вам интересно больше узнать об ИИ, подписывайтесь на мой телеграм‑канал.