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

66 lines
2.2 KiB
Swift

import Foundation
public final class ExistingLyricsRevisionDirector: Sendable {
private let aiService: any AIService
public init(aiService: any AIService) {
self.aiService = aiService
}
public func reviseExistingLyrics(
in project: SongProject,
sourceLyrics: Lyrics? = nil,
instruction: String,
mode: LyricsRevisionMode,
conversation: [AIConversationMessage] = [],
localeIdentifier: String? = nil,
revisedAt: Date = Date()
) async throws -> SongProjectUpdateResult {
guard mode != .writeFromIdea else {
throw ExistingLyricsRevisionDirectorError.unsupportedMode(mode)
}
let trimmedInstruction = instruction.trimmingCharacters(in: .whitespacesAndNewlines)
guard !trimmedInstruction.isEmpty else {
throw ExistingLyricsRevisionDirectorError.emptyInstruction
}
let lyricsToRevise = sourceLyrics ?? project.lyrics
guard !lyricsToRevise.text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty else {
throw ExistingLyricsRevisionDirectorError.emptySourceLyrics
}
guard !project.isUpdateScopeLocked(.lyrics) else {
return SongProjectUpdateResult(project: project)
}
let request = LyricsRevisionRequest(
context: AIRequestContext(
userInstruction: trimmedInstruction,
conversation: conversation,
localeIdentifier: localeIdentifier
),
project: project,
sourceLyrics: lyricsToRevise,
mode: mode
)
let result = try await aiService.reviseLyrics(from: request)
var proposedProject = project
proposedProject.lyrics = result.lyrics
return SongProjectAIUpdateMerger().apply(
snapshot: SongProjectSnapshot(project: proposedProject),
changedScopes: [.lyrics],
notes: result.notes,
to: project,
updatedAt: revisedAt
)
}
}
public enum ExistingLyricsRevisionDirectorError: Error, Equatable, Sendable {
case emptyInstruction
case emptySourceLyrics
case unsupportedMode(LyricsRevisionMode)
}