Implement idea to song project generation
This commit is contained in:
@@ -2,7 +2,6 @@ import Foundation
|
||||
|
||||
public struct AppConfiguration: Equatable, Sendable {
|
||||
public let openAIAPIKey: String?
|
||||
<<<<<<< HEAD
|
||||
public let privateApplicationRules: PrivateApplicationRules?
|
||||
|
||||
public init(
|
||||
@@ -11,21 +10,12 @@ public struct AppConfiguration: Equatable, Sendable {
|
||||
) {
|
||||
self.openAIAPIKey = openAIAPIKey
|
||||
self.privateApplicationRules = privateApplicationRules
|
||||
=======
|
||||
|
||||
public init(openAIAPIKey: String?) {
|
||||
self.openAIAPIKey = openAIAPIKey
|
||||
>>>>>>> origin/master
|
||||
}
|
||||
|
||||
public static func development(environment: [String: String] = ProcessInfo.processInfo.environment) -> AppConfiguration {
|
||||
AppConfiguration(
|
||||
<<<<<<< HEAD
|
||||
openAIAPIKey: environment["MUSIC_ASSISTANT_OPENAI_API_KEY"],
|
||||
privateApplicationRules: PrivateApplicationRules(content: environment["MUSIC_ASSISTANT_PRIVATE_AI_RULES"])
|
||||
=======
|
||||
openAIAPIKey: environment["MUSIC_ASSISTANT_OPENAI_API_KEY"]
|
||||
>>>>>>> origin/master
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -343,7 +343,6 @@ public extension SongProject {
|
||||
versions.first { $0.id == versionID }
|
||||
}
|
||||
|
||||
<<<<<<< HEAD
|
||||
mutating func restoreVersion(id versionID: String, restoredAt: Date = Date()) -> Bool {
|
||||
guard let version = version(id: versionID) else { return false }
|
||||
restoreSnapshot(version.snapshot, updatedAt: restoredAt)
|
||||
@@ -374,8 +373,6 @@ public extension SongProject {
|
||||
self.updatedAt = updatedAt
|
||||
}
|
||||
|
||||
=======
|
||||
>>>>>>> origin/master
|
||||
mutating func appendSection(_ section: SongSection) {
|
||||
var orderedSection = section
|
||||
orderedSection.order = nextSectionOrder
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
<<<<<<< HEAD
|
||||
import Foundation
|
||||
|
||||
public protocol AIService: Sendable {
|
||||
@@ -167,24 +166,5 @@ public struct SongProjectUpdateResult: Equatable, Sendable {
|
||||
self.changedScopes = changedScopes
|
||||
self.notes = notes
|
||||
self.followUpQuestions = followUpQuestions
|
||||
=======
|
||||
public protocol AIService: Sendable {
|
||||
func planSongProject(from request: SongPlanningRequest) async throws -> SongPlanningDraft
|
||||
}
|
||||
|
||||
public struct SongPlanningRequest: Equatable, Sendable {
|
||||
public let userIntent: String
|
||||
|
||||
public init(userIntent: String) {
|
||||
self.userIntent = userIntent
|
||||
}
|
||||
}
|
||||
|
||||
public struct SongPlanningDraft: Equatable, Sendable {
|
||||
public let summary: String
|
||||
|
||||
public init(summary: String) {
|
||||
self.summary = summary
|
||||
>>>>>>> origin/master
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
import Foundation
|
||||
|
||||
public final class SongProjectGenerationDirector: Sendable {
|
||||
private let aiService: any AIService
|
||||
|
||||
public init(aiService: any AIService) {
|
||||
self.aiService = aiService
|
||||
}
|
||||
|
||||
public func generateCompleteProject(
|
||||
fromIdea idea: String,
|
||||
seedProject: SongProject? = nil,
|
||||
discussionMode: ConversationMode = .auto,
|
||||
conversation: [AIConversationMessage] = [],
|
||||
localeIdentifier: String? = nil,
|
||||
generatedAt: Date = Date()
|
||||
) async throws -> SongProjectGenerationResult {
|
||||
let trimmedIdea = idea.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
guard !trimmedIdea.isEmpty else {
|
||||
throw SongProjectGenerationDirectorError.emptyIdea
|
||||
}
|
||||
|
||||
let request = SongProjectGenerationRequest(
|
||||
context: AIRequestContext(
|
||||
userInstruction: trimmedIdea,
|
||||
conversation: conversation,
|
||||
localeIdentifier: localeIdentifier
|
||||
),
|
||||
seedProject: seedProject,
|
||||
discussionMode: discussionMode
|
||||
)
|
||||
let result = try await aiService.generateSongProject(from: request)
|
||||
let project = normalizeGeneratedProject(
|
||||
result.project,
|
||||
idea: trimmedIdea,
|
||||
seedProject: seedProject,
|
||||
discussionMode: discussionMode,
|
||||
generatedAt: generatedAt
|
||||
)
|
||||
|
||||
return SongProjectGenerationResult(
|
||||
project: project,
|
||||
notes: result.notes,
|
||||
followUpQuestions: result.followUpQuestions
|
||||
)
|
||||
}
|
||||
|
||||
private func normalizeGeneratedProject(
|
||||
_ generatedProject: SongProject,
|
||||
idea: String,
|
||||
seedProject: SongProject?,
|
||||
discussionMode: ConversationMode,
|
||||
generatedAt: Date
|
||||
) -> SongProject {
|
||||
let normalizedIdea = generatedProject.idea.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
|
||||
? idea
|
||||
: generatedProject.idea
|
||||
|
||||
guard let seedProject else {
|
||||
var project = generatedProject
|
||||
project.idea = normalizedIdea
|
||||
project.conversationMode = discussionMode
|
||||
project.updatedAt = generatedAt
|
||||
return project
|
||||
}
|
||||
|
||||
return SongProject(
|
||||
id: seedProject.id,
|
||||
title: generatedProject.title,
|
||||
idea: normalizedIdea,
|
||||
duration: generatedProject.duration,
|
||||
conversationMode: discussionMode,
|
||||
languages: generatedProject.languages,
|
||||
dialects: generatedProject.dialects,
|
||||
arabicPronunciationSettings: generatedProject.arabicPronunciationSettings,
|
||||
genres: generatedProject.genres,
|
||||
moods: generatedProject.moods,
|
||||
emotionalArc: generatedProject.emotionalArc,
|
||||
bpm: generatedProject.bpm,
|
||||
key: generatedProject.key,
|
||||
scale: generatedProject.scale,
|
||||
maqam: generatedProject.maqam,
|
||||
sections: generatedProject.sections,
|
||||
instruments: generatedProject.instruments,
|
||||
vocalists: generatedProject.vocalists,
|
||||
lyrics: generatedProject.lyrics,
|
||||
productionDirections: generatedProject.productionDirections,
|
||||
sunoOutput: generatedProject.sunoOutput,
|
||||
versions: seedProject.versions,
|
||||
createdAt: seedProject.createdAt,
|
||||
updatedAt: generatedAt
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
public enum SongProjectGenerationDirectorError: Error, Equatable, Sendable {
|
||||
case emptyIdea
|
||||
}
|
||||
Reference in New Issue
Block a user