- Add TTS service using AVSpeechSynthesizer for voice output - Add STT service using SpeechAnalyzer (macOS 26) for transcription - Add voice input (microphone) button in chat with recording level indicator - Add speak button on assistant messages for TTS playback - Add language toggle (EN-CA/FR-CA) for bilingual speech recognition - Fix Swift 6 strict concurrency issues in audio callbacks - Update proto schema with TTS/STT message types and RPCs - Update gRPC provider with speech service endpoints 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
85 lines
3.0 KiB
Swift
85 lines
3.0 KiB
Swift
import Foundation
|
|
import GRPCCore
|
|
import GRPCNIOTransportHTTP2
|
|
import ArgumentParser
|
|
import AppleIntelligenceCore
|
|
|
|
@main
|
|
struct AppleIntelligenceServer: AsyncParsableCommand {
|
|
static let configuration = CommandConfiguration(
|
|
abstract: "Apple Intelligence gRPC Server",
|
|
discussion: "Exposes Apple Intelligence (Foundation Models) over gRPC for LAN access."
|
|
)
|
|
|
|
@Option(name: .shortAndLong, help: "Host to bind to")
|
|
var host: String?
|
|
|
|
@Option(name: .shortAndLong, help: "Port to listen on")
|
|
var port: Int?
|
|
|
|
func run() async throws {
|
|
let config = Config()
|
|
let bindHost = host ?? config.host
|
|
let bindPort = port ?? config.port
|
|
|
|
print("Initializing Apple Intelligence service...")
|
|
let service = await AppleIntelligenceService()
|
|
|
|
let modelStatus = await service.getModelStatus()
|
|
print("Model status: \(modelStatus)")
|
|
|
|
guard await service.isAvailable else {
|
|
print("Error: Apple Intelligence is not available on this device.")
|
|
print("Please ensure:")
|
|
print(" - You are running macOS 26 (Tahoe) or later")
|
|
print(" - You have an Apple Silicon Mac")
|
|
print(" - Apple Intelligence is enabled in System Settings")
|
|
throw ExitCode.failure
|
|
}
|
|
|
|
// Initialize speech services
|
|
print("Initializing Text-to-Speech service...")
|
|
let ttsService = TextToSpeechService()
|
|
|
|
print("Initializing Speech-to-Text service...")
|
|
let sttService = await SpeechToTextService()
|
|
let sttStatus = await sttService.getStatus()
|
|
print("Speech-to-Text status: \(sttStatus)")
|
|
|
|
let provider = AppleIntelligenceProvider(
|
|
service: service,
|
|
ttsService: ttsService,
|
|
sttService: sttService,
|
|
apiKey: config.apiKey
|
|
)
|
|
|
|
let transport = HTTP2ServerTransport.Posix(
|
|
address: .ipv4(host: bindHost, port: bindPort),
|
|
transportSecurity: .plaintext,
|
|
config: .defaults
|
|
)
|
|
|
|
let server = GRPCServer(transport: transport, services: [provider])
|
|
|
|
print("Starting gRPC server on \(bindHost):\(bindPort)...")
|
|
if config.apiKey != nil {
|
|
print("API key authentication is enabled")
|
|
}
|
|
print("Server is ready to accept connections")
|
|
print("")
|
|
print("Available services:")
|
|
print(" - Complete/StreamComplete: Text generation with Apple Intelligence")
|
|
print(" - TextToSpeech: Convert text to spoken audio")
|
|
print(" - ListVoices: List available TTS voices")
|
|
print(" - Transcribe: Convert audio file to text")
|
|
print(" - StreamTranscribe: Real-time speech-to-text")
|
|
print("")
|
|
print("Health check: grpcurl -plaintext \(bindHost):\(bindPort) appleintelligence.AppleIntelligenceService/Health")
|
|
print("Press Ctrl+C to stop the server")
|
|
|
|
try await server.serve()
|
|
|
|
print("Server stopped.")
|
|
}
|
|
}
|