Implement idea to song project generation
This commit is contained in:
@@ -0,0 +1,130 @@
|
||||
import MusicAssistantCore
|
||||
import XCTest
|
||||
|
||||
final class SongProjectGenerationDirectorTests: XCTestCase {
|
||||
func testGenerateCompleteProjectBuildsGenerationRequestFromTrimmedIdea() async throws {
|
||||
let aiService = RecordingGenerationAIService(
|
||||
generationResult: SongProjectGenerationResult(
|
||||
project: SongProject(
|
||||
title: "Generated Song",
|
||||
idea: "Hopeful cinematic pop",
|
||||
genres: [GenreStyle(id: "cinematic-pop", name: "Cinematic Pop")]
|
||||
),
|
||||
notes: ["Completed from idea."]
|
||||
)
|
||||
)
|
||||
let director = SongProjectGenerationDirector(aiService: aiService)
|
||||
let conversation = [
|
||||
AIConversationMessage(role: .user, content: "Use piano.")
|
||||
]
|
||||
|
||||
let result = try await director.generateCompleteProject(
|
||||
fromIdea: " Hopeful cinematic pop ",
|
||||
discussionMode: .discuss,
|
||||
conversation: conversation,
|
||||
localeIdentifier: "en_US",
|
||||
generatedAt: Date(timeIntervalSince1970: 200)
|
||||
)
|
||||
let recordedRequest = await aiService.recordedGenerationRequests.first
|
||||
|
||||
XCTAssertEqual(recordedRequest?.context.userInstruction, "Hopeful cinematic pop")
|
||||
XCTAssertEqual(recordedRequest?.context.conversation, conversation)
|
||||
XCTAssertEqual(recordedRequest?.context.localeIdentifier, "en_US")
|
||||
XCTAssertEqual(recordedRequest?.discussionMode, .discuss)
|
||||
XCTAssertNil(recordedRequest?.seedProject)
|
||||
XCTAssertEqual(result.project.conversationMode, .discuss)
|
||||
XCTAssertEqual(result.project.updatedAt, Date(timeIntervalSince1970: 200))
|
||||
XCTAssertEqual(result.notes, ["Completed from idea."])
|
||||
}
|
||||
|
||||
func testGenerateCompleteProjectPreservesSeedProjectIdentityAndVersions() async throws {
|
||||
let createdAt = Date(timeIntervalSince1970: 10)
|
||||
let generatedAt = Date(timeIntervalSince1970: 300)
|
||||
var seedProject = SongProject(
|
||||
id: "seed-project",
|
||||
title: "Draft",
|
||||
idea: "Original idea",
|
||||
createdAt: createdAt,
|
||||
updatedAt: createdAt
|
||||
)
|
||||
let version = seedProject.createVersion(
|
||||
id: "seed-version",
|
||||
label: "Before generation",
|
||||
createdAt: createdAt
|
||||
)
|
||||
let aiService = RecordingGenerationAIService(
|
||||
generationResult: SongProjectGenerationResult(
|
||||
project: SongProject(
|
||||
id: "generated-id",
|
||||
title: "Generated Complete Project",
|
||||
idea: "",
|
||||
sections: [
|
||||
SongSection(id: "verse", type: .verse, title: "Verse", order: 0)
|
||||
],
|
||||
lyrics: Lyrics(text: "Generated lyrics")
|
||||
)
|
||||
)
|
||||
)
|
||||
let director = SongProjectGenerationDirector(aiService: aiService)
|
||||
|
||||
let result = try await director.generateCompleteProject(
|
||||
fromIdea: "Build from this idea",
|
||||
seedProject: seedProject,
|
||||
generatedAt: generatedAt
|
||||
)
|
||||
let recordedRequest = await aiService.recordedGenerationRequests.first
|
||||
|
||||
XCTAssertEqual(recordedRequest?.seedProject, seedProject)
|
||||
XCTAssertEqual(result.project.id, "seed-project")
|
||||
XCTAssertEqual(result.project.createdAt, createdAt)
|
||||
XCTAssertEqual(result.project.updatedAt, generatedAt)
|
||||
XCTAssertEqual(result.project.versions, [version])
|
||||
XCTAssertEqual(result.project.title, "Generated Complete Project")
|
||||
XCTAssertEqual(result.project.idea, "Build from this idea")
|
||||
XCTAssertEqual(result.project.sections.first?.id, "verse")
|
||||
XCTAssertEqual(result.project.lyrics.text, "Generated lyrics")
|
||||
}
|
||||
|
||||
func testGenerateCompleteProjectRejectsBlankIdeaBeforeCallingAI() async {
|
||||
let aiService = RecordingGenerationAIService(
|
||||
generationResult: SongProjectGenerationResult(
|
||||
project: SongProject(title: "Unused", idea: "Unused")
|
||||
)
|
||||
)
|
||||
let director = SongProjectGenerationDirector(aiService: aiService)
|
||||
|
||||
do {
|
||||
_ = try await director.generateCompleteProject(fromIdea: " \n ")
|
||||
XCTFail("Expected blank idea to throw.")
|
||||
} catch let error as SongProjectGenerationDirectorError {
|
||||
XCTAssertEqual(error, .emptyIdea)
|
||||
} catch {
|
||||
XCTFail("Expected SongProjectGenerationDirectorError.")
|
||||
}
|
||||
|
||||
let requestCount = await aiService.recordedGenerationRequests.count
|
||||
XCTAssertEqual(requestCount, 0)
|
||||
}
|
||||
}
|
||||
|
||||
private actor RecordingGenerationAIService: AIService {
|
||||
private(set) var recordedGenerationRequests: [SongProjectGenerationRequest] = []
|
||||
private let generationResult: SongProjectGenerationResult
|
||||
|
||||
init(generationResult: SongProjectGenerationResult) {
|
||||
self.generationResult = generationResult
|
||||
}
|
||||
|
||||
func generateSongProject(from request: SongProjectGenerationRequest) async throws -> SongProjectGenerationResult {
|
||||
recordedGenerationRequests.append(request)
|
||||
return generationResult
|
||||
}
|
||||
|
||||
func reviseLyrics(from request: LyricsRevisionRequest) async throws -> LyricsRevisionResult {
|
||||
LyricsRevisionResult(lyrics: request.sourceLyrics)
|
||||
}
|
||||
|
||||
func proposeProjectUpdate(from request: SongProjectUpdateRequest) async throws -> SongProjectUpdateResult {
|
||||
SongProjectUpdateResult(project: request.project)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user