Skip to content

Commit b316788

Browse files
authored
Edits and variations images (#45)
* Add new edit image endpoint * Create new folder structure * Add image variations * Refactor * Update README
1 parent 0e5d8ba commit b316788

40 files changed

+1004
-63
lines changed

Demo/Demo.xcodeproj/project.pbxproj

Lines changed: 86 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,16 @@
3030
F442DD342B8119A20032682E /* VisionViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F442DD332B8119A20032682E /* VisionViewModel.swift */; };
3131
F44D5A1D2BF55D5D007B2D3F /* CreateTranslationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F44D5A1C2BF55D5D007B2D3F /* CreateTranslationView.swift */; };
3232
F44D5A1F2BF55D7D007B2D3F /* CreateTranslationViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F44D5A1E2BF55D7D007B2D3F /* CreateTranslationViewModel.swift */; };
33+
F4AA12212BF72F6100F2B6BB /* EditImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4AA12202BF72F6100F2B6BB /* EditImageView.swift */; };
34+
F4AA12232BF72F8900F2B6BB /* EditImageViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4AA12222BF72F8900F2B6BB /* EditImageViewModel.swift */; };
35+
F4EAB7B62BF7B8D700ECA18F /* Line.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4EAB7B52BF7B8D700ECA18F /* Line.swift */; };
36+
F4EAB7B82BF7B8E000ECA18F /* Point.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4EAB7B72BF7B8E000ECA18F /* Point.swift */; };
37+
F4EAB7BA2BF7B8EE00ECA18F /* SwiftBetaCanvas.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4EAB7B92BF7B8EE00ECA18F /* SwiftBetaCanvas.swift */; };
38+
F4EAB7BC2BF7B8FE00ECA18F /* View+ReverseMask.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4EAB7BB2BF7B8FE00ECA18F /* View+ReverseMask.swift */; };
39+
F4EAB7C12BF7B93E00ECA18F /* GalleryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4EAB7C02BF7B93E00ECA18F /* GalleryView.swift */; };
40+
F4EAB7C32BF7B94C00ECA18F /* CameraView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4EAB7C22BF7B94C00ECA18F /* CameraView.swift */; };
41+
F4EAB7C62BF7F47C00ECA18F /* VariationImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4EAB7C52BF7F47C00ECA18F /* VariationImageView.swift */; };
42+
F4EAB7C82BF7F48800ECA18F /* VariationImageViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4EAB7C72BF7F48800ECA18F /* VariationImageViewModel.swift */; };
3343
/* End PBXBuildFile section */
3444

3545
/* Begin PBXFileReference section */
@@ -56,6 +66,16 @@
5666
F442DD332B8119A20032682E /* VisionViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VisionViewModel.swift; sourceTree = "<group>"; };
5767
F44D5A1C2BF55D5D007B2D3F /* CreateTranslationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateTranslationView.swift; sourceTree = "<group>"; };
5868
F44D5A1E2BF55D7D007B2D3F /* CreateTranslationViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateTranslationViewModel.swift; sourceTree = "<group>"; };
69+
F4AA12202BF72F6100F2B6BB /* EditImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditImageView.swift; sourceTree = "<group>"; };
70+
F4AA12222BF72F8900F2B6BB /* EditImageViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditImageViewModel.swift; sourceTree = "<group>"; };
71+
F4EAB7B52BF7B8D700ECA18F /* Line.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Line.swift; sourceTree = "<group>"; };
72+
F4EAB7B72BF7B8E000ECA18F /* Point.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Point.swift; sourceTree = "<group>"; };
73+
F4EAB7B92BF7B8EE00ECA18F /* SwiftBetaCanvas.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftBetaCanvas.swift; sourceTree = "<group>"; };
74+
F4EAB7BB2BF7B8FE00ECA18F /* View+ReverseMask.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "View+ReverseMask.swift"; sourceTree = "<group>"; };
75+
F4EAB7C02BF7B93E00ECA18F /* GalleryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GalleryView.swift; sourceTree = "<group>"; };
76+
F4EAB7C22BF7B94C00ECA18F /* CameraView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraView.swift; sourceTree = "<group>"; };
77+
F4EAB7C52BF7F47C00ECA18F /* VariationImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VariationImageView.swift; sourceTree = "<group>"; };
78+
F4EAB7C72BF7F48800ECA18F /* VariationImageViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VariationImageViewModel.swift; sourceTree = "<group>"; };
5979
/* End PBXFileReference section */
6080

