cui-llama.rn 1.6.1 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (196) hide show
  1. package/android/src/main/CMakeLists.txt +6 -0
  2. package/android/src/main/java/com/rnllama/LlamaContext.java +38 -5
  3. package/android/src/main/java/com/rnllama/RNLlama.java +139 -4
  4. package/android/src/main/jni.cpp +153 -14
  5. package/android/src/main/jniLibs/arm64-v8a/librnllama.so +0 -0
  6. package/android/src/main/jniLibs/arm64-v8a/librnllama_v8.so +0 -0
  7. package/android/src/main/jniLibs/arm64-v8a/librnllama_v8_2.so +0 -0
  8. package/android/src/main/jniLibs/arm64-v8a/librnllama_v8_2_dotprod.so +0 -0
  9. package/android/src/main/jniLibs/arm64-v8a/librnllama_v8_2_dotprod_i8mm.so +0 -0
  10. package/android/src/main/jniLibs/arm64-v8a/librnllama_v8_2_i8mm.so +0 -0
  11. package/android/src/main/jniLibs/x86_64/librnllama.so +0 -0
  12. package/android/src/main/jniLibs/x86_64/librnllama_x86_64.so +0 -0
  13. package/android/src/newarch/java/com/rnllama/RNLlamaModule.java +24 -4
  14. package/android/src/oldarch/java/com/rnllama/RNLlamaModule.java +22 -2
  15. package/cpp/chat.cpp +128 -106
  16. package/cpp/chat.h +2 -0
  17. package/cpp/common.cpp +41 -76
  18. package/cpp/common.h +23 -19
  19. package/cpp/ggml-backend.cpp +9 -5
  20. package/cpp/ggml-backend.h +4 -4
  21. package/cpp/ggml-cpu/ggml-cpu-aarch64.cpp +0 -2
  22. package/cpp/ggml-cpu/ggml-cpu-quants.c +306 -6
  23. package/cpp/ggml-cpu/ggml-cpu.c +5 -13
  24. package/cpp/ggml-cpu/ggml-cpu.cpp +29 -16
  25. package/cpp/ggml-cpu/ops.cpp +107 -13
  26. package/cpp/ggml-cpu/vec.cpp +0 -6
  27. package/cpp/ggml-cpu/vec.h +16 -0
  28. package/cpp/ggml-llama-sim.metallib +0 -0
  29. package/cpp/ggml-llama.metallib +0 -0
  30. package/cpp/ggml-metal-impl.h +36 -11
  31. package/cpp/ggml-metal.m +321 -132
  32. package/cpp/ggml-opt.cpp +373 -190
  33. package/cpp/ggml-opt.h +49 -28
  34. package/cpp/ggml-quants.c +0 -6
  35. package/cpp/ggml.c +93 -38
  36. package/cpp/ggml.h +21 -7
  37. package/cpp/gguf.cpp +33 -33
  38. package/cpp/llama-adapter.cpp +6 -0
  39. package/cpp/llama-arch.cpp +3 -0
  40. package/cpp/llama-batch.cpp +3 -1
  41. package/cpp/llama-chat.cpp +8 -6
  42. package/cpp/llama-chat.h +1 -0
  43. package/cpp/llama-context.cpp +349 -135
  44. package/cpp/llama-context.h +30 -3
  45. package/cpp/llama-cparams.h +1 -0
  46. package/cpp/llama-graph.cpp +150 -234
  47. package/cpp/llama-graph.h +52 -7
  48. package/cpp/llama-hparams.cpp +17 -1
  49. package/cpp/llama-hparams.h +34 -5
  50. package/cpp/llama-kv-cache.cpp +662 -321
  51. package/cpp/llama-kv-cache.h +203 -93
  52. package/cpp/llama-memory.h +3 -2
  53. package/cpp/llama-model-loader.cpp +24 -15
  54. package/cpp/llama-model-saver.cpp +281 -0
  55. package/cpp/llama-model-saver.h +37 -0
  56. package/cpp/llama-model.cpp +536 -132
  57. package/cpp/llama-model.h +7 -1
  58. package/cpp/llama-sampling.cpp +18 -6
  59. package/cpp/llama-vocab.cpp +46 -8
  60. package/cpp/llama-vocab.h +6 -0
  61. package/cpp/llama.cpp +14 -0
  62. package/cpp/llama.h +72 -131
  63. package/cpp/minja/chat-template.hpp +9 -5
  64. package/cpp/minja/minja.hpp +69 -36
  65. package/cpp/rn-llama.cpp +611 -47
  66. package/cpp/rn-llama.h +33 -3
  67. package/cpp/sampling.cpp +57 -50
  68. package/cpp/tools/mtmd/clip-impl.h +462 -0
  69. package/cpp/tools/mtmd/clip.cpp +4024 -0
  70. package/cpp/tools/mtmd/clip.h +101 -0
  71. package/cpp/tools/mtmd/miniaudio.h +93468 -0
  72. package/cpp/tools/mtmd/mtmd-audio.cpp +855 -0
  73. package/cpp/tools/mtmd/mtmd-audio.h +62 -0
  74. package/cpp/tools/mtmd/mtmd-helper.cpp +297 -0
  75. package/cpp/tools/mtmd/mtmd.cpp +942 -0
  76. package/cpp/tools/mtmd/mtmd.h +362 -0
  77. package/cpp/tools/mtmd/stb_image.h +7988 -0
  78. package/ios/CMakeLists.txt +7 -0
  79. package/ios/RNLlama.mm +77 -3
  80. package/ios/RNLlamaContext.h +5 -1
  81. package/ios/RNLlamaContext.mm +105 -10
  82. package/ios/rnllama.xcframework/ios-arm64/rnllama.framework/Headers/chat.h +2 -0
  83. package/ios/rnllama.xcframework/ios-arm64/rnllama.framework/Headers/common.h +23 -19
  84. package/ios/rnllama.xcframework/ios-arm64/rnllama.framework/Headers/ggml-backend.h +4 -4
  85. package/ios/rnllama.xcframework/ios-arm64/rnllama.framework/Headers/ggml-metal-impl.h +36 -11
  86. package/ios/rnllama.xcframework/ios-arm64/rnllama.framework/Headers/ggml-opt.h +49 -28
  87. package/ios/rnllama.xcframework/ios-arm64/rnllama.framework/Headers/ggml.h +21 -7
  88. package/ios/rnllama.xcframework/ios-arm64/rnllama.framework/Headers/llama-chat.h +1 -0
  89. package/ios/rnllama.xcframework/ios-arm64/rnllama.framework/Headers/llama-context.h +30 -3
  90. package/ios/rnllama.xcframework/ios-arm64/rnllama.framework/Headers/llama-cparams.h +1 -0
  91. package/ios/rnllama.xcframework/ios-arm64/rnllama.framework/Headers/llama-graph.h +52 -7
  92. package/ios/rnllama.xcframework/ios-arm64/rnllama.framework/Headers/llama-hparams.h +34 -5
  93. package/ios/rnllama.xcframework/ios-arm64/rnllama.framework/Headers/llama-kv-cache.h +203 -93
  94. package/ios/rnllama.xcframework/ios-arm64/rnllama.framework/Headers/llama-memory.h +3 -2
  95. package/ios/rnllama.xcframework/ios-arm64/rnllama.framework/Headers/llama-model-saver.h +37 -0
  96. package/ios/rnllama.xcframework/ios-arm64/rnllama.framework/Headers/llama-model.h +7 -1
  97. package/ios/rnllama.xcframework/ios-arm64/rnllama.framework/Headers/llama-vocab.h +6 -0
  98. package/ios/rnllama.xcframework/ios-arm64/rnllama.framework/Headers/llama.h +72 -131
  99. package/ios/rnllama.xcframework/ios-arm64/rnllama.framework/Headers/minja/chat-template.hpp +9 -5
  100. package/ios/rnllama.xcframework/ios-arm64/rnllama.framework/Headers/minja/minja.hpp +69 -36
  101. package/ios/rnllama.xcframework/ios-arm64/rnllama.framework/Headers/rn-llama.h +33 -3
  102. package/ios/rnllama.xcframework/ios-arm64/rnllama.framework/Info.plist +0 -0
  103. package/ios/rnllama.xcframework/ios-arm64/rnllama.framework/ggml-llama.metallib +0 -0
  104. package/ios/rnllama.xcframework/ios-arm64/rnllama.framework/rnllama +0 -0
  105. package/ios/rnllama.xcframework/ios-arm64_x86_64-simulator/rnllama.framework/Headers/chat.h +2 -0
  106. package/ios/rnllama.xcframework/ios-arm64_x86_64-simulator/rnllama.framework/Headers/common.h +23 -19
  107. package/ios/rnllama.xcframework/ios-arm64_x86_64-simulator/rnllama.framework/Headers/ggml-backend.h +4 -4
  108. package/ios/rnllama.xcframework/ios-arm64_x86_64-simulator/rnllama.framework/Headers/ggml-metal-impl.h +36 -11
  109. package/ios/rnllama.xcframework/ios-arm64_x86_64-simulator/rnllama.framework/Headers/ggml-opt.h +49 -28
  110. package/ios/rnllama.xcframework/ios-arm64_x86_64-simulator/rnllama.framework/Headers/ggml.h +21 -7
  111. package/ios/rnllama.xcframework/ios-arm64_x86_64-simulator/rnllama.framework/Headers/llama-chat.h +1 -0
  112. package/ios/rnllama.xcframework/ios-arm64_x86_64-simulator/rnllama.framework/Headers/llama-context.h +30 -3
  113. package/ios/rnllama.xcframework/ios-arm64_x86_64-simulator/rnllama.framework/Headers/llama-cparams.h +1 -0
  114. package/ios/rnllama.xcframework/ios-arm64_x86_64-simulator/rnllama.framework/Headers/llama-graph.h +52 -7
  115. package/ios/rnllama.xcframework/ios-arm64_x86_64-simulator/rnllama.framework/Headers/llama-hparams.h +34 -5
  116. package/ios/rnllama.xcframework/ios-arm64_x86_64-simulator/rnllama.framework/Headers/llama-kv-cache.h +203 -93
  117. package/ios/rnllama.xcframework/ios-arm64_x86_64-simulator/rnllama.framework/Headers/llama-memory.h +3 -2
  118. package/ios/rnllama.xcframework/ios-arm64_x86_64-simulator/rnllama.framework/Headers/llama-model-saver.h +37 -0
  119. package/ios/rnllama.xcframework/ios-arm64_x86_64-simulator/rnllama.framework/Headers/llama-model.h +7 -1
  120. package/ios/rnllama.xcframework/ios-arm64_x86_64-simulator/rnllama.framework/Headers/llama-vocab.h +6 -0
  121. package/ios/rnllama.xcframework/ios-arm64_x86_64-simulator/rnllama.framework/Headers/llama.h +72 -131
  122. package/ios/rnllama.xcframework/ios-arm64_x86_64-simulator/rnllama.framework/Headers/minja/chat-template.hpp +9 -5
  123. package/ios/rnllama.xcframework/ios-arm64_x86_64-simulator/rnllama.framework/Headers/minja/minja.hpp +69 -36
  124. package/ios/rnllama.xcframework/ios-arm64_x86_64-simulator/rnllama.framework/Headers/rn-llama.h +33 -3
  125. package/ios/rnllama.xcframework/ios-arm64_x86_64-simulator/rnllama.framework/Info.plist +0 -0
  126. package/ios/rnllama.xcframework/ios-arm64_x86_64-simulator/rnllama.framework/_CodeSignature/CodeResources +1 -1
  127. package/ios/rnllama.xcframework/ios-arm64_x86_64-simulator/rnllama.framework/ggml-llama-sim.metallib +0 -0
  128. package/ios/rnllama.xcframework/ios-arm64_x86_64-simulator/rnllama.framework/rnllama +0 -0
  129. package/ios/rnllama.xcframework/tvos-arm64/rnllama.framework/Headers/chat.h +2 -0
  130. package/ios/rnllama.xcframework/tvos-arm64/rnllama.framework/Headers/common.h +23 -19
  131. package/ios/rnllama.xcframework/tvos-arm64/rnllama.framework/Headers/ggml-backend.h +4 -4
  132. package/ios/rnllama.xcframework/tvos-arm64/rnllama.framework/Headers/ggml-metal-impl.h +36 -11
  133. package/ios/rnllama.xcframework/tvos-arm64/rnllama.framework/Headers/ggml-opt.h +49 -28
  134. package/ios/rnllama.xcframework/tvos-arm64/rnllama.framework/Headers/ggml.h +21 -7
  135. package/ios/rnllama.xcframework/tvos-arm64/rnllama.framework/Headers/llama-chat.h +1 -0
  136. package/ios/rnllama.xcframework/tvos-arm64/rnllama.framework/Headers/llama-context.h +30 -3
  137. package/ios/rnllama.xcframework/tvos-arm64/rnllama.framework/Headers/llama-cparams.h +1 -0
  138. package/ios/rnllama.xcframework/tvos-arm64/rnllama.framework/Headers/llama-graph.h +52 -7
  139. package/ios/rnllama.xcframework/tvos-arm64/rnllama.framework/Headers/llama-hparams.h +34 -5
  140. package/ios/rnllama.xcframework/tvos-arm64/rnllama.framework/Headers/llama-kv-cache.h +203 -93
  141. package/ios/rnllama.xcframework/tvos-arm64/rnllama.framework/Headers/llama-memory.h +3 -2
  142. package/ios/rnllama.xcframework/tvos-arm64/rnllama.framework/Headers/llama-model-saver.h +37 -0
  143. package/ios/rnllama.xcframework/tvos-arm64/rnllama.framework/Headers/llama-model.h +7 -1
  144. package/ios/rnllama.xcframework/tvos-arm64/rnllama.framework/Headers/llama-vocab.h +6 -0
  145. package/ios/rnllama.xcframework/tvos-arm64/rnllama.framework/Headers/llama.h +72 -131
  146. package/ios/rnllama.xcframework/tvos-arm64/rnllama.framework/Headers/minja/chat-template.hpp +9 -5
  147. package/ios/rnllama.xcframework/tvos-arm64/rnllama.framework/Headers/minja/minja.hpp +69 -36
  148. package/ios/rnllama.xcframework/tvos-arm64/rnllama.framework/Headers/rn-llama.h +33 -3
  149. package/ios/rnllama.xcframework/tvos-arm64/rnllama.framework/Info.plist +0 -0
  150. package/ios/rnllama.xcframework/tvos-arm64/rnllama.framework/ggml-llama.metallib +0 -0
  151. package/ios/rnllama.xcframework/tvos-arm64/rnllama.framework/rnllama +0 -0
  152. package/ios/rnllama.xcframework/tvos-arm64_x86_64-simulator/rnllama.framework/Headers/chat.h +2 -0
  153. package/ios/rnllama.xcframework/tvos-arm64_x86_64-simulator/rnllama.framework/Headers/common.h +23 -19
  154. package/ios/rnllama.xcframework/tvos-arm64_x86_64-simulator/rnllama.framework/Headers/ggml-backend.h +4 -4
  155. package/ios/rnllama.xcframework/tvos-arm64_x86_64-simulator/rnllama.framework/Headers/ggml-metal-impl.h +36 -11
  156. package/ios/rnllama.xcframework/tvos-arm64_x86_64-simulator/rnllama.framework/Headers/ggml-opt.h +49 -28
  157. package/ios/rnllama.xcframework/tvos-arm64_x86_64-simulator/rnllama.framework/Headers/ggml.h +21 -7
  158. package/ios/rnllama.xcframework/tvos-arm64_x86_64-simulator/rnllama.framework/Headers/llama-chat.h +1 -0
  159. package/ios/rnllama.xcframework/tvos-arm64_x86_64-simulator/rnllama.framework/Headers/llama-context.h +30 -3
  160. package/ios/rnllama.xcframework/tvos-arm64_x86_64-simulator/rnllama.framework/Headers/llama-cparams.h +1 -0
  161. package/ios/rnllama.xcframework/tvos-arm64_x86_64-simulator/rnllama.framework/Headers/llama-graph.h +52 -7
  162. package/ios/rnllama.xcframework/tvos-arm64_x86_64-simulator/rnllama.framework/Headers/llama-hparams.h +34 -5
  163. package/ios/rnllama.xcframework/tvos-arm64_x86_64-simulator/rnllama.framework/Headers/llama-kv-cache.h +203 -93
  164. package/ios/rnllama.xcframework/tvos-arm64_x86_64-simulator/rnllama.framework/Headers/llama-memory.h +3 -2
  165. package/ios/rnllama.xcframework/tvos-arm64_x86_64-simulator/rnllama.framework/Headers/llama-model-saver.h +37 -0
  166. package/ios/rnllama.xcframework/tvos-arm64_x86_64-simulator/rnllama.framework/Headers/llama-model.h +7 -1
  167. package/ios/rnllama.xcframework/tvos-arm64_x86_64-simulator/rnllama.framework/Headers/llama-vocab.h +6 -0
  168. package/ios/rnllama.xcframework/tvos-arm64_x86_64-simulator/rnllama.framework/Headers/llama.h +72 -131
  169. package/ios/rnllama.xcframework/tvos-arm64_x86_64-simulator/rnllama.framework/Headers/minja/chat-template.hpp +9 -5
  170. package/ios/rnllama.xcframework/tvos-arm64_x86_64-simulator/rnllama.framework/Headers/minja/minja.hpp +69 -36
  171. package/ios/rnllama.xcframework/tvos-arm64_x86_64-simulator/rnllama.framework/Headers/rn-llama.h +33 -3
  172. package/ios/rnllama.xcframework/tvos-arm64_x86_64-simulator/rnllama.framework/Info.plist +0 -0
  173. package/ios/rnllama.xcframework/tvos-arm64_x86_64-simulator/rnllama.framework/_CodeSignature/CodeResources +1 -1
  174. package/ios/rnllama.xcframework/tvos-arm64_x86_64-simulator/rnllama.framework/ggml-llama-sim.metallib +0 -0
  175. package/ios/rnllama.xcframework/tvos-arm64_x86_64-simulator/rnllama.framework/rnllama +0 -0
  176. package/jest/mock.js +33 -7
  177. package/lib/commonjs/NativeRNLlama.js.map +1 -1
  178. package/lib/commonjs/index.js +153 -21
  179. package/lib/commonjs/index.js.map +1 -1
  180. package/lib/module/NativeRNLlama.js.map +1 -1
  181. package/lib/module/index.js +152 -20
  182. package/lib/module/index.js.map +1 -1
  183. package/lib/typescript/NativeRNLlama.d.ts +50 -4
  184. package/lib/typescript/NativeRNLlama.d.ts.map +1 -1
  185. package/lib/typescript/index.d.ts +72 -6
  186. package/lib/typescript/index.d.ts.map +1 -1
  187. package/package.json +1 -1
  188. package/src/NativeRNLlama.ts +67 -4
  189. package/src/index.ts +212 -38
  190. package/lib/commonjs/chat.js +0 -37
  191. package/lib/commonjs/chat.js.map +0 -1
  192. package/lib/module/chat.js +0 -33
  193. package/lib/module/chat.js.map +0 -1
  194. package/lib/typescript/chat.d.ts +0 -10
  195. package/lib/typescript/chat.d.ts.map +0 -1
  196. package/src/chat.ts +0 -44
