Skip to content

Commit

Permalink
Merge branch 'release/2.5'
Browse files Browse the repository at this point in the history
  • Loading branch information
iHTCboy committed Apr 12, 2023
2 parents 5ba2e08 + d178319 commit a39a996
Show file tree
Hide file tree
Showing 16 changed files with 351 additions and 65 deletions.
29 changes: 21 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@ OpenAI ChatGPT app for iOS, iPadOS, macoS

#### 更新说明

最新版本 v2.3
- Create new conversation. (创建新的对话)
- Save conversation records. (保存对话记录)
- Switch to historical conversations. (切换历史对话)
- Scroll to the top of the conversation list. (滚动到对话列表的顶部)
- Auto-scroll to the bottom of the conversation list. (自动滚动到对话列表的底部)
- Option to request conversations without historical records (click on the icon on the left side of the input box to toggle). (请求时可不带历史对话记录)
- Support for additional languages (Traditional Chinese, Korean, Japanese, French, German, Russian, etc.). (支持更多语言(繁体中文、韩文、日文、法语、德语、俄语等))
最新版本 v2.5

- Added chat room settings with Prompt and Temperature parameter configuration. (新增聊天室设置功能,支持 Prompt 和 Temperature 参数配置。)
- Display current conversation identifier in the history list. (历史对话列表增加显示当前对话标识。)
- Fixed potential crash when sending conversations. (修复发送对话时可能会崩溃的问题。)
- Removed restrictions on creating new conversations and switching history when requesting a conversation. (请求对话时,取消创建新对话和切换历史对话的禁用限制。)
- Improved multi-language translations for sharing feature. (完善分享功能的多语言翻译。)


**支持功能**

