From 54f6cdcdbe1fe9c1034da6a075a033944d3cfb41 Mon Sep 17 00:00:00 2001 From: jhen Date: Fri, 26 Apr 2024 15:46:05 +0800 Subject: [PATCH 1/3] feat: add model details in context --- .../main/java/com/rnllama/LlamaContext.java | 9 +++++ .../src/main/java/com/rnllama/RNLlama.java | 1 + android/src/main/jni.cpp | 32 ++++++++++++++++ docs/API/README.md | 16 ++++---- docs/API/classes/LlamaContext.md | 37 ++++++++++++------- docs/API/classes/SchemaGrammarConverter.md | 32 ++++++++-------- ios/RNLlama.mm | 6 +++ ios/RNLlamaContext.h | 8 ++++ ios/RNLlamaContext.mm | 37 +++++++++++++++++++ src/NativeRNLlama.ts | 1 + src/index.ts | 9 ++++- 11 files changed, 149 insertions(+), 39 deletions(-) diff --git a/android/src/main/java/com/rnllama/LlamaContext.java b/android/src/main/java/com/rnllama/LlamaContext.java index f77026ea..c37fa38a 100644 --- a/android/src/main/java/com/rnllama/LlamaContext.java +++ b/android/src/main/java/com/rnllama/LlamaContext.java @@ -24,6 +24,7 @@ public class LlamaContext { private int id; private ReactApplicationContext reactContext; private long context; + private WritableMap modelDetails; private int jobId = -1; private DeviceEventManagerModule.RCTDeviceEventEmitter eventEmitter; @@ -63,6 +64,7 @@ public LlamaContext(int id, ReactApplicationContext reactContext, ReadableMap pa // float rope_freq_scale params.hasKey("rope_freq_scale") ? (float) params.getDouble("rope_freq_scale") : 0.0f ); + this.modelDetails = loadModelDetails(this.context); this.reactContext = reactContext; eventEmitter = reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class); } @@ -71,6 +73,10 @@ public long getContext() { return context; } + public WritableMap getModelDetails() { + return modelDetails; + } + private void emitPartialCompletion(WritableMap tokenResult) { WritableMap event = Arguments.createMap(); event.putInt("contextId", LlamaContext.this.id); @@ -297,6 +303,9 @@ protected static native long initContext( float rope_freq_base, float rope_freq_scale ); + protected static native WritableMap loadModelDetails( + long contextPtr + ); protected static native WritableMap loadSession( long contextPtr, String path diff --git a/android/src/main/java/com/rnllama/RNLlama.java b/android/src/main/java/com/rnllama/RNLlama.java index 871c78b5..0b673d90 100644 --- a/android/src/main/java/com/rnllama/RNLlama.java +++ b/android/src/main/java/com/rnllama/RNLlama.java @@ -59,6 +59,7 @@ protected WritableMap doInBackground(Void... voids) { result.putInt("contextId", id); result.putBoolean("gpu", false); result.putString("reasonNoGPU", "Currently not supported"); + result.putMap("model", llamaContext.getModelDetails()); return result; } catch (Exception e) { exception = e; diff --git a/android/src/main/jni.cpp b/android/src/main/jni.cpp index 7dff2e03..1bb305bb 100644 --- a/android/src/main/jni.cpp +++ b/android/src/main/jni.cpp @@ -185,6 +185,38 @@ Java_com_rnllama_LlamaContext_initContext( return reinterpret_cast(llama->ctx); } +JNIEXPORT jobject JNICALL +Java_com_rnllama_LlamaContext_loadModelDetails( + JNIEnv *env, + jobject thiz, + jlong context_ptr +) { + UNUSED(thiz); + auto llama = context_map[(long) context_ptr]; + + int count = llama_model_meta_count(llama->model); + auto meta = createWriteableMap(env); + for (int i = 0; i < count; i++) { + char key[256]; + llama_model_meta_key_by_index(llama->model, i, key, sizeof(key)); + char val[256]; + llama_model_meta_val_str_by_index(llama->model, i, val, sizeof(val)); + + putString(env, meta, key, val); + } + + auto result = createWriteableMap(env); + + char desc[1024]; + llama_model_desc(llama->model, desc, sizeof(desc)); + putString(env, result, "model_desc", desc); + putDouble(env, result, "model_size", llama_model_size(llama->model)); + putInt(env, result, "model_n_params", llama_model_n_params(llama->model)); + putMap(env, result, "metadata", meta); + + return reinterpret_cast(result); +} + JNIEXPORT jobject JNICALL Java_com_rnllama_LlamaContext_loadSession( JNIEnv *env, diff --git a/docs/API/README.md b/docs/API/README.md index 52e9ee5b..c1815459 100644 --- a/docs/API/README.md +++ b/docs/API/README.md @@ -43,7 +43,7 @@ llama.rn #### Defined in -[index.ts:43](https://github.com/mybigday/llama.rn/blob/17714d4/src/index.ts#L43) +[index.ts:43](https://github.com/mybigday/llama.rn/blob/a2b459e/src/index.ts#L43) ___ @@ -53,7 +53,7 @@ ___ #### Defined in -[index.ts:41](https://github.com/mybigday/llama.rn/blob/17714d4/src/index.ts#L41) +[index.ts:41](https://github.com/mybigday/llama.rn/blob/a2b459e/src/index.ts#L41) ___ @@ -63,7 +63,7 @@ ___ #### Defined in -[index.ts:39](https://github.com/mybigday/llama.rn/blob/17714d4/src/index.ts#L39) +[index.ts:39](https://github.com/mybigday/llama.rn/blob/a2b459e/src/index.ts#L39) ___ @@ -80,7 +80,7 @@ ___ #### Defined in -[index.ts:29](https://github.com/mybigday/llama.rn/blob/17714d4/src/index.ts#L29) +[index.ts:29](https://github.com/mybigday/llama.rn/blob/a2b459e/src/index.ts#L29) ## Functions @@ -104,7 +104,7 @@ ___ #### Defined in -[grammar.ts:824](https://github.com/mybigday/llama.rn/blob/17714d4/src/grammar.ts#L824) +[grammar.ts:824](https://github.com/mybigday/llama.rn/blob/a2b459e/src/grammar.ts#L824) ___ @@ -124,7 +124,7 @@ ___ #### Defined in -[index.ts:160](https://github.com/mybigday/llama.rn/blob/17714d4/src/index.ts#L160) +[index.ts:165](https://github.com/mybigday/llama.rn/blob/a2b459e/src/index.ts#L165) ___ @@ -138,7 +138,7 @@ ___ #### Defined in -[index.ts:176](https://github.com/mybigday/llama.rn/blob/17714d4/src/index.ts#L176) +[index.ts:181](https://github.com/mybigday/llama.rn/blob/a2b459e/src/index.ts#L181) ___ @@ -158,4 +158,4 @@ ___ #### Defined in -[index.ts:156](https://github.com/mybigday/llama.rn/blob/17714d4/src/index.ts#L156) +[index.ts:161](https://github.com/mybigday/llama.rn/blob/a2b459e/src/index.ts#L161) diff --git a/docs/API/classes/LlamaContext.md b/docs/API/classes/LlamaContext.md index d65fbe21..e789da5e 100644 --- a/docs/API/classes/LlamaContext.md +++ b/docs/API/classes/LlamaContext.md @@ -12,6 +12,7 @@ - [gpu](LlamaContext.md#gpu) - [id](LlamaContext.md#id) +- [model](LlamaContext.md#model) - [reasonNoGPU](LlamaContext.md#reasonnogpu) ### Methods @@ -40,7 +41,7 @@ #### Defined in -[index.ts:60](https://github.com/mybigday/llama.rn/blob/17714d4/src/index.ts#L60) +[index.ts:62](https://github.com/mybigday/llama.rn/blob/a2b459e/src/index.ts#L62) ## Properties @@ -50,7 +51,7 @@ #### Defined in -[index.ts:56](https://github.com/mybigday/llama.rn/blob/17714d4/src/index.ts#L56) +[index.ts:56](https://github.com/mybigday/llama.rn/blob/a2b459e/src/index.ts#L56) ___ @@ -60,7 +61,17 @@ ___ #### Defined in -[index.ts:54](https://github.com/mybigday/llama.rn/blob/17714d4/src/index.ts#L54) +[index.ts:54](https://github.com/mybigday/llama.rn/blob/a2b459e/src/index.ts#L54) + +___ + +### model + +• **model**: `Object` = `{}` + +#### Defined in + +[index.ts:60](https://github.com/mybigday/llama.rn/blob/a2b459e/src/index.ts#L60) ___ @@ -70,7 +81,7 @@ ___ #### Defined in -[index.ts:58](https://github.com/mybigday/llama.rn/blob/17714d4/src/index.ts#L58) +[index.ts:58](https://github.com/mybigday/llama.rn/blob/a2b459e/src/index.ts#L58) ## Methods @@ -93,7 +104,7 @@ ___ #### Defined in -[index.ts:129](https://github.com/mybigday/llama.rn/blob/17714d4/src/index.ts#L129) +[index.ts:134](https://github.com/mybigday/llama.rn/blob/a2b459e/src/index.ts#L134) ___ @@ -114,7 +125,7 @@ ___ #### Defined in -[index.ts:84](https://github.com/mybigday/llama.rn/blob/17714d4/src/index.ts#L84) +[index.ts:89](https://github.com/mybigday/llama.rn/blob/a2b459e/src/index.ts#L89) ___ @@ -134,7 +145,7 @@ ___ #### Defined in -[index.ts:121](https://github.com/mybigday/llama.rn/blob/17714d4/src/index.ts#L121) +[index.ts:126](https://github.com/mybigday/llama.rn/blob/a2b459e/src/index.ts#L126) ___ @@ -154,7 +165,7 @@ ___ #### Defined in -[index.ts:125](https://github.com/mybigday/llama.rn/blob/17714d4/src/index.ts#L125) +[index.ts:130](https://github.com/mybigday/llama.rn/blob/a2b459e/src/index.ts#L130) ___ @@ -176,7 +187,7 @@ Load cached prompt & completion state from a file. #### Defined in -[index.ts:73](https://github.com/mybigday/llama.rn/blob/17714d4/src/index.ts#L73) +[index.ts:78](https://github.com/mybigday/llama.rn/blob/a2b459e/src/index.ts#L78) ___ @@ -190,7 +201,7 @@ ___ #### Defined in -[index.ts:151](https://github.com/mybigday/llama.rn/blob/17714d4/src/index.ts#L151) +[index.ts:156](https://github.com/mybigday/llama.rn/blob/a2b459e/src/index.ts#L156) ___ @@ -214,7 +225,7 @@ Save current cached prompt & completion state to a file. #### Defined in -[index.ts:80](https://github.com/mybigday/llama.rn/blob/17714d4/src/index.ts#L80) +[index.ts:85](https://github.com/mybigday/llama.rn/blob/a2b459e/src/index.ts#L85) ___ @@ -228,7 +239,7 @@ ___ #### Defined in -[index.ts:113](https://github.com/mybigday/llama.rn/blob/17714d4/src/index.ts#L113) +[index.ts:118](https://github.com/mybigday/llama.rn/blob/a2b459e/src/index.ts#L118) ___ @@ -248,4 +259,4 @@ ___ #### Defined in -[index.ts:117](https://github.com/mybigday/llama.rn/blob/17714d4/src/index.ts#L117) +[index.ts:122](https://github.com/mybigday/llama.rn/blob/a2b459e/src/index.ts#L122) diff --git a/docs/API/classes/SchemaGrammarConverter.md b/docs/API/classes/SchemaGrammarConverter.md index 14f33c6c..33088e17 100644 --- a/docs/API/classes/SchemaGrammarConverter.md +++ b/docs/API/classes/SchemaGrammarConverter.md @@ -46,7 +46,7 @@ #### Defined in -[grammar.ts:211](https://github.com/mybigday/llama.rn/blob/17714d4/src/grammar.ts#L211) +[grammar.ts:211](https://github.com/mybigday/llama.rn/blob/a2b459e/src/grammar.ts#L211) ## Properties @@ -56,7 +56,7 @@ #### Defined in -[grammar.ts:201](https://github.com/mybigday/llama.rn/blob/17714d4/src/grammar.ts#L201) +[grammar.ts:201](https://github.com/mybigday/llama.rn/blob/a2b459e/src/grammar.ts#L201) ___ @@ -66,7 +66,7 @@ ___ #### Defined in -[grammar.ts:203](https://github.com/mybigday/llama.rn/blob/17714d4/src/grammar.ts#L203) +[grammar.ts:203](https://github.com/mybigday/llama.rn/blob/a2b459e/src/grammar.ts#L203) ___ @@ -76,7 +76,7 @@ ___ #### Defined in -[grammar.ts:199](https://github.com/mybigday/llama.rn/blob/17714d4/src/grammar.ts#L199) +[grammar.ts:199](https://github.com/mybigday/llama.rn/blob/a2b459e/src/grammar.ts#L199) ___ @@ -90,7 +90,7 @@ ___ #### Defined in -[grammar.ts:207](https://github.com/mybigday/llama.rn/blob/17714d4/src/grammar.ts#L207) +[grammar.ts:207](https://github.com/mybigday/llama.rn/blob/a2b459e/src/grammar.ts#L207) ___ @@ -100,7 +100,7 @@ ___ #### Defined in -[grammar.ts:209](https://github.com/mybigday/llama.rn/blob/17714d4/src/grammar.ts#L209) +[grammar.ts:209](https://github.com/mybigday/llama.rn/blob/a2b459e/src/grammar.ts#L209) ___ @@ -114,7 +114,7 @@ ___ #### Defined in -[grammar.ts:205](https://github.com/mybigday/llama.rn/blob/17714d4/src/grammar.ts#L205) +[grammar.ts:205](https://github.com/mybigday/llama.rn/blob/a2b459e/src/grammar.ts#L205) ## Methods @@ -135,7 +135,7 @@ ___ #### Defined in -[grammar.ts:693](https://github.com/mybigday/llama.rn/blob/17714d4/src/grammar.ts#L693) +[grammar.ts:693](https://github.com/mybigday/llama.rn/blob/a2b459e/src/grammar.ts#L693) ___ @@ -156,7 +156,7 @@ ___ #### Defined in -[grammar.ts:224](https://github.com/mybigday/llama.rn/blob/17714d4/src/grammar.ts#L224) +[grammar.ts:224](https://github.com/mybigday/llama.rn/blob/a2b459e/src/grammar.ts#L224) ___ @@ -179,7 +179,7 @@ ___ #### Defined in -[grammar.ts:710](https://github.com/mybigday/llama.rn/blob/17714d4/src/grammar.ts#L710) +[grammar.ts:710](https://github.com/mybigday/llama.rn/blob/a2b459e/src/grammar.ts#L710) ___ @@ -200,7 +200,7 @@ ___ #### Defined in -[grammar.ts:312](https://github.com/mybigday/llama.rn/blob/17714d4/src/grammar.ts#L312) +[grammar.ts:312](https://github.com/mybigday/llama.rn/blob/a2b459e/src/grammar.ts#L312) ___ @@ -220,7 +220,7 @@ ___ #### Defined in -[grammar.ts:518](https://github.com/mybigday/llama.rn/blob/17714d4/src/grammar.ts#L518) +[grammar.ts:518](https://github.com/mybigday/llama.rn/blob/a2b459e/src/grammar.ts#L518) ___ @@ -241,7 +241,7 @@ ___ #### Defined in -[grammar.ts:323](https://github.com/mybigday/llama.rn/blob/17714d4/src/grammar.ts#L323) +[grammar.ts:323](https://github.com/mybigday/llama.rn/blob/a2b459e/src/grammar.ts#L323) ___ @@ -255,7 +255,7 @@ ___ #### Defined in -[grammar.ts:813](https://github.com/mybigday/llama.rn/blob/17714d4/src/grammar.ts#L813) +[grammar.ts:813](https://github.com/mybigday/llama.rn/blob/a2b459e/src/grammar.ts#L813) ___ @@ -276,7 +276,7 @@ ___ #### Defined in -[grammar.ts:247](https://github.com/mybigday/llama.rn/blob/17714d4/src/grammar.ts#L247) +[grammar.ts:247](https://github.com/mybigday/llama.rn/blob/a2b459e/src/grammar.ts#L247) ___ @@ -297,4 +297,4 @@ ___ #### Defined in -[grammar.ts:529](https://github.com/mybigday/llama.rn/blob/17714d4/src/grammar.ts#L529) +[grammar.ts:529](https://github.com/mybigday/llama.rn/blob/a2b459e/src/grammar.ts#L529) diff --git a/ios/RNLlama.mm b/ios/RNLlama.mm index 4d10938c..d96441e2 100644 --- a/ios/RNLlama.mm +++ b/ios/RNLlama.mm @@ -53,6 +53,12 @@ @implementation RNLlama @"contextId": contextIdNumber, @"gpu": @([context isMetalEnabled]), @"reasonNoGPU": [context reasonNoMetal], + @"model": @{ + @"desc": [context modelDesc], + @"size": @([context modelSize]), + @"nParams": @([context modelNParams]), + @"metadata": [context metadata], + } }); } diff --git a/ios/RNLlamaContext.h b/ios/RNLlamaContext.h index aa6d85bc..86f6d290 100644 --- a/ios/RNLlamaContext.h +++ b/ios/RNLlamaContext.h @@ -8,6 +8,10 @@ bool is_metal_enabled; NSString * reason_no_metal; bool is_model_loaded; + NSString * model_desc; + uint64_t model_size; + int model_n_params; + NSDictionary * metadata; rnllama::llama_rn_context * llama; } @@ -15,6 +19,10 @@ + (instancetype)initWithParams:(NSDictionary *)params; - (bool)isMetalEnabled; - (NSString *)reasonNoMetal; +- (NSDictionary *)metadata; +- (NSString *)modelDesc; +- (uint64_t)modelSize; +- (int)modelNParams; - (bool)isModelLoaded; - (bool)isPredicting; - (NSDictionary *)completion:(NSDictionary *)params onToken:(void (^)(NSMutableDictionary *tokenResult))onToken; diff --git a/ios/RNLlamaContext.mm b/ios/RNLlamaContext.mm index ded5af8b..ef063ec8 100644 --- a/ios/RNLlamaContext.mm +++ b/ios/RNLlamaContext.mm @@ -82,6 +82,27 @@ + (instancetype)initWithParams:(NSDictionary *)params { context->is_model_loaded = context->llama->loadModel(defaultParams); context->is_metal_enabled = isMetalEnabled; context->reason_no_metal = reasonNoMetal; + + int count = llama_model_meta_count(context->llama->model); + NSDictionary *meta = [[NSMutableDictionary alloc] init]; + for (int i = 0; i < count; i++) { + char key[256]; + llama_model_meta_key_by_index(context->llama->model, i, key, sizeof(key)); + char val[256]; + llama_model_meta_val_str_by_index(context->llama->model, i, val, sizeof(val)); + + NSString *keyStr = [NSString stringWithUTF8String:key]; + NSString *valStr = [NSString stringWithUTF8String:val]; + [meta setValue:valStr forKey:keyStr]; + } + context->metadata = meta; + + char desc[1024]; + llama_model_desc(context->llama->model, desc, sizeof(desc)); + context->model_desc = [NSString stringWithUTF8String:desc]; + context->model_size = llama_model_size(context->llama->model); + context->model_n_params = llama_model_n_params(context->llama->model); + return context; } @@ -93,6 +114,22 @@ - (NSString *)reasonNoMetal { return reason_no_metal; } +- (NSDictionary *)metadata { + return metadata; +} + +- (NSString *)modelDesc { + return model_desc; +} + +- (size_t)modelSize { + return model_size; +} + +- (size_t)modelNParams { + return model_n_params; +} + - (bool)isModelLoaded { return is_model_loaded; } diff --git a/src/NativeRNLlama.ts b/src/NativeRNLlama.ts index 11894a97..7ec08de2 100644 --- a/src/NativeRNLlama.ts +++ b/src/NativeRNLlama.ts @@ -103,6 +103,7 @@ export type NativeLlamaContext = { contextId: number gpu: boolean reasonNoGPU: string + model: Object } export type NativeSessionLoadResult = { diff --git a/src/index.ts b/src/index.ts index cc7843a1..6875e07d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -57,14 +57,19 @@ export class LlamaContext { reasonNoGPU: string = '' + model: Object = {} + constructor({ contextId, gpu, reasonNoGPU, + model, }: NativeLlamaContext) { this.id = contextId this.gpu = gpu this.reasonNoGPU = reasonNoGPU + this.model = model + console.log(model) } /** @@ -164,13 +169,13 @@ export async function initLlama({ }: ContextParams): Promise { let path = model if (path.startsWith('file://')) path = path.slice(7) - const { contextId, gpu, reasonNoGPU } = + const { contextId, gpu, reasonNoGPU, model: modelDetails } = await RNLlama.initContext({ model: path, is_model_asset: !!isModelAsset, ...rest, }) - return new LlamaContext({ contextId, gpu, reasonNoGPU }) + return new LlamaContext({ contextId, gpu, reasonNoGPU, model: modelDetails }) } export async function releaseAllLlama(): Promise { From 1b5731f4f81bcd12ac25af1c0c015059f30b0a11 Mon Sep 17 00:00:00 2001 From: jhen Date: Fri, 26 Apr 2024 16:02:24 +0800 Subject: [PATCH 2/3] fix: type and key --- android/src/main/jni.cpp | 6 +++--- example/src/App.tsx | 1 + ios/RNLlamaContext.h | 4 ++-- ios/RNLlamaContext.mm | 4 ++-- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/android/src/main/jni.cpp b/android/src/main/jni.cpp index 1bb305bb..68d6231f 100644 --- a/android/src/main/jni.cpp +++ b/android/src/main/jni.cpp @@ -209,9 +209,9 @@ Java_com_rnllama_LlamaContext_loadModelDetails( char desc[1024]; llama_model_desc(llama->model, desc, sizeof(desc)); - putString(env, result, "model_desc", desc); - putDouble(env, result, "model_size", llama_model_size(llama->model)); - putInt(env, result, "model_n_params", llama_model_n_params(llama->model)); + putString(env, result, "desc", desc); + putDouble(env, result, "size", llama_model_size(llama->model)); + putDouble(env, result, "nParams", llama_model_n_params(llama->model)); putMap(env, result, "metadata", meta); return reinterpret_cast(result); diff --git a/example/src/App.tsx b/example/src/App.tsx index 4799a4bd..b0e05555 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -110,6 +110,7 @@ export default function App() { }) .then((ctx) => { setContext(ctx) + console.log(ctx) addSystemMessage( `Context initialized! \n\nGPU: ${ctx.gpu ? 'YES' : 'NO'} (${ ctx.reasonNoGPU diff --git a/ios/RNLlamaContext.h b/ios/RNLlamaContext.h index 86f6d290..7e07c96f 100644 --- a/ios/RNLlamaContext.h +++ b/ios/RNLlamaContext.h @@ -10,7 +10,7 @@ bool is_model_loaded; NSString * model_desc; uint64_t model_size; - int model_n_params; + uint64_t model_n_params; NSDictionary * metadata; rnllama::llama_rn_context * llama; @@ -22,7 +22,7 @@ - (NSDictionary *)metadata; - (NSString *)modelDesc; - (uint64_t)modelSize; -- (int)modelNParams; +- (uint64_t)modelNParams; - (bool)isModelLoaded; - (bool)isPredicting; - (NSDictionary *)completion:(NSDictionary *)params onToken:(void (^)(NSMutableDictionary *tokenResult))onToken; diff --git a/ios/RNLlamaContext.mm b/ios/RNLlamaContext.mm index ef063ec8..fb912d73 100644 --- a/ios/RNLlamaContext.mm +++ b/ios/RNLlamaContext.mm @@ -122,11 +122,11 @@ - (NSString *)modelDesc { return model_desc; } -- (size_t)modelSize { +- (uint64_t)modelSize { return model_size; } -- (size_t)modelNParams { +- (uint64_t)modelNParams { return model_n_params; } From 34446c783ed672e41d5eb510e3c32e97878d9390 Mon Sep 17 00:00:00 2001 From: jhen Date: Fri, 26 Apr 2024 16:10:03 +0800 Subject: [PATCH 3/3] chore(example): cleanup --- example/src/App.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/example/src/App.tsx b/example/src/App.tsx index b0e05555..4799a4bd 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -110,7 +110,6 @@ export default function App() { }) .then((ctx) => { setContext(ctx) - console.log(ctx) addSystemMessage( `Context initialized! \n\nGPU: ${ctx.gpu ? 'YES' : 'NO'} (${ ctx.reasonNoGPU