224 lines
6.9 KiB
Swift
224 lines
6.9 KiB
Swift
import Foundation
|
|
|
|
// MARK: - Workflow Types
|
|
|
|
enum WorkflowType: String, CaseIterable, Identifiable, Codable {
|
|
case transcription
|
|
case localTranscription
|
|
case textImprover
|
|
case dampfAblassen
|
|
case emojiText
|
|
|
|
var id: String { rawValue }
|
|
|
|
static var mainMenuCases: [WorkflowType] {
|
|
allCases.filter { $0 != .localTranscription }
|
|
}
|
|
|
|
var displayName: String {
|
|
switch self {
|
|
case .transcription: return "Blitztext"
|
|
case .localTranscription: return "Blitztext Lokal"
|
|
case .textImprover: return "Blitztext+"
|
|
case .dampfAblassen: return "Blitztext $%&!"
|
|
case .emojiText: return "Blitztext :)"
|
|
}
|
|
}
|
|
|
|
var icon: String {
|
|
switch self {
|
|
case .transcription: return "mic.fill"
|
|
case .localTranscription: return "lock.shield.fill"
|
|
case .textImprover: return "text.badge.checkmark"
|
|
case .dampfAblassen: return "flame.fill"
|
|
case .emojiText: return "face.smiling"
|
|
}
|
|
}
|
|
|
|
var subtitle: String {
|
|
switch self {
|
|
case .transcription: return "Sprache rein. Text raus."
|
|
case .localTranscription: return "Nur lokal. Kein Server."
|
|
case .textImprover: return "Geschrieben sprechen."
|
|
case .dampfAblassen: return "Frust rein. Entspannt raus."
|
|
case .emojiText: return "Text rein. Emojis dazu."
|
|
}
|
|
}
|
|
|
|
var hotkeyLabel: String {
|
|
switch self {
|
|
case .transcription: return "fn + Shift"
|
|
case .localTranscription: return "fn + Shift + Ctrl"
|
|
case .textImprover: return "fn + Control"
|
|
case .dampfAblassen: return "fn + Option"
|
|
case .emojiText: return "fn + Cmd"
|
|
}
|
|
}
|
|
|
|
var accentColor: String {
|
|
switch self {
|
|
case .transcription: return "blue"
|
|
case .localTranscription: return "green"
|
|
case .textImprover: return "purple"
|
|
case .dampfAblassen: return "orange"
|
|
case .emojiText: return "cyan"
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: - Workflow State
|
|
|
|
enum WorkflowPhase: Equatable {
|
|
case idle
|
|
case running(String)
|
|
case done(String)
|
|
case error(String)
|
|
|
|
var isActive: Bool {
|
|
switch self {
|
|
case .idle: return false
|
|
default: return true
|
|
}
|
|
}
|
|
}
|
|
|
|
enum WorkflowLaunchSource: Equatable {
|
|
case manual
|
|
case hotkeyBackground
|
|
|
|
var presentsWorkflowPage: Bool {
|
|
switch self {
|
|
case .manual:
|
|
return true
|
|
case .hotkeyBackground:
|
|
return false
|
|
}
|
|
}
|
|
}
|
|
|
|
typealias WorkflowOutputHandler = @MainActor (String) -> Void
|
|
typealias WorkflowPhaseChangeHandler = @MainActor (WorkflowPhase) -> Void
|
|
|
|
// MARK: - Workflow Protocol
|
|
|
|
@MainActor
|
|
protocol Workflow: AnyObject, Observable {
|
|
var type: WorkflowType { get }
|
|
var phase: WorkflowPhase { get set }
|
|
var isRecording: Bool { get }
|
|
var onOutput: WorkflowOutputHandler? { get set }
|
|
var onPhaseChange: WorkflowPhaseChangeHandler? { get set }
|
|
|
|
func start()
|
|
func stop()
|
|
func reset()
|
|
}
|
|
|
|
// MARK: - App Settings
|
|
|
|
struct AppSettings: Codable {
|
|
var hotkeyMode: HotkeyMode = .hold
|
|
var hasSeenOnboarding: Bool = false
|
|
var secureLocalModeEnabled: Bool = false
|
|
var selectedLocalTranscriptionModelName: String = LocalTranscriptionService.recommendedFastModelName
|
|
var hasAutoSelectedFastLocalModel: Bool = false
|
|
|
|
init(
|
|
hotkeyMode: HotkeyMode = .hold,
|
|
hasSeenOnboarding: Bool = false,
|
|
secureLocalModeEnabled: Bool = false,
|
|
selectedLocalTranscriptionModelName: String = LocalTranscriptionService.recommendedFastModelName,
|
|
hasAutoSelectedFastLocalModel: Bool = false
|
|
) {
|
|
self.hotkeyMode = hotkeyMode
|
|
self.hasSeenOnboarding = hasSeenOnboarding
|
|
self.secureLocalModeEnabled = secureLocalModeEnabled
|
|
self.selectedLocalTranscriptionModelName = selectedLocalTranscriptionModelName
|
|
self.hasAutoSelectedFastLocalModel = hasAutoSelectedFastLocalModel
|
|
}
|
|
|
|
enum CodingKeys: String, CodingKey {
|
|
case hotkeyMode
|
|
case hasSeenOnboarding
|
|
case secureLocalModeEnabled
|
|
case selectedLocalTranscriptionModelName
|
|
case hasAutoSelectedFastLocalModel
|
|
}
|
|
|
|
init(from decoder: Decoder) throws {
|
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
|
hotkeyMode = try container.decodeIfPresent(HotkeyMode.self, forKey: .hotkeyMode) ?? .hold
|
|
hasSeenOnboarding = try container.decodeIfPresent(Bool.self, forKey: .hasSeenOnboarding) ?? false
|
|
secureLocalModeEnabled = try container.decodeIfPresent(Bool.self, forKey: .secureLocalModeEnabled) ?? false
|
|
selectedLocalTranscriptionModelName = try container.decodeIfPresent(
|
|
String.self,
|
|
forKey: .selectedLocalTranscriptionModelName
|
|
) ?? LocalTranscriptionService.recommendedFastModelName
|
|
hasAutoSelectedFastLocalModel = try container.decodeIfPresent(
|
|
Bool.self,
|
|
forKey: .hasAutoSelectedFastLocalModel
|
|
) ?? false
|
|
}
|
|
}
|
|
|
|
enum TranscriptionBackend: String, Codable {
|
|
case remote
|
|
case local
|
|
}
|
|
|
|
// MARK: - Workflow Settings
|
|
|
|
struct TranscriptionSettings: Codable {
|
|
var language: String = "de"
|
|
}
|
|
|
|
struct DampfAblassenSettings: Codable {
|
|
var systemPrompt: String = "Du erhältst ein emotional gesprochenes Transkript. Erkenne zuerst das eigentliche Ziel, Anliegen und den wahren Frust der Person. Formuliere daraus eine klare, respektvolle und wirksame Nachricht, mit der die Person ihr Ziel eher erreicht. Bewahre relevante Fakten, konkrete Probleme, Grenzen, Erwartungen und die nötige Dringlichkeit. Entferne Beleidigungen, Drohungen, Sarkasmus, Unterstellungen und unnötige Eskalation. Wenn mehrere Vorwürfe genannt werden, verdichte sie auf die entscheidenden Kernpunkte. Der Ton soll ruhig, menschlich, bestimmt und lösungsorientiert sein. Gib NUR die fertige Nachricht zurück."
|
|
var customName: String = ""
|
|
}
|
|
|
|
struct EmojiTextSettings: Codable {
|
|
var emojiDensity: EmojiDensity = .mittel
|
|
var customName: String = ""
|
|
|
|
enum EmojiDensity: String, Codable, CaseIterable, Identifiable {
|
|
case wenig
|
|
case mittel
|
|
case viel
|
|
|
|
var id: String { rawValue }
|
|
|
|
var displayName: String {
|
|
switch self {
|
|
case .wenig: return "Wenig"
|
|
case .mittel: return "Mittel"
|
|
case .viel: return "Viel"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
struct TextImprovementSettings: Codable {
|
|
var systemPrompt: String = ""
|
|
var customTerms: [String] = []
|
|
var context: String = ""
|
|
var tone: TextTone = .neutral
|
|
var customName: String = ""
|
|
|
|
enum TextTone: String, Codable, CaseIterable, Identifiable {
|
|
case formal
|
|
case neutral
|
|
case casual
|
|
|
|
var id: String { rawValue }
|
|
|
|
var displayName: String {
|
|
switch self {
|
|
case .formal: return "Formell"
|
|
case .neutral: return "Neutral"
|
|
case .casual: return "Locker"
|
|
}
|
|
}
|
|
}
|
|
}
|