Expand Down Expand Up @@ -101,6 +101,19 @@ TestFlight 下载地址:[https://testflight.apple.com/join/GR4BOt2M](https://t

#### 3.4 历史更新功能

v2.4:
- Add sharing function(增加分享功能)
- Fix the history list is too high(修复历史列表过高)

v2.3:
- Create new conversation. (创建新的对话)
- Save conversation records. (保存对话记录)
- Switch to historical conversations. (切换历史对话)
- Scroll to the top of the conversation list. (滚动到对话列表的顶部)
- Auto-scroll to the bottom of the conversation list. (自动滚动到对话列表的底部)
- Option to request conversations without historical records (click on the icon on the left side of the input box to toggle). (请求时可不带历史对话记录)
- Support for additional languages (Traditional Chinese, Korean, Japanese, French, German, Russian, etc.). (支持更多语言(繁体中文、韩文、日文、法语、德语、俄语等))

v2.2:
- Increased request timeout from 30 seconds to 60 seconds.(请求超时从 30 秒增加到 60 秒。)
- When sending dialog context, only send the first three Q&A rounds, and submit only the first 100 characters of the answer.(发送对话上下文时,只发送提问的前三轮问答,且答案只提交前100个字。)
Expand Down
8 changes: 4 additions & 4 deletions iChatGPT.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -569,7 +569,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "-";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 2023.04.05;
CURRENT_PROJECT_VERSION = 2023.04.12;
DEVELOPMENT_ASSET_PATHS = "\"iChatGPT/Preview Content\"";
DEVELOPMENT_TEAM = "";
ENABLE_PREVIEWS = YES;
Expand All @@ -587,7 +587,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 2.4;
MARKETING_VERSION = 2.5;
PRODUCT_BUNDLE_IDENTIFIER = com.37iOS.iChatGPT;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
Expand All @@ -609,7 +609,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "-";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 2023.04.05;
CURRENT_PROJECT_VERSION = 2023.04.12;
DEVELOPMENT_ASSET_PATHS = "\"iChatGPT/Preview Content\"";
DEVELOPMENT_TEAM = "";
ENABLE_PREVIEWS = YES;
Expand All @@ -627,7 +627,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 2.4;
MARKETING_VERSION = 2.5;
PRODUCT_BUNDLE_IDENTIFIER = com.37iOS.iChatGPT;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
Expand Down
10 changes: 5 additions & 5 deletions iChatGPT/AIChatView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ struct AIChatView: View {
})
}
.sheet(isPresented: $inputModel.isConfigChatRoom) {
ChatRoomConfigView(isKeyPresented: $inputModel.isConfigChatRoom)
ChatRoomConfigView(isKeyPresented: $inputModel.isConfigChatRoom, chatModel: chatModel)
}
.sheet(isPresented: $isSharing) {
ActivityView(activityItems: $shareContent.activityItems)
Expand Down Expand Up @@ -192,12 +192,12 @@ extension AIChatView {
}

func ShareContents() -> Alert {
Alert(title: Text("Share"),
message: Text("Choose a sharing format"),
primaryButton: .default(Text("Image")) {
Alert(title: Text("Share".localized()),
message: Text("Choose a sharing format".localized()),
primaryButton: .default(Text("Image".localized())) {
screenshotAndShare(isImage: true)
},
secondaryButton: .default(Text("PDF")) {
secondaryButton: .default(Text("PDF".localized())) {
screenshotAndShare(isImage: false)
}
)
Expand Down
12 changes: 11 additions & 1 deletion iChatGPT/ChatHistoryListView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,21 @@ struct ChatHistoryListView: View {
VStack(alignment: .leading) {

HStack() {
Text(item.roomID.formatTimestamp())
Text(item.roomName ?? item.roomID.formatTimestamp())
.font(.headline)

Spacer()

if item.roomID == chatModel.roomID {
Text(" \("Current Chat".localized()) ")
.font(.footnote)
.foregroundColor(.white)
.padding([.top, .bottom], 3)
.padding([.leading, .trailing], 4)
.background(Color.red.opacity(0.8))
.clipShape(Capsule())
}

Text(" \(ChatMessageStore.shared.messages(forRoom: item.roomID).count) ")
.font(.footnote)
.foregroundColor(.white)
Expand Down
3 changes: 0 additions & 3 deletions iChatGPT/ChatInputView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ struct ChatInputView: View {
.padding(.trailing, 5)
.foregroundColor(.lightGray)
.buttonStyle(PlainButtonStyle())
.disabled(!chatModel.contents.filter({ $0.isResponse == false }).isEmpty)

if !chatModel.contents.isEmpty {
Button(action: {
Expand Down Expand Up @@ -72,7 +71,6 @@ struct ChatInputView: View {
.padding(.trailing, 5)
.foregroundColor(.lightGray)
.buttonStyle(PlainButtonStyle())
.disabled(!chatModel.contents.filter({ $0.isResponse == false }).isEmpty)

Button(action: {
model.isConfigChatRoom.toggle()
Expand All @@ -82,7 +80,6 @@ struct ChatInputView: View {
.padding(.trailing, 8)
.foregroundColor(.lightGray)
.buttonStyle(PlainButtonStyle())
.disabled(!chatModel.contents.filter({ $0.isResponse == false }).isEmpty)

if !chatModel.contents.isEmpty {
Button(action: {
Expand Down
138 changes: 130 additions & 8 deletions iChatGPT/ChatRoomConfigView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,34 +7,156 @@
//

import SwiftUI
import Combine
import SwiftUIX

struct ChatRoomConfigView: View {

@Binding var isKeyPresented: Bool
@StateObject var chatModel: AIChatModel

@State var roomName: String = ""
@State var prompt: String = ""
@State var temperature: String = ""
@State var historyCount: String = ""
@State var model: String = ""
@State var isDirty: Bool = false
@State var showingAlert: Bool = false
@State var alertMessage: String = ""

init(isKeyPresented: Binding<Bool>, chatModel: AIChatModel) {
_isKeyPresented = isKeyPresented
_chatModel = StateObject(wrappedValue: chatModel)

let room = ChatRoomStore.shared.chatRoom(chatModel.roomID)
_roomName = State(initialValue: room?.roomName ?? room?.roomID.formatTimestamp() ?? "")
_prompt = State(initialValue: room?.prompt ?? "")
_temperature = State(initialValue: "\(room?.temperature ?? 0.7)")
_historyCount = State(initialValue: "\(room?.historyCount ?? 0)")
_model = State(initialValue: room?.model ?? "")
_isDirty = State(initialValue: false)
}

var body: some View {
NavigationView {
VStack {
Text("Coming soon..".localized()).font(.title2)
List {
ConfigCellView(title: "Room Name".localized(),
subtitle: "",
value: $roomName,
description: "The name of the room".localized())
ConfigCellView(title: "Prompt".localized(), subtitle: "Prompt description.".localized(), value: $prompt, description: "Prompt text to generate contextual information for the corresponding text.".localized())
ConfigCellView(title: "Temperature".localized(), subtitle: "What sampling temperature to use, between 0 and 2. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic.".localized(), value: $temperature, description: "The default temperature is 0.7".localized())
ConfigCellView(title: "Chat History".localized(), subtitle: "How much context information is carried when sending a dialog.".localized(), value: $historyCount, description: "Default is the last 3 conversations.".localized())
//ConfigCellView(title: "Model", subtitle: "ChatGPT 模型", value: $model, description: "The model used for processing")
}
.navigationTitle("Room Settings".localized())
.toolbar {
Button(action: onCloseButtonTapped) {
Image(systemName: "xmark.circle").imageScale(.large)
}
.navigationBarTitle(Text("Room Settings".localized()))
.navigationBarItems(
trailing:
HStack {
Button(action: onSaveButtonTapped, label: {
Text("Save".localized()).bold()
}).disabled(!isDirty)

Button(action: onCloseButtonTapped) {
Image(systemName: "xmark.circle").imageScale(.large)
}
}
)
.alert(isPresented: $showingAlert) {
ShowAlterView()
}
.onChange(of: [roomName, prompt, temperature, historyCount, model]) { _ in
self.isDirty = true
}
.gesture(
TapGesture().onEnded {
hideKeyboard()
}
)
}
}

private func onSaveButtonTapped() {
// 检查 temperature 数据格式是否符合
guard let tempValue = Double(temperature), 0.0 <= tempValue && tempValue <= 2.0 else {
alertMessage = "Temperature is between 0 and 2.".localized()
showingAlert = true
return
}

// 检查 historyCount 数据格式是否符合
guard let histCountValue = Int(historyCount), histCountValue >= 0 else {
alertMessage = "History message count must be an integer greater than or equal to 0.".localized()
showingAlert = true
return
}

let room = ChatRoom(roomID: chatModel.roomID, roomName: roomName, model: model, prompt: prompt.isEmpty ? nil : prompt, temperature: tempValue, historyCount: histCountValue)
ChatRoomStore.shared.updateChatRoom(for: chatModel.roomID, room: room)
self.isDirty = false

alertMessage = "Settings have been updated~".localized()
showingAlert = true
}

func ShowAlterView() -> Alert {
Alert(
title: Text("Tips".localized()),
message: Text(alertMessage),
dismissButton: .default(Text("OK".localized()))
)
}

private func onCloseButtonTapped() {
isKeyPresented = false
}

/// 当用户点击其他区域时隐藏软键盘
private func hideKeyboard() {
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
}
}

struct ConfigCellView: View {
let title: String
let subtitle: String
@Binding var value: String
let description: String

var body: some View {
VStack(alignment: .leading) {
Text(title)
.font(.headline)
.padding(.top, 10)

if !subtitle.isEmpty {
Text(subtitle)
.font(.body)
.foregroundColor(.secondaryLabel)
.padding(.top, 0.5)
.padding(.bottom, 10)
.fixedSize(horizontal: false, vertical: true)
}

TextView(description, text: $value, onEditingChanged: {_ in

}, onCommit: {

})
.returnKeyType(.default)
.padding(10)
.maxHeight(90)
.border(.blue.opacity(0.8), cornerRadius: 10)

Spacer()
.height(15)
}
}
}

struct ChatRoomConfigView_Previews: PreviewProvider {
static var previews: some View {
ChatRoomConfigView(isKeyPresented: .constant(true))
ChatRoomConfigView(isKeyPresented: .constant(true), chatModel: AIChatModel(roomID: nil))
}
}

28 changes: 12 additions & 16 deletions iChatGPT/Models/AIChatModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,26 +32,19 @@ class AIChatModel: ObservableObject {
}
/// room id
var roomID: String
/// api model
var apiModel: String {
didSet {
saveRoomConfigData()
}
}
/// 更新 token 时更新请求的会话
var isRefreshSession: Bool = false
private var bot: Chatbot?

init(roomID: String?) {
let roomID = roomID ?? String(Int(Date().timeIntervalSince1970))
self.roomID = roomID
if let room = ChatRoomStore.shared.chatRoom(roomID) {
apiModel = room.model ?? UserDefaults.standard.string(forKey: ChatGPTModelName) ?? "gpt-3.5-turbo"
if ChatRoomStore.shared.chatRoom(roomID) != nil {
let messages = ChatMessageStore.shared.messages(forRoom: roomID)
contents.append(contentsOf: messages)
} else {
apiModel = UserDefaults.standard.string(forKey: ChatGPTModelName) ?? "gpt-3.5-turbo"
ChatRoomStore.shared.addChatRoom(ChatRoom(roomID: roomID))
let model = UserDefaults.standard.string(forKey: ChatGPTModelName) ?? "gpt-3.5-turbo"
ChatRoomStore.shared.addChatRoom(ChatRoom(roomID: roomID, model: model))
}
loadChatbot()
}
Expand All @@ -60,8 +53,8 @@ class AIChatModel: ObservableObject {
let newRoomID = roomID ?? String(Int(Date().timeIntervalSince1970))
self.roomID = newRoomID
self.contents = ChatMessageStore.shared.messages(forRoom: newRoomID)
apiModel = UserDefaults.standard.string(forKey: ChatGPTModelName) ?? "gpt-3.5-turbo"
let room = ChatRoomStore.shared.chatRoom(newRoomID) ?? ChatRoom(roomID: newRoomID)
let model = UserDefaults.standard.string(forKey: ChatGPTModelName) ?? "gpt-3.5-turbo"
let room = ChatRoomStore.shared.chatRoom(newRoomID) ?? ChatRoom(roomID: newRoomID, model: model)
ChatRoomStore.shared.addChatRoom(room)
loadChatbot()
}
Expand All @@ -70,27 +63,30 @@ class AIChatModel: ObservableObject {
if isRefreshSession {
loadChatbot()
}
let index = contents.count
let userAvatarUrl = self.bot?.getUserAvatar() ?? ""
let roomModel = ChatRoomStore.shared.chatRoom(roomID)
let model = UserDefaults.standard.string(forKey: ChatGPTModelName) ?? "gpt-3.5-turbo"
var chat = AIChat(datetime: Date().currentDateString(), issue: prompt, model: model, userAvatarUrl: userAvatarUrl)
contents.append(chat)
isScrollListBottom.toggle()

self.bot?.getChatGPTAnswer(prompts: contents, sendContext: isSendContext) { answer in
self.bot?.getChatGPTAnswer(prompts: contents, sendContext: isSendContext, roomModel: roomModel) { answer in
let content = answer
DispatchQueue.main.async { [self] in
chat.answer = content
chat.isResponse = true
contents[index] = chat
// 找到要替换的元素在数组中的索引位置
if let index = contents.lastIndex(where: { $0.datetime == chat.datetime && $0.issue == chat.issue }) {
contents[index] = chat
}
}
}
}

func loadChatbot() {
isRefreshSession = false
let chatGPTOpenAIKey = UserDefaults.standard.string(forKey: ChatGPTOpenAIKey) ?? ""
bot = Chatbot( openAIKey: chatGPTOpenAIKey)
bot = Chatbot(openAIKey: chatGPTOpenAIKey)
}

func saveMessagesData() {
Expand Down
Loading

0 comments on commit a39a996

Please sign in to comment.