Skip to content

Commit

Permalink
Merge pull request #63 from SunburstEnzo/demoapp_create_image
Browse files Browse the repository at this point in the history
Add Create Image example to Demo app
  • Loading branch information
ingvarus-bc authored Nov 14, 2023
2 parents d9192df + 9898058 commit a9d1e30
Show file tree
Hide file tree
Showing 7 changed files with 215 additions and 7 deletions.
7 changes: 7 additions & 0 deletions Demo/App/APIProvidedView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import SwiftUI
struct APIProvidedView: View {
@Binding var apiKey: String
@StateObject var chatStore: ChatStore
@StateObject var imageStore: ImageStore
@StateObject var miscStore: MiscStore
@State var isShowingAPIConfigModal: Bool = true

Expand All @@ -29,6 +30,11 @@ struct APIProvidedView: View {
idProvider: idProvider
)
)
self._imageStore = StateObject(
wrappedValue: ImageStore(
openAIClient: OpenAI(apiToken: apiKey.wrappedValue)
)
)
self._miscStore = StateObject(
wrappedValue: MiscStore(
openAIClient: OpenAI(apiToken: apiKey.wrappedValue)
Expand All @@ -39,6 +45,7 @@ struct APIProvidedView: View {
var body: some View {
ContentView(
chatStore: chatStore,
imageStore: imageStore,
miscStore: miscStore
)
.onChange(of: apiKey) { newApiKey in
Expand Down
9 changes: 2 additions & 7 deletions Demo/App/ContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import SwiftUI

struct ContentView: View {
@ObservedObject var chatStore: ChatStore
@ObservedObject var imageStore: ImageStore
@ObservedObject var miscStore: MiscStore
@State private var selectedTab = 0
@Environment(\.idProviderValue) var idProvider
Expand All @@ -33,6 +34,7 @@ struct ContentView: View {
.tag(1)

ImageView(
store: imageStore
)
.tabItem {
Label("Image", systemImage: "photo")
Expand Down Expand Up @@ -63,10 +65,3 @@ struct TranscribeView: View {
.font(.largeTitle)
}
}

struct ImageView: View {
var body: some View {
Text("Image: TBD")
.font(.largeTitle)
}
}
33 changes: 33 additions & 0 deletions Demo/DemoChat/Sources/ImageStore.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//
// ImageStore.swift
// DemoChat
//
// Created by Aled Samuel on 24/04/2023.
//

import Foundation
import OpenAI

public final class ImageStore: ObservableObject {
public var openAIClient: OpenAIProtocol

@Published var images: [ImagesResult.URLResult] = []

public init(
openAIClient: OpenAIProtocol
) {
self.openAIClient = openAIClient
}

@MainActor
func images(query: ImagesQuery) async {
images.removeAll()
do {
let response = try await openAIClient.images(query: query)
images = response.data
} catch {
// TODO: Better error handling
print(error.localizedDescription)
}
}
}
75 changes: 75 additions & 0 deletions Demo/DemoChat/Sources/UI/Images/ImageCreationView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
//
// ImageCreationView.swift
// DemoChat
//
// Created by Aled Samuel on 24/04/2023.
//

import SwiftUI
import OpenAI

public struct ImageCreationView: View {
@ObservedObject var store: ImageStore

@State private var prompt: String = ""
@State private var n: Int = 1
@State private var size: String

private var sizes = ["256x256", "512x512", "1024x1024"]

public init(store: ImageStore) {
self.store = store
size = sizes[0]
}

public var body: some View {
List {
Section {
HStack {
Text("Prompt")
Spacer()
TextEditor(text: $prompt)
.multilineTextAlignment(.trailing)
}
HStack {
Stepper("Amount: \(n)", value: $n, in: 1...10)
}
HStack {
Picker("Size", selection: $size) {
ForEach(sizes, id: \.self) {
Text($0)
}
}
}
}
Section {
HStack {
Button("Create Image" + (n == 1 ? "" : "s")) {
Task {
let query = ImagesQuery(prompt: prompt, n: n, size: size)
await store.images(query: query)
}
}
.foregroundColor(.accentColor)
Spacer()
}
}
if !$store.images.isEmpty {
Section("Images") {
ForEach($store.images, id: \.self) { image in
let urlString = image.wrappedValue.url
if let imageURL = URL(string: urlString), UIApplication.shared.canOpenURL(imageURL) {
LinkPreview(previewURL: imageURL)
.aspectRatio(contentMode: .fit)
} else {
Text(urlString)
.foregroundStyle(.secondary)
}
}
}
}
}
.listStyle(.insetGrouped)
.navigationTitle("Create Image")
}
}
63 changes: 63 additions & 0 deletions Demo/DemoChat/Sources/UI/Images/ImageView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
//
// ImageView.swift
// DemoChat
//
// Created by Aled Samuel on 24/04/2023.
//

import SwiftUI

public struct ImageView: View {
@ObservedObject var store: ImageStore

public init(store: ImageStore) {
self.store = store
}

public var body: some View {
NavigationStack {
List {
NavigationLink("Create Image", destination: ImageCreationView(store: store))
NavigationLink("Create Image Edit", destination: ImageEditView(store: store))
.disabled(true)
NavigationLink("Create Image Variation", destination: ImageVariationView(store: store))
.disabled(true)

}
.listStyle(.insetGrouped)
.navigationTitle("Image")
}
}
}

public struct ImageEditView: View {
@ObservedObject var store: ImageStore

public init(store: ImageStore) {
self.store = store
}

public var body: some View {
List {

}
.listStyle(.insetGrouped)
.navigationTitle("Create Image Edit")
}
}

public struct ImageVariationView: View {
@ObservedObject var store: ImageStore

public init(store: ImageStore) {
self.store = store
}

public var body: some View {
List {

}
.listStyle(.insetGrouped)
.navigationTitle("Create Image Variation")
}
}
33 changes: 33 additions & 0 deletions Demo/DemoChat/Sources/UI/Images/LinkPreview.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//
// LinkPreview.swift
// DemoChat
//
// Created by Aled Samuel on 25/04/2023.
//

import SwiftUI
import LinkPresentation

struct LinkPreview: UIViewRepresentable {
typealias UIViewType = LPLinkView

var previewURL: URL

func makeUIView(context: Context) -> LPLinkView {
LPLinkView(url: previewURL)
}

func updateUIView(_ uiView: UIViewType, context: Context) {
LPMetadataProvider().startFetchingMetadata(for: previewURL) { metadata, error in
if let error = error {
print(error.localizedDescription)
return
}
guard let metadata = metadata else {
print("Metadata missing for \(previewURL.absoluteString)")
return
}
uiView.metadata = metadata
}
}
}
2 changes: 2 additions & 0 deletions Sources/OpenAI/Public/Models/ImagesResult.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,5 @@ public struct ImagesResult: Codable, Equatable {
public let created: TimeInterval
public let data: [URLResult]
}

extension ImagesResult.URLResult: Hashable { }

0 comments on commit a9d1e30

Please sign in to comment.