v2: add EmbeddingServerApp, fix Sendable issues (WIP)

This commit is contained in:
MarkBase Admin
2026-07-06 09:47:06 +08:00
parent 88aeff7935
commit e7a94b3203
4 changed files with 162 additions and 13 deletions
+38 -10
View File
@@ -20,16 +20,36 @@ struct SimpleServerApp {
print("")
let engine = try MarkBaseEngine(autoCompile: true)
let model = try E4BModel(modelDir: modelPath, engine: engine, maxContextLength: 512)
// Detect model type
let isEmbeddingGemma = modelName.contains("embeddinggemma") || modelName.contains("embedding")
let isE4B = !isEmbeddingGemma
var e4bModel: E4BModel? = nil
var embedModel: EmbeddingGemmaModel? = nil
let tokenizer = try TokenizerFactory.load(modelDir: modelPath)
let generator = StreamingGenerator(model: model, tokenizer: tokenizer, engine: engine)
let embeddingModel = try TextEmbeddingModel(modelDir: modelPath, engine: engine, config: TextEmbeddingConfig())
print("✓ E4B loaded (\(model.numHiddenLayers) layers)")
var generator: StreamingGenerator? = nil
if isE4B {
e4bModel = try E4BModel(modelDir: modelPath, engine: engine, maxContextLength: 512)
generator = StreamingGenerator(model: e4bModel!, tokenizer: tokenizer, engine: engine)
print("✓ E4B loaded (\(e4bModel!.numHiddenLayers) layers)")
} else {
embedModel = try EmbeddingGemmaModel(modelDir: modelPath, engine: engine)
print("✓ EmbeddingGemma loaded (\(embedModel!.config.numHiddenLayers) layers, hidden=\(embedModel!.config.hiddenSize))")
}
// Embedding model (use EmbeddingGemma if available, fallback to E4B)
let textEmbedModel: TextEmbeddingModel?
if isE4B {
textEmbedModel = try TextEmbeddingModel(modelDir: modelPath, engine: engine, config: TextEmbeddingConfig())
} else {
textEmbedModel = nil
}
let router = Router()
let layers = model.numHiddenLayers
let layers = isE4B ? e4bModel!.numHiddenLayers : embedModel!.config.numHiddenLayers
@Sendable func helpJSON() -> String {
return """
@@ -184,7 +204,8 @@ struct SimpleServerApp {
}
@Sendable func healthResponse() -> String {
return "{\"status\":\"healthy\",\"model\":\"e4b\",\"layers\":\(layers)}"
let m = isEmbeddingGemma ? "embeddinggemma-300m" : "e4b"
return "{\"status\":\"healthy\",\"model\":\"\(m)\",\"layers\":\(layers)}"
}
router.get("/") { _, _ in
@@ -229,7 +250,7 @@ struct SimpleServerApp {
topP: topP
)
let generatedTokens = try generator.generateTokens(promptTokens: promptTokens, config: config)
let generatedTokens = try generator!.generateTokens(promptTokens: promptTokens, config: config)
let id = UUID().uuidString
let ts = Int(Date().timeIntervalSince1970)
@@ -313,7 +334,14 @@ struct SimpleServerApp {
var embeddings: [[String: Any]] = []
for (i, text) in inputs.enumerated() {
let t0 = Date()
let embedding = try embeddingModel.embed(text: text)
let embedding: [Float]
if let eg = embedModelCopy {
embedding = try eg.embed(text: text)
} else if let tem = textEmbedModelCopy {
embedding = try tem.embed(text: text)
} else {
return "{\"error\":\"no embedding model available\",\"type\":\"server_error\",\"code\":500}"
}
let duration = Date().timeIntervalSince(t0)
let embeddingData: [String: Any]
@@ -338,7 +366,7 @@ struct SimpleServerApp {
let id = UUID().uuidString
let ts = Int(Date().timeIntervalSince1970)
let totalTokens = inputs.reduce(0) { $0 + tokenizer.encode(text: $1).count }
let totalTokens = inputs.reduce(0) { $0 + $1.components(separatedBy: .whitespaces).count }
let response: [String: Any] = [
"id": id,