ac75faa0cc
CI / build-and-test (push) Has been cancelled
- E4B-MarkBase model (42 layers, 4.4GB) loaded successfully - All Phase 1-6 tests passed (model loading, forward pass, vision/audio towers, token generation, performance) - All stress tests passed (5/5 in 127.6s) - Concurrent inference - Memory stress (67.5 tok/s, 0 NaN) - Continuous generation - Batch processing - Long-running stability - Swift Metal inference engine with multimodal support
151 lines
4.3 KiB
Swift
151 lines
4.3 KiB
Swift
import Foundation
|
|
|
|
// ─────────────────────────────────────────────────────────────
|
|
// Server-Sent Events (SSE) Support
|
|
// ─────────────────────────────────────────────────────────────
|
|
|
|
/// SSE Event structure
|
|
public struct SSEEvent {
|
|
public let id: String?
|
|
public let event: String?
|
|
public let data: String
|
|
public let retry: Int?
|
|
|
|
public init(id: String? = nil, event: String? = nil, data: String, retry: Int? = nil) {
|
|
self.id = id
|
|
self.event = event
|
|
self.data = data
|
|
self.retry = retry
|
|
}
|
|
|
|
/// Format as SSE string
|
|
public func format() -> String {
|
|
var output = ""
|
|
|
|
if let id = id {
|
|
output += "id: \(id)\n"
|
|
}
|
|
|
|
if let event = event {
|
|
output += "event: \(event)\n"
|
|
}
|
|
|
|
if let retry = retry {
|
|
output += "retry: \(retry)\n"
|
|
}
|
|
|
|
// Handle multi-line data
|
|
let lines = data.split(separator: "\n")
|
|
for line in lines {
|
|
output += "data: \(line)\n"
|
|
}
|
|
|
|
output += "\n"
|
|
return output
|
|
}
|
|
}
|
|
|
|
/// SSE Stream Generator
|
|
public final class SSEStream {
|
|
private var buffer = ""
|
|
|
|
public init() {}
|
|
|
|
/// Add event to stream
|
|
public func add(event: SSEEvent) -> String {
|
|
let formatted = event.format()
|
|
buffer += formatted
|
|
return formatted
|
|
}
|
|
|
|
/// Create chat completion chunk
|
|
public static func chatChunk(
|
|
id: String,
|
|
model: String,
|
|
content: String? = nil,
|
|
role: String? = nil,
|
|
finishReason: String? = nil
|
|
) -> SSEEvent {
|
|
var delta: [String: String] = [:]
|
|
if let role = role {
|
|
delta["role"] = role
|
|
}
|
|
if let content = content {
|
|
delta["content"] = content
|
|
}
|
|
|
|
let chunk: [String: Any] = [
|
|
"id": id,
|
|
"object": "chat.completion.chunk",
|
|
"created": Int(Date().timeIntervalSince1970),
|
|
"model": model,
|
|
"choices": [
|
|
[
|
|
"index": 0,
|
|
"delta": delta,
|
|
"finish_reason": finishReason as Any
|
|
]
|
|
]
|
|
]
|
|
|
|
guard let jsonData = try? JSONSerialization.data(withJSONObject: chunk),
|
|
let jsonString = String(data: jsonData, encoding: .utf8) else {
|
|
return SSEEvent(data: "")
|
|
}
|
|
|
|
return SSEEvent(data: jsonString)
|
|
}
|
|
|
|
/// Create text completion chunk
|
|
public static func textChunk(
|
|
id: String,
|
|
model: String,
|
|
text: String,
|
|
finishReason: String? = nil
|
|
) -> SSEEvent {
|
|
let chunk: [String: Any] = [
|
|
"id": id,
|
|
"object": "text_completion",
|
|
"created": Int(Date().timeIntervalSince1970),
|
|
"model": model,
|
|
"choices": [
|
|
[
|
|
"index": 0,
|
|
"text": text,
|
|
"finish_reason": finishReason as Any
|
|
]
|
|
]
|
|
]
|
|
|
|
guard let jsonData = try? JSONSerialization.data(withJSONObject: chunk),
|
|
let jsonString = String(data: jsonData, encoding: .utf8) else {
|
|
return SSEEvent(data: "")
|
|
}
|
|
|
|
return SSEEvent(data: jsonString)
|
|
}
|
|
|
|
/// Create [DONE] event
|
|
public static func done() -> SSEEvent {
|
|
SSEEvent(data: "[DONE]")
|
|
}
|
|
|
|
/// Create error event
|
|
public static func error(message: String) -> SSEEvent {
|
|
let error: [String: Any] = [
|
|
"error": [
|
|
"message": message,
|
|
"type": "invalid_request_error",
|
|
"code": nil
|
|
]
|
|
]
|
|
|
|
guard let jsonData = try? JSONSerialization.data(withJSONObject: error),
|
|
let jsonString = String(data: jsonData, encoding: .utf8) else {
|
|
return SSEEvent(data: "")
|
|
}
|
|
|
|
return SSEEvent(event: "error", data: jsonString)
|
|
}
|
|
}
|