add cloud more Data

This commit is contained in:
陈连辰
2023-04-06 17:11:26 +08:00
parent 99c9f15640
commit 85a2093902
12 changed files with 575 additions and 232 deletions

View File

@@ -29,6 +29,7 @@
CB0F5A6029D059C4005B71D2 /* SplashCodeSyntaxHighlighter.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB0F5A5E29D059C4005B71D2 /* SplashCodeSyntaxHighlighter.swift */; };
CB1DCAC629B4F09F00B1D4E1 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = CB1DCAC529B4F09F00B1D4E1 /* Assets.xcassets */; };
CB1DCAC929B4F09F00B1D4E1 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = CB1DCAC829B4F09F00B1D4E1 /* Preview Assets.xcassets */; };
CB1F1DD029DDBA0B008CFD0B /* AIPromptPopView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB1F1DCF29DDBA0B008CFD0B /* AIPromptPopView.swift */; };
CB2449F829D721F3006EE829 /* SystemManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB2449F729D721F3006EE829 /* SystemManager.swift */; };
CB2449FA29D7FE38006EE829 /* ServerManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB2449F929D7FE38006EE829 /* ServerManager.swift */; };
CB27655C29D1C12C00897E0E /* MarkdownView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB27655B29D1C12C00897E0E /* MarkdownView.swift */; };
@@ -72,6 +73,7 @@
CB1DCAC529B4F09F00B1D4E1 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
CB1DCAC829B4F09F00B1D4E1 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
CB1DCACA29B4F09F00B1D4E1 /* OSXChatGPT.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = OSXChatGPT.entitlements; sourceTree = "<group>"; };
CB1F1DCF29DDBA0B008CFD0B /* AIPromptPopView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AIPromptPopView.swift; sourceTree = "<group>"; };
CB228EA129CD4949006B3559 /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; };
CB2449F729D721F3006EE829 /* SystemManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SystemManager.swift; sourceTree = "<group>"; };
CB2449F929D7FE38006EE829 /* ServerManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerManager.swift; sourceTree = "<group>"; };
@@ -136,6 +138,7 @@
CB2F972129CED6AE004EBD96 /* ChatRoomInputView.swift */,
182B436429BC5C8700F06778 /* UserInitializeView.swift */,
CB27656529D1DA9800897E0E /* AIPromptView.swift */,
CB1F1DCF29DDBA0B008CFD0B /* AIPromptPopView.swift */,
CB27657429D33D7A00897E0E /* AIPromptInputView.swift */,
182B436129BC5C8700F06778 /* View.swift */,
182B437A29BC5FBE00F06778 /* EnterAPIView.swift */,
@@ -348,6 +351,7 @@
CB2F972829CEFB65004EBD96 /* ChatRoomToolBar.swift in Sources */,
CBC4B12329B8D28D00650296 /* Message+CoreDataClass.swift in Sources */,
CB27657329D30F1400897E0E /* AIPromptViewMdoel.swift in Sources */,
CB1F1DD029DDBA0B008CFD0B /* AIPromptPopView.swift in Sources */,
CB27655C29D1C12C00897E0E /* MarkdownView.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;

View File

@@ -13,11 +13,13 @@ class AIPromptSessionViewMdoel: ObservableObject {
@Published var selectedItem :Prompt?
func fetchAllPrompts(session: Conversation) {
let completedDateSort = NSSortDescriptor(keyPath: \Prompt.createdDate, ascending: false)
var aa: [Prompt] = CoreDataManager.shared.fetch("Prompt", sorting: [completedDateSort])
if (aa.count == 0) {
aa = AIPromptSessionViewMdoel.createDefaultPrompt()
}
let request: NSFetchRequest<Prompt> = Prompt.fetchRequest()
request.predicate = NSPredicate(format: "type == %d", 3)
let timestampSortDescriptor = NSSortDescriptor(key: "createdDate", ascending: false)
request.sortDescriptors = [timestampSortDescriptor]
var aa: [Prompt] = CoreDataManager.shared.fetch(request: request)
if let prompt = session.prompt {
if aa.contains(where: {$0.id == prompt.id && $0.type != 1}) {
selectedItem = prompt
@@ -35,88 +37,31 @@ class AIPromptSessionViewMdoel: ObservableObject {
}
CoreDataManager.shared.saveData()
allPrompts = aa
//
HTTPClient.getPrompt { [weak self] datas, err in
print("获取云端数据成功")
guard let self = self else { return }
var temp: [Prompt] = []
datas.forEach { json in
if let jsonData = json as? [String: Any] {
if let idString = jsonData["idString"] as? String {
if !self.allPrompts.contains(where: {$0.idString == idString}) {
let p = Prompt(context: CoreDataManager.shared.container.viewContext)
p.id = UUID(uuidString: idString)
p.createdDate = Date()
p.author = jsonData["author"] as? String
p.title = jsonData["title"] as? String
p.prompt = jsonData["prompt"] as? String
p.hexColor = NSColor.randomColor().toHexString()
CoreDataManager.shared.saveData()
temp.append(p)
}
}else {
let p = Prompt(context: CoreDataManager.shared.container.viewContext)
p.id = UUID()
p.createdDate = Date()
p.author = jsonData["author"] as? String
p.title = jsonData["title"] as? String
p.prompt = jsonData["prompt"] as? String
p.hexColor = NSColor.randomColor().toHexString()
CoreDataManager.shared.saveData()
temp.append(p)
}
}
}
if temp.count > 0 {
DispatchQueue.main.async {
self.allPrompts += temp
}
}
}
}
func deletePrompt(prompt: Prompt) {
if prompt.type == 1 {
return
}
allPrompts.removeAll(where: {$0.id == prompt.id})
prompt.type = 2
if let idx = allPrompts.firstIndex(where: {$0.id == prompt.id}) {
allPrompts[idx].type = 2
}
allPrompts.removeAll(where: {$0.type == 2 })
if prompt.id == selectedItem?.id {
selectedItem = allPrompts.first
}
CoreDataManager.shared.delete(object: prompt)
}
static func createDefaultPrompt() -> [Prompt] {
var temp: [Prompt] = []
let prompt1 = Prompt(context: CoreDataManager.shared.container.viewContext)
prompt1.id = UUID()
prompt1.createdDate = Date()
prompt1.title = "翻译"
prompt1.prompt = "翻译我说的任何中文或英文。只返回翻译结果,不解释它"
prompt1.hexColor = NSColor.randomColor().toHexString()
temp.append(prompt1)
CoreDataManager.shared.saveData()
return temp
}
}
class AIPromptViewMdoel: ObservableObject {
let isSession: Bool
@Published var allPrompts: [Prompt] = []
@Published var prompts: [Prompt] = []
init(isSession: Bool) {
self.isSession = isSession
if isSession {
fetchPrompts()
}else {
fetchAllPrompts()
}
init() {
fetchAllPrompts()
}
static func randomColor() -> Color {
@@ -134,20 +79,111 @@ class AIPromptViewMdoel: ObservableObject {
prompt.author = author
prompt.id = UUID()
prompt.createdDate = Date()
prompt.type = 2
allPrompts.insert(prompt, at: 0)
CoreDataManager.shared.saveData()
if isToggleOn {
HTTPClient.uploadPrompt(prompt: prompt)
}
}
func updatePrompt(prompt: Prompt, isToggleOn: Bool) {
if let idx = allPrompts.firstIndex(where: {$0.id == prompt.id}) {
allPrompts[idx] = prompt
}else {
allPrompts.append(prompt)
}
CoreDataManager.shared.saveData()
if isToggleOn {
HTTPClient.uploadPrompt(prompt: prompt)
}
}
func deletePrompt(prompt: Prompt) {
allPrompts.removeAll(where: {$0.id == prompt.id})
CoreDataManager.shared.delete(object: prompt)
CoreDataManager.shared.saveData()
}
}
extension AIPromptViewMdoel {
private func fetchAllPrompts() {
let completedDateSort = NSSortDescriptor(keyPath: \Prompt.serial, ascending: false)
let aa: [Prompt] = CoreDataManager.shared.fetch("Prompt", sorting: [completedDateSort])
//
let deleteRequest: NSFetchRequest<Prompt> = Prompt.fetchRequest()
deleteRequest.predicate = NSPredicate(format: "type == 0")
CoreDataManager.shared.delete(request: deleteRequest)
//
let request: NSFetchRequest<Prompt> = Prompt.fetchRequest()
let type2Predicate = NSPredicate(format: "type == %d", 2)
let type3Predicate = NSPredicate(format: "type == %d", 3)
let compoundPredicate = NSCompoundPredicate(orPredicateWithSubpredicates: [type2Predicate, type3Predicate])
request.predicate = compoundPredicate
let typeSortDescriptor = NSSortDescriptor(key: "type", ascending: false)
let timestampSortDescriptor = NSSortDescriptor(key: "createdDate", ascending: false)
request.sortDescriptors = [typeSortDescriptor, timestampSortDescriptor]
var aa: [Prompt] = CoreDataManager.shared.fetch(request: request)
//
let remove = aa.filter { $0.title == nil || $0.prompt == nil || $0.id == nil}
CoreDataManager.shared.delete(objects: remove)
aa.removeAll { $0.title == nil || $0.prompt == nil || $0.id == nil }
//
allPrompts = aa
//
HTTPClient.getPrompt { [weak self] datas, err in
print("云端数据请求成功")
guard let self = self else { return }
var temp: [Prompt] = []
datas.forEach { json in
if let jsonData = json as? [String: Any] {
if let idString = jsonData["idString"] as? String {
if !self.allPrompts.contains(where: {$0.idString == idString}) {
let p = Prompt(context: CoreDataManager.shared.container.viewContext)
p.id = UUID(uuidString: idString)
p.type = 0
p.createdDate = Date()
p.author = jsonData["author"] as? String
p.title = jsonData["title"] as? String
p.prompt = jsonData["prompt"] as? String
p.hexColor = NSColor.randomColor().toHexString()
p.cloudId = jsonData["cloudId"] as? Int32 ?? 0
CoreDataManager.shared.saveData()
temp.append(p)
}
}else {
let p = Prompt(context: CoreDataManager.shared.container.viewContext)
p.id = UUID()
p.type = 0
p.createdDate = Date()
p.author = jsonData["author"] as? String
p.title = jsonData["title"] as? String
p.prompt = jsonData["prompt"] as? String
p.cloudId = jsonData["cloudId"] as? Int32 ?? 0
p.hexColor = NSColor.randomColor().toHexString()
CoreDataManager.shared.saveData()
temp.append(p)
}
}
}
if temp.count > 0 {
self.allPrompts.forEach { p in
temp.removeAll(where: {$0.cloudId == p.cloudId})
}
DispatchQueue.main.async {
self.allPrompts += temp
}
}else {
print("获取云端数据失败需要更新token")
}
}
}
private func fetchPrompts() {

View File

@@ -427,9 +427,9 @@ extension ViewModel {
func fetchConversations() {
let completedDateSort = NSSortDescriptor(keyPath: \Conversation.updateData, ascending: false)
var aa: [Conversation] = CoreDataManager.shared.fetch("Conversation", sorting: [completedDateSort])
let remove = aa.filter { $0.lastMessage == nil}
let remove = aa.filter { $0.lastMessage == nil && $0.prompt == nil }
CoreDataManager.shared.delete(objects: remove)
aa.removeAll { $0.lastMessage == nil}
aa.removeAll { $0.lastMessage == nil && $0.prompt == nil}
conversations = aa
}
private func fetchConversation(sesstionId: String) -> Conversation? {

View File

@@ -26,4 +26,5 @@ public class Prompt: NSManagedObject {
}
}
}

View File

@@ -10,6 +10,8 @@ import Foundation
import CoreData
extension Prompt {
@nonobjc public class func fetchRequest() -> NSFetchRequest<Prompt> {
@@ -25,6 +27,7 @@ extension Prompt {
@NSManaged public var type: Int16
@NSManaged public var hexColor: String?
@NSManaged public var sesstion: NSSet?
@NSManaged public var cloudId: Int32
}

View File

@@ -285,19 +285,22 @@ extension HTTPClient {
code = response.statusCode
}
if let data = data,
let json = try? JSONSerialization.jsonObject(with: data) as? [String: Any],
let base64Str = json["content"] as? String {
let base64String = base64Str.replacingOccurrences(of: "\n", with: "")
if let da = NSData(base64Encoded: base64String, options: NSData.Base64DecodingOptions.init(rawValue: 0)),
let dataString = String(data: da as Data, encoding: .utf8),
let jsonData = dataString.data(using: .utf8),
let jsonObject = try? JSONSerialization.jsonObject(with: jsonData, options: []) as? [Any] {
callback(jsonObject, nil)
let json = try? JSONSerialization.jsonObject(with: data) as? [String: Any] {
if let base64Str = json["content"] as? String {
let base64String = base64Str.replacingOccurrences(of: "\n", with: "")
if let da = NSData(base64Encoded: base64String, options: NSData.Base64DecodingOptions.init(rawValue: 0)),
let dataString = String(data: da as Data, encoding: .utf8),
let jsonData = dataString.data(using: .utf8),
let jsonObject = try? JSONSerialization.jsonObject(with: jsonData, options: []) as? [Any] {
callback(jsonObject, nil)
}else {
callback([], "data error code:\(code)")
}
}else {
//token
callback([], "data error code:\(code)")
}
}else {
callback([], "data error code:\(code)")
}
}
task.resume()

View File

@@ -18,6 +18,7 @@
</entity>
<entity name="Prompt" representedClassName=".Prompt" syncable="YES">
<attribute name="author" optional="YES" attributeType="String"/>
<attribute name="cloudId" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="createdDate" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="hexColor" optional="YES" attributeType="String"/>
<attribute name="id" optional="YES" attributeType="UUID" usesScalarValueType="NO"/>

View File

@@ -8,10 +8,10 @@
import SwiftUI
struct AIPromptInputView: View {
@StateObject var viewModel = AIPromptViewMdoel(isSession: true)
@StateObject var viewModel: AIPromptViewMdoel
@Binding var isPresented: Bool
@State private var title: String = ""
@State private var prompt: String = ""
@State private var content: String = ""
@State private var author: String = ""
@State private var isToggleOn: Bool = true
@Environment(\.colorScheme) private var colorScheme
@@ -22,7 +22,7 @@ struct AIPromptInputView: View {
VStack {
VStack {
Spacer()
Text("自定义提示")
Text("自定义添加")
.font(.title3)
.foregroundColor((colorScheme == .dark) ? .white.opacity(0.9) :.black.opacity(0.9))
Spacer()
@@ -73,7 +73,7 @@ struct AIPromptInputView: View {
}.padding(.top, 5)
HStack {
TextEditor(text: $prompt)
TextEditor(text: $content)
.font(Font.system(size: 13))
.padding(8)
.background((colorScheme == .dark) ? .gray.opacity(0.1) :.white.opacity(0.9))
@@ -90,12 +90,12 @@ struct AIPromptInputView: View {
.padding(.leading, 20)
.padding(.bottom, 0)
.frame(height: 18)
Text("(选填)")
.font(Font.system(size: 11))
.padding(.top, 5)
.foregroundColor(.gray.opacity(0.6))
.frame(height: 18)
Text("后台审核通过后可分享给其他人")
// Text("()")
// .font(Font.system(size: 11))
// .padding(.top, 5)
// .foregroundColor(.gray.opacity(0.6))
// .frame(height: 18)
Text("分享您的修饰语到词库")
.font(Font.system(size: 10))
.padding(.top, 5)
.foregroundColor(.gray.opacity(0.6))
@@ -119,7 +119,7 @@ struct AIPromptInputView: View {
VStack {
HStack {
Toggle("是否上传至云端", isOn: $isToggleOn)
Toggle("是否分享", isOn: $isToggleOn)
.padding()
.foregroundColor(.gray)
.font(Font.system(size: 13))
@@ -132,7 +132,11 @@ struct AIPromptInputView: View {
}
Button {
viewModel.addPrompt(title: title, content: prompt, author: author, isToggleOn: isToggleOn)
if title.isEmpty || content.isEmpty {
self.isPresented = false
return
}
viewModel.addPrompt(title: title, content: content, author: author, isToggleOn: isToggleOn)
self.isPresented = false
} label: {

View File

@@ -0,0 +1,154 @@
//
// AIPromptPopView.swift
// OSXChatGPT
//
// Created by CoderChan on 2023/4/5.
//
import SwiftUI
struct AIPromptPopView: View {
@Environment(\.colorScheme) private var colorScheme
@EnvironmentObject var viewModel: ViewModel
@StateObject var data = AIPromptSessionViewMdoel()
@Binding var showInputView: Bool
@Binding var showPopover: Bool
@State private var isPresented = false
var titleColor: Color {
switch colorScheme {
case .dark:
return Color.white.opacity(0.9)
default:
return Color.black.opacity(0.9)
}
}
var body: some View {
ZStack {
VStack {
Spacer()
Text("选择提示")
.font(.title3)
.foregroundColor(titleColor)
Spacer()
}
HStack {
Button {
if let prompt = data.selectedItem {
viewModel.updateConversation(sesstionId: viewModel.currentConversation!.sesstionId, prompt: prompt)
}
self.showPopover = false
} label: {
Text("确定")
}.padding(10)
Spacer()
Button {
self.showPopover = false
withAnimation {
viewModel.currentConversation = nil
viewModel.showAIPrompt = true
}
} label: {
Text("词库")
}
.padding(10)
}
}
List(data.allPrompts) { item in
AIPromptPopCellView(item: item, isSelected: data.selectedItem == item)
.onTapGesture {
data.selectedItem = item
}
.contextMenu {
Button(action: {
withAnimation {
data.deletePrompt(prompt: item)
}
}) {
Text("移除快捷方式")
}
}
}.frame(width: 560, height: 380)
.onAppear {
if let conversation = viewModel.currentConversation {
data.fetchAllPrompts(session: conversation)
}
}
}
}
struct AIPromptPopCellView: View {
@Environment(\.colorScheme) private var colorScheme
let item: Prompt
let isSelected: Bool
var body: some View {
HStack {
if self.isSelected {
Image(systemName: "checkmark.square.fill")
.resizable()
.scaledToFit()
.frame(width: 20, height: 20)
.foregroundColor((colorScheme == .dark) ? .white.opacity(0.8) : .white)
.background(Color.blue)
.clipShape(Circle())
.padding(5)
} else {
Circle()
.stroke(Color.blue, lineWidth: 1)
.frame(width: 20, height: 20)
.padding(5)
}
if item.type == 1 {
VStack(alignment: .leading, spacing: 4) {
HStack {
Text("【默认无修饰语】")
.font(Font.system(size: 15))
.foregroundColor((colorScheme == .dark) ? .white.opacity(0.8) : .white)
.padding(.trailing, 6)
.padding(.bottom, 6)
Text("当前选中的修饰语")
.font(Font.system(size: 14))
.foregroundColor((colorScheme == .dark) ? .white.opacity(0.8) : .white)
.padding(.bottom, 6)
Spacer()
Text("(没有修饰语请到词库添加)")
.font(Font.system(size: 11))
.foregroundColor((colorScheme == .dark) ? .white.opacity(0.8) : .white)
.padding(.bottom, 6)
}
Text("每个会话只能选择一个修饰语, 也可以自定义添加修饰语")
.font(.subheadline)
.foregroundColor((colorScheme == .dark) ? .white.opacity(0.6) : .white)
}.padding(.leading, 2)
}else {
VStack(alignment: .leading, spacing: 4) {
Text(item.title ?? "")
.font(.headline)
.foregroundColor((colorScheme == .dark) ? .white.opacity(0.8) : .white)
.foregroundColor(.primary)
.padding(.bottom, 6)
Text(item.prompt ?? "")
.font(.subheadline)
.foregroundColor((colorScheme == .dark) ? .white.opacity(0.6) : .white)
}.padding(.leading, 2)
}
Spacer()
}
.frame(height: 60)
.padding(.vertical, 5)
.padding(.horizontal, 10)
.background(
item.color.brightness((self.colorScheme == .dark) ? -0.5 : -0.2)
)
.cornerRadius(6)
}
}
//struct AIPromptPopView_Previews: PreviewProvider {
// static var previews: some View {
// AIPromptPopView()
// }
//}

View File

@@ -7,24 +7,144 @@
import SwiftUI
struct AIPromptDetailView: View {
let prompt: Prompt
@StateObject var data: AIPromptViewMdoel
@Environment(\.presentationMode) var presentationMode
@Environment(\.colorScheme) private var colorScheme
var body: some View {
GeometryReader { geometry in
ZStack {
VStack(alignment: .leading) {
HStack {
VStack(alignment: .leading) {
Text(prompt.title ?? "")
.font(.headline)
.foregroundColor((colorScheme == .dark) ? .white.opacity(0.8) : .white)
.padding(.bottom, 6)
HStack {
Button {
if prompt.type == 3 {
//
prompt.type = 2
data.updatePrompt(prompt: prompt, isToggleOn: false)
presentationMode.wrappedValue.dismiss()
}else {
//
prompt.type = 3
data.updatePrompt(prompt: prompt, isToggleOn: false)
presentationMode.wrappedValue.dismiss()
}
} label: {
HStack {
if prompt.type == 3 {
Image(systemName: "minus.square")
.resizable()
.frame(width: 10, height: 10)
.foregroundColor(.white)
.padding(0)
Text("移除快捷方式")
.padding(0)
.foregroundColor(.white)
}else {
HStack {
Image(systemName: "plus.app")
.resizable()
.frame(width: 10, height: 10)
.foregroundColor(.white)
.padding(0)
Text("添加快捷方式")
.padding(0)
.foregroundColor(.white)
}
}
}
.padding(EdgeInsets(top: 6, leading: 10, bottom: 6, trailing: 10))
}
.buttonStyle(LinkButtonStyle())
.background(
RoundedRectangle(cornerRadius: 20)
.stroke(Color.white, lineWidth: 0.5)
)
if prompt.type == 2 {
Button {
data.deletePrompt(prompt: prompt)
} label: {
HStack {
Image(systemName: "trash.slash")
.resizable()
.frame(width: 10, height: 10)
.foregroundColor(.white)
.padding(0)
Text("删除数据")
.padding(0)
.foregroundColor(.white)
}
.padding(EdgeInsets(top: 6, leading: 10, bottom: 6, trailing: 10))
}.buttonStyle(LinkButtonStyle())
.background(
RoundedRectangle(cornerRadius: 20)
.stroke(Color.white, lineWidth: 0.5)
)
}
}
}.padding(.leading, 6)
Spacer()
}.padding(.bottom, 10)
ScrollView {
HStack() {
Text(prompt.prompt ?? "")
.font(.subheadline)
.foregroundColor((colorScheme == .dark) ? .white.opacity(0.6) : .white)
.padding(10)
Spacer()
}
}
.frame(width: geometry.size.width - 30, height: geometry.size.height - 120)
.background(.white.opacity(0.1))
.cornerRadius(5)
}
if let author = prompt.author {
VStack {
HStack {
Spacer()
Text("\(author)")
.foregroundColor((colorScheme == .dark) ? .white.opacity(0.8) : .white)
.font(.system(size: 11))
.padding(.top, 5)
}
Spacer()
}
}
}
.padding()
.frame(width: geometry.size.width, height: geometry.size.height)
.cornerRadius(6)
.background(
prompt.color.brightness((self.colorScheme == .dark) ? -0.5 : -0.2)
)
}
.frame(width: 500, height: 350)
}
}
struct AIPromptView: View {
let sesstionId: String? //
var body: some View {
Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/)
}
}
struct AIPromptPopView: View {
@Environment(\.colorScheme) private var colorScheme
@EnvironmentObject var viewModel: ViewModel
@StateObject var data = AIPromptSessionViewMdoel()
@Binding var showInputView: Bool
@Binding var showPopover: Bool
@StateObject var data = AIPromptViewMdoel()
@State private var isPresented = false
@State private var showInputView = false
var titleColor: Color {
switch colorScheme {
@@ -36,109 +156,102 @@ struct AIPromptPopView: View {
}
var body: some View {
ZStack {
VStack {
Spacer()
Text("选择提示")
.font(.title3)
.foregroundColor(titleColor)
Spacer()
}
HStack {
Spacer()
Button {
self.showPopover = false
self.showInputView = true
} label: {
Text("自定义")
GeometryReader { geometry in
if data.allPrompts.count > 0 {
ScrollView {
LazyVStack(spacing: 8) {
ForEach(data.allPrompts) { (item) in
AIPromptCellView(data: data, item: item)
}
}
.background(Color.clear)
}
.padding(10)
.padding(.leading, 16)
.padding(.trailing, 16)
.frame(width: geometry.size.width, height: geometry.size.height - 50)
.onAppear {
}
}else {
VStack(alignment: .center) {
Text("请点击右上角自定义添加新的修饰语")
}.frame(width: geometry.size.width, height: geometry.size.height - 50)
}
}
.padding(.top, 1)
.toolbar {
Spacer()
Button(action: {
showInputView.toggle()
}) {
Image(systemName: "plus")
}
}
List(data.allPrompts) { item in
AIPromptPopCellView(item: item, isSelected: data.selectedItem == item) {
data.selectedItem = item
}.contextMenu {
Button(action: {
data.deletePrompt(prompt: item)
}) {
Text("删除")
}
// Button(action: {
//
// }) {
// Text("")
// }
}
}.frame(width: 560, height: 380)
.onAppear {
if let conversation = viewModel.currentConversation {
data.fetchAllPrompts(session: conversation)
}
}
.onDisappear {
viewModel.updateConversation(sesstionId: viewModel.currentConversation!.sesstionId, prompt: data.selectedItem!)
}
.sheet(isPresented: $showInputView) {
AIPromptInputView(viewModel: data, isPresented: $showInputView)
}
}
}
struct AIPromptPopCellView: View {
struct AIPromptCellView: View {
@Environment(\.colorScheme) private var colorScheme
let item: Prompt
let isSelected: Bool
let action: () -> Void
@StateObject var data: AIPromptViewMdoel
@State private var isTapped = false
@State var item: Prompt
var body: some View {
HStack {
if self.isSelected {
Image(systemName: "checkmark.square.fill")
.resizable()
.scaledToFit()
.frame(width: 20, height: 20)
.foregroundColor((colorScheme == .dark) ? .white.opacity(0.8) : .white)
.background(Color.blue)
.clipShape(Circle())
.padding(5)
} else {
Circle()
.stroke(Color.blue, lineWidth: 1)
.frame(width: 20, height: 20)
.padding(5)
}
if item.type == 1 {
VStack(alignment: .leading, spacing: 4) {
HStack {
Text("【默认无修饰语】")
.font(Font.system(size: 15))
.foregroundColor((colorScheme == .dark) ? .white.opacity(0.8) : .white)
.padding(.trailing, 6)
.padding(.bottom, 6)
Text("当前选中的修饰语")
.font(Font.system(size: 14))
.foregroundColor((colorScheme == .dark) ? .white.opacity(0.8) : .white)
.padding(.bottom, 6)
}
Text("每个会话只能选择一个修饰语, 也可以自定义添加修饰语")
.font(.subheadline)
.foregroundColor((colorScheme == .dark) ? .white.opacity(0.6) : .white)
}.padding(.leading, 2)
}else {
VStack(alignment: .leading, spacing: 4) {
Text(item.title ?? "")
.font(.headline)
.foregroundColor((colorScheme == .dark) ? .white.opacity(0.8) : .white)
.foregroundColor(.primary)
.padding(.bottom, 6)
Text(item.prompt ?? "")
.font(.subheadline)
.foregroundColor((colorScheme == .dark) ? .white.opacity(0.6) : .white)
}.padding(.leading, 2)
ZStack {
VStack(alignment: .leading) {
HStack {
VStack(alignment: .leading, spacing: 4) {
HStack {
if item.type == 3 {
Image(systemName: "checkmark.square")
.resizable()
.frame(width: 10, height: 10)
.foregroundColor(.white)
.padding(.trailing, 0)
}else {
Image(systemName: "plus.app")
.resizable()
.frame(width: 10, height: 10)
.foregroundColor(.white)
.padding(.trailing, 0)
}
Text(item.title ?? "")
.font(.headline)
.foregroundColor((colorScheme == .dark) ? .white.opacity(0.8) : .white)
.padding(.leading, 0)
}.padding(.bottom, 6)
Text(item.prompt ?? "")
.font(.subheadline)
.foregroundColor((colorScheme == .dark) ? .white.opacity(0.6) : .white)
}.padding(.leading, 2)
Spacer()
}
}
Spacer()
if let author = item.author {
VStack {
HStack {
Spacer()
Text("\(author)")
.foregroundColor((colorScheme == .dark) ? .white.opacity(0.8) : .white)
.font(.system(size: 11))
.padding(.top, 5)
}
Spacer()
}
}
}
.frame(height: 60)
.padding(.vertical, 5)
@@ -148,13 +261,23 @@ struct AIPromptPopCellView: View {
)
.cornerRadius(6)
.onTapGesture {
self.action()
self.isTapped.toggle()
}
.sheet(isPresented: $isTapped) {
AIPromptDetailView(prompt: item, data: data)
.onTapGesture {
isTapped = false
}
}
}
}
struct AIPromptView_Previews: PreviewProvider {
static var previews: some View {
AIPromptView(sesstionId: nil)
}
}
//struct AIPromptView_Previews: PreviewProvider {
// static var previews: some View {
// AIPromptView(sesstionId: nil)
// }
//}

View File

@@ -36,6 +36,12 @@ struct ChatRoomToolBar: View {
AIPromptPopView(showInputView: $showInputView, showPopover: $showPopover).environmentObject(viewModel)
}
Button("清空消息") {
viewModel.messages.removeAll()
viewModel.deleteAllMessage(sesstionId: viewModel.currentConversation?.sesstionId ?? "")
viewModel.updateConversation(sesstionId: viewModel.currentConversation?.sesstionId ?? "", message: nil)
}
Spacer()
if viewModel.showStopAnswerBtn {
Button("停止生成") {
@@ -47,10 +53,6 @@ struct ChatRoomToolBar: View {
}
}
.sheet(isPresented: $showInputView) {
// sheet
AIPromptInputView(isPresented: $showInputView)
}
.padding(.leading, 12)
.background(Color.clear)

View File

@@ -21,6 +21,9 @@ struct SessionsView: View {
}.buttonStyle(BorderlessButtonStyle())
Spacer()
Button(action: {
viewModel.showUserInitialize = false
viewModel.showAIPrompt = false
// New Chat
viewModel.currentConversation = viewModel.addNewConversation()
viewModel.createNewChat = true
@@ -37,13 +40,16 @@ struct SessionsView: View {
}
.buttonStyle(BorderlessButtonStyle())
.frame(maxWidth: .infinity, alignment: .leading)
.padding(.leading,10)
.padding(.leading,0)
NavigationLink(destination: UserInitializeView().environmentObject(viewModel), isActive: $viewModel.showUserInitialize) {
Button(action: {
//
viewModel.currentConversation = nil//
// viewModel.showAIPrompt = false
if viewModel.currentConversation != nil {
viewModel.currentConversation = nil//
}
viewModel.createNewChat = false
viewModel.showAIPrompt = false
viewModel.showUserInitialize = true
KeyboardMonitor.shared.stopKeyMonitor()
KeyboardMonitor.shared.stopMonitorPasteboard()
@@ -55,27 +61,30 @@ struct SessionsView: View {
.cornerRadius(5)
}
.buttonStyle(PlainButtonStyle())
.padding(.trailing, 20)
.padding(.trailing, 0)
}.buttonStyle(PlainButtonStyle())
// NavigationLink(destination: AIPromptView(sesstionId: nil), isActive: $viewModel.showAIPrompt) {
// Button(action: {
// //
// viewModel.currentConversation = nil//
// viewModel.showUserInitialize = false
// viewModel.showAIPrompt = true
// KeyboardMonitor.shared.stopKeyMonitor()
// KeyboardMonitor.shared.stopMonitorPasteboard()
// }) {
// Image(systemName: "swift")
// .padding(10)
// .foregroundColor(.white)
// .background(Color.gray)
// .cornerRadius(5)
// }
// .buttonStyle(PlainButtonStyle())
// .padding(.trailing, 10)
// }.buttonStyle(PlainButtonStyle())
NavigationLink(destination: AIPromptView().environmentObject(viewModel), isActive: $viewModel.showAIPrompt) {
Button(action: {
//
if viewModel.currentConversation != nil {
viewModel.currentConversation = nil//
}
viewModel.createNewChat = false
viewModel.showUserInitialize = false
viewModel.showAIPrompt = true
KeyboardMonitor.shared.stopKeyMonitor()
KeyboardMonitor.shared.stopMonitorPasteboard()
}) {
Image(systemName: "swift")
.padding(10)
.foregroundColor(.white)
.background(Color.gray)
.cornerRadius(5)
}
.buttonStyle(PlainButtonStyle())
.padding(.trailing, 10)
}.buttonStyle(PlainButtonStyle())
})
@@ -99,6 +108,9 @@ struct SessionsView: View {
.leftSessionContentSize()
}
.onAppear {
let _ = ServerManager.shared.checkToken()
}
}
}