Skip to content

Commit 3bd0627

Browse files
authored
Reasoning chat and other simplifications
Reasoning chat
2 parents b180795 + 8ce37fe commit 3bd0627

File tree

23 files changed

+1228
-114
lines changed

23 files changed

+1228
-114
lines changed
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
name: Build And Soundness checks
2+
3+
on: [push, pull_request]
4+
5+
jobs:
6+
build:
7+
runs-on: ubuntu-latest
8+
steps:
9+
- name: Checkout repository
10+
uses: actions/checkout@v4
11+
- name: Run tests
12+
working-directory: backend
13+
run: swift build
14+
15+
soundness:
16+
name: Soundness
17+
uses: swiftlang/github-workflows/.github/workflows/soundness.yml@main
18+
with:
19+
license_header_check_enabled: true
20+
license_header_check_project_name: "Swift Foundation Models Playground"
21+
shell_check_enabled: false
22+
python_lint_check_enabled: false
23+
api_breakage_check_enabled: false
24+
# api_breakage_check_container_image: "swift:6.0-noble"
25+
docs_check_container_image: "swift:6.0-noble"
26+
format_check_container_image: "swift:6.0-noble"
27+
yamllint_check_enabled: true

.github/workflows/build_test_soundness.yml

Lines changed: 0 additions & 48 deletions
This file was deleted.

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Package.resolved
1212
.serverless
1313
.vscode
1414
.env
15+
Makefile
1516

1617
# backend
1718
backend/.DS_Store
@@ -27,6 +28,7 @@ backend/.env.*
2728
backend/.env
2829
backend/img/generated_images
2930
backend/.vscode
31+
backend/Makefile
3032

3133
# frontend
3234
frontend/node_modules
@@ -54,3 +56,4 @@ frontend/.vercel
5456

