Section 18/201 menit
18. Real Use Cases
18. Real Use Cases
Use Case 1: Smart Photo Tagger — Klasifikasi dan Tagging Otomatis
App galeri foto yang otomatis men-tag konten gambar menggunakan kombinasi Vision (built-in) dan Core ML (custom model untuk kategori spesifik).
swift
// Smart Photo Tagger: pipeline klasifikasi multi-level
import Vision
import CoreML
import Photos
@MainActor
final class PhotoTaggerViewModel: ObservableObject {
@Published private(set) var tags: [PhotoTag] = []
@Published private(set) var isProcessing = false
private let builtinAnalyzer = VisionAnalyzer()
private let customClassifier: ImageClassifier?
init() {
self.customClassifier = try? ImageClassifier()
}
func tagPhoto(_ asset: PHAsset) async {
isProcessing = true
defer { isProcessing = false }
guard let image = await loadImage(from: asset) else { return }
async let builtinTask: [PhotoTag] = generateBuiltinTags(from: image)
async let customTask: [PhotoTag] = generateCustomTags(from: image)
let allTags = await (builtinTask + customTask)
tags = Array(Set(allTags)).sorted { $0.confidence > $1.confidence }
}
private func generateBuiltinTags(from image: UIImage) async -> [PhotoTag] {
var tags: [PhotoTag] = []
// Face detection
if let faces = try? await builtinAnalyzer.detectFaces(in: image), !faces.isEmpty {
tags.append(PhotoTag(name: "people", confidence: Double(faces.first?.confidence ?? 0.9), source: .builtin))
}
// Text detection (ada teks di gambar?)
let texts = (try? await builtinAnalyzer.recognizeText(in: image)) ?? []
if !texts.isEmpty {
tags.append(PhotoTag(name: "document", confidence: 0.8, source: .builtin))
}
return tags
}
private func generateCustomTags(from image: UIImage) async -> [PhotoTag] {
guard let classifier = customClassifier,
let results = try? await classifier.classify(image: image) else {
return []
}
return results
.filter { $0.confidence > 0.6 }
.map { PhotoTag(name: $0.label, confidence: Double($0.confidence), source: .custom) }
}
private func loadImage(from asset: PHAsset) async -> UIImage? {
await withCheckedContinuation { continuation in
let options = PHImageRequestOptions()
options.deliveryMode = .highQualityFormat
options.isSynchronous = false
PHImageManager.default().requestImage(
for: asset,
targetSize: CGSize(width: 512, height: 512),
contentMode: .aspectFill,
options: options
) { image, _ in
continuation.resume(returning: image)
}
}
}
}
struct PhotoTag: Hashable {
let name: String
let confidence: Double
enum Source { case builtin, custom }
let source: Source
func hash(into hasher: inout Hasher) { hasher.combine(name) }
static func == (lhs: PhotoTag, rhs: PhotoTag) -> Bool { lhs.name == rhs.name }
}
Use Case 2: Customer Support AI — Intent Detection dan Smart Reply
App e-commerce yang mendeteksi intent dari pesan customer dan menyarankan respons otomatis kepada agen.
swift
// Customer Support AI: intent detection + smart reply pipeline
import NaturalLanguage
import CoreML
final class CustomerSupportAI {
private let intentClassifier: NLModel
private let semanticEngine: SemanticSearchEngine?
private let responseTemplates: [String: [String]]
init() throws {
// Model intent di-train dengan Create ML → NLModel
let modelURL = Bundle.main.url(forResource: "IntentClassifier", withExtension: "mlmodelc")!
self.intentClassifier = try NLModel(contentsOf: modelURL)
self.semanticEngine = SemanticSearchEngine()
// Template respons per intent
self.responseTemplates = [
"order_status": [
"Halo! Nomor pesanan Anda bisa dicek di menu 'Pesanan Saya'. Apakah ada nomor order yang bisa saya bantu cek?",
"Kami akan segera mengecek status pesanan Anda. Bisa berikan nomor order-nya?"
],
"refund_request": [
"Kami mohon maaf atas ketidaknyamanannya. Proses refund biasanya 3-5 hari kerja setelah diajukan.",
"Untuk proses refund, silakan isi form di menu Bantuan > Refund dengan melampirkan bukti pembelian."
],
"product_inquiry": [
"Terima kasih atas pertanyaannya! Bisa saya jelaskan lebih detail tentang produk apa yang ingin Anda tanyakan?",
"Saya dengan senang hati membantu informasi produk. Produk apa yang ingin Anda ketahui?"
],
]
// Load FAQ sebagai knowledge base
let faqItems = loadFAQ()
faqItems.forEach { faq in
semanticEngine?.addDocument(id: faq.id, text: faq.question, metadata: ["answer": faq.answer])
}
}
func processMessage(_ message: String) -> SupportResponse {
// 1. Detect intent
let intent = intentClassifier.predictedLabel(for: message) ?? "general"
let intentConfidence = intentClassifier.predictedLabelHypotheses(for: message, maximumCount: 3)
// 2. Cari FAQ yang relevan via semantic search
let relevantFAQs = semanticEngine?.search(query: message, topK: 3, threshold: 0.6) ?? []
// 3. Pilih respons template
let templates = responseTemplates[intent] ?? responseTemplates["product_inquiry"]!
let suggestedReply = templates.randomElement()!
// 4. Analisis sentimen untuk eskalasi
let tagger = NLTagger(tagSchemes: [.sentimentScore])
tagger.string = message
let (sentimentTag, _) = tagger.tag(at: message.startIndex, unit: .paragraph, scheme: .sentimentScore)
let sentimentScore = Double(sentimentTag?.rawValue ?? "0") ?? 0
let needsEscalation = sentimentScore < -0.5 // Sangat negatif → escalate ke human agent
return SupportResponse(
detectedIntent: intent,
intentConfidence: (intentConfidence[intent] ?? 0),
suggestedReply: suggestedReply,
relevantFAQs: relevantFAQs.map { SearchResult(document: $0.document, score: $0.score) },
needsEscalation: needsEscalation,
escalationReason: needsEscalation ? "Customer sentiment sangat negatif" : nil
)
}
private func loadFAQ() -> [FAQItem] {
// Load dari JSON bundled di app
guard let url = Bundle.main.url(forResource: "faq", withExtension: "json"),
let data = try? Data(contentsOf: url),
let items = try? JSONDecoder().decode([FAQItem].self, from: data) else {
return []
}
return items
}
}
struct SupportResponse {
let detectedIntent: String
let intentConfidence: Double
let suggestedReply: String
let relevantFAQs: [SearchResult]
let needsEscalation: Bool
let escalationReason: String?
}
struct FAQItem: Codable {
let id: String
let question: String
let answer: String
let category: String
}
Use Case 3: Offline Recipe Scanner — OCR + NER + Rekomendasi
App yang memotret resep dari majalah, mengekstrak bahan-bahan via OCR + NER, lalu merekomendasikan resep serupa.
swift
// Recipe Scanner: OCR → NER → semantic recommendation pipeline
import Vision
import NaturalLanguage
@MainActor
final class RecipeScannerViewModel: ObservableObject {
@Published var scannedText: String = ""
@Published var extractedIngredients: [String] = []
@Published var similarRecipes: [RecipeRecommendation] = []
@Published var isProcessing = false
private let analyzer = VisionAnalyzer()
private let textAnalyzer = TextAnalyzer()
private let recipeEngine: SemanticSearchEngine?
init() {
self.recipeEngine = SemanticSearchEngine()
loadRecipeDatabase()
}
func scanRecipe(from image: UIImage) async {
isProcessing = true
defer { isProcessing = false }
// Step 1: OCR — ekstrak teks dari gambar
guard let texts = try? await analyzer.recognizeText(in: image) else { return }
let fullText = texts.joined(separator: "\n")
scannedText = fullText
// Step 2: NER — identifikasi bahan makanan
// Kita gunakan custom logic + NER untuk kata benda
let tokens = textAnalyzer.tagPartsOfSpeech(in: fullText)
let nouns = tokens
.filter { $0.1 == .noun }
.map { $0.0.lowercased() }
// Filter kata yang kemungkinan bahan makanan (bisa gunakan custom wordlist)
let foodKeywords = Set(["bawang", "merah", "putih", "cabai", "garam", "gula", "minyak", "telur", "tepung", "santan"])
let ingredients = nouns.filter { word in
foodKeywords.contains(where: { word.contains($0) })
}
extractedIngredients = Array(Set(ingredients)).sorted()
// Step 3: Semantic search untuk resep serupa
let query = extractedIngredients.prefix(5).joined(separator: " ")
let results = recipeEngine?.search(query: query, topK: 5, threshold: 0.4) ?? []
similarRecipes = results.map { result in
RecipeRecommendation(
title: result.document.metadata["title"] ?? result.document.text,
similarity: result.score,
cookingTime: result.document.metadata["time"] ?? "Unknown"
)
}
}
private func loadRecipeDatabase() {
// Load database resep dan buat embedding
let recipes = [
("rendang-001", "daging sapi bawang merah bawang putih cabai santan lengkuas", ["title": "Rendang Padang", "time": "180 menit"]),
("opor-001", "ayam santan bawang putih bawang merah kunyit serai", ["title": "Opor Ayam", "time": "60 menit"]),
("tempe-001", "tempe bawang putih kecap manis cabai minyak goreng", ["title": "Tempe Bacem", "time": "45 menit"]),
]
recipes.forEach { (id, ingredients, metadata) in
recipeEngine?.addDocument(id: id, text: ingredients, metadata: metadata)
}
}
}
struct RecipeRecommendation {
let title: String
let similarity: Double
let cookingTime: String
}