Browse Source

astra: live camera with overlay debug info / ui

Alex Cheema 10 months ago
parent
commit
e87e7260f8
1 changed files with 82 additions and 88 deletions
  1. 82 88
      examples/astra/astra/ContentView.swift

+ 82 - 88
examples/astra/astra/ContentView.swift

@@ -111,20 +111,21 @@ enum CameraError: Error {
     case imageProcessingFailed
 }
 
-struct CameraPreview: UIViewRepresentable {
+struct CameraPreview: UIViewControllerRepresentable {
     let cameraActor: CameraActor
 
-    func makeUIView(context: Context) -> UIView {
-        let view = UIView(frame: .zero)
+    func makeUIViewController(context: Context) -> UIViewController {
+        let viewController = UIViewController()
         let previewLayer = AVCaptureVideoPreviewLayer(session: cameraActor.captureSession)
         previewLayer.videoGravity = .resizeAspectFill
-        view.layer.addSublayer(previewLayer)
-        return view
+        viewController.view.layer.addSublayer(previewLayer)
+        previewLayer.frame = viewController.view.bounds
+        return viewController
     }
 
-    func updateUIView(_ uiView: UIView, context: Context) {
-        if let previewLayer = uiView.layer.sublayers?.first as? AVCaptureVideoPreviewLayer {
-            previewLayer.frame = uiView.bounds
+    func updateUIViewController(_ uiViewController: UIViewController, context: Context) {
+        if let previewLayer = uiViewController.view.layer.sublayers?.first as? AVCaptureVideoPreviewLayer {
+            previewLayer.frame = uiViewController.view.bounds
         }
     }
 }
@@ -173,106 +174,99 @@ struct ContentView: View {
     @State private var isFirst3WordsOfResponse = true
 
     var body: some View {
-        VStack {
-            Text(currentText)
-                .padding()
+        ZStack {
+            if showLiveCamera, isCameraReady, let actor = cameraActor {
+                CameraPreview(cameraActor: actor)
+                    .edgesIgnoringSafeArea(.all)
+            }
 
-            Text(isListening ? "Listening..." : "Not listening")
-                .foregroundColor(isListening ? .green : .red)
+            ScrollView {
+                VStack {
+                    Text(currentText)
+                        .padding()
 
-            if isRecordingMemo {
-                Text("Recording memo...")
-                    .foregroundColor(.blue)
-            }
+                    Text(isListening ? "Listening..." : "Not listening")
+                        .foregroundColor(isListening ? .green : .red)
 
-            Picker("Model", selection: $selectedModel) {
-                Text("large-v3").tag("large-v3")
-                Text("base").tag("base")
-                Text("small").tag("small")
-            }
-            .pickerStyle(SegmentedPickerStyle())
-            .padding()
+                    if isRecordingMemo {
+                        Text("Recording...")
+                            .foregroundColor(.blue)
+                    }
 
-            Button("Load Model") {
-                loadModel(selectedModel)
-            }
-            .disabled(modelState == .loaded)
-            .padding()
+                    Picker("Model", selection: $selectedModel) {
+                        Text("large-v3").tag("large-v3")
+                        Text("base").tag("base")
+                        Text("small").tag("small")
+                    }
+                    .pickerStyle(SegmentedPickerStyle())
+                    .padding()
 
-            Text("Model State: \(modelState.description)")
+                    Button("Load Model") {
+                        loadModel(selectedModel)
+                    }
+                    .disabled(modelState == .loaded)
+                    .padding()
 
-            Text(debugText)
-                .font(.caption)
-                .foregroundColor(.gray)
+                    Text("Model State: \(modelState.description)")
 
-            Text("TTS Active: \(isTTSActive ? "Yes" : "No")")
-                .font(.caption)
-                .foregroundColor(isTTSActive ? .green : .red)
+                    Text(debugText)
+                        .font(.caption)
+                        .foregroundColor(.gray)
 
-            Text("Current Silence Threshold: \(voiceActivityThreshold, specifier: "%.2f")")
-                .font(.caption)
-                .foregroundColor(.blue)
+                    Text("TTS Active: \(isTTSActive ? "Yes" : "No")")
+                        .font(.caption)
+                        .foregroundColor(isTTSActive ? .green : .red)
 
-            Text("Original Silence Threshold: \(originalSilenceThreshold, specifier: "%.2f")")
-                .font(.caption)
-                .foregroundColor(.orange)
+                    Text("Current Silence Threshold: \(voiceActivityThreshold, specifier: "%.2f")")
+                        .font(.caption)
+                        .foregroundColor(.blue)
 
-            Slider(value: $voiceActivityThreshold, in: 0.01...1.0) {
-                Text("Voice Activity Threshold: \(voiceActivityThreshold, specifier: "%.2f")")
-            }
+                    Text("Original Silence Threshold: \(originalSilenceThreshold, specifier: "%.2f")")
+                        .font(.caption)
+                        .foregroundColor(.orange)
 
-            Text("API Response:")
-                .font(.headline)
-                .padding(.top)
+                    Slider(value: $voiceActivityThreshold, in: 0.01...1.0) {
+                        Text("Voice Activity Threshold: \(voiceActivityThreshold, specifier: "%.2f")")
+                    }
 
-            ScrollView {
-                Text(streamingResponse)
-                    .padding()
-            }
-            .frame(height: 200)
-            .border(Color.gray, width: 1)
-
-            Toggle("Show Live Camera", isOn: $showLiveCamera)
-                .padding()
-                .onChange(of: showLiveCamera) { newValue in
-                    if newValue {
-                        Task {
-                            await setupCamera()
-                        }
-                    } else {
-                        cameraActor = nil
-                        isCameraReady = false
-                        print("Camera disabled")
+                    Text("API Response:")
+                        .font(.headline)
+                        .padding(.top)
+
+                    ScrollView {
+                        Text(streamingResponse)
+                            .padding()
                     }
-                }
+                    .frame(height: 200)
+                    .border(Color.gray, width: 1)
 
-            if showLiveCamera {
-                if isCameraReady, let actor = cameraActor {
-                    CameraPreview(cameraActor: actor)
-                        .frame(height: 200)
-                        .cornerRadius(10)
+                    Toggle("Show Live Camera", isOn: $showLiveCamera)
                         .padding()
+                        .onChange(of: showLiveCamera) { newValue in
+                            if newValue {
+                                Task {
+                                    await setupCamera()
+                                }
+                            } else {
+                                cameraActor = nil
+                                isCameraReady = false
+                                print("Camera disabled")
+                            }
+                        }
+
+                    if !showLiveCamera {
+                        Text("Camera Ready: \(isCameraReady ? "Yes" : "No")")
+                            .padding()
 
-                    Button("Capture Photo") {
-                        Task {
-                            await capturePhoto()
+                        if let errorMessage = errorMessage {
+                            Text("Error: \(errorMessage)")
+                                .foregroundColor(.red)
+                                .padding()
                         }
                     }
-                    .padding()
-                } else {
-                    ProgressView("Initializing camera...")
-                        .padding()
                 }
             }
-
-            Text("Camera Ready: \(isCameraReady ? "Yes" : "No")")
-                .padding()
-
-            if let errorMessage = errorMessage {
-                Text("Error: \(errorMessage)")
-                    .foregroundColor(.red)
-                    .padding()
-            }
+            .opacity(showLiveCamera ? 0.7 : 1)
         }
         .onAppear {
             setupWhisperKit()