Skip to content

Commit 51fd218

Browse files
adding macos app
1 parent a97ecdd commit 51fd218

34 files changed

Lines changed: 2812 additions & 92 deletions

Playground/YapRun/YapRun.xcodeproj/project.pbxproj

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@
77
objects = {
88

99
/* Begin PBXBuildFile section */
10-
54398FEF2F497A03009D6B51 /* YapRunKeyboard.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 54398FE82F497A02009D6B51 /* YapRunKeyboard.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
10+
54398FEF2F497A03009D6B51 /* YapRunKeyboard.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 54398FE82F497A02009D6B51 /* YapRunKeyboard.appex */; platformFilter = ios; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
1111
54398FFC2F497A34009D6B51 /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 54398FFB2F497A34009D6B51 /* WidgetKit.framework */; };
1212
54398FFE2F497A34009D6B51 /* SwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 54398FFD2F497A34009D6B51 /* SwiftUI.framework */; };
13-
5439900B2F497A35009D6B51 /* YapRunActivityExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 54398FF92F497A34009D6B51 /* YapRunActivityExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
13+
5439900B2F497A35009D6B51 /* YapRunActivityExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 54398FF92F497A34009D6B51 /* YapRunActivityExtension.appex */; platformFilter = ios; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
1414
543991CD2F498152009D6B51 /* RunAnywhere in Frameworks */ = {isa = PBXBuildFile; productRef = 543991CC2F498152009D6B51 /* RunAnywhere */; };
1515
543991CF2F498152009D6B51 /* RunAnywhereONNX in Frameworks */ = {isa = PBXBuildFile; productRef = 543991CE2F498152009D6B51 /* RunAnywhereONNX */; };
1616
/* End PBXBuildFile section */
@@ -475,11 +475,13 @@
475475
};
476476
54398FEE2F497A03009D6B51 /* PBXTargetDependency */ = {
477477
isa = PBXTargetDependency;
478+
platformFilter = ios;
478479
target = 54398FE72F497A02009D6B51 /* YapRunKeyboard */;
479480
targetProxy = 54398FED2F497A03009D6B51 /* PBXContainerItemProxy */;
480481
};
481482
5439900A2F497A35009D6B51 /* PBXTargetDependency */ = {
482483
isa = PBXTargetDependency;
484+
platformFilter = ios;
483485
target = 54398FF82F497A34009D6B51 /* YapRunActivityExtension */;
484486
targetProxy = 543990092F497A35009D6B51 /* PBXContainerItemProxy */;
485487
};
@@ -617,6 +619,7 @@
617619
ENABLE_USER_SELECTED_FILES = readonly;
618620
GENERATE_INFOPLIST_FILE = YES;
619621
INFOPLIST_FILE = YapRun/Info.plist;
622+
"INFOPLIST_KEY_LSUIElement[sdk=macosx*]" = YES;
620623
"INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES;
621624
"INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphonesimulator*]" = YES;
622625
"INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphoneos*]" = YES;
@@ -630,7 +633,7 @@
630633
IPHONEOS_DEPLOYMENT_TARGET = 17.0;
631634
LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
632635
"LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks";
633-
MACOSX_DEPLOYMENT_TARGET = 17.0;
636+
MACOSX_DEPLOYMENT_TARGET = 14.0;
634637
MARKETING_VERSION = 1.0;
635638
PRODUCT_BUNDLE_IDENTIFIER = com.runanywhere.YapRun;
636639
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -663,6 +666,7 @@
663666
ENABLE_USER_SELECTED_FILES = readonly;
664667
GENERATE_INFOPLIST_FILE = YES;
665668
INFOPLIST_FILE = YapRun/Info.plist;
669+
"INFOPLIST_KEY_LSUIElement[sdk=macosx*]" = YES;
666670
"INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES;
667671
"INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphonesimulator*]" = YES;
668672
"INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphoneos*]" = YES;
@@ -676,7 +680,7 @@
676680
IPHONEOS_DEPLOYMENT_TARGET = 17.0;
677681
LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
678682
"LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks";
679-
MACOSX_DEPLOYMENT_TARGET = 17.0;
683+
MACOSX_DEPLOYMENT_TARGET = 14.0;
680684
MARKETING_VERSION = 1.0;
681685
PRODUCT_BUNDLE_IDENTIFIER = com.runanywhere.YapRun;
682686
PRODUCT_NAME = "$(TARGET_NAME)";
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
//
2+
// AppTypes.swift
3+
// YapRun
4+
//
5+
// Shared types used across iOS and macOS.
6+
//
7+
8+
import SwiftUI
9+
10+
// MARK: - Dictation Phase
11+
12+
enum DictationPhase: Equatable {
13+
case idle
14+
case recording
15+
case transcribing
16+
case inserting
17+
case done(String)
18+
case error(String)
19+
}
20+
21+
// MARK: - Dictation Entry
22+
23+
struct DictationEntry: Codable, Identifiable {
24+
let id: UUID
25+
let text: String
26+
let date: Date
27+
28+
init(id: UUID = UUID(), text: String, date: Date = Date()) {
29+
self.id = id
30+
self.text = text
31+
self.date = date
32+
}
33+
}
34+
35+
// MARK: - Mic Permission State
36+
37+
enum MicPermissionState: String {
38+
case unknown, granted, denied
39+
40+
var icon: String {
41+
switch self {
42+
case .unknown: "mic.fill"
43+
case .granted: "checkmark.circle.fill"
44+
case .denied: "xmark.circle.fill"
45+
}
46+
}
47+
48+
var color: Color {
49+
switch self {
50+
case .unknown: .orange
51+
case .granted: AppColors.primaryGreen
52+
case .denied: AppColors.primaryRed
53+
}
54+
}
55+
56+
var label: String {
57+
switch self {
58+
case .unknown: "Not determined"
59+
case .granted: "Granted"
60+
case .denied: "Denied — open Settings to allow"
61+
}
62+
}
63+
}
64+
65+
// MARK: - Hub Section (macOS sidebar)
66+
67+
enum HubSection: String, CaseIterable, Identifiable {
68+
case home = "Home"
69+
case playground = "Playground"
70+
case notepad = "Notepad"
71+
case settings = "Settings"
72+
73+
var id: String { rawValue }
74+
75+
var icon: String {
76+
switch self {
77+
case .home: "house"
78+
case .playground: "waveform"
79+
case .notepad: "note.text"
80+
case .settings: "gear"
81+
}
82+
}
83+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//
2+
// ClipboardService.swift
3+
// YapRun
4+
//
5+
// Abstracts clipboard access across iOS (UIPasteboard) and macOS (NSPasteboard).
6+
//
7+
8+
import Foundation
9+
10+
#if os(iOS)
11+
import UIKit
12+
#elseif os(macOS)
13+
import AppKit
14+
#endif
15+
16+
enum ClipboardService {
17+
18+
static func copyText(_ text: String) {
19+
#if os(iOS)
20+
UIPasteboard.general.string = text
21+
#elseif os(macOS)
22+
NSPasteboard.general.clearContents()
23+
NSPasteboard.general.setString(text, forType: .string)
24+
#endif
25+
}
26+
27+
static func getText() -> String? {
28+
#if os(iOS)
29+
return UIPasteboard.general.string
30+
#elseif os(macOS)
31+
return NSPasteboard.general.string(forType: .string)
32+
#endif
33+
}
34+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
//
2+
// DictationHistory.swift
3+
// YapRun
4+
//
5+
// UserDefaults-backed store for recent dictation entries.
6+
// Shared between iOS and macOS.
7+
//
8+
9+
import Foundation
10+
11+
@MainActor
12+
final class DictationHistory {
13+
14+
static let shared = DictationHistory()
15+
16+
private let key = "dictationHistoryEntries"
17+
private let maxEntries = 50
18+
private let defaults = UserDefaults.standard
19+
20+
private(set) var entries: [DictationEntry] = []
21+
22+
private init() {
23+
entries = load()
24+
}
25+
26+
func append(_ text: String) {
27+
let entry = DictationEntry(text: text)
28+
entries.insert(entry, at: 0)
29+
if entries.count > maxEntries {
30+
entries = Array(entries.prefix(maxEntries))
31+
}
32+
save()
33+
}
34+
35+
func clear() {
36+
entries = []
37+
defaults.removeObject(forKey: key)
38+
}
39+
40+
// MARK: - Persistence
41+
42+
private func load() -> [DictationEntry] {
43+
guard let data = defaults.data(forKey: key),
44+
let decoded = try? JSONDecoder().decode([DictationEntry].self, from: data) else {
45+
return []
46+
}
47+
return decoded
48+
}
49+
50+
private func save() {
51+
guard let data = try? JSONEncoder().encode(entries) else { return }
52+
defaults.set(data, forKey: key)
53+
}
54+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
//
2+
// ModelRegistry.swift
3+
// YapRun
4+
//
5+
// Centralized ASR model definitions shared across iOS and macOS.
6+
//
7+
8+
import Foundation
9+
import RunAnywhere
10+
11+
enum ModelRegistry {
12+
13+
struct ASRModel {
14+
let id: String
15+
let name: String
16+
let url: URL
17+
let archiveType: ArchiveType
18+
let sizeBytes: Int64
19+
}
20+
21+
/// Default model used during onboarding.
22+
static let defaultModelId = "asr-moonshine-tiny-en-int8"
23+
24+
/// All available ASR models (tar.gz for fast native gzip extraction on iOS/macOS).
25+
static let asrModels: [ASRModel] = [
26+
ASRModel(
27+
id: "asr-moonshine-tiny-en-int8",
28+
name: "Moonshine Tiny EN (int8)",
29+
url: URL(string: "https://github.com/RunanywhereAI/sherpa-onnx/releases/download/runanywhere-models-v2/sherpa-onnx-moonshine-tiny-en-int8.tar.gz")!,
30+
archiveType: .tarGz,
31+
sizeBytes: 118_000_000
32+
),
33+
ASRModel(
34+
id: "asr-moonshine-base-en-int8",
35+
name: "Moonshine Base EN (int8)",
36+
url: URL(string: "https://github.com/RunanywhereAI/sherpa-onnx/releases/download/runanywhere-models-v2/sherpa-onnx-moonshine-base-en-int8.tar.gz")!,
37+
archiveType: .tarGz,
38+
sizeBytes: 273_000_000
39+
),
40+
ASRModel(
41+
id: "sherpa-onnx-whisper-tiny.en",
42+
name: "Whisper Tiny EN",
43+
url: URL(string: "https://github.com/RunanywhereAI/sherpa-onnx/releases/download/runanywhere-models-v2/sherpa-onnx-whisper-tiny.en.tar.gz")!,
44+
archiveType: .tarGz,
45+
sizeBytes: 75_000_000
46+
),
47+
ASRModel(
48+
id: "asr-parakeet-tdt-ctc-110m-en-int8",
49+
name: "Parakeet TDT-CTC 110M EN (int8)",
50+
url: URL(string: "https://github.com/RunanywhereAI/sherpa-onnx/releases/download/runanywhere-models-v2/sherpa-onnx-nemo-parakeet_tdt_ctc_110m-en-36000-int8.tar.gz")!,
51+
archiveType: .tarGz,
52+
sizeBytes: 126_000_000
53+
),
54+
]
55+
56+
/// Register all ASR models with the RunAnywhere SDK.
57+
static func registerAll() {
58+
for model in asrModels {
59+
RunAnywhere.registerModel(
60+
id: model.id,
61+
name: model.name,
62+
url: model.url,
63+
framework: .onnx,
64+
modality: .speechRecognition,
65+
artifactType: .archive(model.archiveType, structure: .nestedDirectory),
66+
memoryRequirement: model.sizeBytes
67+
)
68+
}
69+
}
70+
}

Playground/YapRun/YapRun/Features/Home/AddModelURLSheet.swift

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
// YapRun
44
//
55
// Sheet for adding a custom STT model from a URL.
6+
// Shared between iOS and macOS.
67
//
78

8-
#if os(iOS)
99
import SwiftUI
1010

1111
struct AddModelURLSheet: View {
@@ -26,9 +26,11 @@ struct AddModelURLSheet: View {
2626
Form {
2727
Section {
2828
TextField("https://example.com/model.tar.gz", text: $urlString)
29+
#if os(iOS)
2930
.keyboardType(.URL)
30-
.autocorrectionDisabled()
3131
.textInputAutocapitalization(.never)
32+
#endif
33+
.autocorrectionDisabled()
3234
} header: {
3335
Text("Model URL")
3436
} footer: {
@@ -40,7 +42,9 @@ struct AddModelURLSheet: View {
4042
}
4143
}
4244
.navigationTitle("Add Model")
45+
#if os(iOS)
4346
.navigationBarTitleDisplayMode(.inline)
47+
#endif
4448
.toolbar {
4549
ToolbarItem(placement: .cancellationAction) {
4650
Button("Cancel") { isPresented = false }
@@ -60,5 +64,3 @@ struct AddModelURLSheet: View {
6064
.preferredColorScheme(.dark)
6165
}
6266
}
63-
64-
#endif

0 commit comments

Comments
 (0)