Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions NotchIA.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -1277,15 +1277,15 @@
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "-";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 20803;
CURRENT_PROJECT_VERSION = 20804;
DEVELOPMENT_TEAM = "";
ENABLE_HARDENED_RUNTIME = NO;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = NotchIAXPCHelper/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = NotchIAXPCHelper;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
MACOSX_DEPLOYMENT_TARGET = 15.0;
MARKETING_VERSION = 2.8.3;
MARKETING_VERSION = 2.8.4;
PRODUCT_BUNDLE_IDENTIFIER = com.coaxel2.notchia.NotchIAXPCHelper;
PRODUCT_NAME = "$(TARGET_NAME)";
REGISTER_APP_GROUPS = YES;
Expand All @@ -1303,15 +1303,15 @@
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "-";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 20803;
CURRENT_PROJECT_VERSION = 20804;
DEVELOPMENT_TEAM = "";
ENABLE_HARDENED_RUNTIME = NO;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = NotchIAXPCHelper/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = NotchIAXPCHelper;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
MACOSX_DEPLOYMENT_TARGET = 15.0;
MARKETING_VERSION = 2.8.3;
MARKETING_VERSION = 2.8.4;
PRODUCT_BUNDLE_IDENTIFIER = com.coaxel2.notchia.NotchIAXPCHelper;
PRODUCT_NAME = "$(TARGET_NAME)";
REGISTER_APP_GROUPS = YES;
Expand Down Expand Up @@ -1462,7 +1462,7 @@
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "-";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 20803;
CURRENT_PROJECT_VERSION = 20804;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_ASSET_PATHS = "\"NotchIA/Preview Content\"";
DEVELOPMENT_TEAM = "";
Expand Down Expand Up @@ -1490,7 +1490,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 15.0;
MARKETING_VERSION = 2.8.3;
MARKETING_VERSION = 2.8.4;
PRODUCT_BUNDLE_IDENTIFIER = com.coaxel2.notchia;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
Expand Down Expand Up @@ -1518,7 +1518,7 @@
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = YES;
CURRENT_PROJECT_VERSION = 20803;
CURRENT_PROJECT_VERSION = 20804;
DEAD_CODE_STRIPPING = YES;
DEPLOYMENT_POSTPROCESSING = YES;
DEVELOPMENT_ASSET_PATHS = "\"NotchIA/Preview Content\"";
Expand Down Expand Up @@ -1546,7 +1546,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 15.0;
MARKETING_VERSION = 2.8.3;
MARKETING_VERSION = 2.8.4;
PRODUCT_BUNDLE_IDENTIFIER = com.coaxel2.notchia;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
Expand Down
196 changes: 196 additions & 0 deletions NotchIA/Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -42807,6 +42807,202 @@
}
}
}
},
"Apple Intelligence indisponible — %@.": {
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "Apple Intelligence unavailable — %@."
}
},
"fr": {
"stringUnit": {
"state": "translated",
"value": "Apple Intelligence indisponible — %@."
}
},
"es": {
"stringUnit": {
"state": "translated",
"value": "Apple Intelligence no disponible — %@."
}
},
"de": {
"stringUnit": {
"state": "translated",
"value": "Apple Intelligence nicht verfügbar — %@."
}
}
}
},
"Mac non compatible Apple Intelligence": {
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "Mac not compatible with Apple Intelligence"
}
},
"fr": {
"stringUnit": {
"state": "translated",
"value": "Mac non compatible Apple Intelligence"
}
},
"es": {
"stringUnit": {
"state": "translated",
"value": "Mac no compatible con Apple Intelligence"
}
},
"de": {
"stringUnit": {
"state": "translated",
"value": "Mac nicht mit Apple Intelligence kompatibel"
}
}
}
},
"Apple Intelligence désactivée": {
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "Apple Intelligence is disabled"
}
},
"fr": {
"stringUnit": {
"state": "translated",
"value": "Apple Intelligence désactivée"
}
},
"es": {
"stringUnit": {
"state": "translated",
"value": "Apple Intelligence está desactivada"
}
},
"de": {
"stringUnit": {
"state": "translated",
"value": "Apple Intelligence ist deaktiviert"
}
}
}
},
"modèle Apple Intelligence pas encore prêt": {
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "Apple Intelligence model not ready yet"
}
},
"fr": {
"stringUnit": {
"state": "translated",
"value": "modèle Apple Intelligence pas encore prêt"
}
},
"es": {
"stringUnit": {
"state": "translated",
"value": "el modelo de Apple Intelligence aún no está listo"
}
},
"de": {
"stringUnit": {
"state": "translated",
"value": "Apple-Intelligence-Modell noch nicht bereit"
}
}
}
},
"Apple Intelligence indisponible": {
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "Apple Intelligence unavailable"
}
},
"fr": {
"stringUnit": {
"state": "translated",
"value": "Apple Intelligence indisponible"
}
},
"es": {
"stringUnit": {
"state": "translated",
"value": "Apple Intelligence no disponible"
}
},
"de": {
"stringUnit": {
"state": "translated",
"value": "Apple Intelligence nicht verfügbar"
}
}
}
},
"macOS 26 requis pour l’IA locale": {
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "macOS 26 required for on-device AI"
}
},
"fr": {
"stringUnit": {
"state": "translated",
"value": "macOS 26 requis pour l’IA locale"
}
},
"es": {
"stringUnit": {
"state": "translated",
"value": "macOS 26 necesario para la IA local"
}
},
"de": {
"stringUnit": {
"state": "translated",
"value": "macOS 26 erforderlich für lokale KI"
}
}
}
},
"FoundationModels non disponible": {
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "FoundationModels framework unavailable"
}
},
"fr": {
"stringUnit": {
"state": "translated",
"value": "FoundationModels non disponible"
}
},
"es": {
"stringUnit": {
"state": "translated",
"value": "FoundationModels no disponible"
}
},
"de": {
"stringUnit": {
"state": "translated",
"value": "FoundationModels nicht verfügbar"
}
}
}
}
},
"version": "1.0"
Expand Down
23 changes: 14 additions & 9 deletions NotchIA/components/Shelf/Services/DocumentSummaryService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@
// or when Apple Intelligence isn't enabled by the user.
//

