Tentei usar Machine Learning local em um app iOS. Não funcionou, mas o app ficou até melhor!
E aí, gente! Eu sou dev iOS há alguns anos e recentemente me dei um desafio que não tinha feito até então: criar um app do zero e publicar na loja.
E depois de pensar muito eu vi uma ideia do meu lado: minha mãe tinha dificuldades pra entender porque as plantinhas dela estavam ruins (murchas, com partes queimadas e tal) e queria entender como recuperá-las. Eu fui baixar uns apps pra mostrar pra ela, mas todos eles tinham um Paywall chato (e caro) com subscription mensal, e ali veio a ideia que todo dev tem: vou fazer minha própria versão!!
E na hora pensei: vou documentar tudo, já que estamos na moda de Build-In-Public, né? kkkk
Coloquei um desafio que não seria algo obrigatório mas tentaria fazer: Criar um app funcional em apenas 1 semana. A ideia inicial era simples e super factível: um app de análise de plantas usando Machine Learning.
O plano inicial: Machine Learning puro com CoreML
Comecei empolgado com a ideia de usar CoreML. Para quem não conhece, CoreML é o framework de ML da Apple que permite rodar modelos de machine learning diretamente no dispositivo - isso significa privacidade total (nenhuma foto sai do celular) e funciona offline.
O processo seria:
- Pegar um dataset público de plantas
- Treinar um modelo usando Create ML (ferramenta da Apple)
- Converter para .mlmodel
- Integrar no app usando Vision framework (sim, o do óculos) para processar as imagens
Peguei um dataset, treinei meu modelo e os primeiros testes pareciam promissores. Mas aí veio a realidade: o dataset tinha poucas variedades de plantas E poucas fotos de cada variedade. E mesmo depois de buscar vários outros modelos/datasets, eu cansei de pesquisar. A maioria que parecia interessante era relacionada a plantas agrícolas.. tomate, milho, soja.. e nada sobre plantas caseiras (Jibóia, Samambaia, Pinheirinho, Lírio da Paz, etc)
E o modelo até funcionava, mas a acurácia era baixa demais. Ele confundia plantas similares, não lidava bem com diferentes ângulos ou iluminação, e basicamente só funcionava bem com as exatas espécies do dataset. Não dava pra lançar isso como um produto real.
A mudança de rota (e o que aprendi)
Tive que tomar uma decisão chata: usar uma API externa. Chata porque a ideia que mais tinha me empolgado era entrar de cabeça no machine learning.
Acabei usando a Plant.id API, que tem:
- Identificação de plantas com acurácia muito maior
- Health assessment (detecta doenças, pragas, deficiências)
- Sugestões de tratamento
- Banco de dados com milhares de espécies
Mas essa mudança me fez repensar toda a arquitetura:
Arquitetura que implementei:
// Criei um NetworkManager genérico com async/await
actor NetworkManager {
func request<T: Decodable>(_ endpoint: Endpoint) async throws -> T
}
// E um PlantIDService específico para a API
class PlantIDService {
func identifyPlant(image: UIImage) async throws -> PlantIdentification
func assessHealth(image: UIImage) async throws -> HealthAssessment
}
Usei Swift Concurrency (async/await + actors) para lidar com as chamadas de rede de forma limpa e segura (muito melhor que completion handlers)
Gerenciamento de estado com SwiftUI
Como o app cresceu além da identificação simples, precisei pensar em como gerenciar o estado. Acabei usando uma combinação de:
@StateObjecte@ObservableObjectpara ViewModels- SwiftData para persistência local (novo framework da Apple, substituto do Core Data)
- Firebase para autenticação e backup na nuvem
@Model
class Plant {
var name: String
var species: String?
var photos: [PlantPhoto]
var healthRecords: [HealthRecord]
var wateringSchedule: NotificationSchedule?
// ...
}
Features que acabei implementando:
Com a API liberando várias possibilidades, o app ganhou:
- Identificação de plantas - óbvio, mas com múltiplas sugestões e nível de confiança
- Health assessment - detecta doenças, pragas, falta de água/luz
- Biblioteca pessoal - salva suas plantas com fotos e histórico
- Notificações inteligentes - lembretes de rega baseados na espécie
- Chat com IA (integrei GPT) - para tirar dúvidas específicas sobre suas plantas
- Timeline de saúde - acompanha a evolução da planta com fotos
Desafios técnicos interessantes:
1. Processamento de imagem antes do upload:
- Implementei crop e compressão de imagens para não estourar o limite da API
- Usei
UIGraphicsImageRendererpara manter qualidade mas reduzir tamanho
2. Gerenciamento de créditos:
- A API cobra por requisição, então implementei um sistema de créditos
- Integrei com o framework StoreKit 2 para compras in-app (e aqui a ideia era cobrar por créditos/uso. Isso porque a maioria dos apps similares são por assinatura mensal ou anual e isso sinceramente não faz sentido pra mim)
3. Notificações locais:
- Criei um
NotificationManagerque possibilita configurar notificações pra cada planta (ou seja, pra planta X deve me notificar 1x ao dia, pra planta Y 1x por semana)
4. Background removal:
- Para deixar as fotos mais bonitas na UI, implementei remoção de fundo
- Usei Vision framework da Apple (VNGeneratePersonSegmentationRequest)
O resultado
O que era pra ser um app simples de identificação simples virou um app completo para cuidar de plantas!
A stack final ficou:
- SwiftUI para toda a UI (mas alguns pedacinhos de UIKit pra fazer edição de imagens)
- Swift Concurrency (async/await, actors, tasks)
- SwiftData para persistência local
- Firebase (Auth + Firestore) para backup
- StoreKit 2 para monetização
- Vision e CoreImage para processamento de imagem
- UserNotifications para lembretes
Ainda não está na App Store, mas já enviei para review (se a querida Apple aprovar, vai estar disponível em breve)!
Quer ver [quase] o processo completo?
Momento auto-jabá (e vulnerabilidade): Se você ficou curioso sobre toda essa jornada, eu documentei todo o processo em um vídeo no YouTube!
É literalmente meu primeiro vídeo, ainda tô testando o que funciona e o que não funciona. A ideia era misturar temas que eu gosto: filmmaking, natureza, café e programação. Confesso que tô saindo bastante da zona de conforto fazendo e compartilahndo por aí kkkk
Se você assistir e curtir, comenta lá! Vai me incentivar demais a continuar fazendo conteúdo assim.
Fonte: https://youtu.be/HYB2zYfH37w