mirror of
https://github.com/Dimillian/IceCubesApp.git
synced 2025-02-05 08:57:31 +01:00
Generation image description using GPT Vision
This commit is contained in:
parent
5c204fd06f
commit
28ab417b0a
@ -61771,6 +61771,125 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"status.editor.media.generate-description" : {
|
||||||
|
"extractionState" : "manual",
|
||||||
|
"localizations" : {
|
||||||
|
"be" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "needs_review",
|
||||||
|
"value" : "🤖 Generate description"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ca" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "needs_review",
|
||||||
|
"value" : "🤖 Generate description"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"de" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "needs_review",
|
||||||
|
"value" : "🤖 Generate description"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"en" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "🤖 Generate description"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"en-GB" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "🤖 Generate description"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"es" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "needs_review",
|
||||||
|
"value" : "🤖 Generate description"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"eu" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "needs_review",
|
||||||
|
"value" : "🤖 Generate description"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"fr" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "🤖 Générer la description"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"it" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "needs_review",
|
||||||
|
"value" : "🤖 Generate description"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ja" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "needs_review",
|
||||||
|
"value" : "🤖 Generate description"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ko" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "needs_review",
|
||||||
|
"value" : "🤖 Generate description"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nb" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "needs_review",
|
||||||
|
"value" : "🤖 Generate description"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nl" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "needs_review",
|
||||||
|
"value" : "🤖 Generate description"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"pl" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "needs_review",
|
||||||
|
"value" : "🤖 Generate description"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"pt-BR" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "needs_review",
|
||||||
|
"value" : "🤖 Generate description"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tr" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "needs_review",
|
||||||
|
"value" : "🤖 Generate description"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"uk" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "needs_review",
|
||||||
|
"value" : "🤖 Generate description"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"zh-Hans" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "needs_review",
|
||||||
|
"value" : "🤖 Generate description"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"zh-Hant" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "needs_review",
|
||||||
|
"value" : "🤖 Generate description"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"status.editor.media.image-description" : {
|
"status.editor.media.image-description" : {
|
||||||
"extractionState" : "manual",
|
"extractionState" : "manual",
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
|
@ -2,6 +2,13 @@ import Foundation
|
|||||||
|
|
||||||
protocol OpenAIRequest: Encodable {
|
protocol OpenAIRequest: Encodable {
|
||||||
var path: String { get }
|
var path: String { get }
|
||||||
|
var model: String { get }
|
||||||
|
}
|
||||||
|
|
||||||
|
extension OpenAIRequest {
|
||||||
|
var path: String {
|
||||||
|
"chat/completions"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct OpenAIClient {
|
public struct OpenAIClient {
|
||||||
@ -42,22 +49,39 @@ public struct OpenAIClient {
|
|||||||
|
|
||||||
let temperature: CGFloat
|
let temperature: CGFloat
|
||||||
|
|
||||||
var path: String {
|
|
||||||
"chat/completions"
|
|
||||||
}
|
|
||||||
|
|
||||||
public init(content: String, temperature: CGFloat) {
|
public init(content: String, temperature: CGFloat) {
|
||||||
messages = [.init(content: content)]
|
messages = [.init(content: content)]
|
||||||
self.temperature = temperature
|
self.temperature = temperature
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public struct VisionRequest: OpenAIRequest {
|
||||||
|
public struct Message: Encodable {
|
||||||
|
public struct MessageContent: Encodable {
|
||||||
|
public struct ImageUrl: Encodable {
|
||||||
|
public let url: URL
|
||||||
|
}
|
||||||
|
public let type: String
|
||||||
|
public let text: String?
|
||||||
|
public let imageUrl: ImageUrl?
|
||||||
|
}
|
||||||
|
|
||||||
|
public let role = "user"
|
||||||
|
public let content: [MessageContent]
|
||||||
|
}
|
||||||
|
|
||||||
|
let model = "gpt-4-vision-preview"
|
||||||
|
let messages: [Message]
|
||||||
|
let maxTokens = 50
|
||||||
|
}
|
||||||
|
|
||||||
public enum Prompt {
|
public enum Prompt {
|
||||||
case correct(input: String)
|
case correct(input: String)
|
||||||
case shorten(input: String)
|
case shorten(input: String)
|
||||||
case emphasize(input: String)
|
case emphasize(input: String)
|
||||||
case addTags(input: String)
|
case addTags(input: String)
|
||||||
case insertTags(input: String)
|
case insertTags(input: String)
|
||||||
|
case imageDescription(image: URL)
|
||||||
|
|
||||||
var request: OpenAIRequest {
|
var request: OpenAIRequest {
|
||||||
switch self {
|
switch self {
|
||||||
@ -71,6 +95,9 @@ public struct OpenAIClient {
|
|||||||
ChatRequest(content: "Make a shorter version of this text: \(input)", temperature: 0.5)
|
ChatRequest(content: "Make a shorter version of this text: \(input)", temperature: 0.5)
|
||||||
case let .emphasize(input):
|
case let .emphasize(input):
|
||||||
ChatRequest(content: "Make this text catchy, more fun: \(input)", temperature: 1)
|
ChatRequest(content: "Make this text catchy, more fun: \(input)", temperature: 1)
|
||||||
|
case let .imageDescription(image):
|
||||||
|
VisionRequest(messages: [.init(content: [.init(type: "text", text: "What’s in this image?", imageUrl: nil)
|
||||||
|
, .init(type: "image_url", text: nil, imageUrl: .init(url: image))])])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,11 +3,14 @@ import Env
|
|||||||
import Models
|
import Models
|
||||||
import Shimmer
|
import Shimmer
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
import Network
|
||||||
|
|
||||||
struct StatusEditorMediaEditView: View {
|
struct StatusEditorMediaEditView: View {
|
||||||
@Environment(\.dismiss) private var dismiss
|
@Environment(\.dismiss) private var dismiss
|
||||||
@Environment(Theme.self) private var theme
|
@Environment(Theme.self) private var theme
|
||||||
@Environment(CurrentInstance.self) private var currentInstance
|
@Environment(CurrentInstance.self) private var currentInstance
|
||||||
|
@Environment(UserPreferences.self) private var preferences
|
||||||
|
|
||||||
var viewModel: StatusEditorViewModel
|
var viewModel: StatusEditorViewModel
|
||||||
let container: StatusEditorMediaContainer
|
let container: StatusEditorMediaContainer
|
||||||
|
|
||||||
@ -17,6 +20,7 @@ struct StatusEditorMediaEditView: View {
|
|||||||
@State private var isUpdating: Bool = false
|
@State private var isUpdating: Bool = false
|
||||||
|
|
||||||
@State private var didAppear: Bool = false
|
@State private var didAppear: Bool = false
|
||||||
|
@State private var isGeneratingDescription: Bool = false
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
NavigationStack {
|
NavigationStack {
|
||||||
@ -26,6 +30,23 @@ struct StatusEditorMediaEditView: View {
|
|||||||
text: $imageDescription,
|
text: $imageDescription,
|
||||||
axis: .vertical)
|
axis: .vertical)
|
||||||
.focused($isFieldFocused)
|
.focused($isFieldFocused)
|
||||||
|
if let url = container.mediaAttachment?.url, preferences.isOpenAIEnabled {
|
||||||
|
Button {
|
||||||
|
isGeneratingDescription = true
|
||||||
|
Task {
|
||||||
|
let client = OpenAIClient()
|
||||||
|
let response = try await client.request(.imageDescription(image: url))
|
||||||
|
imageDescription = response.trimmedText
|
||||||
|
isGeneratingDescription = false
|
||||||
|
}
|
||||||
|
} label: {
|
||||||
|
if isGeneratingDescription {
|
||||||
|
ProgressView()
|
||||||
|
} else {
|
||||||
|
Text("status.editor.media.generate-description")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.listRowBackground(theme.primaryBackgroundColor)
|
.listRowBackground(theme.primaryBackgroundColor)
|
||||||
Section {
|
Section {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user