@@ -73,6 +73,7 @@ add_library(rnllama SHARED
73
73
  ${SOURCE_DIR}/llama.cpp
74
74
  ${SOURCE_DIR}/llama-model.cpp
75
75
  ${SOURCE_DIR}/llama-model-loader.cpp
76
+ ${SOURCE_DIR}/llama-model-saver.cpp
76
77
  ${SOURCE_DIR}/llama-mmap.cpp
77
78
  ${SOURCE_DIR}/llama-vocab.cpp
78
79
  ${SOURCE_DIR}/llama-memory.cpp
@@ -87,6 +88,11 @@ add_library(rnllama SHARED
87
88
  ${SOURCE_DIR}/minja/minja.hpp
88
89
  ${SOURCE_DIR}/minja/chat-template.hpp
89
90
  ${SOURCE_DIR}/json.hpp
91
+ # Multimodal support
92
+ ${SOURCE_DIR}/tools/mtmd/mtmd.cpp
93
+ ${SOURCE_DIR}/tools/mtmd/mtmd-audio.cpp
94
+ ${SOURCE_DIR}/tools/mtmd/clip.cpp
95
+ ${SOURCE_DIR}/tools/mtmd/mtmd-helper.cpp
90
96
  ${SOURCE_DIR}/rn-llama.cpp
91
97
  )
92
98
 
@@ -95,6 +101,7 @@ target_include_directories(rnllama
95
101
  PUBLIC
96
102
  $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../cpp>
97
103
  $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../cpp/ggml-cpu>
104
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../cpp/tools/mtmd>
98
105
  $<INSTALL_INTERFACE:include>
99
106
  )
100
107
 
package/ios/RNLlama.mm CHANGED
@@ -234,6 +234,7 @@ RCT_EXPORT_METHOD(stopCompletion:(double)contextId
234
234
 
235
235
  RCT_EXPORT_METHOD(tokenizeASync:(double)contextId
236
236
  text:(NSString *)text
237
+ imagePaths:(NSArray *)imagePaths
237
238
  withResolver:(RCTPromiseResolveBlock)resolve
238
239
  withRejecter:(RCTPromiseRejectBlock)reject)
239
240
  {
@@ -242,9 +243,13 @@ RCT_EXPORT_METHOD(tokenizeASync:(double)contextId
242
243
  reject(@"llama_error", @"Context not found", nil);
243
244
  return;
244
245
  }
245
- NSMutableArray *tokens = [context tokenize:text];
246
- resolve(@{ @"tokens": tokens });
247
- [tokens release];
246
+ @try {
247
+ NSMutableDictionary *result = [context tokenize:text imagePaths:imagePaths];
248
+ resolve(result);
249
+ [result release];
250
+ } @catch (NSException *exception) {
251
+ reject(@"llama_error", exception.reason, nil);
252
+ }
248
253
  }
249
254
 
250
255
  RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(tokenizeSync:(double)contextId
@@ -360,6 +365,75 @@ RCT_EXPORT_METHOD(getLoadedLoraAdapters:(double)contextId
360
365
  resolve([context getLoadedLoraAdapters]);
361
366
  }
362
367
 
368
+ RCT_EXPORT_METHOD(initMultimodal:(double)contextId
369
+ withParams:(NSDictionary *)params
370
+ withResolver:(RCTPromiseResolveBlock)resolve
371
+ withRejecter:(RCTPromiseRejectBlock)reject)
372
+ {
373
+ RNLlamaContext *context = llamaContexts[[NSNumber numberWithDouble:contextId]];
374
+ if (context == nil) {
375
+ reject(@"llama_error", @"Context not found", nil);
376
+ return;
377
+ }
378
+ if ([context isPredicting]) {
379
+ reject(@"llama_error", @"Context is busy", nil);
380
+ return;
381
+ }
382
+
383
+ @try {
384
+ bool success = [context initMultimodal:params];
385
+ resolve(@(success));
386
+ } @catch (NSException *exception) {
387
+ reject(@"llama_cpp_error", exception.reason, nil);
388
+ }
389
+ }
390
+
391
+ RCT_EXPORT_METHOD(isMultimodalEnabled:(double)contextId
392
+ withResolver:(RCTPromiseResolveBlock)resolve
393
+ withRejecter:(RCTPromiseRejectBlock)reject)
394
+ {
395
+ RNLlamaContext *context = llamaContexts[[NSNumber numberWithDouble:contextId]];
396
+ if (context == nil) {
397
+ reject(@"llama_error", @"Context not found", nil);
398
+ return;
399
+ }
400
+
401
+ resolve(@([context isMultimodalEnabled]));
402
+ }
403
+
404
+ RCT_EXPORT_METHOD(getMultimodalSupport:(double)contextId
405
+ withResolver:(RCTPromiseResolveBlock)resolve
406
+ withRejecter:(RCTPromiseRejectBlock)reject)
407
+ {
408
+ RNLlamaContext *context = llamaContexts[[NSNumber numberWithDouble:contextId]];
409
+ if (context == nil) {
410
+ reject(@"llama_error", @"Context not found", nil);
411
+ return;
412
+ }
413
+
414
+ if (![context isMultimodalEnabled]) {
415
+ reject(@"llama_error", @"Multimodal is not enabled", nil);
416
+ return;
417
+ }
418
+
419
+ NSDictionary *multimodalSupport = [context getMultimodalSupport];
420
+ resolve(multimodalSupport);
421
+ }
422
+
423
+ RCT_EXPORT_METHOD(releaseMultimodal:(double)contextId
424
+ withResolver:(RCTPromiseResolveBlock)resolve
425
+ withRejecter:(RCTPromiseRejectBlock)reject)
426
+ {
427
+ RNLlamaContext *context = llamaContexts[[NSNumber numberWithDouble:contextId]];
428
+ if (context == nil) {
429
+ reject(@"llama_error", @"Context not found", nil);
430
+ return;
431
+ }
432
+
433
+ [context releaseMultimodal];
434
+ resolve(nil);
435
+ }
436
+
363
437
  RCT_EXPORT_METHOD(releaseContext:(double)contextId
364
438
  withResolver:(RCTPromiseResolveBlock)resolve
365
439
  withRejecter:(RCTPromiseRejectBlock)reject)
@@ -34,9 +34,13 @@
34
34
  - (NSDictionary *)modelInfo;
35
35
  - (bool)isModelLoaded;
36
36
  - (bool)isPredicting;
37
+ - (bool)initMultimodal:(NSDictionary *)params;
38
+ - (NSDictionary *)getMultimodalSupport;
39
+ - (bool)isMultimodalEnabled;
40
+ - (void)releaseMultimodal;
37
41
  - (NSDictionary *)completion:(NSDictionary *)params onToken:(void (^)(NSMutableDictionary *tokenResult))onToken;
38
42
  - (void)stopCompletion;
39
- - (NSArray *)tokenize:(NSString *)text;
43
+ - (NSDictionary *)tokenize:(NSString *)text imagePaths:(NSArray *)imagePaths;
40
44
  - (NSString *)detokenize:(NSArray *)tokens;
41
45
  - (NSDictionary *)embedding:(NSString *)text params:(NSDictionary *)params;
42
46
  - (NSDictionary *)getFormattedChatWithJinja:(NSString *)messages
@@ -332,6 +332,30 @@
332
332
  return llama->is_predicting;
333
333
  }
334
334
 
335
+ - (bool)initMultimodal:(NSDictionary *)params {
336
+ NSString *mmproj_path = params[@"path"];
337
+ BOOL use_gpu = params[@"use_gpu"] ? [params[@"use_gpu"] boolValue] : true;
338
+ return llama->initMultimodal([mmproj_path UTF8String], use_gpu);
339
+ }
340
+
341
+ - (NSDictionary *)getMultimodalSupport {
342
+ if (!is_model_loaded) return nil;
343
+ return @{
344
+ @"vision": @(llama->isMultimodalSupportVision()),
345
+ @"audio": @(llama->isMultimodalSupportAudio())
346
+ };
347
+ }
348
+
349
+ - (bool)isMultimodalEnabled {
350
+ if (!is_model_loaded) return false;
351
+ return llama->isMultimodalEnabled();
352
+ }
353
+
354
+ - (void)releaseMultimodal {
355
+ if (!is_model_loaded) return;
356
+ llama->releaseMultimodal();
357
+ }
358
+
335
359
  - (NSDictionary *)getFormattedChatWithJinja:(NSString *)messages
336
360
  withChatTemplate:(NSString *)chatTemplate
337
361
  withJsonSchema:(NSString *)jsonSchema
@@ -560,9 +584,30 @@
560
584
  if (!llama->initSampling()) {
561
585
  @throw [NSException exceptionWithName:@"LlamaException" reason:@"Failed to initialize sampling" userInfo:nil];
562
586
  }
587
+
563
588
  llama->beginCompletion();
564
- llama->loadPrompt();
589
+ try {
590
+ // Use the unified loadPrompt function with image paths if available
591
+ NSArray *imagePaths = params[@"media_paths"];
592
+ if (imagePaths && [imagePaths count] > 0) {
593
+ // Multiple image paths
594
+ std::vector<std::string> media_paths_vector;
595
+ for (NSString *path in imagePaths) {
596
+ if ([path isKindOfClass:[NSString class]]) {
597
+ media_paths_vector.push_back([path UTF8String]);
598
+ }
599
+ }
600
+ llama->loadPrompt(media_paths_vector);
601
+ } else {
602
+ llama->loadPrompt({});
603
+ }
604
+ } catch (const std::exception &e) {
605
+ llama->endCompletion();
606
+ @throw [NSException exceptionWithName:@"LlamaException" reason:[NSString stringWithUTF8String:e.what()] userInfo:nil];
607
+ }
608
+
565
609
  if (llama->context_full) {
610
+ llama->endCompletion();
566
611
  @throw [NSException exceptionWithName:@"LlamaException" reason:@"Context is full" userInfo:nil];
567
612
  }
568
613
 
@@ -625,7 +670,7 @@
625
670
  }
626
671
 
627
672
  llama_perf_context_print(llama->ctx);
628
- llama->is_predicting = false;
673
+ llama->endCompletion();
629
674
 
630
675
  const auto timings = llama_perf_context(llama->ctx);
631
676
 
@@ -689,13 +734,48 @@
689
734
  llama->is_interrupted = true;
690
735
  }