5557
frontend/*.tsbuildinfo
5658
frontend/next-env.d.ts
59+
frontend/Makefile

backend/Package.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ let package = Package(
1212
dependencies: [
1313
.package(url: "https://github.com/hummingbird-project/hummingbird.git", from: "2.0.0"),
1414
.package(url: "https://github.com/apple/swift-argument-parser.git", from: "1.3.0"),
15-
.package(url: "https://github.com/monadierickx/swift-bedrock-library.git", branch: "week16"),
15+
.package(url: "https://github.com/sebsto/swift-bedrock-library.git", branch: "main"),
1616
],
1717
targets: [
1818
.executableTarget(

backend/Sources/PlaygroundAPI/App.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,11 @@ struct AppCommand: AsyncParsableCommand, AppArguments {
2828
@Option(name: .shortAndLong)
2929
var logLevel: Logger.Level?
3030

31-
@Flag var sso = false
31+
@Flag(name: .shortAndLong, help: "Use SSO authentication (default: false))")
32+
var sso: Bool = false
33+
34+
@Option(name: [.customShort("n"), .long], help: "The name of the profile to use (default: default)")
35+
var profileName: String = "default"
3236

3337
func run() async throws {
3438
let app = try await buildApplication(self)

backend/Sources/PlaygroundAPI/Application+build.swift

Lines changed: 64 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ public protocol AppArguments {
2828
var port: Int { get }
2929
var logLevel: Logger.Level? { get }
3030
var sso: Bool { get }
31+
var profileName: String { get }
3132
}
3233

3334
// Request context used by application
@@ -46,7 +47,7 @@ public func buildApplication(
4647
arguments.logLevel ?? environment.get("LOG_LEVEL").flatMap {
4748
Logger.Level(rawValue: $0)
4849
} ?? .info
49-
let router = try await buildRouter(useSSO: arguments.sso, logger: logger)
50+
let router = try await buildRouter(useSSO: arguments.sso, logger: logger, profileName: arguments.profileName)
5051
let app = Application(
5152
router: router,
5253
configuration: .init(
@@ -59,7 +60,7 @@ public func buildApplication(
5960
}
6061

6162
/// Build router
62-
func buildRouter(useSSO: Bool, logger: Logger) async throws -> Router<AppRequestContext> {
63+
func buildRouter(useSSO: Bool, logger: Logger, profileName: String) async throws -> Router<AppRequestContext> {
6364
let router = Router(context: AppRequestContext.self)
6465

6566
// CORS
@@ -76,7 +77,22 @@ func buildRouter(useSSO: Bool, logger: Logger) async throws -> Router<AppRequest
7677
}
7778

7879
// SwiftBedrock
79-
let bedrock = try await BedrockService(useSSO: useSSO)
80+
var auth: BedrockAuthentication = .default
81+
if useSSO {
82+
auth = .sso(profileName: profileName)
83+
}
84+
let bedrock = try await BedrockService(authentication: auth)
85+
86+
// Error handling
87+
@Sendable func handleBedrockServiceError(_ error: Error, context: String) throws {
88+
if let bedrockServiceError = error as? BedrockServiceError {
89+
logger.trace("BedrockServiceError while \(context)", metadata: ["error": "\(error)"])
90+
throw HTTPError(.badRequest, message: bedrockServiceError.message)
91+
} else {
92+
logger.trace("Error while \(context)", metadata: ["error": "\(error)"])
93+
throw HTTPError(.internalServerError, message: "Error: \(error)")
94+
}
95+
}
8096

8197
// List models
8298
// GET /foundation-models lists all models
@@ -173,25 +189,56 @@ func buildRouter(useSSO: Bool, logger: Logger) async throws -> Router<AppRequest
173189
throw HTTPError(.badRequest, message: "Model \(modelId) does not support converse.")
174190
}
175191
let input = try await request.decode(as: ChatInput.self, context: context)
176-
return try await bedrock.converse(
177-
with: model,
178-
prompt: input.prompt,
179-
imageFormat: input.imageFormat ?? .jpeg, // default to simplify frontend
180-
imageBytes: input.imageBytes,
181-
history: input.history ?? [],
182-
maxTokens: input.maxTokens,
183-
temperature: input.temperature,
184-
topP: input.topP,
185-
stopSequences: input.stopSequences,
186-
systemPrompts: input.systemPrompts,
187-
tools: input.tools,
188-
toolResult: input.toolResult
189-
)
192+
var image: ImageBlock? = nil
193+
if let imageBytes = input.imageBytes {
194+
image = try ImageBlock(format: input.imageFormat ?? .jpeg, source: imageBytes)
195+
}
196+
var document: DocumentBlock? = nil
197+
if let documentBytes = input.documentBytes, let name = input.documentName {
198+
document = try DocumentBlock(name: name, format: input.documentFormat ?? .pdf, source: documentBytes)
199+
}
200+
var builder = try ConverseRequestBuilder(with: model)
201+
.withHistory(input.history ?? [])
202+
.withMaxTokens(input.maxTokens)
203+
.withTemperature(input.temperature)
204+
.withTopP(input.topP)
205+
206+
if let stopSequences = input.stopSequences,
207+
!stopSequences.isEmpty
208+
{
209+
builder = try builder.withStopSequences(stopSequences)
210+
}
211+
if let systemPrompts = input.systemPrompts,
212+
!systemPrompts.isEmpty
213+
{
214+
builder = try builder.withStopSequences(systemPrompts)
215+
}
216+
if let prompt = input.prompt {
217+
builder = try builder.withPrompt(prompt)
218+
}
219+
if let tools = input.tools {
220+
builder = try builder.withTools(tools)
221+
}
222+
if let toolResult = input.toolResult {
223+
builder = try builder.withToolResult(toolResult)
224+
}
225+
if let document {
226+
builder = try builder.withDocument(document)
227+
}
228+
if let image {
229+
builder = try builder.withImage(image)
230+
}
231+
if let enableReasoning = input.enableReasoning, enableReasoning {
232+
builder = try builder.withReasoning()
233+
.withMaxReasoningTokens(input.maxReasoningTokens)
234+
}
235+
return try await bedrock.converse(with: builder)
190236
} catch {
191237
logger.info(
192238
"An error occured while generating chat",
193239
metadata: ["url": "/foundation-models/chat/:modelId", "error": "\(error)"]
194240
)
241+
try handleBedrockServiceError(error, context: "/foundation-models/chat/:modelId")
195242
throw HTTPError(.internalServerError, message: "Error: \(error)")
196243
}
197244
}

backend/Sources/PlaygroundAPI/Types/Chat.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,18 @@ struct ChatInput: Codable {
2424
let history: [Message]?
2525
let imageFormat: ImageBlock.Format?
2626
let imageBytes: String?
27+
let documentName: String?
28+
let documentFormat: DocumentBlock.Format?
29+
let documentBytes: String?
2730
let maxTokens: Int?
2831
let temperature: Double?
2932
let topP: Double?
3033
let stopSequences: [String]?
3134
let systemPrompts: [String]?
3235
let tools: [Tool]?
3336
let toolResult: ToolResultBlock?
37+
let enableReasoning: Bool?
38+
let maxReasoningTokens: Int?
3439
}
3540

3641
extension ConverseReply: @retroactive ResponseCodable {}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
export default function Loading() {
2+
return (
3+
<div className="container px-6 py-8 mx-auto">
4+
<div className="text-center">
5+
<div role="status">
6+
<svg aria-hidden="true" className="inline w-8 h-8 mr-2 text-gray-200 animate-spin dark:text-gray-600 fill-blue-600" viewBox="0 0 100 101" fill="none" xmlns="http://www.w3.org/2000/svg">
7+
<path d="M100 50.5908C100 78.2051 77.6142 100.591 50 100.591C22.3858 100.591 0 78.2051 0 50.5908C0 22.9766 22.3858 0.59082 50 0.59082C77.6142 0.59082 100 22.9766 100 50.5908ZM9.08144 50.5908C9.08144 73.1895 27.4013 91.5094 50 91.5094C72.5987 91.5094 90.9186 73.1895 90.9186 50.5908C90.9186 27.9921 72.5987 9.67226 50 9.67226C27.4013 9.67226 9.08144 27.9921 9.08144 50.5908Z" fill="currentColor"/>
8+
<path d="M93.9676 39.0409C96.393 38.4038 97.8624 35.9116 97.0079 33.5539C95.2932 28.8227 92.871 24.3692 89.8167 20.348C85.8452 15.1192 80.8826 10.7238 75.2124 7.41289C69.5422 4.10194 63.2754 1.94025 56.7698 1.05124C51.7666 0.367541 46.6976 0.446843 41.7345 1.27873C39.2613 1.69328 37.813 4.19778 38.4501 6.62326C39.0873 9.04874 41.5694 10.4717 44.0505 10.1071C47.8511 9.54855 51.7191 9.52689 55.5402 10.0491C60.8642 10.7766 65.9928 12.5457 70.6331 15.2552C75.2735 17.9648 79.3347 21.5619 82.5849 25.841C84.9175 28.9121 86.7997 32.2913 88.1811 35.8758C89.083 38.2158 91.5421 39.6781 93.9676 39.0409Z" fill="currentFill"/>
9+
</svg>
10+
<span className="sr-only">Loading...</span>
11+
</div>
12+
</div>
13+
</div>
14+
)
15+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
"use client";
2+
3+
import ReasoningChatComponent from "@/components/reasoningChatPlayground/ReasoningChatComponent";
4+
5+
export default async function Chat() {
6+
return (
7+
<ReasoningChatComponent />
8+
)
9+
}

frontend/components/Navigation.jsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,14 @@ export default function Navigation() {
1919
className="flex items-center px-6 py-2 mt-4 text-gray-400 hover:bg-gray-700 hover:bg-opacity-25 hover:text-gray-100">
2020
<span className="mx-3">Chat Playground</span>
2121
</Link>
22-
<Link href="/text"
22+
<Link href="/reasoning_chat"
2323
className="flex items-center px-6 py-2 mt-4 text-gray-400 hover:bg-gray-700 hover:bg-opacity-25 hover:text-gray-100">
24-
<span className="mx-3">Text Playground</span>
24+
<span className="mx-3">Reasoning Chat Playground</span>
2525
</Link>
26+
{/* <Link href="/text"
27+
className="flex items-center px-6 py-2 mt-4 text-gray-400 hover:bg-gray-700 hover:bg-opacity-25 hover:text-gray-100">
28+
<span className="mx-3">Text Playground</span>
29+
</Link> */}
2630
<Link href="/image"
2731
className="flex items-center px-6 py-2 mt-4 text-gray-400 hover:bg-gray-700 hover:bg-opacity-25 hover:text-gray-100">
2832
<span className="mx-3">Image Playground</span>

0 commit comments

Comments
 (0)