Files
music-assistant/Sources/MusicAssistantCore/Services/AI/SongProjectGenerationDirector.swift
T

99 lines
3.4 KiB
Swift

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
}