691
736
 
692
- - (NSArray *)tokenize:(NSString *)text {
693
- const std::vector<llama_token> toks = common_tokenize(llama->ctx, [text UTF8String], false);
694
- NSMutableArray *result = [[NSMutableArray alloc] init];
695
- for (llama_token tok : toks) {
696
- [result addObject:@(tok)];
737
+ - (NSDictionary *)tokenize:(NSString *)text imagePaths:(NSArray *)imagePaths {
738
+ std::vector<std::string> media_paths_vector;
739
+ if (imagePaths && [imagePaths count] > 0) {
740
+ for (NSString *path in imagePaths) {
741
+ if ([path isKindOfClass:[NSString class]]) {
742
+ media_paths_vector.push_back([path UTF8String]);
743
+ }
744
+ }
745
+ }
746
+ try {
747
+ rnllama::llama_rn_tokenize_result tokenize_result = llama->tokenize([text UTF8String], media_paths_vector);
748
+
749
+ NSMutableDictionary *result = [[NSMutableDictionary alloc] init];
750
+
751
+ result[@"tokens"] = [NSMutableArray arrayWithCapacity:tokenize_result.tokens.size()];
752
+ for (llama_token tok : tokenize_result.tokens) {
753
+ [result[@"tokens"] addObject:@(tok)];
754
+ }
755
+ result[@"has_media"] = @(tokenize_result.has_media);
756
+
757
+ NSMutableArray *bitmap_hashes = [[NSMutableArray alloc] init];
758
+ for (std::string hash : tokenize_result.bitmap_hashes) {
759
+ [bitmap_hashes addObject:[NSString stringWithUTF8String:hash.c_str()]];
760
+ }
761
+ result[@"bitmap_hashes"] = bitmap_hashes;
762
+
763
+ NSMutableArray *chunk_pos = [[NSMutableArray alloc] init];
764
+ for (int pos : tokenize_result.chunk_pos) {
765
+ [chunk_pos addObject:@(pos)];
766
+ }
767
+ result[@"chunk_pos"] = chunk_pos;
768
+
769
+ NSMutableArray *chunk_pos_media = [[NSMutableArray alloc] init];
770
+ for (int pos : tokenize_result.chunk_pos_media) {
771
+ [chunk_pos_media addObject:@(pos)];
772
+ }
773
+ result[@"chunk_pos_media"] = chunk_pos_media;
774
+
775
+ return result;
776
+ } catch (const std::exception &e) {
777
+ @throw [NSException exceptionWithName:@"LlamaException" reason:[NSString stringWithUTF8String:e.what()] userInfo:nil];
697
778
  }
698
- return result;
699
779
  }
700
780
 
701
781
  - (NSString *)detokenize:(NSArray *)tokens {
@@ -732,7 +812,12 @@
732
812
  @throw [NSException exceptionWithName:@"LlamaException" reason:@"Failed to initialize sampling" userInfo:nil];
733
813
  }
734
814
  llama->beginCompletion();
735
- llama->loadPrompt();
815
+ try {
816
+ llama->loadPrompt({});
817
+ } catch (const std::exception &e) {
818
+ llama->endCompletion();
819
+ @throw [NSException exceptionWithName:@"LlamaException" reason:[NSString stringWithUTF8String:e.what()] userInfo:nil];
820
+ }
736
821
  llama->doCompletion();
737
822
 
738
823
  std::vector<float> result = llama->getEmbedding(embdParams);
@@ -749,7 +834,7 @@
749
834
  }
750
835
  resultDict[@"prompt_tokens"] = promptTokens;
751
836
 
752
- llama->is_predicting = false;
837
+ llama->endCompletion();
753
838
  return resultDict;
754
839
  }