6181
/* Begin PBXFrameworksBuildPhase section */
@@ -92,10 +112,8 @@
92112
F442DCF62B80A2B20032682E /* DemoApp.swift */,
93113
F442DCF82B80A2B20032682E /* ContentView.swift */,
94114
F442DD092B80A3D10032682E /* ChatCompletions */,
95-
F442DD1C2B80B74E0032682E /* CreateImages */,
96-
F442DD262B8110C10032682E /* CreateAudio */,
97-
F442DD2B2B8113B40032682E /* CreateTranscription */,
98-
F44D5A1B2BF55D50007B2D3F /* CreateTranslation */,
115+
F4AA121F2BF72EB300F2B6BB /* Image */,
116+
F4AA121E2BF72EAB00F2B6BB /* Audio */,
99117
F442DD302B8119770032682E /* Vision */,
100118
F442DCFA2B80A2B30032682E /* Assets.xcassets */,
101119
F442DD1A2B80A5990032682E /* SwiftOpenAI.plist */,
@@ -195,6 +213,58 @@
195213
path = CreateTranslation;
196214
sourceTree = "<group>";
197215
};
216+
F4AA121D2BF72E9600F2B6BB /* EditImage */ = {
217+
isa = PBXGroup;
218+
children = (
219+
F4AA12202BF72F6100F2B6BB /* EditImageView.swift */,
220+
F4AA12222BF72F8900F2B6BB /* EditImageViewModel.swift */,
221+
F4EAB7B42BF7B8CC00ECA18F /* Dependencies */,
222+
);
223+
path = EditImage;
224+
sourceTree = "<group>";
225+
};
226+
F4AA121E2BF72EAB00F2B6BB /* Audio */ = {
227+
isa = PBXGroup;
228+
children = (
229+
F442DD262B8110C10032682E /* CreateAudio */,
230+
F442DD2B2B8113B40032682E /* CreateTranscription */,
231+
F44D5A1B2BF55D50007B2D3F /* CreateTranslation */,
232+
);
233+
path = Audio;
234+
sourceTree = "<group>";
235+
};
236+
F4AA121F2BF72EB300F2B6BB /* Image */ = {
237+
isa = PBXGroup;
238+
children = (
239+
F4EAB7C42BF7F47000ECA18F /* VariationImage */,
240+
F442DD1C2B80B74E0032682E /* CreateImages */,
241+
F4AA121D2BF72E9600F2B6BB /* EditImage */,
242+
);
243+
path = Image;
244+
sourceTree = "<group>";
245+
};
246+
F4EAB7B42BF7B8CC00ECA18F /* Dependencies */ = {
247+
isa = PBXGroup;
248+
children = (
249+
F4EAB7B52BF7B8D700ECA18F /* Line.swift */,
250+
F4EAB7B72BF7B8E000ECA18F /* Point.swift */,
251+
F4EAB7B92BF7B8EE00ECA18F /* SwiftBetaCanvas.swift */,
252+
F4EAB7BB2BF7B8FE00ECA18F /* View+ReverseMask.swift */,
253+
F4EAB7C02BF7B93E00ECA18F /* GalleryView.swift */,
254+
F4EAB7C22BF7B94C00ECA18F /* CameraView.swift */,
255+
);
256+
path = Dependencies;
257+
sourceTree = "<group>";
258+
};
259+
F4EAB7C42BF7F47000ECA18F /* VariationImage */ = {
260+
isa = PBXGroup;
261+
children = (
262+
F4EAB7C52BF7F47C00ECA18F /* VariationImageView.swift */,
263+
F4EAB7C72BF7F48800ECA18F /* VariationImageViewModel.swift */,
264+
);
265+
path = VariationImage;
266+
sourceTree = "<group>";
267+
};
198268
/* End PBXGroup section */
199269

