AR Version Pre-test pt2
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user