Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
61ea48f
Adding the thumbs-up/thumbs down for assist chat. [ignore-commit-lint]
reabbotted Jul 8, 2025
a0fd8ac
WIP [ignore-commit-lint]
reabbotted Jul 8, 2025
643590e
WIP
reabbotted Jul 10, 2025
156c1b1
Merge branch 'feature/horizon' into feature/assist-welcome
reabbotted Jul 10, 2025
891d0fe
WIP
reabbotted Jul 11, 2025
a98ae00
Adding Cedar API calls and making the CoursePageGoal more capable
reabbotted Jul 12, 2025
26a6a50
Adding some more options when viewing a page.
reabbotted Jul 12, 2025
e71ed7a
Disabling line length violations
reabbotted Jul 12, 2025
2dd66a4
Disabling line length violations
reabbotted Jul 12, 2025
537c048
Making it so we can reset the environment
reabbotted Jul 12, 2025
f202155
Making it so the course document goal actually does something
reabbotted Jul 12, 2025
23d2225
Making the translate option a little more generic
reabbotted Jul 12, 2025
ff6c6df
Removing the translation abilities for the moment
reabbotted Jul 14, 2025
4736f81
Removing the translation abilities for the moment
reabbotted Jul 14, 2025
355e616
Code cleanup
reabbotted Jul 14, 2025
f8efbfb
Just updating a prompt
reabbotted Jul 15, 2025
9e74e7f
Addressing merge comments and improving the look of the assist chat
reabbotted Jul 15, 2025
b5159c1
Adding in the Thumbs-up/Thumbs-down
reabbotted Jul 15, 2025
91b60e2
Fixing lint
reabbotted Jul 16, 2025
6791837
Making it so you can press the back button while an assist message is…
reabbotted Jul 16, 2025
0961d4d
Making it so if we have lots of course options, it only presents the …
reabbotted Jul 16, 2025
134ce3e
Moving the related CourseDocument and CoursePage goals into a group
reabbotted Jul 16, 2025
aeee707
Satisfying swiftlint
reabbotted Jul 16, 2025
e917083
Adding comments and section deliniation
reabbotted Jul 16, 2025
678df35
Merging in from feature/horizon
reabbotted Jul 16, 2025
90f4d9d
Fixing Localizable.xcstrings
reabbotted Jul 16, 2025
0b1bfb7
More code cleanup
reabbotted Jul 16, 2025
b72e6f0
Fixing a build error
reabbotted Jul 16, 2025
e1e7bc3
Code Review
reabbotted Jul 17, 2025
6fdc83e
Code Review
reabbotted Jul 17, 2025
505ba96
Code Review
reabbotted Jul 17, 2025
e16daf8
fix: resolve memory leaks
szabinst Jul 17, 2025
133066d
Fixing an empty response and back button not appearing in assist
reabbotted Jul 17, 2025
53dc012
Fixing Goals
reabbotted Jul 17, 2025
373d63d
Adding back error handling
reabbotted Jul 17, 2025
2a8051f
Adding back error handling
reabbotted Jul 17, 2025
9b079a5
Swiftlint fix
reabbotted Jul 17, 2025
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
1 change: 1 addition & 0 deletions Core/Core/Common/CommonModels/API/API.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//

import Combine
import Foundation

