New features: - Offline Dictionary: reverse index of 175K verb forms + 200 common words, cached to disk, powers instant word lookups in Stories - Vocab SRS Review: spaced repetition for course vocabulary cards with due count badge and Again/Hard/Good/Easy rating - Cloze Practice: fill-in-the-blank using SentenceQuizEngine with distractor generation from vocabulary pool - Grammar Exercises: interactive quizzes for 5 grammar topics (ser/estar, por/para, preterite/imperfect, subjunctive, personal a) with "Practice This" button on grammar note detail - Listening Practice: listen-and-type + pronunciation check modes using Speech framework with word-by-word match scoring - Conversational Practice: AI chat partner via Foundation Models with 10 scenario types, saved to cloud container Other changes: - Add Conversation model to SharedModels and cloud container - Add Info.plist keys for speech recognition and microphone - Skip speech auth on simulator to prevent crash - Fix preparing data screen to only show during seed/migration - Extract courseDataVersion to static property on DataLoader - Add "How Features Work" reference page in Settings Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
79 lines
3.1 KiB
Swift
79 lines
3.1 KiB
Swift
import Foundation
|
|
import FoundationModels
|
|
import SharedModels
|
|
|
|
@MainActor
|
|
@Observable
|
|
final class ConversationService {
|
|
var isResponding = false
|
|
|
|
private var session: LanguageModelSession?
|
|
|
|
static let scenarios = [
|
|
"Ordering at a restaurant",
|
|
"Asking for directions",
|
|
"Shopping at a market",
|
|
"Checking into a hotel",
|
|
"Making plans with a friend",
|
|
"At the doctor's office",
|
|
"Job interview",
|
|
"Renting an apartment",
|
|
"At the airport",
|
|
"Meeting someone new",
|
|
]
|
|
|
|
func startConversation(scenario: String, level: String) -> String {
|
|
session = LanguageModelSession(instructions: """
|
|
You are a friendly Spanish conversation partner. The scenario is: \(scenario).
|
|
The student's level is: \(level).
|
|
|
|
Rules:
|
|
- Respond ONLY in Spanish appropriate for the student's level.
|
|
- Keep responses to 1-3 sentences.
|
|
- If the student makes a grammar mistake, gently correct it in parentheses \
|
|
at the end of your response, like: (Pequeña corrección: "fuiste" en vez de "fue")
|
|
- Stay in character for the scenario.
|
|
- Be encouraging and natural.
|
|
""")
|
|
|
|
// Return the opening message based on scenario
|
|
switch scenario {
|
|
case "Ordering at a restaurant":
|
|
return "¡Bienvenido! Soy su mesero. ¿Ya sabe qué le gustaría ordenar?"
|
|
case "Asking for directions":
|
|
return "¡Hola! ¿En qué le puedo ayudar? ¿Está buscando algún lugar?"
|
|
case "Shopping at a market":
|
|
return "¡Buenos días! Tenemos frutas muy frescas hoy. ¿Qué le gustaría comprar?"
|
|
case "Checking into a hotel":
|
|
return "Buenas tardes, bienvenido al Hotel Sol. ¿Tiene una reservación?"
|
|
case "Making plans with a friend":
|
|
return "¡Oye! ¿Qué quieres hacer este fin de semana? Estoy libre el sábado."
|
|
case "At the doctor's office":
|
|
return "Buenos días. Soy el doctor García. ¿Cómo se siente hoy? ¿Qué le pasa?"
|
|
case "Job interview":
|
|
return "Buenos días, gracias por venir. Cuénteme un poco sobre usted."
|
|
case "Renting an apartment":
|
|
return "¡Hola! Gracias por su interés en el apartamento. ¿Qué preguntas tiene?"
|
|
case "At the airport":
|
|
return "Buenas tardes, pasajero. ¿Me puede mostrar su pasaporte y su boleto?"
|
|
case "Meeting someone new":
|
|
return "¡Hola! Me llamo Carlos. ¿Cómo te llamas? ¿De dónde eres?"
|
|
default:
|
|
return "¡Hola! ¿Cómo estás? Vamos a practicar español juntos."
|
|
}
|
|
}
|
|
|
|
func respond(to userMessage: String) async throws -> String {
|
|
guard let session else { return "Error: no session" }
|
|
isResponding = true
|
|
defer { isResponding = false }
|
|
|
|
let response = try await session.respond(to: userMessage)
|
|
return response.content
|
|
}
|
|
|
|
static var isAvailable: Bool {
|
|
SystemLanguageModel.default.availability == .available
|
|
}
|
|
}
|