755
840
 
@@ -767,6 +852,11 @@
767
852
  @throw [NSException exceptionWithName:@"LlamaException" reason:@"Failed to load session" userInfo:nil];
768
853
  }
769
854
  llama->embd.resize(n_token_count_out);
855
+ // Find LLAMA_TOKEN_NULL in the tokens and resize the array to the index of the null token
856
+ auto null_token_iter = std::find(llama->embd.begin(), llama->embd.end(), LLAMA_TOKEN_NULL);
857
+ if (null_token_iter != llama->embd.end()) {
858
+ llama->embd.resize(std::distance(llama->embd.begin(), null_token_iter));
859
+ }
770
860
  const std::string text = rnllama::tokens_to_str(llama->ctx, llama->embd.cbegin(), llama->embd.cend());
771
861
  return @{
772
862
  @"tokens_loaded": @(n_token_count_out),
@@ -779,6 +869,11 @@
779
869
  @throw [NSException exceptionWithName:@"LlamaException" reason:@"Session path is empty" userInfo:nil];
780
870
  }
781
871
  std::vector<llama_token> session_tokens = llama->embd;
872
+ // Find LLAMA_TOKEN_NULL in the tokens and resize the array to the index of the null token
873
+ auto null_token_iter = std::find(session_tokens.begin(), session_tokens.end(), LLAMA_TOKEN_NULL);
874
+ if (null_token_iter != session_tokens.end()) {
875
+ session_tokens.resize(std::distance(session_tokens.begin(), null_token_iter));
876
+ }
782
877
  int default_size = session_tokens.size();