200270
/* Begin PBXNativeTarget section */
@@ -272,25 +342,35 @@
272342
isa = PBXSourcesBuildPhase;
273343
buildActionMask = 2147483647;
274344
files = (
345+
F4AA12232BF72F8900F2B6BB /* EditImageViewModel.swift in Sources */,
275346
F442DD2D2B8114330032682E /* CreateTranscriptView.swift in Sources */,
347+
F4EAB7C62BF7F47C00ECA18F /* VariationImageView.swift in Sources */,
276348
F442DD202B80B7810032682E /* CreateImagesView.swift in Sources */,
277349
F44D5A1F2BF55D7D007B2D3F /* CreateTranslationViewModel.swift in Sources */,
278350
F442DD0B2B80A3E80032682E /* ChatView.swift in Sources */,
279351
F442DD0F2B80A4330032682E /* TextMessageView.swift in Sources */,
280352
F44D5A1D2BF55D5D007B2D3F /* CreateTranslationView.swift in Sources */,
353+
F4AA12212BF72F6100F2B6BB /* EditImageView.swift in Sources */,
281354
F442DD232B80B79C0032682E /* LoadingView.swift in Sources */,
355+
F4EAB7B62BF7B8D700ECA18F /* Line.swift in Sources */,
282356
F442DD162B80A4E40032682E /* ChatCompletionsViewModel.swift in Sources */,
357+
F4EAB7BC2BF7B8FE00ECA18F /* View+ReverseMask.swift in Sources */,
283358
F442DD2F2B8114450032682E /* CreateTranscriptViewModel.swift in Sources */,
284359
F442DCF92B80A2B20032682E /* ContentView.swift in Sources */,
360+
F4EAB7C82BF7F48800ECA18F /* VariationImageViewModel.swift in Sources */,
285361
F442DD192B80A57D0032682E /* Bundle+OpenAIAPIKey.swift in Sources */,
286362
F442DD282B8110FA0032682E /* CreateAudioView.swift in Sources */,
287363
F442DD132B80A4760032682E /* TypingIndicatorView.swift in Sources */,
364+
F4EAB7C12BF7B93E00ECA18F /* GalleryView.swift in Sources */,
288365
F442DD252B80B7C70032682E /* CreateImageViewModel.swift in Sources */,
289366
F442DCF72B80A2B20032682E /* DemoApp.swift in Sources */,
290367
F442DD2A2B8111190032682E /* CreateAudioViewModel.swift in Sources */,
368+
F4EAB7C32BF7B94C00ECA18F /* CameraView.swift in Sources */,
291369
F442DD322B8119900032682E /* VisionView.swift in Sources */,
292370
F442DD342B8119A20032682E /* VisionViewModel.swift in Sources */,
371+
F4EAB7BA2BF7B8EE00ECA18F /* SwiftBetaCanvas.swift in Sources */,
293372
F442DD0D2B80A4230032682E /* ConversationView.swift in Sources */,
373+
F4EAB7B82BF7B8E000ECA18F /* Point.swift in Sources */,
294374
);
295375
runOnlyForDeploymentPostprocessing = 0;
296376
};
@@ -427,6 +507,7 @@
427507
DEVELOPMENT_TEAM = K4FV5B8ZC4;
428508
ENABLE_PREVIEWS = YES;
429509
GENERATE_INFOPLIST_FILE = YES;
510+
INFOPLIST_KEY_NSCameraUsageDescription = "We need access to your camera so you can take photos.";
430511
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
431512
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
432513
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
@@ -456,6 +537,7 @@
456537
DEVELOPMENT_TEAM = K4FV5B8ZC4;
457538
ENABLE_PREVIEWS = YES;
458539
GENERATE_INFOPLIST_FILE = YES;
540+
INFOPLIST_KEY_NSCameraUsageDescription = "We need access to your camera so you can take photos.";
459541
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
460542
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
461543
INFOPLIST_KEY_UILaunchScreen_Generation = YES;

