@insidepics/expo-apple-intelligence 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,197 @@
1
+ import Vision
2
+
3
+ /// Raw passthrough processing for VNRequest results.
4
+ /// Returns Apple API values directly — no filtering, no coordinate conversion.
5
+ /// All coordinates are normalized (0-1, bottom-left origin) as Apple returns them.
6
+ /// Face landmark points are normalized to the face bounding box.
7
+ enum VisionProcessors {
8
+
9
+ // MARK: - Faces
10
+
11
+ static func processFaces(
12
+ landmarks landmarkObs: [VNFaceObservation],
13
+ quality qualityObs: [VNFaceObservation]
14
+ ) -> [[String: Any]] {
15
+ return landmarkObs.map { face in
16
+ var dict: [String: Any] = [
17
+ "boundingBox": VisionHelpers.rawRect(face.boundingBox),
18
+ "confidence": Double(face.confidence),
19
+ ]
20
+
21
+ if let roll = face.roll { dict["roll"] = roll.doubleValue }
22
+ if let yaw = face.yaw { dict["yaw"] = yaw.doubleValue }
23
+ if let pitch = face.pitch { dict["pitch"] = pitch.doubleValue }
24
+
25
+ if let lm = face.landmarks {
26
+ var landmarks: [String: Any] = [:]
27
+ if let r = lm.faceContour { landmarks["faceContour"] = rawLandmarkPoints(r) }
28
+ if let r = lm.leftEye { landmarks["leftEye"] = rawLandmarkPoints(r) }
29
+ if let r = lm.rightEye { landmarks["rightEye"] = rawLandmarkPoints(r) }
30
+ if let r = lm.leftEyebrow { landmarks["leftEyebrow"] = rawLandmarkPoints(r) }
31
+ if let r = lm.rightEyebrow { landmarks["rightEyebrow"] = rawLandmarkPoints(r) }
32
+ if let r = lm.nose { landmarks["nose"] = rawLandmarkPoints(r) }
33
+ if let r = lm.noseCrest { landmarks["noseCrest"] = rawLandmarkPoints(r) }
34
+ if let r = lm.medianLine { landmarks["medianLine"] = rawLandmarkPoints(r) }
35
+ if let r = lm.outerLips { landmarks["outerLips"] = rawLandmarkPoints(r) }
36
+ if let r = lm.innerLips { landmarks["innerLips"] = rawLandmarkPoints(r) }
37
+ if let r = lm.leftPupil { landmarks["leftPupil"] = rawLandmarkPoints(r) }
38
+ if let r = lm.rightPupil { landmarks["rightPupil"] = rawLandmarkPoints(r) }
39
+ dict["landmarks"] = landmarks
40
+ }
41
+
42
+ let qualityMatch = qualityObs.first { $0.uuid == face.uuid }
43
+ if let q = qualityMatch?.faceCaptureQuality {
44
+ dict["quality"] = Double(q)
45
+ }
46
+
47
+ return dict
48
+ }
49
+ }
50
+
51
+ private static func rawLandmarkPoints(_ region: VNFaceLandmarkRegion2D) -> [[String: Double]] {
52
+ (0..<region.pointCount).map { i in
53
+ let pt = region.normalizedPoints[i]
54
+ return ["x": Double(pt.x), "y": Double(pt.y)]
55
+ }
56
+ }
57
+
58
+ // MARK: - Text
59
+
60
+ static func processText(_ observations: [VNRecognizedTextObservation]) -> [[String: Any]] {
61
+ return observations.compactMap { obs in
62
+ let candidates: [[String: Any]] = obs.topCandidates(10).map { candidate in
63
+ ["string": candidate.string, "confidence": Double(candidate.confidence)]
64
+ }
65
+ if candidates.isEmpty { return nil }
66
+ return [
67
+ "boundingBox": VisionHelpers.rawRect(obs.boundingBox),
68
+ "confidence": Double(obs.confidence),
69
+ "candidates": candidates,
70
+ ] as [String: Any]
71
+ }
72
+ }
73
+
74
+ // MARK: - Classification
75
+
76
+ static func processClassification(_ observations: [VNClassificationObservation]) -> [[String: Any]] {
77
+ return observations.map {
78
+ ["identifier": $0.identifier, "confidence": Double($0.confidence)]
79
+ }
80
+ }
81
+
82
+ // MARK: - Barcodes
83
+
84
+ static func processBarcodes(_ observations: [VNBarcodeObservation]) -> [[String: Any]] {
85
+ return observations.map { obs in
86
+ var dict: [String: Any] = [
87
+ "boundingBox": VisionHelpers.rawRect(obs.boundingBox),
88
+ "confidence": Double(obs.confidence),
89
+ "symbology": obs.symbology.rawValue,
90
+ "topLeft": VisionHelpers.rawPoint(obs.topLeft),
91
+ "topRight": VisionHelpers.rawPoint(obs.topRight),
92
+ "bottomLeft": VisionHelpers.rawPoint(obs.bottomLeft),
93
+ "bottomRight": VisionHelpers.rawPoint(obs.bottomRight),
94
+ ]
95
+ if let payload = obs.payloadStringValue {
96
+ dict["payloadStringValue"] = payload
97
+ }
98
+ return dict
99
+ }
100
+ }
101
+
102
+ // MARK: - Body pose
103
+
104
+ static func processBodyPoses(_ observations: [VNHumanBodyPoseObservation]) -> [[String: Any]] {
105
+ return observations.compactMap { obs in
106
+ guard let points = try? obs.recognizedPoints(.all) else { return nil }
107
+ let joints: [[String: Any]] = points.map { (key, point) in
108
+ ["name": key.rawValue, "x": Double(point.location.x), "y": Double(point.location.y), "confidence": Double(point.confidence)]
109
+ }
110
+ return ["joints": joints]
111
+ }
112
+ }
113
+
114
+ // MARK: - Hand pose
115
+
116
+ static func processHandPoses(_ observations: [VNHumanHandPoseObservation]) -> [[String: Any]] {
117
+ return observations.compactMap { obs in
118
+ guard let points = try? obs.recognizedPoints(.all) else { return nil }
119
+ let joints: [[String: Any]] = points.map { (key, point) in
120
+ ["name": key.rawValue, "x": Double(point.location.x), "y": Double(point.location.y), "confidence": Double(point.confidence)]
121
+ }
122
+ return ["joints": joints]
123
+ }
124
+ }
125
+
126
+ // MARK: - Feature print
127
+
128
+ static func processFeaturePrint(_ obs: VNFeaturePrintObservation?) -> [String: Any]? {
129
+ guard let obs = obs else { return nil }
130
+ var data: [Double] = []
131
+ let count = obs.elementCount
132
+ if obs.elementType == .float {
133
+ var floats = [Float](repeating: 0, count: count)
134
+ _ = floats.withUnsafeMutableBytes { ptr in
135
+ obs.data.copyBytes(to: ptr)
136
+ }
137
+ data = floats.map { Double($0) }
138
+ } else {
139
+ var doubles = [Double](repeating: 0, count: count)
140
+ _ = doubles.withUnsafeMutableBytes { ptr in
141
+ obs.data.copyBytes(to: ptr)
142
+ }
143
+ data = doubles
144
+ }
145
+ return ["data": data as [Any], "elementType": obs.elementType == .float ? "float" : "double", "elementCount": Double(count)]
146
+ }
147
+
148
+ // MARK: - Saliency
149
+
150
+ static func processSaliency(_ observations: [VNSaliencyImageObservation]) -> [[String: Any]] {
151
+ var regions: [[String: Any]] = []
152
+ for obs in observations {
153
+ guard let salientObjects = obs.salientObjects else { continue }
154
+ for obj in salientObjects {
155
+ regions.append(["boundingBox": VisionHelpers.rawRect(obj.boundingBox), "confidence": Double(obj.confidence)])
156
+ }
157
+ }
158
+ return regions
159
+ }
160
+
161
+ // MARK: - Animals
162
+
163
+ static func processAnimals(_ observations: [VNRecognizedObjectObservation]) -> [[String: Any]] {
164
+ return observations.map { obs in
165
+ let labels: [[String: Any]] = obs.labels.map {
166
+ ["identifier": $0.identifier, "confidence": Double($0.confidence)]
167
+ }
168
+ return [
169
+ "boundingBox": VisionHelpers.rawRect(obs.boundingBox),
170
+ "confidence": Double(obs.confidence),
171
+ "labels": labels,
172
+ ]
173
+ }
174
+ }
175
+
176
+ // MARK: - Rectangles
177
+
178
+ static func processRectangles(_ observations: [VNRectangleObservation]) -> [[String: Any]] {
179
+ return observations.map { obs in
180
+ [
181
+ "boundingBox": VisionHelpers.rawRect(obs.boundingBox),
182
+ "topLeft": VisionHelpers.rawPoint(obs.topLeft),
183
+ "topRight": VisionHelpers.rawPoint(obs.topRight),
184
+ "bottomLeft": VisionHelpers.rawPoint(obs.bottomLeft),
185
+ "bottomRight": VisionHelpers.rawPoint(obs.bottomRight),
186
+ "confidence": Double(obs.confidence),
187
+ ]
188
+ }
189
+ }
190
+
191
+ // MARK: - Horizon
192
+
193
+ static func processHorizon(_ obs: VNHorizonObservation?) -> [String: Any]? {
194
+ guard let obs = obs else { return nil }
195
+ return ["angle": Double(obs.angle)]
196
+ }
197
+ }
package/package.json ADDED
@@ -0,0 +1,59 @@
1
+ {
2
+ "name": "@insidepics/expo-apple-intelligence",
3
+ "version": "0.1.0",
4
+ "description": "Expo module for Apple Intelligence: Vision, Foundation Models, SpeechAnalyzer, ImagePlayground",
5
+ "main": "build/index.js",
6
+ "types": "build/index.d.ts",
7
+ "scripts": {
8
+ "build": "expo-module build",
9
+ "clean": "expo-module clean",
10
+ "lint": "expo-module lint",
11
+ "lint:check": "expo-module lint",
12
+ "test": "expo-module test --passWithNoTests",
13
+ "prepare": "expo-module prepare",
14
+ "expo-module": "expo-module",
15
+ "open:ios": "xed example/ios"
16
+ },
17
+ "keywords": [
18
+ "react-native",
19
+ "expo",
20
+ "apple-intelligence",
21
+ "machine-learning",
22
+ "vision-framework",
23
+ "foundation-models",
24
+ "speech-analyzer",
25
+ "image-playground"
26
+ ],
27
+ "repository": {
28
+ "type": "git",
29
+ "url": "git+https://github.com/InsidePics/expo-apple-intelligence.git"
30
+ },
31
+ "bugs": "https://github.com/InsidePics/expo-apple-intelligence/issues",
32
+ "author": "INSP LLC",
33
+ "license": "MIT",
34
+ "homepage": "https://github.com/InsidePics/expo-apple-intelligence#readme",
35
+ "publishConfig": {
36
+ "access": "public"
37
+ },
38
+ "files": [
39
+ "build",
40
+ "ios/*.swift",
41
+ "ios/*.podspec",
42
+ "expo-module.config.json",
43
+ "README.md",
44
+ "LICENSE"
45
+ ],
46
+ "dependencies": {},
47
+ "devDependencies": {
48
+ "@types/react": "~19.2.10",
49
+ "expo": "^55.0.8",
50
+ "expo-module-scripts": "^55.0.2",
51
+ "expo-modules-test-core": "^55.0.2",
52
+ "react-native": "0.83.2"
53
+ },
54
+ "peerDependencies": {
55
+ "expo": "*",
56
+ "react": "*",
57
+ "react-native": "*"
58
+ }
59
+ }