783
878
  int save_size = size > 0 && size <= default_size ? size : default_size;
784
879
  if (!llama_state_save_file(llama->ctx, [path UTF8String], session_tokens.data(), save_size)) {
@@ -3,6 +3,7 @@
3
3
  #pragma once
4
4
 
5
5
  #include "common.h"
6
+ #include <chrono>
6
7
  #include <string>
7
8
  #include <vector>
8
9
  #include "minja/chat-template.hpp"
@@ -79,6 +80,7 @@ struct common_chat_templates_inputs {
79
80
  common_chat_tool_choice tool_choice = COMMON_CHAT_TOOL_CHOICE_AUTO;
80
81
  bool parallel_tool_calls = false;
81
82
  bool extract_reasoning = true;
83
+ std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
82
84
  };
83
85
 
84
86
  struct common_chat_params {
@@ -6,6 +6,7 @@
6
6
 
7
7
  #include <set>
8
8
  #include <string>
9
+ #include <string_view>
9
10
  #include <vector>
10
11
  #include <sstream>
11
12
 
@@ -77,7 +78,6 @@ enum llama_example {
77
78
  LLAMA_EXAMPLE_COMMON,
78
79
  LLAMA_EXAMPLE_SPECULATIVE,
79
80
  LLAMA_EXAMPLE_MAIN,
80
- LLAMA_EXAMPLE_INFILL,
81
81
  LLAMA_EXAMPLE_EMBEDDING,
82
82
  LLAMA_EXAMPLE_PERPLEXITY,
83
83
  LLAMA_EXAMPLE_RETRIEVAL,
@@ -87,7 +87,7 @@ enum llama_example {
87
87
  LLAMA_EXAMPLE_SERVER,
88
88
  LLAMA_EXAMPLE_CVECTOR_GENERATOR,
89
89
  LLAMA_EXAMPLE_EXPORT_LORA,
90
- LLAMA_EXAMPLE_LLAVA,
90
+ LLAMA_EXAMPLE_MTMD,
91
91
  LLAMA_EXAMPLE_LOOKUP,
92
92
  LLAMA_EXAMPLE_PARALLEL,
93
93
  LLAMA_EXAMPLE_TTS,
@@ -107,6 +107,7 @@ enum common_sampler_type {
107
107
  COMMON_SAMPLER_TYPE_XTC = 8,
108
108
  COMMON_SAMPLER_TYPE_INFILL = 9,
109
109
  COMMON_SAMPLER_TYPE_PENALTIES = 10,
110
+ COMMON_SAMPLER_TYPE_TOP_N_SIGMA = 11,
110
111
  };
111
112
 
112
113
  // dimensionality reduction methods, used by cvector-generator
@@ -172,6 +173,7 @@ struct common_params_sampling {
172
173
  std::vector<enum common_sampler_type> samplers = {
173
174
  COMMON_SAMPLER_TYPE_PENALTIES,
174
175
  COMMON_SAMPLER_TYPE_DRY,
176
+ COMMON_SAMPLER_TYPE_TOP_N_SIGMA,
175
177
  COMMON_SAMPLER_TYPE_TOP_K,
176
178
  COMMON_SAMPLER_TYPE_TYPICAL_P,
177
179
  COMMON_SAMPLER_TYPE_TOP_P,
@@ -336,17 +338,17 @@ struct common_params {
336
338
  bool flash_attn = false; // flash attention
337
339
  bool no_perf = false; // disable performance metrics
338
340
  bool ctx_shift = true; // context shift on inifinite text generation
341
+ bool swa_full = false; // use full-size SWA cache (https://github.com/ggml-org/llama.cpp/pull/13194#issuecomment-2868343055)
339
342
 
340
343
  bool input_prefix_bos = false; // prefix BOS to user inputs, preceding input_prefix
341
- bool logits_all = false; // return logits for all tokens in the batch
342
344
  bool use_mmap = true; // use mmap for faster loads
343
345
  bool use_mlock = false; // use mlock to keep model in memory
344
346
  bool verbose_prompt = false; // print prompt tokens before generation
345
347
  bool display_prompt = true; // print prompt before generation
346
- bool dump_kv_cache = false; // dump the KV cache contents for debugging purposes
347
348
  bool no_kv_offload = false; // disable KV offloading
348
349
  bool warmup = true; // warmup run
349
350
  bool check_tensors = false; // validate tensor data
351
+ bool no_op_offload = false; // globally disable offload host tensor operations to device
350
352
 
351
353
  bool single_turn = false; // single turn chat conversation
352
354
 
@@ -355,7 +357,7 @@ struct common_params {
355
357
 
356
358
  common_conversation_mode conversation_mode = COMMON_CONVERSATION_MODE_AUTO;
357
359
 
358
- // multimodal models (see tools/llava)
360
+ // multimodal models (see tools/mtmd)
359
361
  struct common_params_model mmproj;
360
362
  bool mmproj_use_gpu = true; // use GPU for multimodal model
361
363
  bool no_mmproj = false; // explicitly disable multimodal model
@@ -381,6 +383,7 @@ struct common_params {
381
383
  bool use_jinja = false; // NOLINT
382
384
  bool enable_chat_template = true;
383
385
  common_reasoning_format reasoning_format = COMMON_REASONING_FORMAT_DEEPSEEK;
386
+ bool prefill_assistant = true; // if true, any trailing assistant message will be prefilled into the response
384
387
 
385
388
  std::vector<std::string> api_keys;
386
389
 
@@ -424,6 +427,7 @@ struct common_params {
424
427
 
425
428
  bool process_output = false; // collect data for the output tensor
426
429
  bool compute_ppl = true; // whether to compute perplexity
430
+ bool parse_special = false; // whether to parse special tokens during imatrix tokenization
427
431
 
428
432
  // cvector-generator params
429
433
  int n_pca_batch = 100;
@@ -439,6 +443,11 @@ struct common_params {
439
443
 
440
444
  // common params
441
445
  std::string out_file; // output filename for all example programs
446
+ // optional callback for model loading progress and cancellation:
447
+ // called with a progress value between 0.0 and 1.0.
448
+ // return false from callback to abort model loading or true to continue
449
+ llama_progress_callback load_progress_callback = NULL;
450
+ void * load_progress_callback_user_data = NULL;
442
451
  };
443
452
 
444
453
  // call once at the start of a program if it uses libcommon
@@ -516,10 +525,9 @@ static bool string_starts_with(const std::string & str,
516
525
  return str.rfind(prefix, 0) == 0;
517
526
  }
518
527
 
519
- static bool string_ends_with(const std::string & str,
520
- const std::string & suffix) { // While we wait for C++20's std::string::ends_with...
521
- return str.size() >= suffix.size() && str.compare(str.size()-suffix.size(), suffix.size(), suffix) == 0;
522
- }
528
+ // While we wait for C++20's std::string::ends_with...
529
+ bool string_ends_with(const std::string_view & str, const std::string_view & suffix);
530
+ size_t string_find_partial_stop(const std::string_view & str, const std::string_view & stop);
523
531
 
524
532
  bool string_parse_kv_override(const char * data, std::vector<llama_model_kv_override> & overrides);
525
533
  void string_process_escapes(std::string & input);
@@ -628,16 +636,6 @@ std::string common_detokenize(
628
636
  const std::vector<llama_token> & tokens,
629
637
  bool special = true);
630
638
 
631
- //
632
- // KV cache utils
633
- //
634
-
635
- // Dump the KV cache view with the number of sequences per cell.
636
- void common_kv_cache_dump_view(const llama_kv_cache_view & view, int row_size = 80);
637
-
638
- // Dump the KV cache view showing individual sequences in each cell (long output).
639
- void common_kv_cache_dump_view_seqs(const llama_kv_cache_view & view, int row_size = 40);
640
-
641
639
  //
642
640
  // Embedding utils
643
641
  //
@@ -679,3 +677,9 @@ const char * const LLM_KV_SPLIT_COUNT = "split.count";
679
677
  const char * const LLM_KV_SPLIT_TENSORS_COUNT = "split.tensors.count";
680
678
 
681
679
  }
680
+
681
+ //
682
+ // training utils
683
+ //
684
+
685
+ lm_ggml_opt_dataset_t common_opt_dataset_init(struct llama_context * ctx, const std::vector<llama_token> & tokens, int64_t stride);
@@ -38,7 +38,7 @@ extern "C" {
38
38
  LM_GGML_API lm_ggml_backend_buffer_t lm_ggml_backend_buft_alloc_buffer (lm_ggml_backend_buffer_type_t buft, size_t size);
39
39
  LM_GGML_API size_t lm_ggml_backend_buft_get_alignment (lm_ggml_backend_buffer_type_t buft);
40
40
  LM_GGML_API size_t lm_ggml_backend_buft_get_max_size (lm_ggml_backend_buffer_type_t buft);
41
- LM_GGML_API size_t lm_ggml_backend_buft_get_alloc_size(lm_ggml_backend_buffer_type_t buft, struct lm_ggml_tensor * tensor);
41
+ LM_GGML_API size_t lm_ggml_backend_buft_get_alloc_size(lm_ggml_backend_buffer_type_t buft, const struct lm_ggml_tensor * tensor);
42
42
  LM_GGML_API bool lm_ggml_backend_buft_is_host (lm_ggml_backend_buffer_type_t buft);
43
43
  LM_GGML_API lm_ggml_backend_dev_t lm_ggml_backend_buft_get_device (lm_ggml_backend_buffer_type_t buft);
44
44
 
@@ -59,7 +59,7 @@ extern "C" {
59
59
  LM_GGML_API enum lm_ggml_status lm_ggml_backend_buffer_init_tensor (lm_ggml_backend_buffer_t buffer, struct lm_ggml_tensor * tensor);
60
60
  LM_GGML_API size_t lm_ggml_backend_buffer_get_alignment (lm_ggml_backend_buffer_t buffer);
61
61
  LM_GGML_API size_t lm_ggml_backend_buffer_get_max_size (lm_ggml_backend_buffer_t buffer);
62
- LM_GGML_API size_t lm_ggml_backend_buffer_get_alloc_size(lm_ggml_backend_buffer_t buffer, struct lm_ggml_tensor * tensor);
62
+ LM_GGML_API size_t lm_ggml_backend_buffer_get_alloc_size(lm_ggml_backend_buffer_t buffer, const struct lm_ggml_tensor * tensor);
63
63
  LM_GGML_API void lm_ggml_backend_buffer_clear (lm_ggml_backend_buffer_t buffer, uint8_t value);
64
64
  LM_GGML_API bool lm_ggml_backend_buffer_is_host (lm_ggml_backend_buffer_t buffer);
65
65
  LM_GGML_API void lm_ggml_backend_buffer_set_usage (lm_ggml_backend_buffer_t buffer, enum lm_ggml_backend_buffer_usage usage);
@@ -248,7 +248,7 @@ extern "C" {
248
248
  // preferrably to run on the same backend as the buffer
249
249
  lm_ggml_backend_buffer_set_usage(buf_weights, LM_GGML_BACKEND_BUFFER_USAGE_WEIGHTS);
250
250
 
251
- sched = lm_ggml_backend_sched_new({backend_gpu, backend_gpu2, backend_cpu}, NULL, num_backends, LM_GGML_DEFAULT_GRAPH_SIZE, false);
251
+ sched = lm_ggml_backend_sched_new({backend_gpu, backend_gpu2, backend_cpu}, NULL, num_backends, LM_GGML_DEFAULT_GRAPH_SIZE, false, true);
252
252
 
253
253
  // initialize buffers from a max size graph (optional)
254
254
  reserve_graph = build_graph(sched, max_batch_size);
@@ -289,7 +289,7 @@ extern "C" {
289
289
  typedef bool (*lm_ggml_backend_sched_eval_callback)(struct lm_ggml_tensor * t, bool ask, void * user_data);
290
290
 
291
291
  // Initialize a backend scheduler, backends with low index are given priority over backends with high index
292
- LM_GGML_API lm_ggml_backend_sched_t lm_ggml_backend_sched_new(lm_ggml_backend_t * backends, lm_ggml_backend_buffer_type_t * bufts, int n_backends, size_t graph_size, bool parallel);
292
+ LM_GGML_API lm_ggml_backend_sched_t lm_ggml_backend_sched_new(lm_ggml_backend_t * backends, lm_ggml_backend_buffer_type_t * bufts, int n_backends, size_t graph_size, bool parallel, bool op_offload);
293
293
  LM_GGML_API void lm_ggml_backend_sched_free(lm_ggml_backend_sched_t sched);
294
294
 
295
295
  // Initialize backend buffers from a measure graph
@@ -207,6 +207,10 @@ typedef struct {
207
207
  float attn_factor;
208
208
  float beta_fast;
209
209
  float beta_slow;
210
+ int32_t sect_0;
211
+ int32_t sect_1;
212
+ int32_t sect_2;
213
+ int32_t sect_3;
210
214
  } lm_ggml_metal_kargs_rope;
211
215
 
212
216
  typedef struct {
@@ -299,21 +303,42 @@ typedef struct {
299
303
  } lm_ggml_metal_kargs_mul_mv_ext;
300
304
 
301
305
  typedef struct {
302
- int32_t nei0;
303
- int32_t nei1;
304
- uint64_t nbi1;
306
+ int32_t ne10;
307
+ int32_t ne11; // n_expert_used (bcast)
308
+ uint64_t nb11;
309
+ uint64_t nb12;
310
+ int32_t neh11; // n_tokens
311
+ uint64_t nbh11;
312
+ int32_t ne20; // n_expert_used
313
+ uint64_t nb21;
314
+ } lm_ggml_metal_kargs_mul_mm_id_map0;
315
+
316
+ typedef struct {
317
+ int32_t ne20; // n_expert_used
318
+ int32_t neh0;
319
+ int32_t neh1;
320
+ uint64_t nbh1;
321
+ uint64_t nbh2;
322
+ int32_t ne0;
323
+ uint64_t nb1;
324
+ uint64_t nb2;
325
+ } lm_ggml_metal_kargs_mul_mm_id_map1;
326
+
327
+ typedef struct {
305
328
  int32_t ne00;
306
329
  int32_t ne02;
307
330
  uint64_t nb01;
308
331
  uint64_t nb02;
309
- int32_t ne11;
310
- int32_t ne12;
311
- int32_t ne13;
312
- uint64_t nb10;
313
- uint64_t nb11;
314
- uint64_t nb12;
315
- int32_t ne0;
316
- int32_t ne1;
332
+ uint64_t nb03;
333
+ int32_t neh12;
334
+ uint64_t nbh10;
335
+ uint64_t nbh11;
336
+ uint64_t nbh12;
337
+ uint64_t nbh13;
338
+ int32_t neh0;
339
+ int32_t neh1;
340
+ int16_t r2;
341
+ int16_t r3;
317
342
  } lm_ggml_metal_kargs_mul_mm_id;
318
343
 
319
344
  typedef struct {