AR Version Pre-test pt2

This commit is contained in:
2026-02-14 23:11:38 -06:00
parent f7f14b2c5d
commit 45035e67e0
7 changed files with 105 additions and 41 deletions

View File

@@ -361,6 +361,7 @@
SDKROOT = iphoneos;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 6.0;
};
name = Debug;
};
@@ -417,6 +418,7 @@
MTL_FAST_MATH = YES;
SDKROOT = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_VERSION = 6.0;
VALIDATE_PRODUCT = YES;
};
name = Release;

View File

@@ -7,13 +7,8 @@
import Foundation
enum AppConfig {
// MARK: - Overshoot Vision API
/// Overshoot API key for real-time video inference
/// [INSERT_OVERSHOOT_API_KEY_HERE]
static let overshootAPIKey = "INSERT_KEY_HERE"
static let overshootWebSocketURL = "wss://api.overshoot.ai/v1/stream" // Placeholder URL
enum AppConfig: Sendable {
// MARK: - Google Gemini API
/// Google Gemini API key for recipe generation and reasoning
/// [INSERT_GEMINI_API_KEY_HERE]
@@ -27,6 +22,10 @@ enum AppConfig {
/// 2. Add it to the Xcode project root
/// 3. Ensure it's added to the target
// MARK: - AR Configuration
/// Enable AR-based scanning features
static let enableARScanning = true
// MARK: - Feature Flags
static let enableRealTimeDetection = true
static let enableCookingMode = true

View File

@@ -149,11 +149,11 @@ struct ContentView: View {
Section("API Configuration") {
VStack(alignment: .leading, spacing: 8) {
Text("Overshoot API")
Text("AR Scanning")
.font(.headline)
Text(AppConfig.overshootAPIKey == "INSERT_KEY_HERE" ? "Not configured" : "Configured")
Text(AppConfig.enableARScanning ? "Enabled" : "Disabled")
.font(.caption)
.foregroundStyle(AppConfig.overshootAPIKey == "INSERT_KEY_HERE" ? .red : .green)
.foregroundStyle(AppConfig.enableARScanning ? .green : .red)
}
VStack(alignment: .leading, spacing: 8) {

View File

@@ -15,9 +15,11 @@ import ARKit
/// AR-based implementation for vision and spatial scanning
final class ARVisionService: VisionService, @unchecked Sendable {
nonisolated init() {}
// MARK: - VisionService Protocol Implementation
func detectIngredients(from stream: AsyncStream<CVPixelBuffer>) async throws -> [Ingredient] {
nonisolated func detectIngredients(from stream: AsyncStream<CVPixelBuffer>) async throws -> [Ingredient] {
// Mock implementation - in a real app, this would use ML models
// to detect ingredients from AR camera frames
var detectedIngredients: [Ingredient] = []
@@ -49,11 +51,11 @@ final class ARVisionService: VisionService, @unchecked Sendable {
.sorted { $0.confidence > $1.confidence }
}
func detectIngredients(from pixelBuffer: CVPixelBuffer) async throws -> [Ingredient] {
nonisolated func detectIngredients(from pixelBuffer: CVPixelBuffer) async throws -> [Ingredient] {
return try await processARFrame(pixelBuffer)
}
func analyzeCookingProgress(from stream: AsyncStream<CVPixelBuffer>, for step: String) async throws -> CookingProgress {
nonisolated func analyzeCookingProgress(from stream: AsyncStream<CVPixelBuffer>, for step: String) async throws -> CookingProgress {
// Mock implementation for cooking progress monitoring
return CookingProgress(
isComplete: false,
@@ -64,7 +66,7 @@ final class ARVisionService: VisionService, @unchecked Sendable {
// MARK: - Private Helper Methods
private func processARFrame(_ pixelBuffer: CVPixelBuffer) async throws -> [Ingredient] {
nonisolated private func processARFrame(_ pixelBuffer: CVPixelBuffer) async throws -> [Ingredient] {
// Mock ingredient detection
// In a real implementation, this would use Vision framework or ML models
// to detect objects in the AR camera feed

View File

@@ -44,7 +44,7 @@ final class CookingModeViewModel: ObservableObject {
}
nonisolated init(recipe: Recipe,
visionService: VisionService = OvershootVisionService(),
visionService: VisionService = ARVisionService(),
recipeService: RecipeService = GeminiRecipeService(),
cameraManager: CameraManager = CameraManager()) {
self.recipe = recipe

View File

@@ -23,7 +23,7 @@ final class ScannerViewModel: ObservableObject {
private let cameraManager: CameraManager
private var scanTask: Task<Void, Never>?
nonisolated init(visionService: VisionService = OvershootVisionService(),
nonisolated init(visionService: VisionService = ARVisionService(),
cameraManager: CameraManager = CameraManager()) {
self.visionService = visionService
self.cameraManager = cameraManager

View File

@@ -2,23 +2,35 @@
// ScannerView.swift
// SousChefAI
//
// Camera view for scanning and detecting ingredients in real-time
// AR camera view for scanning and detecting ingredients in real-time
//
import SwiftUI
import AVFoundation
import ARKit
import RealityKit
struct ScannerView: View {
@StateObject private var viewModel = ScannerViewModel()
@State private var showingInventory = false
@State private var showingManualEntry = false
@State private var detectedPlanes = 0
@State private var lastRaycastResult = ""
@State private var showARView = false
var body: some View {
NavigationStack {
ZStack {
// Camera preview
// AR camera preview or regular camera
if showARView {
ARViewContainer(
detectedPlanes: $detectedPlanes,
lastRaycastResult: $lastRaycastResult
)
.ignoresSafeArea()
} else {
CameraPreviewView(previewLayer: viewModel.getPreviewLayer())
.ignoresSafeArea()
}
// Overlay UI
VStack {
@@ -26,6 +38,12 @@ struct ScannerView: View {
statusBar
.padding()
// AR Debug info (only when AR is active)
if showARView {
arDebugInfo
.padding(.horizontal)
}
Spacer()
// Detected ingredients list
@@ -38,7 +56,7 @@ struct ScannerView: View {
.padding()
}
}
.navigationTitle("Scan Ingredients")
.navigationTitle(showARView ? "AR Scanner" : "Camera Preview")
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
@@ -50,9 +68,11 @@ struct ScannerView: View {
}
}
.task {
if !showARView {
await viewModel.setupCamera()
viewModel.startCamera()
}
}
.onDisappear {
viewModel.cleanup()
}
@@ -81,7 +101,7 @@ struct ScannerView: View {
private var statusBar: some View {
HStack {
VStack(alignment: .leading, spacing: 4) {
Text(viewModel.scanProgress)
Text(showARView ? "AR Mode Active" : viewModel.scanProgress)
.font(.headline)
.foregroundStyle(.white)
@@ -107,6 +127,23 @@ struct ScannerView: View {
.clipShape(RoundedRectangle(cornerRadius: 12))
}
private var arDebugInfo: some View {
VStack(alignment: .leading, spacing: 4) {
Text("Detected Planes: \(detectedPlanes)")
.font(.caption)
.foregroundStyle(.white)
if !lastRaycastResult.isEmpty {
Text(lastRaycastResult)
.font(.caption2)
.foregroundStyle(.white)
}
}
.padding(8)
.background(.ultraThinMaterial)
.clipShape(RoundedRectangle(cornerRadius: 8))
}
private var detectedIngredientsOverlay: some View {
ScrollView(.horizontal, showsIndicators: false) {
HStack(spacing: 12) {
@@ -131,7 +168,30 @@ struct ScannerView: View {
private var controlsBar: some View {
VStack(spacing: 16) {
// Main action button
// AR Toggle button
if !viewModel.isScanning {
Button {
withAnimation {
showARView.toggle()
if !showARView {
viewModel.startCamera()
} else {
viewModel.stopCamera()
}
}
} label: {
Label(showARView ? "Exit AR Mode" : "Start AR Scan", systemImage: showARView ? "camera.fill" : "arkit")
.font(.headline)
.foregroundStyle(.white)
.frame(maxWidth: .infinity)
.padding()
.background(showARView ? Color.orange : Color.blue)
.clipShape(RoundedRectangle(cornerRadius: 16))
}
}
// Main scanning action button (only in non-AR mode)
if !showARView {
if viewModel.isScanning {
Button {
viewModel.stopScanning()
@@ -148,15 +208,16 @@ struct ScannerView: View {
Button {
viewModel.startScanning()
} label: {
Label("Scan Fridge", systemImage: "camera.fill")
Label("Detect Ingredients", systemImage: "camera.viewfinder")
.font(.headline)
.foregroundStyle(.white)
.frame(maxWidth: .infinity)
.padding()
.background(Color.blue)
.background(Color.green)
.clipShape(RoundedRectangle(cornerRadius: 16))
}
}
}
// Secondary actions
if !viewModel.detectedIngredients.isEmpty {
@@ -168,7 +229,7 @@ struct ScannerView: View {
.foregroundStyle(.white)
.frame(maxWidth: .infinity)
.padding()
.background(Color.green)
.background(Color.purple)
.clipShape(RoundedRectangle(cornerRadius: 16))
}
}