Merge master into main
This commit is contained in:
@@ -1,8 +1,50 @@
|
||||
<<<<<<< HEAD
|
||||
import SwiftUI
|
||||
|
||||
struct RootView: View {
|
||||
var body: some View {
|
||||
ProjectBrowserView()
|
||||
=======
|
||||
import MusicAssistantCore
|
||||
import SwiftUI
|
||||
|
||||
struct RootView: View {
|
||||
private let appName = "AI Music Studio"
|
||||
private let boundarySummary = ProductBoundarySummary.initial
|
||||
|
||||
var body: some View {
|
||||
NavigationSplitView {
|
||||
List {
|
||||
Label("Projects", systemImage: "music.note.list")
|
||||
Label("Settings", systemImage: "gearshape")
|
||||
}
|
||||
.navigationTitle(appName)
|
||||
} detail: {
|
||||
VStack(alignment: .leading, spacing: 16) {
|
||||
Text("New Song Project")
|
||||
.font(.largeTitle.weight(.semibold))
|
||||
|
||||
Text(boundarySummary.description)
|
||||
.font(.body)
|
||||
.foregroundStyle(.secondary)
|
||||
.frame(maxWidth: 560, alignment: .leading)
|
||||
|
||||
Divider()
|
||||
|
||||
VStack(alignment: .leading, spacing: 8) {
|
||||
Text("Foundation status")
|
||||
.font(.headline)
|
||||
|
||||
Label("Presentation, Domain, Services, Integrations, and Persistence boundaries are separated.", systemImage: "checkmark.circle")
|
||||
Label("External providers are represented by protocols only.", systemImage: "lock.shield")
|
||||
Label("Secrets are expected from local environment configuration.", systemImage: "key")
|
||||
}
|
||||
.labelStyle(.titleAndIcon)
|
||||
}
|
||||
.padding(32)
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading)
|
||||
}
|
||||
>>>>>>> origin/master
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import Foundation
|
||||
|
||||
public struct AppConfiguration: Equatable, Sendable {
|
||||
public let openAIAPIKey: String?
|
||||
<<<<<<< HEAD
|
||||
public let privateApplicationRules: PrivateApplicationRules?
|
||||
|
||||
public init(
|
||||
@@ -10,12 +11,21 @@ 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,6 +343,7 @@ 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)
|
||||
@@ -373,6 +374,8 @@ public extension SongProject {
|
||||
self.updatedAt = updatedAt
|
||||
}
|
||||
|
||||
=======
|
||||
>>>>>>> origin/master
|
||||
mutating func appendSection(_ section: SongSection) {
|
||||
var orderedSection = section
|
||||
orderedSection.order = nextSectionOrder
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
<<<<<<< HEAD
|
||||
import Foundation
|
||||
|
||||
public protocol AIService: Sendable {
|
||||
@@ -166,5 +167,24 @@ 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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,18 +4,28 @@ import XCTest
|
||||
final class AppConfigurationTests: XCTestCase {
|
||||
func testDevelopmentConfigurationReadsKnownEnvironmentKeys() {
|
||||
let configuration = AppConfiguration.development(environment: [
|
||||
<<<<<<< HEAD
|
||||
"MUSIC_ASSISTANT_OPENAI_API_KEY": "openai-test-key",
|
||||
"MUSIC_ASSISTANT_PRIVATE_AI_RULES": " private product rules "
|
||||
])
|
||||
|
||||
XCTAssertEqual(configuration.openAIAPIKey, "openai-test-key")
|
||||
XCTAssertEqual(configuration.privateApplicationRules?.content, "private product rules")
|
||||
=======
|
||||
"MUSIC_ASSISTANT_OPENAI_API_KEY": "openai-test-key"
|
||||
])
|
||||
|
||||
XCTAssertEqual(configuration.openAIAPIKey, "openai-test-key")
|
||||
>>>>>>> origin/master
|
||||
}
|
||||
|
||||
func testDevelopmentConfigurationAllowsMissingSecrets() {
|
||||
let configuration = AppConfiguration.development(environment: [:])
|
||||
|
||||
XCTAssertNil(configuration.openAIAPIKey)
|
||||
<<<<<<< HEAD
|
||||
XCTAssertNil(configuration.privateApplicationRules)
|
||||
=======
|
||||
>>>>>>> origin/master
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,6 +119,7 @@ final class SongProjectModelTests: XCTestCase {
|
||||
XCTAssertEqual(project.genres.map(\.id), ["folk", "electronic"])
|
||||
}
|
||||
|
||||
<<<<<<< HEAD
|
||||
func testRestoresPreviousVersionWithoutDestroyingLaterVersions() {
|
||||
let createdAt = Date(timeIntervalSince1970: 100)
|
||||
let restoredAt = Date(timeIntervalSince1970: 900)
|
||||
@@ -177,6 +178,8 @@ final class SongProjectModelTests: XCTestCase {
|
||||
XCTAssertEqual(project, restoredProject)
|
||||
}
|
||||
|
||||
=======
|
||||
>>>>>>> origin/master
|
||||
func testGenreStylesAreModeledAsMultiSelect() {
|
||||
let arabicPop = GenreStyle(id: "arabic-pop", name: "Arabic Pop")
|
||||
let synthwave = GenreStyle(id: "synthwave", name: "Synthwave")
|
||||
|
||||
@@ -35,6 +35,7 @@ requirement is missing and blocks implementation, record it in
|
||||
- [x] Create new/open/save song projects locally.
|
||||
- [x] Implement project list.
|
||||
- [x] Implement immutable or snapshot-based version history.
|
||||
<<<<<<< HEAD
|
||||
- [x] Restore a previous version without destroying later versions.
|
||||
- [x] Add autosave strategy that does not create excessive versions.
|
||||
|
||||
@@ -49,14 +50,37 @@ requirement is missing and blocks implementation, record it in
|
||||
timestamp-based placement.
|
||||
- [x] Add Manual/Auto toggles for supported controls.
|
||||
- [x] Build final review screen where every generated field can be
|
||||
=======
|
||||
- [ ] Restore a previous version without destroying later versions.
|
||||
- [ ] Add autosave strategy that does not create excessive versions.
|
||||
|
||||
## Phase 3 --- Core macOS UI
|
||||
|
||||
- [ ] Build project browser.
|
||||
- [ ] Build natural chat workspace as the primary entry point.
|
||||
- [ ] Build editable project inspector for duration, genres,
|
||||
instruments, vocals and language.
|
||||
- [ ] Build song structure editor.
|
||||
- [ ] Build arrangement editor supporting section-based and
|
||||
timestamp-based placement.
|
||||
- [ ] Add Manual/Auto toggles for supported controls.
|
||||
- [ ] Build final review screen where every generated field can be
|
||||
>>>>>>> origin/master
|
||||
edited.
|
||||
|
||||
## Phase 4 --- OpenAI Integration
|
||||
|
||||
<<<<<<< HEAD
|
||||
- [x] Create provider-independent `AIService` interface.
|
||||
- [x] Implement OpenAI client.
|
||||
- [x] Define private application-rule injection mechanism.
|
||||
- [x] Define structured AI response schema for SongProject updates.
|
||||
=======
|
||||
- [ ] Create provider-independent `AIService` interface.
|
||||
- [ ] Implement OpenAI client.
|
||||
- [ ] Define private application-rule injection mechanism.
|
||||
- [ ] Define structured AI response schema for SongProject updates.
|
||||
>>>>>>> origin/master
|
||||
- [ ] Implement idea → complete project generation.
|
||||
- [ ] Implement existing lyrics → correction/improvement flow.
|
||||
- [ ] Implement Auto mode for structure, arrangement, BPM/key/maqam
|
||||
|
||||
Reference in New Issue
Block a user