100% SwiftUI GPT/LLM Client with Prompt Engineering support. With Microsoft's Azure OpenAI functionality.
General Query View | Prompt Studio |
---|---|
Table of Contents
- Requirements
- Swift Packages & Credits
- Setting Up Azure OpenAI
- Persisting Chat Messages
- Guide WIP
- FAQ
- More Previews
- TODO
macOS 12.4+
Build passing 🟢
- Granite
- This app uses my own design pattern. A decoupling guide will be provided in the repo above. But, should be pretty straightforward overall.
- VaultKit
- SwiftGPT by @SwiftedMind
- GPT3-Tokenizer by @aespinilla
- swiftui-markdown by @jaywcjlove
- Ink by @JohnSundell
- LaunchAtLogin by @sindresorhus
- PureSwiftUI by @Brett-Best
Locally Diverged
- [SandKit] is a private repo at the moment, diverged a localized version for use. It houses
SwiftGPT
andswiftui-markdown
from above as well. This kit handles custom prompt/command routing for the applicatoin.
Removed
- [MarqueKit] is a private repo that handles encryption this has been removed and comments show where encryption can take place to safely store data like API Keys.
- Enable Azure in Settings
static var AZURE_CONFIG: ChatGPTAzure.Config {
.init(apiKey: "...",
apiVersion: "2023-05-15", //apiVersion not necessary for initialization
resourceName: "...",
deploymentName: "...")
}
Repo will be updated to include this out of the box, front-end side, in the future.
Back in SandGPT: https://github.com/pexavc/Nea/blob/24fbcfbac23eb7f13b84cdee6307211596ee54d0/Services/Sand/Models/SandGPT.swift#L48
Simply build a flow to store the type ChatMessage
prior to using the Swift Package.
private var messages: [ChatMessage] = []
func ask<E: EventExecutable>(_ prompt: String,
withSystemPrompt systemPrompt: String? = nil,
withConfig config: PromptConfig,
stream: Bool = false,
logMessages: Bool = false,
event: E) {
Append the user prompt with the role user
.
self.messages.append(.init(role: .user, content: prompt)) //add user prompt
Append the chat-bot's response with the role assistant
.
reply = try await client.ask(messages: self?.messages ?? [],
withConfig: config)
DispatchQueue.main.async { [weak self] in
self?.isResponding = false
}
if logMessages {
self?.messages.append(.init(role: .assistant, content: reply))
}
event.send(Response(data: reply, isComplete: true, isStream: false))
The role .system
is good for setting a persona prior to message collection.
self?.messages.append(.init(role: .system, content: "Act as..."))
Linking the reset() function in SandGPT()
to clear messages is helpful too:
func reset(messages: Bool = false) {
self.currentTask?.cancel()
self.reqDebounceTimer?.invalidate()
self.replyCompletedTimer?.invalidate()
self.isResponding = false
if messages {
self.messages = []
}
}
- Window resizing and size management occurs here.
Declaritevly update a single window's size whenever an action requires
state.pane?.display {
WindowComponent(WindowComponent.Kind.query)
if addResponse {
WindowComponent(WindowComponent.Kind.divider)
WindowComponent(WindowComponent.Kind.response)
WindowComponent(WindowComponent.Kind.spacer)
WindowComponent(WindowComponent.Kind.shortcutbar)
}
}
- Popups and Hotkey observation/registration
Example of Using PopupableView to easily trigger popups in any window instance.
PopupableView(.promptStudio,
size: .init(200, 200),
edge: .maxX, {
RoundedRectangle(cornerRadius: 6)
.frame(width: 60, height: 60)
.foregroundColor(Color(hex: promptColor))
}) {
ColorPicker(hex: $promptColor)
}
.frame(width: 60, height: 60)
- No specific reason besides, finding it to provide better results for my own needs.
- Completions endpoint capability will be added soon along with a toggle to switch between.
Advanced Tuning | Helper Tab |
---|---|
Using Commands | Switching Commands |
---|---|
- Clean up Azure OpenAI integration in SwiftGPT.
- Integrate Azure and chat history properly into main App. Cleanup README after.
- Completions support along with chat completions.