Demo/Demo/ContentView.swift

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import SwiftOpenAI
44
struct ContentView: View {
55
@State var chatCompletionsViewModel: ChatCompletionsViewModel = .init()
66
@State var createImagesViewModel: CreateImageViewModel = .init()
7+
@State var editImageViewModel: EditImageViewModel = .init()
8+
@State var variationImageViewModel: VariationImageViewModel = .init()
79
@State var createAudioViewModel: CreateAudioViewModel = .init()
810
@State var createTranscriptViewModel: CreateTranscriptViewModel = .init()
911
@State var createTranslationViewModel: CreateTranslationViewModel = .init()
@@ -52,6 +54,46 @@ struct ContentView: View {
5254
}
5355
}
5456
}
57+
NavigationLink {
58+
EditImageView(viewModel: editImageViewModel)
59+
.navigationBarTitleDisplayMode(.large)
60+
.navigationTitle("Edit Image")
61+
} label: {
62+
HStack {
63+
Image(systemName: "photo.badge.checkmark.fill")
64+
.foregroundStyle(.white)
65+
.frame(width: 40, height: 40)
66+
.padding(4)
67+
.background(.pink.gradient)
68+
.clipShape(RoundedRectangle(cornerRadius: 10))
69+
VStack(alignment: .leading) {
70+
Text("Edit Image")
71+
.font(.system(size: 18))
72+
.bold()
73+
Text("Learn how to edit images with masks and prompts")
74+
}
75+
}
76+
}
77+
NavigationLink {
78+
VariationImageView(viewModel: variationImageViewModel)
79+
.navigationBarTitleDisplayMode(.large)
80+
.navigationTitle("Variate Image")
81+
} label: {
82+
HStack {
83+
Image(systemName: "die.face.6.fill")
84+
.foregroundStyle(.white)
85+
.frame(width: 40, height: 40)
86+
.padding(4)
87+
.background(.cyan.gradient)
88+
.clipShape(RoundedRectangle(cornerRadius: 10))
89+
VStack(alignment: .leading) {
90+
Text("Variation Image")
91+
.font(.system(size: 18))
92+
.bold()
93+
Text("Learn how to get a variation of images")
94+
}
95+
}
96+
}
5597
NavigationLink {
5698
CreateAudioView(viewModel: createAudioViewModel)
5799
.navigationBarTitleDisplayMode(.large)
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
//
2+
// CameraView.swift
3+
// OpenAI
4+
//
5+
// Created by Home on 4/11/22.
6+
//
7+
8+
import Foundation
9+
import UIKit
10+
import SwiftUI
11+
12+
public struct CameraView: UIViewControllerRepresentable {
13+
@Binding var selectedImage: Image?
14+
@Environment(\.dismiss) var dismiss
15+
16+
public init(selectedImage: Binding<Image?>) {
17+
self._selectedImage = selectedImage
18+
}
19+
20+
public func makeUIViewController(context: Context) -> some UIViewController {
21+
let imagePickerController = UIImagePickerController()
22+
imagePickerController.delegate = context.coordinator
23+
imagePickerController.sourceType = .camera
24+
imagePickerController.allowsEditing = true
25+
imagePickerController.showsCameraControls = true
26+
return imagePickerController
27+
}
28+
29+
public func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {
30+
// Empty
31+
}
32+
33+
public func makeCoordinator() -> Coordinator {
34+
Coordinator(cameraView: self)
35+
}
36+
}
37+
38+
final public class Coordinator: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
39+
40+
var cameraView: CameraView
41+
42+
init(cameraView: CameraView) {
43+
self.cameraView = cameraView
44+
}
45+
46+
public func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
47+
48+
if let image = info[UIImagePickerController.InfoKey.editedImage] as? UIImage {
49+
cameraView.selectedImage = Image(uiImage: image)
50+
}
51+
cameraView.dismiss()
52+
}
53+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import Foundation
2+
import UIKit
3+
import SwiftUI
4+
5+
public struct GalleryView: UIViewControllerRepresentable {
6+
@Binding var selectedImage: Image?
7+
@Environment(\.dismiss) var dismiss
8+
9+
public init(selectedImage: Binding<Image?>) {
10+
self._selectedImage = selectedImage
11+
}
12+
13+
public func makeUIViewController(context: Context) -> some UIViewController {
14+
let imagePickerController = UIImagePickerController()
15+
imagePickerController.delegate = context.coordinator
16+
imagePickerController.sourceType = .photoLibrary
17+
imagePickerController.allowsEditing = true
18+
return imagePickerController
19+
}
20+
21+
public func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {
22+
// Empty
23+
}
24+
25+
public func makeCoordinator() -> GalleryCoordinator {
26+
GalleryCoordinator(galleryView: self)
27+
}
28+
}
29+
30+
final public class GalleryCoordinator: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
31+
32+
var galleryView: GalleryView
33+
34+
init(galleryView: GalleryView) {
35+
self.galleryView = galleryView
36+
}
37+
38+
public func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
39+
40+
if let image = info[UIImagePickerController.InfoKey.editedImage] as? UIImage {
41+
galleryView.selectedImage = Image(uiImage: image)
42+
}
43+
galleryView.dismiss()
44+
}
45+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import Foundation
2+
import SwiftUI
3+
4+
public struct Line {
5+
var points: [Point]
6+
var color: Color
7+
var width: Float
8+
9+
public init(points: [Point], color: Color, width: Float) {
10+
self.points = points
11+
self.color = color
12+
self.width = width
13+
}
14+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import Foundation
2+
3+
public struct Point {
4+
let currentPoint: CGPoint
5+
let lastPoint: CGPoint
6+
7+
public init(currentPoint: CGPoint, lastPoint: CGPoint) {
8+
self.currentPoint = currentPoint
9+
self.lastPoint = lastPoint
10+
}
11+
}

0 commit comments

Comments
 (0)