public class API {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,21 @@ public struct WrappingHStack<Model, V>: View where Model: Hashable, V: View {
public typealias ViewGenerator = (Model) -> V
var models: [Model]
var viewGenerator: ViewGenerator
var horizontalSpacing: CGFloat = 5
var verticalSpacing: CGFloat = 5
var horizontalSpacing: CGFloat
var verticalSpacing: CGFloat

@State private var totalHeight = CGFloat.zero

public init(
models: [Model],
horizontalSpacing: CGFloat = 5,
verticalSpacing: CGFloat = 5,
viewGenerator: @escaping ViewGenerator
) {
self.models = models
self.viewGenerator = viewGenerator
self.horizontalSpacing = horizontalSpacing
self.verticalSpacing = horizontalSpacing
}

public var body: some View {
Expand Down
54 changes: 36 additions & 18 deletions Horizon/Horizon/Resources/Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,9 @@
},
"Cairo (+02:00/+03:00)" : {

},
"Can I answer any questions about this document for you?" : {

},
"Canberra (+10:00/+11:00)" : {

Expand Down Expand Up @@ -285,6 +288,9 @@
},
"Copenhagen (+01:00/+02:00)" : {

},
"Create a Quiz" : {

},
"Create message" : {

Expand Down Expand Up @@ -390,9 +396,6 @@
},
"Filter by person" : {

},
"Flash cards" : {

},
"Fortaleza (-03:00/-03:00)" : {

Expand All @@ -402,6 +405,9 @@
},
"Full Name can only be changed by your institution." : {

},
"Generate Flash Cards" : {

},
"Georgetown (-04:00/-04:00)" : {

Expand Down Expand Up @@ -435,6 +441,9 @@
},
"Hello, Career!" : {

},
"Hello! Which course you'd like to discuss today?" : {

},
"Helsinki (+02:00/+03:00)" : {

Expand All @@ -454,7 +463,7 @@
"hours" : {

},
"How can I help today?" : {
"How can I help you with this page?" : {

},
"Important" : {
Expand Down Expand Up @@ -504,9 +513,6 @@
},
"Kathmandu (+05:45/+05:45)" : {

},
"Key takeaways" : {

},
"Kolkata (+05:30)" : {

Expand Down Expand Up @@ -534,9 +540,6 @@
},
"Learn" : {

},
"Learner" : {

},
"Lima (-05:00/-05:00)" : {

Expand Down Expand Up @@ -648,9 +651,18 @@
},
"No" : {

},
"No additional information found." : {

},
"No key takeaways found." : {

},
"No notification activity yet." : {

},
"No summary found." : {

},
"Norfolk Island (+11:00/+12:00)" : {

Expand Down Expand Up @@ -758,9 +770,6 @@
},
"Quito (-05:00/-05:00)" : {

},
"Quiz" : {

},
"Rangoon (+06:30/+06:30)" : {

Expand Down Expand Up @@ -866,6 +875,12 @@
},
"Something went wrong" : {

},
"Sorry, can we try that again? Which course is it you'd like to discuss?" : {

},
"Sorry, I don't have an answer for that right now." : {

},
"Sort By" : {

Expand Down Expand Up @@ -896,9 +911,6 @@
},
"Submitted" : {

},
"Summarize" : {

},
"Support" : {

Expand Down Expand Up @@ -927,10 +939,10 @@
"Tehran (+03:30/+03:30)" : {

},
"Tell me more" : {
"Text" : {

},
"Text" : {
"Thank you for your feedback!" : {

},
"There are no scored activities in this course." : {
Expand Down Expand Up @@ -1037,6 +1049,12 @@
},
"West Central Africa (+01:00)" : {

},
"What would you like to discuss about the course %@?" : {

},
"What would you like to discuss today?" : {

},
"Yakutsk (+09:00/+09:00)" : {

Expand Down
28 changes: 13 additions & 15 deletions Horizon/Horizon/Sources/Features/Assist/AssistAssembly.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,21 +44,19 @@ final class AssistAssembly {
return navigationController
}

static func makeChatBotInteractor(courseId: String? = nil, pageUrl: String? = nil, fileId: String? = nil) -> AssistChatInteractor {
if let courseId = courseId, let pageUrl = pageUrl {
return AssistChatInteractorLive(
courseId: courseId,
pageUrl: pageUrl
)
}
if let courseId = courseId, let fileId = fileId {
return AssistChatInteractorLive(
courseId: courseId,
fileId: fileId,
downloadFileInteractor: DownloadFileInteractorLive(courseID: courseId)
)
}
return AssistChatInteractorLive()
static func makeChatBotInteractor(
courseId: String? = nil,
pageUrl: String? = nil,
fileId: String? = nil
) -> AssistChatInteractor {
AssistChatInteractorLive(
courseID: courseId,
fileID: fileId,
pageURL: pageUrl,
downloadFileInteractor: courseId.map {
DownloadFileInteractorLive(courseID: $0)
}
)
}

static func makeAIQuizView(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@ import Core

/// ChatBotActions are published to the AssistChatInteractor. The Interactor reacts to the action and publishes one or more ChatBotResponses.
enum AssistChatAction {
case begin

/// the user is chatting with the bot
case chat(prompt: String = "", history: [AssistChatMessage] = [])
case chat(prompt: String?, history: [AssistChatMessage] = [])

/// the user has selected a chip while viewing a file
case chip(option: AssistChipOption, history: [AssistChatMessage] = [])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,51 +19,85 @@
import Foundation

/// A message returned from the interactor
struct AssistChatMessage: Codable, Equatable {
struct AssistChatMessage {

let id: UUID

/// The prompt that was sent to the AI. Not shown to the user
/// If set to null, then it is removed from the list of messages sent to the AI
let prompt: String?

/// The text shown to the user in the history. This may be different from the prompt sent to the AI
let text: String
/// The text shown to the user on screen. This may be different from the prompt sent to the AI
let text: String?

/// Whether or not this came from the AI
let role: Role

init(botResponse: String) {
prompt = botResponse
text = botResponse
role = .Assistant
id = UUID()
/// A list of options that the user can select from.
let chipOptions: [AssistChipOption]?

let flashCards: [AssistChatFlashCard]?

let quizItems: [QuizItem]?

init(botResponse: String, chipOptions: [AssistChipOption] = []) {
self.init(
role: .Assistant,
prompt: botResponse,
text: botResponse,
chipOptions: chipOptions
)
}

init(userResponse: String) {
prompt = userResponse
text = userResponse
role = .User
id = UUID()
/// The user has asked for FlashCards
init(flashCards: [AssistChatFlashCard]) {
self.init(
role: .Assistant,
flashCards: flashCards
)
}

init(prompt: String?, text: String, role: Role = .User) {
self.prompt = prompt
self.text = text
id = UUID()
/// The user has asked for a quiz
init(quizItems: [QuizItem]) {
self.init(
role: .Assistant,
quizItems: quizItems
)
}

self.role = role
init(userResponse: String, prompt: String? = nil) {
self.init(
role: .User,
prompt: prompt ?? userResponse,
text: userResponse
)
}

func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(prompt, forKey: .prompt)
try container.encode(text, forKey: .text)
try container.encode(role, forKey: .role)
private init(
role: Role,
prompt: String? = nil,
text: String? = nil,
chipOptions: [AssistChipOption] = [],
flashCards: [AssistChatFlashCard] = [],
quizItems: [QuizItem]? = nil
) {
self.id = UUID()
self.role = role
self.prompt = prompt
self.text = text
self.chipOptions = chipOptions
self.flashCards = flashCards
self.quizItems = quizItems
}

enum Role: String, Codable, Equatable {
case Assistant
case User
}

struct QuizItem: Codable, Equatable {
let question: String
let answers: [String]
let correctAnswerIndex: Int
}
}
Loading