diff --git a/GimiFeedback/GimiFeedback.xcodeproj/project.pbxproj b/GimiFeedback/GimiFeedback.xcodeproj/project.pbxproj index 9bdee70..4b9b1f8 100644 --- a/GimiFeedback/GimiFeedback.xcodeproj/project.pbxproj +++ b/GimiFeedback/GimiFeedback.xcodeproj/project.pbxproj @@ -18,6 +18,9 @@ D306028E2E377EC500908D1D /* FeedbackWriteViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D306028C2E377EC500908D1D /* FeedbackWriteViewModel.swift */; }; D30602962E3782A200908D1D /* KcELECTRA-base-v2022.mlpackage in Sources */ = {isa = PBXBuildFile; fileRef = D30602952E3782A200908D1D /* KcELECTRA-base-v2022.mlpackage */; }; D36C43842E38A029006A027E /* TokenizerREADME.md in Resources */ = {isa = PBXBuildFile; fileRef = D36C43832E38A025006A027E /* TokenizerREADME.md */; }; + EC25CC332E5975880087EC50 /* FirebaseAppCheck in Frameworks */ = {isa = PBXBuildFile; productRef = EC25CC322E5975880087EC50 /* FirebaseAppCheck */; }; + EC371D842E55E9AA008E4AB7 /* GeminiManger.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC371D832E55E9AA008E4AB7 /* GeminiManger.swift */; }; + EC371DC92E560D76008E4AB7 /* FirebaseAI in Frameworks */ = {isa = PBXBuildFile; productRef = EC371DC82E560D76008E4AB7 /* FirebaseAI */; }; EC6A4C842E31284F0087DB5C /* ChannelDetail+DescriptionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC6A4C832E31284F0087DB5C /* ChannelDetail+DescriptionView.swift */; }; EC6A4C862E3129300087DB5C /* ChannelDetail+EmptyFeedbackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC6A4C852E3129300087DB5C /* ChannelDetail+EmptyFeedbackView.swift */; }; EC6A4C882E312A3B0087DB5C /* ChannelDetail+FeedbackListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC6A4C872E312A3B0087DB5C /* ChannelDetail+FeedbackListView.swift */; }; @@ -64,7 +67,6 @@ EE41FEDC2E2250DF0002E595 /* KakaoSDKAuth in Frameworks */ = {isa = PBXBuildFile; productRef = EE41FEDB2E2250DF0002E595 /* KakaoSDKAuth */; }; EE41FEDE2E2250DF0002E595 /* KakaoSDKCommon in Frameworks */ = {isa = PBXBuildFile; productRef = EE41FEDD2E2250DF0002E595 /* KakaoSDKCommon */; }; EE41FEE02E2250DF0002E595 /* KakaoSDKUser in Frameworks */ = {isa = PBXBuildFile; productRef = EE41FEDF2E2250DF0002E595 /* KakaoSDKUser */; }; - EE41FEE52E2256280002E595 /* Config.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = EE41FEE42E2256280002E595 /* Config.xcconfig */; }; EE41FEE72E22572C0002E595 /* Bundle+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE41FEE62E2257260002E595 /* Bundle+Extension.swift */; }; EE41FEE92E2259350002E595 /* UserViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE41FEE82E2259310002E595 /* UserViewModel.swift */; }; EE41FEEB2E22599C0002E595 /* KakaoAuthManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE41FEEA2E2259980002E595 /* KakaoAuthManager.swift */; }; @@ -132,6 +134,7 @@ D306028C2E377EC500908D1D /* FeedbackWriteViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedbackWriteViewModel.swift; sourceTree = ""; }; D30602952E3782A200908D1D /* KcELECTRA-base-v2022.mlpackage */ = {isa = PBXFileReference; lastKnownFileType = folder.mlpackage; path = "KcELECTRA-base-v2022.mlpackage"; sourceTree = ""; }; D36C43832E38A025006A027E /* TokenizerREADME.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = TokenizerREADME.md; sourceTree = ""; }; + EC371D832E55E9AA008E4AB7 /* GeminiManger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeminiManger.swift; sourceTree = ""; }; EC6A4C832E31284F0087DB5C /* ChannelDetail+DescriptionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ChannelDetail+DescriptionView.swift"; sourceTree = ""; }; EC6A4C852E3129300087DB5C /* ChannelDetail+EmptyFeedbackView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ChannelDetail+EmptyFeedbackView.swift"; sourceTree = ""; }; EC6A4C872E312A3B0087DB5C /* ChannelDetail+FeedbackListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ChannelDetail+FeedbackListView.swift"; sourceTree = ""; }; @@ -238,10 +241,12 @@ EEDBB1BE2E2913CE00F16407 /* FirebaseFunctions in Frameworks */, D306027D2E377E8400908D1D /* Transformers in Frameworks */, EE41FEDE2E2250DF0002E595 /* KakaoSDKCommon in Frameworks */, + EC25CC332E5975880087EC50 /* FirebaseAppCheck in Frameworks */, EE3755462E1E5B8D009AD262 /* FirebaseAuth in Frameworks */, ECC980B12E290DC4004A483B /* KakaoSDKTemplate in Frameworks */, EE3755482E1E5B8D009AD262 /* FirebaseFirestore in Frameworks */, EE41FEE02E2250DF0002E595 /* KakaoSDKUser in Frameworks */, + EC371DC92E560D76008E4AB7 /* FirebaseAI in Frameworks */, EE41FEDC2E2250DF0002E595 /* KakaoSDKAuth in Frameworks */, ECC980AF2E290DC4004A483B /* KakaoSDKShare in Frameworks */, ); @@ -300,6 +305,15 @@ path = MLWeights; sourceTree = ""; }; + EC371D822E55E99C008E4AB7 /* LLM */ = { + isa = PBXGroup; + children = ( + EC94C0F22E3746130020E59D /* GPTManger.swift */, + EC371D832E55E9AA008E4AB7 /* GeminiManger.swift */, + ); + path = LLM; + sourceTree = ""; + }; EC6A4C822E31274B0087DB5C /* SubViews */ = { isa = PBXGroup; children = ( @@ -594,7 +608,6 @@ EE856A4B2E1CD3AA006820B9 /* FirestoreManager.swift */, EE41FEEC2E225A1C0002E595 /* FirebaseAuthManager.swift */, EEDBB1BB2E28DEB900F16407 /* FCMManager.swift */, - EC94C0F22E3746130020E59D /* GPTManger.swift */, ECC980AB2E28E91E004A483B /* DeepLinkManager.swift */, ECC980B42E294835004A483B /* KakaoShareManager.swift */, EE41FEEA2E2259980002E595 /* KakaoAuthManager.swift */, @@ -667,6 +680,7 @@ EEFEBF592E4B7EFB001D824D /* AI */ = { isa = PBXGroup; children = ( + EC371D822E55E99C008E4AB7 /* LLM */, D30602832E377E9700908D1D /* MLModel */, D30602892E377EA100908D1D /* MLWeights */, ); @@ -701,6 +715,8 @@ EEDBB1B72E28D45700F16407 /* FirebaseMessaging */, EEDBB1BD2E2913CE00F16407 /* FirebaseFunctions */, D306027C2E377E8400908D1D /* Transformers */, + EC371DC82E560D76008E4AB7 /* FirebaseAI */, + EC25CC322E5975880087EC50 /* FirebaseAppCheck */, ); productName = A10; productReference = EE856A262E1CD093006820B9 /* GimiFeedback.app */; @@ -714,7 +730,7 @@ attributes = { BuildIndependentTargetsInParallel = 1; LastSwiftUpdateCheck = 1630; - LastUpgradeCheck = 1630; + LastUpgradeCheck = 1640; TargetAttributes = { EE856A252E1CD093006820B9 = { CreatedOnToolsVersion = 16.3; @@ -751,7 +767,6 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - EE41FEE52E2256280002E595 /* Config.xcconfig in Resources */, EE465EE92E26205D0096109A /* GoogleService-Info.plist in Resources */, EE3754AF2E1D7B36009AD262 /* .swiftlint.yml in Resources */, D36C43842E38A029006A027E /* TokenizerREADME.md in Resources */, @@ -838,6 +853,7 @@ EC6A4CA52E350B720087DB5C /* Spicy+Extension.swift in Sources */, EE37553D2E1E10EA009AD262 /* FeedbackContentType.swift in Sources */, EE37554A2E1E5BBD009AD262 /* AppDelegate.swift in Sources */, + EC371D842E55E9AA008E4AB7 /* GeminiManger.swift in Sources */, D30602962E3782A200908D1D /* KcELECTRA-base-v2022.mlpackage in Sources */, EE3755412E1E1105009AD262 /* FeedbackChannel.swift in Sources */, EE37553F2E1E10F9009AD262 /* FeedbackContent.swift in Sources */, @@ -1145,6 +1161,16 @@ package = D306027B2E377E8400908D1D /* XCRemoteSwiftPackageReference "swift-transformers" */; productName = Transformers; }; + EC25CC322E5975880087EC50 /* FirebaseAppCheck */ = { + isa = XCSwiftPackageProductDependency; + package = EE3755442E1E5B8D009AD262 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; + productName = FirebaseAppCheck; + }; + EC371DC82E560D76008E4AB7 /* FirebaseAI */ = { + isa = XCSwiftPackageProductDependency; + package = EE3755442E1E5B8D009AD262 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; + productName = FirebaseAI; + }; ECC980AE2E290DC4004A483B /* KakaoSDKShare */ = { isa = XCSwiftPackageProductDependency; package = EE41FEDA2E2250DF0002E595 /* XCRemoteSwiftPackageReference "kakao-ios-sdk" */; diff --git a/GimiFeedback/GimiFeedback.xcodeproj/xcshareddata/xcschemes/GimiFeedback.xcscheme b/GimiFeedback/GimiFeedback.xcodeproj/xcshareddata/xcschemes/GimiFeedback.xcscheme index 91162d9..068ecf4 100644 --- a/GimiFeedback/GimiFeedback.xcodeproj/xcshareddata/xcschemes/GimiFeedback.xcscheme +++ b/GimiFeedback/GimiFeedback.xcodeproj/xcshareddata/xcschemes/GimiFeedback.xcscheme @@ -1,6 +1,6 @@ + <입력 예시>회의 시간에 집중 좀 해. 계속 딴짓해서 짜증나. + <출력 예시>회의에 더 집중해주면 좋겠어요. 가끔 딴짓하는 모습이 보여서 회의 흐름이 조금 끊기는 느낌이 있었어요. + + + <예시> + <입력 예시>일을 너무 느리게 해. 같이 일하기 힘들어. + <출력 예시>업무 속도가 조금 더 빨라지면 협업이 훨씬 원활할 것 같아요. 지금도 충분히 잘하고 있지만, 약간만 더 신경 써주면 좋겠어요. + + + <예시> + <입력 예시>말이 너무 많고 눈치가 없어서 분위기 망치고 있어. + <출력 예시>이야기를 적극적으로 해주는 건 좋지만, 상황에 맞게 조절해주면 더 좋은 분위기가 될 수 있을 것 같아요. + + + 위와 같이, 표현은 순화하지만 피드백의 본질은 흐리지 않도록 해줘. + """ + +} + +extension GeminiManger { + func generate(inputText: String) async throws -> String { + guard let model else { return "" } + + let response = try await model.generateContent(inputText) + return response.text ?? "" + } +} diff --git a/GimiFeedback/GimiFeedback/App/AppDelegate.swift b/GimiFeedback/GimiFeedback/App/AppDelegate.swift index 7beba06..5e4f87f 100644 --- a/GimiFeedback/GimiFeedback/App/AppDelegate.swift +++ b/GimiFeedback/GimiFeedback/App/AppDelegate.swift @@ -9,6 +9,7 @@ import SwiftUI import FirebaseCore import UserNotifications import FirebaseMessaging +import FirebaseAppCheck final class AppDelegate: NSObject, UIApplicationDelegate { var saveUserInfo: [AnyHashable: Any]? @@ -17,6 +18,10 @@ final class AppDelegate: NSObject, UIApplicationDelegate { _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil ) -> Bool { + + let providerFactory = YourAppCheckProviderFactory() + AppCheck.setAppCheckProviderFactory(providerFactory) + FirebaseApp.configure() setUIAppearance() @@ -134,3 +139,14 @@ extension AppDelegate { ) } } + +final class YourAppCheckProviderFactory: NSObject, AppCheckProviderFactory { + func createProvider(with app: FirebaseApp) -> AppCheckProvider? { + // 시뮬레이터 환경에서는 AppCheckDebugProvider를 사용하도록 설정합니다. + #if targetEnvironment(simulator) + return AppCheckDebugProvider(app: app) + #else + return AppAttestProvider(app: app) + #endif + } +} diff --git a/GimiFeedback/GimiFeedback/App/GimiFeedback.entitlements b/GimiFeedback/GimiFeedback/App/GimiFeedback.entitlements index 903def2..d2ae5a1 100644 --- a/GimiFeedback/GimiFeedback/App/GimiFeedback.entitlements +++ b/GimiFeedback/GimiFeedback/App/GimiFeedback.entitlements @@ -4,5 +4,7 @@ aps-environment development + com.apple.developer.devicecheck.appattest-environment + production diff --git a/GimiFeedback/GimiFeedback/Presentation/FeedbackDetail/FeedbackDetailViewModel.swift b/GimiFeedback/GimiFeedback/Presentation/FeedbackDetail/FeedbackDetailViewModel.swift index ba03ad1..425c0e1 100644 --- a/GimiFeedback/GimiFeedback/Presentation/FeedbackDetail/FeedbackDetailViewModel.swift +++ b/GimiFeedback/GimiFeedback/Presentation/FeedbackDetail/FeedbackDetailViewModel.swift @@ -73,7 +73,7 @@ extension FeedbackDetailViewModel { private func transFeedbackContent(content: FeedbackContent) { Task { isTransLoading = true - let response = try await GPTManger.shared.sendChatCompletion(inputText: content.content) + let response = try await GeminiManger.shared.generate(inputText: content.content) guard let index = feedbackItem.content.firstIndex(where: { $0.id == content.id }) else { return }