import AppKit
import Defaults
import Foundation
import OSLog
import PDFKit
import Vision
import AppKit
import OSLog

#if canImport(FoundationModels)
import FoundationModels
Expand All @@ -34,7 +35,7 @@ final class DocumentSummaryService {
var errorDescription: String? {
switch self {
case .unavailable(let reason):
return "Apple Intelligence indisponible — \(reason)."
return String(localized: "Apple Intelligence indisponible — \(reason).")
case .unsupportedFile(let ext):
return String(localized: "Type de fichier « \(ext) » non pris en charge.")
case .noTextFound:
Expand Down Expand Up @@ -200,13 +201,15 @@ final class DocumentSummaryService {
#if canImport(FoundationModels)
if #available(macOS 26.0, *) {
do {
let lang = Defaults[.appLanguage].promptInstruction
let session = LanguageModelSession(instructions: """
Tu es un assistant qui résume des documents pour un utilisateur \
pressé. Pour chaque document, produis un résumé clair en \
français sous forme de 5 à 8 puces concises (chacune commence \
par « • »). Garde les chiffres, dates, noms et points clés. \
Ne dépasse pas 220 mots au total. Ne reformule pas la consigne, \
ne mets pas de préambule — uniquement les puces.
pressé. Pour chaque document, produis un résumé clair \(lang) \
sous forme de 5 à 8 puces concises (chacune commence par « • »). \
Garde les chiffres, dates, noms et points clés. Ne dépasse pas \
220 mots au total. Ne reformule pas la consigne, ne mets pas \
de préambule — uniquement les puces.
**LANGUE DE SORTIE OBLIGATOIRE : \(lang).**
""")
let response = try await session.respond(to: prompt)
return response.content.trimmingCharacters(in: .whitespacesAndNewlines)
Expand Down Expand Up @@ -341,14 +344,16 @@ final class DocumentSummaryService {
#if canImport(FoundationModels)
if #available(macOS 26.0, *) {
do {
let lang = Defaults[.appLanguage].promptInstruction
let session = LanguageModelSession(instructions: """
Tu reçois plusieurs documents thématiquement liés, \
séparés par « === ». Produis UN résumé unifié en français \
séparés par « === ». Produis UN résumé unifié \(lang) \
en 6 à 10 puces (chacune commence par « • »). \
Synthétise les informations importantes en mélangeant \
les sources sans les nommer une par une. Garde chiffres, \
dates et points clés. Ne dépasse pas 250 mots. Pas de \
préambule, uniquement les puces.
**LANGUE DE SORTIE OBLIGATOIRE : \(lang).**
""")
let response = try await session.respond(to: payload)
return response.content.trimmingCharacters(in: .whitespacesAndNewlines)
Expand Down
21 changes: 21 additions & 0 deletions NotchIA/extensions/AppLanguage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,27 @@ enum AppLanguage: String, CaseIterable, Identifiable, Defaults.Serializable {
case .de: return ["de"]
}
}

/// Phrase à injecter dans un prompt LLM (FoundationModels) pour forcer
/// la langue de sortie. `.system` retombe sur la langue préférée macOS.
/// Utilisé par DigestManager + DocumentSummaryService.
var promptInstruction: String {
switch self {
case .system:
let primary = (Locale.preferredLanguages.first ?? "en")
.split(separator: "-").first.map(String.init)?.lowercased() ?? "en"
switch primary {
case "fr": return "en français"
case "es": return "en español"
case "de": return "auf Deutsch"
default: return "in English"
}
case .en: return "in English"
case .fr: return "en français"
case .es: return "en español"
case .de: return "auf Deutsch"
}
}
}

enum AppLanguageManager {
Expand Down
Loading
Loading