llama-cpp-pro 0.2.2
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.
- package/CHANGELOG.md +295 -0
- package/LICENSE +21 -0
- package/LlamaCpp.podspec +33 -0
- package/LlamaCppCapacitor.podspec +33 -0
- package/Package.swift +29 -0
- package/README.md +93 -0
- package/android/build.gradle +88 -0
- package/android/src/main/AndroidManifest.xml +4 -0
- package/android/src/main/CMakeLists-arm64.txt +138 -0
- package/android/src/main/CMakeLists-x86_64.txt +141 -0
- package/android/src/main/CMakeLists.txt +138 -0
- package/android/src/main/java/ai/annadata/plugin/capacitor/LlamaCpp.java +1340 -0
- package/android/src/main/java/ai/annadata/plugin/capacitor/LlamaCppPlugin.java +814 -0
- package/android/src/main/java/ai/annadata/plugin/capacitor/ModelAdmissionController.java +214 -0
- package/android/src/main/jni-chat-session.cpp +261 -0
- package/android/src/main/jni-lora.cpp +197 -0
- package/android/src/main/jni-multimodal.cpp +167 -0
- package/android/src/main/jni-tts.cpp +290 -0
- package/android/src/main/jni-utils.h +148 -0
- package/android/src/main/jni.cpp +1808 -0
- package/android/src/main/jniLibs/arm64-v8a/libllama-cpp-arm64.so +0 -0
- package/android/src/main/res/.gitkeep +0 -0
- package/build-native.sh +280 -0
- package/cmake/desktop-metal-embed.cmake +30 -0
- package/cmake/desktop-sources.cmake +100 -0
- package/cmake/ggml-backends.cmake +44 -0
- package/cpp/LICENSE +21 -0
- package/cpp/README.md +15 -0
- package/cpp/anyascii.c +22223 -0
- package/cpp/anyascii.h +42 -0
- package/cpp/cap-completion.cpp +942 -0
- package/cpp/cap-completion.h +127 -0
- package/cpp/cap-embedding.cpp +193 -0
- package/cpp/cap-embedding.h +35 -0
- package/cpp/cap-ios-bridge.cpp +1810 -0
- package/cpp/cap-ios-bridge.h +61 -0
- package/cpp/cap-llama.cpp +412 -0
- package/cpp/cap-llama.h +161 -0
- package/cpp/cap-mtmd.hpp +602 -0
- package/cpp/cap-native-server.cpp +1095 -0
- package/cpp/cap-native-server.h +40 -0
- package/cpp/cap-tts.cpp +591 -0
- package/cpp/cap-tts.h +59 -0
- package/cpp/cap-wasm-fs.cpp +156 -0
- package/cpp/cap-wasm-jspi.cpp +19 -0
- package/cpp/cap-wasm-jspi.h +30 -0
- package/cpp/cap-wasm-vfs.cpp +22 -0
- package/cpp/chat-parser.cpp +393 -0
- package/cpp/chat-parser.h +120 -0
- package/cpp/chat.cpp +2315 -0
- package/cpp/chat.h +221 -0
- package/cpp/common.cpp +1664 -0
- package/cpp/common.h +744 -0
- package/cpp/ggml-alloc.c +1028 -0
- package/cpp/ggml-alloc.h +76 -0
- package/cpp/ggml-backend-impl.h +255 -0
- package/cpp/ggml-backend-reg.cpp +600 -0
- package/cpp/ggml-backend.cpp +2121 -0
- package/cpp/ggml-backend.h +354 -0
- package/cpp/ggml-common.h +1878 -0
- package/cpp/ggml-cpp.h +39 -0
- package/cpp/ggml-cpu/amx/amx.cpp +221 -0
- package/cpp/ggml-cpu/amx/amx.h +8 -0
- package/cpp/ggml-cpu/amx/common.h +91 -0
- package/cpp/ggml-cpu/amx/mmq.cpp +2512 -0
- package/cpp/ggml-cpu/amx/mmq.h +10 -0
- package/cpp/ggml-cpu/arch/arm/cpu-feats.cpp +94 -0
- package/cpp/ggml-cpu/arch/arm/quants.c +3650 -0
- package/cpp/ggml-cpu/arch/arm/repack.cpp +1891 -0
- package/cpp/ggml-cpu/arch/x86/cpu-feats.cpp +327 -0
- package/cpp/ggml-cpu/arch/x86/quants.c +3820 -0
- package/cpp/ggml-cpu/arch/x86/repack.cpp +6307 -0
- package/cpp/ggml-cpu/arch-fallback.h +215 -0
- package/cpp/ggml-cpu/binary-ops.cpp +158 -0
- package/cpp/ggml-cpu/binary-ops.h +16 -0
- package/cpp/ggml-cpu/common.h +73 -0
- package/cpp/ggml-cpu/ggml-cpu-impl.h +559 -0
- package/cpp/ggml-cpu/ggml-cpu.c +3578 -0
- package/cpp/ggml-cpu/ggml-cpu.cpp +672 -0
- package/cpp/ggml-cpu/ops.cpp +10587 -0
- package/cpp/ggml-cpu/ops.h +114 -0
- package/cpp/ggml-cpu/quants.c +1193 -0
- package/cpp/ggml-cpu/quants.h +97 -0
- package/cpp/ggml-cpu/repack.cpp +1982 -0
- package/cpp/ggml-cpu/repack.h +120 -0
- package/cpp/ggml-cpu/simd-mappings.h +1184 -0
- package/cpp/ggml-cpu/traits.cpp +36 -0
- package/cpp/ggml-cpu/traits.h +38 -0
- package/cpp/ggml-cpu/unary-ops.cpp +186 -0
- package/cpp/ggml-cpu/unary-ops.h +28 -0
- package/cpp/ggml-cpu/vec.cpp +348 -0
- package/cpp/ggml-cpu/vec.h +1121 -0
- package/cpp/ggml-cpu.h +145 -0
- package/cpp/ggml-impl.h +622 -0
- package/cpp/ggml-metal-impl.h +688 -0
- package/cpp/ggml-metal.h +66 -0
- package/cpp/ggml-metal.m +6833 -0
- package/cpp/ggml-metal.metal +10754 -0
- package/cpp/ggml-opt.cpp +1093 -0
- package/cpp/ggml-opt.h +256 -0
- package/cpp/ggml-quants.c +5324 -0
- package/cpp/ggml-quants.h +106 -0
- package/cpp/ggml-threading.cpp +12 -0
- package/cpp/ggml-threading.h +14 -0
- package/cpp/ggml.c +7108 -0
- package/cpp/ggml.h +2492 -0
- package/cpp/gguf.cpp +1358 -0
- package/cpp/gguf.h +202 -0
- package/cpp/json-partial.cpp +256 -0
- package/cpp/json-partial.h +38 -0
- package/cpp/json-schema-to-grammar.cpp +985 -0
- package/cpp/json-schema-to-grammar.h +21 -0
- package/cpp/llama-adapter.cpp +388 -0
- package/cpp/llama-adapter.h +76 -0
- package/cpp/llama-arch.cpp +2355 -0
- package/cpp/llama-arch.h +499 -0
- package/cpp/llama-batch.cpp +875 -0
- package/cpp/llama-batch.h +160 -0
- package/cpp/llama-chat.cpp +783 -0
- package/cpp/llama-chat.h +65 -0
- package/cpp/llama-context.cpp +2788 -0
- package/cpp/llama-context.h +306 -0
- package/cpp/llama-cparams.cpp +5 -0
- package/cpp/llama-cparams.h +41 -0
- package/cpp/llama-cpp.h +30 -0
- package/cpp/llama-grammar.cpp +1229 -0
- package/cpp/llama-grammar.h +173 -0
- package/cpp/llama-graph.cpp +1891 -0
- package/cpp/llama-graph.h +810 -0
- package/cpp/llama-hparams.cpp +180 -0
- package/cpp/llama-hparams.h +233 -0
- package/cpp/llama-impl.cpp +167 -0
- package/cpp/llama-impl.h +61 -0
- package/cpp/llama-io.cpp +15 -0
- package/cpp/llama-io.h +35 -0
- package/cpp/llama-kv-cache-iswa.cpp +318 -0
- package/cpp/llama-kv-cache-iswa.h +135 -0
- package/cpp/llama-kv-cache.cpp +2059 -0
- package/cpp/llama-kv-cache.h +374 -0
- package/cpp/llama-kv-cells.h +491 -0
- package/cpp/llama-memory-hybrid.cpp +258 -0
- package/cpp/llama-memory-hybrid.h +137 -0
- package/cpp/llama-memory-recurrent.cpp +1146 -0
- package/cpp/llama-memory-recurrent.h +179 -0
- package/cpp/llama-memory.cpp +59 -0
- package/cpp/llama-memory.h +119 -0
- package/cpp/llama-mmap.cpp +609 -0
- package/cpp/llama-mmap.h +68 -0
- package/cpp/llama-model-loader.cpp +1166 -0
- package/cpp/llama-model-loader.h +170 -0
- package/cpp/llama-model-saver.cpp +282 -0
- package/cpp/llama-model-saver.h +37 -0
- package/cpp/llama-model.cpp +19061 -0
- package/cpp/llama-model.h +491 -0
- package/cpp/llama-sampling.cpp +2575 -0
- package/cpp/llama-sampling.h +32 -0
- package/cpp/llama-vocab.cpp +3792 -0
- package/cpp/llama-vocab.h +176 -0
- package/cpp/llama.cpp +358 -0
- package/cpp/llama.h +1373 -0
- package/cpp/log.cpp +428 -0
- package/cpp/log.h +103 -0
- package/cpp/minja/chat-template.hpp +550 -0
- package/cpp/minja/minja.hpp +3009 -0
- package/cpp/nlohmann/json.hpp +25526 -0
- package/cpp/nlohmann/json_fwd.hpp +187 -0
- package/cpp/regex-partial.cpp +204 -0
- package/cpp/regex-partial.h +56 -0
- package/cpp/sampling.cpp +579 -0
- package/cpp/sampling.h +107 -0
- package/cpp/tools/mtmd/clip-impl.h +473 -0
- package/cpp/tools/mtmd/clip.cpp +4322 -0
- package/cpp/tools/mtmd/clip.h +106 -0
- package/cpp/tools/mtmd/miniaudio/miniaudio.h +93468 -0
- package/cpp/tools/mtmd/mtmd-audio.cpp +769 -0
- package/cpp/tools/mtmd/mtmd-audio.h +47 -0
- package/cpp/tools/mtmd/mtmd-helper.cpp +460 -0
- package/cpp/tools/mtmd/mtmd-helper.h +95 -0
- package/cpp/tools/mtmd/mtmd.cpp +1066 -0
- package/cpp/tools/mtmd/mtmd.h +302 -0
- package/cpp/tools/mtmd/stb/stb_image.h +7988 -0
- package/cpp/unicode-data.cpp +7034 -0
- package/cpp/unicode-data.h +20 -0
- package/cpp/unicode.cpp +1061 -0
- package/cpp/unicode.h +68 -0
- package/cpp/vendor/cpp-httplib/httplib.cpp +16509 -0
- package/cpp/vendor/cpp-httplib/httplib.h +3883 -0
- package/desktop/electron-builder.config.cjs +157 -0
- package/desktop/entitlements.mac.plist +12 -0
- package/desktop/package.json +11 -0
- package/desktop/resolve-package-root.cjs +88 -0
- package/desktop/src/main/backend-selector.cjs +148 -0
- package/desktop/src/main/gpu-probe.cjs +142 -0
- package/desktop/src/main/index.cjs +58 -0
- package/desktop/src/main/ipc-handlers.cjs +212 -0
- package/desktop/src/main/model-store.cjs +50 -0
- package/desktop/src/main/preload.cjs +39 -0
- package/desktop/src/main/sidecar-client.cjs +76 -0
- package/desktop/src/main/sidecar-manager.cjs +364 -0
- package/dist/docs.json +14357 -0
- package/dist/esm/definitions.d.ts +731 -0
- package/dist/esm/definitions.js +2 -0
- package/dist/esm/definitions.js.map +1 -0
- package/dist/esm/desktop.d.ts +37 -0
- package/dist/esm/desktop.js +133 -0
- package/dist/esm/desktop.js.map +1 -0
- package/dist/esm/index.d.ts +200 -0
- package/dist/esm/index.js +612 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/isomorphic/desktop.runtime.d.ts +37 -0
- package/dist/esm/isomorphic/desktop.runtime.js +36 -0
- package/dist/esm/isomorphic/desktop.runtime.js.map +1 -0
- package/dist/esm/isomorphic/errors.d.ts +6 -0
- package/dist/esm/isomorphic/errors.js +9 -0
- package/dist/esm/isomorphic/errors.js.map +1 -0
- package/dist/esm/isomorphic/model.admission.d.ts +17 -0
- package/dist/esm/isomorphic/model.admission.js +27 -0
- package/dist/esm/isomorphic/model.admission.js.map +1 -0
- package/dist/esm/isomorphic/model.scheduler.d.ts +31 -0
- package/dist/esm/isomorphic/model.scheduler.js +95 -0
- package/dist/esm/isomorphic/model.scheduler.js.map +1 -0
- package/dist/esm/isomorphic/provider.desktop.d.ts +40 -0
- package/dist/esm/isomorphic/provider.desktop.js +411 -0
- package/dist/esm/isomorphic/provider.desktop.js.map +1 -0
- package/dist/esm/isomorphic/provider.factory.d.ts +2 -0
- package/dist/esm/isomorphic/provider.factory.js +16 -0
- package/dist/esm/isomorphic/provider.factory.js.map +1 -0
- package/dist/esm/isomorphic/provider.interface.d.ts +76 -0
- package/dist/esm/isomorphic/provider.interface.js +2 -0
- package/dist/esm/isomorphic/provider.interface.js.map +1 -0
- package/dist/esm/isomorphic/provider.native.d.ts +18 -0
- package/dist/esm/isomorphic/provider.native.js +173 -0
- package/dist/esm/isomorphic/provider.native.js.map +1 -0
- package/dist/esm/isomorphic/provider.web.d.ts +88 -0
- package/dist/esm/isomorphic/provider.web.js +573 -0
- package/dist/esm/isomorphic/provider.web.js.map +1 -0
- package/dist/esm/isomorphic/sidecar-sse.d.ts +14 -0
- package/dist/esm/isomorphic/sidecar-sse.js +76 -0
- package/dist/esm/isomorphic/sidecar-sse.js.map +1 -0
- package/dist/esm/isomorphic/wasmMemoryCalibration.d.ts +26 -0
- package/dist/esm/isomorphic/wasmMemoryCalibration.js +60 -0
- package/dist/esm/isomorphic/wasmMemoryCalibration.js.map +1 -0
- package/dist/esm/isomorphic/wasmMemoryPolicy.d.ts +55 -0
- package/dist/esm/isomorphic/wasmMemoryPolicy.js +93 -0
- package/dist/esm/isomorphic/wasmMemoryPolicy.js.map +1 -0
- package/dist/esm/storage/manifest.d.ts +13 -0
- package/dist/esm/storage/manifest.js +87 -0
- package/dist/esm/storage/manifest.js.map +1 -0
- package/dist/esm/storage/opfs.store.d.ts +31 -0
- package/dist/esm/storage/opfs.store.js +241 -0
- package/dist/esm/storage/opfs.store.js.map +1 -0
- package/dist/esm/web.d.ts +206 -0
- package/dist/esm/web.js +521 -0
- package/dist/esm/web.js.map +1 -0
- package/dist/esm/workers/async-file.d.ts +13 -0
- package/dist/esm/workers/async-file.js +12 -0
- package/dist/esm/workers/async-file.js.map +1 -0
- package/dist/esm/workers/heapfs.d.ts +55 -0
- package/dist/esm/workers/heapfs.js +115 -0
- package/dist/esm/workers/heapfs.js.map +1 -0
- package/dist/esm/workers/wasm.engine.d.ts +86 -0
- package/dist/esm/workers/wasm.engine.js +504 -0
- package/dist/esm/workers/wasm.engine.js.map +1 -0
- package/dist/esm/workers/worker.protocol.d.ts +160 -0
- package/dist/esm/workers/worker.protocol.js +2 -0
- package/dist/esm/workers/worker.protocol.js.map +1 -0
- package/dist/plugin.cjs +3179 -0
- package/dist/plugin.cjs.map +1 -0
- package/dist/plugin.js +3181 -0
- package/dist/plugin.js.map +1 -0
- package/dist/wasm/llama_engine.d.ts +74 -0
- package/dist/wasm/llama_engine.js +1829 -0
- package/dist/wasm/llama_engine.wasm +0 -0
- package/dist/wasm/llama_engine_emscripten.mjs +2 -0
- package/dist/wasm/package.json +16 -0
- package/dist/workers/llm.worker.js +1226 -0
- package/dist/workers/llm.worker.js.map +7 -0
- package/extraResources/llama-wasm/llama_engine.d.ts +74 -0
- package/extraResources/llama-wasm/llama_engine.js +1829 -0
- package/extraResources/llama-wasm/llama_engine.wasm +0 -0
- package/extraResources/llama-wasm/llama_engine_emscripten.mjs +2 -0
- package/extraResources/llama-wasm/package.json +16 -0
- package/extraResources/sidecar/README.md +11 -0
- package/extraResources/sidecar/darwin-arm64 +0 -0
- package/extraResources/sidecar/darwin-x64 +0 -0
- package/ios/CMakeLists-arm64.txt +161 -0
- package/ios/CMakeLists-x86_64.txt +188 -0
- package/ios/CMakeLists.txt +161 -0
- package/ios/Frameworks/llama-cpp.framework/Info.plist +28 -0
- package/ios/Frameworks/llama-cpp.framework/llama-cpp +0 -0
- package/ios/Sources/LlamaCppCapacitor/LlamaCpp.swift +1365 -0
- package/ios/Sources/LlamaCppCapacitor/LlamaCppPlugin.swift +694 -0
- package/ios/Sources/LlamaCppCapacitor/LlamaNativeBridge.swift +349 -0
- package/ios/Sources/LlamaCppCapacitor/ModelAdmissionController.swift +177 -0
- package/ios/embed-metal-shaders.sh +24 -0
- package/ios/metal-embed.cmake +29 -0
- package/package.json +281 -0
- package/scripts/build-js-preserve-wasm.cjs +53 -0
- package/scripts/build-sidecar-linux.sh +6 -0
- package/scripts/build-sidecar-win.bat +19 -0
- package/scripts/build-sidecar.sh +184 -0
- package/scripts/embed-llama-ios-app-framework.sh +63 -0
- package/scripts/ensure-desktop-sidecar-bundle.cjs +103 -0
- package/scripts/ensure-llama-ios-xcframework.sh +108 -0
- package/scripts/fix-esm-extensions.cjs +45 -0
- package/scripts/prepare-js-dist.cjs +28 -0
- package/scripts/stage-desktop-resources.cjs +116 -0
- package/sidecar/CMakeLists.txt +192 -0
- package/sidecar/cap-sidecar-main.cpp +68 -0
- package/types/llama-cpp-pro.d.ts +441 -0
|
@@ -0,0 +1,942 @@
|
|
|
1
|
+
#include "cap-completion.h"
|
|
2
|
+
#include "cap-llama.h"
|
|
3
|
+
#include "cap-tts.h"
|
|
4
|
+
#include "cap-mtmd.hpp"
|
|
5
|
+
#include <algorithm> // For std::sort in speculative decoding
|
|
6
|
+
#include <chrono>
|
|
7
|
+
#include <cmath>
|
|
8
|
+
|
|
9
|
+
// Include multimodal support
|
|
10
|
+
#include "tools/mtmd/mtmd.h"
|
|
11
|
+
#include "tools/mtmd/mtmd-helper.h"
|
|
12
|
+
#include "tools/mtmd/clip.h"
|
|
13
|
+
|
|
14
|
+
namespace capllama {
|
|
15
|
+
|
|
16
|
+
static bool ends_with(const std::string &str, const std::string &suffix)
|
|
17
|
+
{
|
|
18
|
+
return str.size() >= suffix.size() &&
|
|
19
|
+
0 == str.compare(str.size() - suffix.size(), suffix.size(), suffix);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
static size_t find_partial_stop_string(const std::string &stop,
|
|
23
|
+
const std::string &text)
|
|
24
|
+
{
|
|
25
|
+
if (!text.empty() && !stop.empty())
|
|
26
|
+
{
|
|
27
|
+
const char text_last_char = text.back();
|
|
28
|
+
for (int64_t char_index = stop.size() - 1; char_index >= 0; char_index--)
|
|
29
|
+
{
|
|
30
|
+
if (stop[char_index] == text_last_char)
|
|
31
|
+
{
|
|
32
|
+
const std::string current_partial = stop.substr(0, char_index + 1);
|
|
33
|
+
if (ends_with(text, current_partial))
|
|
34
|
+
{
|
|
35
|
+
return text.size() - char_index - 1;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return std::string::npos;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Helper function to format rerank task: [BOS]query[EOS][SEP]doc[EOS]
|
|
44
|
+
static std::vector<llama_token> format_rerank(const llama_vocab * vocab, const std::vector<llama_token> & query, const std::vector<llama_token> & doc) {
|
|
45
|
+
std::vector<llama_token> result;
|
|
46
|
+
|
|
47
|
+
// Get EOS token - use SEP token as fallback if EOS is not available
|
|
48
|
+
llama_token eos_token = llama_vocab_eos(vocab);
|
|
49
|
+
if (eos_token == LLAMA_TOKEN_NULL) {
|
|
50
|
+
eos_token = llama_vocab_sep(vocab);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
result.reserve(doc.size() + query.size() + 4);
|
|
54
|
+
if (llama_vocab_get_add_bos(vocab)) {
|
|
55
|
+
result.push_back(llama_vocab_bos(vocab));
|
|
56
|
+
}
|
|
57
|
+
result.insert(result.end(), query.begin(), query.end());
|
|
58
|
+
if (llama_vocab_get_add_eos(vocab)) {
|
|
59
|
+
result.push_back(eos_token);
|
|
60
|
+
}
|
|
61
|
+
if (llama_vocab_get_add_sep(vocab)) {
|
|
62
|
+
result.push_back(llama_vocab_sep(vocab));
|
|
63
|
+
}
|
|
64
|
+
result.insert(result.end(), doc.begin(), doc.end());
|
|
65
|
+
if (llama_vocab_get_add_eos(vocab)) {
|
|
66
|
+
result.push_back(eos_token);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return result;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** When the sampler picks EOG on the first new token, take the best non-EOG logit instead. */
|
|
73
|
+
static llama_token sample_completion_token(
|
|
74
|
+
struct common_sampler * ctx_sampling,
|
|
75
|
+
llama_context * ctx,
|
|
76
|
+
const llama_vocab * vocab,
|
|
77
|
+
bool allow_eog)
|
|
78
|
+
{
|
|
79
|
+
llama_token id = common_sampler_sample(ctx_sampling, ctx, -1);
|
|
80
|
+
if (allow_eog || !llama_vocab_is_eog(vocab, id)) {
|
|
81
|
+
return id;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const float * logits = llama_get_logits_ith(ctx, -1);
|
|
85
|
+
if (!logits) {
|
|
86
|
+
return id;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const int n_vocab = llama_vocab_n_tokens(vocab);
|
|
90
|
+
llama_token best = LLAMA_TOKEN_NULL;
|
|
91
|
+
float best_logit = -INFINITY;
|
|
92
|
+
for (llama_token tid = 0; tid < n_vocab; ++tid) {
|
|
93
|
+
if (llama_vocab_is_eog(vocab, tid)) {
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
if (logits[tid] > best_logit) {
|
|
97
|
+
best_logit = logits[tid];
|
|
98
|
+
best = tid;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (best != LLAMA_TOKEN_NULL && std::isfinite(best_logit)) {
|
|
103
|
+
#ifdef __EMSCRIPTEN__
|
|
104
|
+
fprintf(stderr, "@@WASM_GEN@@ first_token_eog=%d fallback=%d logit=%.3f\n",
|
|
105
|
+
id, best, best_logit);
|
|
106
|
+
#endif
|
|
107
|
+
return best;
|
|
108
|
+
}
|
|
109
|
+
return id;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Constructor
|
|
113
|
+
llama_cap_context_completion::llama_cap_context_completion(llama_cap_context* parent)
|
|
114
|
+
: parent_ctx(parent) {
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Destructor
|
|
118
|
+
llama_cap_context_completion::~llama_cap_context_completion() {
|
|
119
|
+
if (ctx_sampling != nullptr) {
|
|
120
|
+
common_sampler_free(ctx_sampling);
|
|
121
|
+
ctx_sampling = nullptr;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
void llama_cap_context_completion::rewind() {
|
|
126
|
+
is_interrupted = false;
|
|
127
|
+
parent_ctx->params.antiprompt.clear();
|
|
128
|
+
parent_ctx->params.sampling.grammar.clear();
|
|
129
|
+
num_prompt_tokens = 0;
|
|
130
|
+
num_tokens_predicted = 0;
|
|
131
|
+
prefill_text = "";
|
|
132
|
+
generated_text = "";
|
|
133
|
+
generated_text.reserve(parent_ctx->params.n_ctx);
|
|
134
|
+
truncated = false;
|
|
135
|
+
context_full = false;
|
|
136
|
+
stopped_eos = false;
|
|
137
|
+
stopped_word = false;
|
|
138
|
+
stopped_limit = false;
|
|
139
|
+
stopping_word = "";
|
|
140
|
+
incomplete = false;
|
|
141
|
+
n_remain = 0;
|
|
142
|
+
n_past = 0;
|
|
143
|
+
embd.clear();
|
|
144
|
+
parent_ctx->params.sampling.n_prev = parent_ctx->n_ctx;
|
|
145
|
+
if (parent_ctx->isVocoderEnabled()) {
|
|
146
|
+
parent_ctx->tts_wrapper->audio_tokens.clear();
|
|
147
|
+
parent_ctx->tts_wrapper->next_token_uses_guide_token = true;
|
|
148
|
+
parent_ctx->tts_wrapper->guide_tokens.clear();
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
bool llama_cap_context_completion::initSampling() {
|
|
153
|
+
if (ctx_sampling != nullptr) {
|
|
154
|
+
common_sampler_free(ctx_sampling);
|
|
155
|
+
}
|
|
156
|
+
ctx_sampling = common_sampler_init(parent_ctx->model, parent_ctx->params.sampling);
|
|
157
|
+
return ctx_sampling != nullptr;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
void llama_cap_context_completion::truncatePrompt(std::vector<llama_token> &prompt_tokens) {
|
|
161
|
+
const int n_left = parent_ctx->n_ctx - parent_ctx->params.n_keep;
|
|
162
|
+
const int n_block_size = n_left / 2;
|
|
163
|
+
const int erased_blocks = (prompt_tokens.size() - parent_ctx->params.n_keep - n_block_size) / n_block_size;
|
|
164
|
+
|
|
165
|
+
// Keep n_keep tokens at start of prompt (at most n_ctx - 4)
|
|
166
|
+
std::vector<llama_token> new_tokens(prompt_tokens.begin(), prompt_tokens.begin() + parent_ctx->params.n_keep);
|
|
167
|
+
|
|
168
|
+
new_tokens.insert(new_tokens.end(), prompt_tokens.begin() + parent_ctx->params.n_keep + erased_blocks * n_block_size, prompt_tokens.end());
|
|
169
|
+
|
|
170
|
+
LOG_INFO("input truncated, n_ctx: %d, n_keep: %d, n_left: %d, old_size: %d, new_size: %d",
|
|
171
|
+
parent_ctx->n_ctx,
|
|
172
|
+
parent_ctx->params.n_keep,
|
|
173
|
+
n_left,
|
|
174
|
+
prompt_tokens.size(),
|
|
175
|
+
new_tokens.size()
|
|
176
|
+
);
|
|
177
|
+
|
|
178
|
+
truncated = true;
|
|
179
|
+
prompt_tokens = new_tokens;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
void llama_cap_context_completion::loadPrompt(const std::vector<std::string> &media_paths) {
|
|
183
|
+
bool has_media = !media_paths.empty();
|
|
184
|
+
|
|
185
|
+
if (!has_media) {
|
|
186
|
+
std::vector<llama_token> text_tokens;
|
|
187
|
+
// Text-only path — chat templates from the app already include BOS/start markers.
|
|
188
|
+
bool add_bos = true;
|
|
189
|
+
#ifdef __EMSCRIPTEN__
|
|
190
|
+
const std::string & pr = parent_ctx->params.prompt;
|
|
191
|
+
if (pr.find("<|startoftext|>") != std::string::npos ||
|
|
192
|
+
pr.find("<|im_start|>") != std::string::npos ||
|
|
193
|
+
pr.rfind("<|startoftext|>", 0) == 0) {
|
|
194
|
+
add_bos = false;
|
|
195
|
+
}
|
|
196
|
+
#endif
|
|
197
|
+
text_tokens = ::common_tokenize(parent_ctx->ctx, parent_ctx->params.prompt, add_bos, true);
|
|
198
|
+
num_prompt_tokens = text_tokens.size();
|
|
199
|
+
|
|
200
|
+
// LOG tokens
|
|
201
|
+
std::stringstream ss;
|
|
202
|
+
ss << "\n" << __func__ << ": prompt_tokens = ";
|
|
203
|
+
for (auto& token : text_tokens) {
|
|
204
|
+
ss << token << " ";
|
|
205
|
+
}
|
|
206
|
+
LOG_INFO("%s\n", ss.str().c_str());
|
|
207
|
+
|
|
208
|
+
if (parent_ctx->params.n_keep < 0) {
|
|
209
|
+
parent_ctx->params.n_keep = (int)num_prompt_tokens;
|
|
210
|
+
}
|
|
211
|
+
parent_ctx->params.n_keep = std::min(parent_ctx->n_ctx - 4, parent_ctx->params.n_keep);
|
|
212
|
+
|
|
213
|
+
// Handle truncation if needed
|
|
214
|
+
if (num_prompt_tokens >= (size_t)parent_ctx->n_ctx) {
|
|
215
|
+
if (!parent_ctx->params.ctx_shift) {
|
|
216
|
+
context_full = true;
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
truncatePrompt(text_tokens);
|
|
220
|
+
num_prompt_tokens = text_tokens.size();
|
|
221
|
+
LM_GGML_ASSERT(num_prompt_tokens < (size_t)parent_ctx->n_ctx);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// Update sampling context
|
|
225
|
+
for (auto & token : text_tokens) {
|
|
226
|
+
common_sampler_accept(ctx_sampling, token, false);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// compare the evaluated prompt with the new prompt
|
|
230
|
+
n_past = common_part(embd, text_tokens);
|
|
231
|
+
|
|
232
|
+
embd = text_tokens;
|
|
233
|
+
if (n_past == num_prompt_tokens) {
|
|
234
|
+
// we have to evaluate at least 1 token to generate logits.
|
|
235
|
+
n_past--;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// Manage KV cache
|
|
239
|
+
auto * kv = llama_get_memory(parent_ctx->ctx);
|
|
240
|
+
llama_memory_seq_rm(kv, 0, n_past, -1);
|
|
241
|
+
|
|
242
|
+
LOG_VERBOSE("prompt ingested, n_past: %d, cached: %s, to_eval: %s",
|
|
243
|
+
n_past,
|
|
244
|
+
tokens_to_str(parent_ctx->ctx, embd.cbegin(), embd.cbegin() + n_past).c_str(),
|
|
245
|
+
tokens_to_str(parent_ctx->ctx, embd.cbegin() + n_past, embd.cend()).c_str()
|
|
246
|
+
);
|
|
247
|
+
|
|
248
|
+
// Prefill prompt here so the generate loop only samples new tokens.
|
|
249
|
+
#ifdef __EMSCRIPTEN__
|
|
250
|
+
const auto prefill_t0 = std::chrono::steady_clock::now();
|
|
251
|
+
#endif
|
|
252
|
+
while (n_past < (int) embd.size()) {
|
|
253
|
+
const int n_eval = std::min((int) embd.size() - n_past, parent_ctx->params.n_batch);
|
|
254
|
+
if (llama_decode(parent_ctx->ctx, llama_batch_get_one(embd.data() + n_past, n_eval))) {
|
|
255
|
+
LOG_ERROR("loadPrompt: prefill decode failed at n_past=%d n_eval=%d", n_past, n_eval);
|
|
256
|
+
has_next_token = false;
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
n_past += n_eval;
|
|
260
|
+
}
|
|
261
|
+
#ifdef __EMSCRIPTEN__
|
|
262
|
+
const auto prefill_ms = std::chrono::duration_cast<std::chrono::milliseconds>(
|
|
263
|
+
std::chrono::steady_clock::now() - prefill_t0).count();
|
|
264
|
+
fprintf(stderr, "@@WASM_GEN@@ prefill_done tokens=%zu n_batch=%d ms=%lld\n",
|
|
265
|
+
embd.size(), parent_ctx->params.n_batch, (long long) prefill_ms);
|
|
266
|
+
#endif
|
|
267
|
+
} else {
|
|
268
|
+
// Multimodal path - process all media paths
|
|
269
|
+
processMedia(parent_ctx->params.prompt, media_paths);
|
|
270
|
+
num_prompt_tokens = embd.size();
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
has_next_token = true;
|
|
274
|
+
|
|
275
|
+
LOG_INFO("[DEBUG] Input processed: n_past=%d, embd.size=%zu, num_prompt_tokens=%zu, has_media=%d",
|
|
276
|
+
n_past, embd.size(), num_prompt_tokens, has_media ? 1 : 0);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
void llama_cap_context_completion::beginCompletion() {
|
|
280
|
+
beginCompletion(COMMON_CHAT_FORMAT_CONTENT_ONLY, COMMON_REASONING_FORMAT_NONE, false);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
void llama_cap_context_completion::beginCompletion(int chat_format, common_reasoning_format reasoning_format, bool thinking_forced_open) {
|
|
284
|
+
// number of tokens to keep when resetting context
|
|
285
|
+
n_remain = parent_ctx->params.n_predict;
|
|
286
|
+
llama_perf_context_reset(parent_ctx->ctx);
|
|
287
|
+
is_predicting = true;
|
|
288
|
+
|
|
289
|
+
current_chat_format = chat_format;
|
|
290
|
+
current_reasoning_format = reasoning_format;
|
|
291
|
+
current_thinking_forced_open = thinking_forced_open;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
void llama_cap_context_completion::endCompletion() {
|
|
295
|
+
is_predicting = false;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
completion_token_output llama_cap_context_completion::nextToken()
|
|
299
|
+
{
|
|
300
|
+
completion_token_output result;
|
|
301
|
+
result.tok = -1;
|
|
302
|
+
|
|
303
|
+
if (embd.size() >= (size_t)parent_ctx->params.n_ctx)
|
|
304
|
+
{
|
|
305
|
+
if (!parent_ctx->params.ctx_shift) {
|
|
306
|
+
// If context shifting is disabled, stop generation
|
|
307
|
+
LOG_WARNING("context full, n_ctx: %d, tokens: %d", parent_ctx->params.n_ctx, embd.size());
|
|
308
|
+
has_next_token = false;
|
|
309
|
+
context_full = true;
|
|
310
|
+
return result;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// Shift context
|
|
314
|
+
|
|
315
|
+
const int n_left = n_past - parent_ctx->params.n_keep - 1;
|
|
316
|
+
const int n_discard = n_left/2;
|
|
317
|
+
|
|
318
|
+
auto * kv = llama_get_memory(parent_ctx->ctx);
|
|
319
|
+
llama_memory_seq_rm (kv, 0, parent_ctx->params.n_keep + 1 , parent_ctx->params.n_keep + n_discard + 1);
|
|
320
|
+
llama_memory_seq_add(kv, 0, parent_ctx->params.n_keep + 1 + n_discard, n_past, -n_discard);
|
|
321
|
+
|
|
322
|
+
for (size_t i = parent_ctx->params.n_keep + 1 + n_discard; i < embd.size(); i++)
|
|
323
|
+
{
|
|
324
|
+
embd[i - n_discard] = embd[i];
|
|
325
|
+
}
|
|
326
|
+
embd.resize(embd.size() - n_discard);
|
|
327
|
+
|
|
328
|
+
n_past -= n_discard;
|
|
329
|
+
truncated = true;
|
|
330
|
+
|
|
331
|
+
LOG_VERBOSE("context shifted, new n_past: %d, new size: %d", n_past, embd.size());
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
bool tg = true;
|
|
335
|
+
while (n_past < embd.size())
|
|
336
|
+
{
|
|
337
|
+
int n_eval = (int)embd.size() - n_past;
|
|
338
|
+
tg = n_eval == 1;
|
|
339
|
+
if (n_eval > parent_ctx->params.n_batch)
|
|
340
|
+
{
|
|
341
|
+
n_eval = parent_ctx->params.n_batch;
|
|
342
|
+
}
|
|
343
|
+
if (llama_decode(parent_ctx->ctx, llama_batch_get_one(&embd[n_past], n_eval)))
|
|
344
|
+
{
|
|
345
|
+
LOG_ERROR("failed to eval, n_eval: %d, n_past: %d, n_threads: %d, embd: %s",
|
|
346
|
+
n_eval,
|
|
347
|
+
n_past,
|
|
348
|
+
parent_ctx->params.cpuparams.n_threads,
|
|
349
|
+
tokens_to_str(parent_ctx->ctx, embd.cbegin() + n_past, embd.cend()).c_str()
|
|
350
|
+
);
|
|
351
|
+
has_next_token = false;
|
|
352
|
+
return result;
|
|
353
|
+
}
|
|
354
|
+
n_past += n_eval;
|
|
355
|
+
|
|
356
|
+
if(is_interrupted) {
|
|
357
|
+
LOG_INFO("Decoding Interrupted");
|
|
358
|
+
embd.resize(n_past);
|
|
359
|
+
has_next_token = false;
|
|
360
|
+
return result;
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
const llama_vocab* vocab = llama_model_get_vocab(parent_ctx->model);
|
|
365
|
+
|
|
366
|
+
if (parent_ctx->params.n_predict == 0)
|
|
367
|
+
{
|
|
368
|
+
has_next_token = false;
|
|
369
|
+
result.tok = llama_vocab_eos(vocab);
|
|
370
|
+
return result;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
{
|
|
374
|
+
// out of user input, sample next token
|
|
375
|
+
#ifndef __EMSCRIPTEN__
|
|
376
|
+
std::vector<llama_token_data> candidates;
|
|
377
|
+
candidates.reserve(llama_vocab_n_tokens(vocab));
|
|
378
|
+
#endif
|
|
379
|
+
|
|
380
|
+
const bool allow_eog = num_tokens_predicted > 0;
|
|
381
|
+
llama_token new_token_id = sample_completion_token(
|
|
382
|
+
ctx_sampling, parent_ctx->ctx, vocab, allow_eog);
|
|
383
|
+
|
|
384
|
+
if (llama_vocab_is_eog(vocab, new_token_id)) {
|
|
385
|
+
has_next_token = false;
|
|
386
|
+
stopped_eos = true;
|
|
387
|
+
LOG_VERBOSE("EOS: %s", common_token_to_piece(parent_ctx->ctx, new_token_id).c_str());
|
|
388
|
+
return result;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
if (parent_ctx->tts_wrapper != nullptr && parent_ctx->tts_wrapper->next_token_uses_guide_token && !parent_ctx->tts_wrapper->guide_tokens.empty() && !llama_vocab_is_control(vocab, new_token_id)) {
|
|
392
|
+
new_token_id = parent_ctx->tts_wrapper->guide_tokens[0];
|
|
393
|
+
parent_ctx->tts_wrapper->guide_tokens.erase(parent_ctx->tts_wrapper->guide_tokens.begin());
|
|
394
|
+
}
|
|
395
|
+
if (parent_ctx->tts_wrapper != nullptr) {
|
|
396
|
+
parent_ctx->tts_wrapper->next_token_uses_guide_token = (new_token_id == 198);
|
|
397
|
+
}
|
|
398
|
+
result.tok = new_token_id;
|
|
399
|
+
|
|
400
|
+
llama_token_data_array cur_p = *common_sampler_get_candidates(ctx_sampling);
|
|
401
|
+
|
|
402
|
+
const int32_t n_probs = parent_ctx->params.sampling.n_probs;
|
|
403
|
+
|
|
404
|
+
for (size_t i = 0; i < std::min(cur_p.size, (size_t)n_probs); ++i)
|
|
405
|
+
{
|
|
406
|
+
result.probs.push_back({cur_p.data[i].id, cur_p.data[i].p});
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
common_sampler_accept(ctx_sampling, result.tok, true);
|
|
410
|
+
if (tg) {
|
|
411
|
+
num_tokens_predicted++;
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
// add it to the context
|
|
416
|
+
embd.push_back(result.tok);
|
|
417
|
+
// decrement remaining sampling budget
|
|
418
|
+
--n_remain;
|
|
419
|
+
|
|
420
|
+
has_next_token = parent_ctx->params.n_predict == -1 || n_remain != 0;
|
|
421
|
+
return result;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
size_t llama_cap_context_completion::findStoppingStrings(const std::string &text, const size_t last_token_size,
|
|
425
|
+
const stop_type type)
|
|
426
|
+
{
|
|
427
|
+
size_t stop_pos = std::string::npos;
|
|
428
|
+
for (const std::string &word : parent_ctx->params.antiprompt)
|
|
429
|
+
{
|
|
430
|
+
size_t pos;
|
|
431
|
+
if (type == STOP_FULL)
|
|
432
|
+
{
|
|
433
|
+
const size_t tmp = word.size() + last_token_size;
|
|
434
|
+
const size_t from_pos = text.size() > tmp ? text.size() - tmp : 0;
|
|
435
|
+
pos = text.find(word, from_pos);
|
|
436
|
+
}
|
|
437
|
+
else
|
|
438
|
+
{
|
|
439
|
+
pos = find_partial_stop_string(word, text);
|
|
440
|
+
}
|
|
441
|
+
if (pos != std::string::npos &&
|
|
442
|
+
(stop_pos == std::string::npos || pos < stop_pos))
|
|
443
|
+
{
|
|
444
|
+
if (type == STOP_FULL)
|
|
445
|
+
{
|
|
446
|
+
stopping_word = word;
|
|
447
|
+
stopped_word = true;
|
|
448
|
+
has_next_token = false;
|
|
449
|
+
}
|
|
450
|
+
stop_pos = pos;
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
return stop_pos;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
completion_token_output llama_cap_context_completion::doCompletion()
|
|
457
|
+
{
|
|
458
|
+
completion_token_output token_with_probs = nextToken();
|
|
459
|
+
|
|
460
|
+
const std::string token_text = token_with_probs.tok == -1 ? "" : common_token_to_piece(parent_ctx->ctx, token_with_probs.tok);
|
|
461
|
+
generated_text += token_text;
|
|
462
|
+
|
|
463
|
+
if (parent_ctx->isVocoderEnabled()) {
|
|
464
|
+
tts_type type = parent_ctx->tts_wrapper->getTTSType(parent_ctx);
|
|
465
|
+
if (parent_ctx->tts_wrapper->type == UNKNOWN) {
|
|
466
|
+
parent_ctx->tts_wrapper->type = type;
|
|
467
|
+
}
|
|
468
|
+
if ((type == OUTETTS_V0_2 || type == OUTETTS_V0_3) && (token_with_probs.tok >= 151672 && token_with_probs.tok <= 155772)) {
|
|
469
|
+
parent_ctx->tts_wrapper->audio_tokens.push_back(token_with_probs.tok);
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
if (parent_ctx->params.sampling.n_probs > 0)
|
|
474
|
+
{
|
|
475
|
+
generated_token_probs.push_back(token_with_probs);
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
if (!parent_ctx->params.antiprompt.empty() && token_with_probs.tok >= 0) {
|
|
479
|
+
const size_t stop_pos = findStoppingStrings(generated_text, token_text.size(), STOP_FULL);
|
|
480
|
+
if (stop_pos != std::string::npos) {
|
|
481
|
+
generated_text = generated_text.substr(0, stop_pos);
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
// check if there is incomplete UTF-8 character at the end
|
|
486
|
+
for (unsigned i = 1; i < 5 && i <= generated_text.size(); ++i) {
|
|
487
|
+
unsigned char c = generated_text[generated_text.size() - i];
|
|
488
|
+
if ((c & 0xC0) == 0x80) {
|
|
489
|
+
// continuation byte: 10xxxxxx
|
|
490
|
+
continue;
|
|
491
|
+
}
|
|
492
|
+
if ((c & 0xE0) == 0xC0) {
|
|
493
|
+
// 2-byte character: 110xxxxx ...
|
|
494
|
+
incomplete = i < 2;
|
|
495
|
+
} else if ((c & 0xF0) == 0xE0) {
|
|
496
|
+
// 3-byte character: 1110xxxx ...
|
|
497
|
+
incomplete = i < 3;
|
|
498
|
+
} else if ((c & 0xF8) == 0xF0) {
|
|
499
|
+
// 4-byte character: 11110xxx ...
|
|
500
|
+
incomplete = i < 4;
|
|
501
|
+
}
|
|
502
|
+
// else 1-byte character or invalid byte
|
|
503
|
+
break;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
if (incomplete && !has_next_token)
|
|
507
|
+
{
|
|
508
|
+
has_next_token = true;
|
|
509
|
+
n_remain++;
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
if (!has_next_token && n_remain == 0)
|
|
513
|
+
{
|
|
514
|
+
stopped_limit = true;
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
LOG_VERBOSE("next token, token: %s, token_text: %s, has_next_token: %d, n_remain: %d, num_tokens_predicted: %d, stopped_eos: %d, stopped_word: %d, stopped_limit: %d, stopping_word: %s",
|
|
518
|
+
common_token_to_piece(parent_ctx->ctx, token_with_probs.tok),
|
|
519
|
+
tokens_to_output_formatted_string(parent_ctx->ctx, token_with_probs.tok).c_str(),
|
|
520
|
+
has_next_token,
|
|
521
|
+
n_remain,
|
|
522
|
+
num_tokens_predicted,
|
|
523
|
+
stopped_eos,
|
|
524
|
+
stopped_word,
|
|
525
|
+
stopped_limit,
|
|
526
|
+
stopping_word.c_str()
|
|
527
|
+
);
|
|
528
|
+
return token_with_probs;
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
completion_partial_output llama_cap_context_completion::getPartialOutput(const std::string &token_text) {
|
|
532
|
+
common_chat_syntax syntax;
|
|
533
|
+
syntax.format = static_cast<common_chat_format>(current_chat_format);
|
|
534
|
+
syntax.reasoning_format = current_reasoning_format;
|
|
535
|
+
syntax.thinking_forced_open = current_thinking_forced_open;
|
|
536
|
+
syntax.parse_tool_calls = true;
|
|
537
|
+
|
|
538
|
+
common_chat_msg parsed_msg = common_chat_parse(prefill_text + generated_text, true, syntax);
|
|
539
|
+
|
|
540
|
+
completion_partial_output result;
|
|
541
|
+
|
|
542
|
+
result.content = parsed_msg.content;
|
|
543
|
+
result.reasoning_content = parsed_msg.reasoning_content;
|
|
544
|
+
result.accumulated_text = prefill_text + generated_text;
|
|
545
|
+
result.tool_calls = parsed_msg.tool_calls;
|
|
546
|
+
|
|
547
|
+
return result;
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
std::vector<float> llama_cap_context_completion::getEmbedding(common_params &embd_params)
|
|
551
|
+
{
|
|
552
|
+
static const int n_embd = llama_model_n_embd(llama_get_model(parent_ctx->ctx));
|
|
553
|
+
if (!embd_params.embedding)
|
|
554
|
+
{
|
|
555
|
+
LOG_WARNING("embedding disabled, embedding: %s", embd_params.embedding);
|
|
556
|
+
return std::vector<float>(n_embd, 0.0f);
|
|
557
|
+
}
|
|
558
|
+
float *data;
|
|
559
|
+
|
|
560
|
+
const enum llama_pooling_type pooling_type = llama_pooling_type(parent_ctx->ctx);
|
|
561
|
+
printf("pooling_type: %d\n", pooling_type);
|
|
562
|
+
if (pooling_type == LLAMA_POOLING_TYPE_NONE) {
|
|
563
|
+
data = llama_get_embeddings(parent_ctx->ctx);
|
|
564
|
+
} else {
|
|
565
|
+
data = llama_get_embeddings_seq(parent_ctx->ctx, 0);
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
if (!data) {
|
|
569
|
+
return std::vector<float>(n_embd, 0.0f);
|
|
570
|
+
}
|
|
571
|
+
std::vector<float> embedding(data, data + n_embd), out(data, data + n_embd);
|
|
572
|
+
common_embd_normalize(embedding.data(), out.data(), n_embd, embd_params.embd_normalize);
|
|
573
|
+
return out;
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
std::vector<float> llama_cap_context_completion::rerank(const std::string &query, const std::vector<std::string> &documents)
|
|
577
|
+
{
|
|
578
|
+
std::vector<float> scores;
|
|
579
|
+
|
|
580
|
+
// Check if this model supports reranking (requires rank pooling type)
|
|
581
|
+
const enum llama_pooling_type pooling_type = llama_pooling_type(parent_ctx->ctx);
|
|
582
|
+
if (pooling_type != LLAMA_POOLING_TYPE_RANK) {
|
|
583
|
+
throw std::runtime_error("reranking not supported, pooling_type: " + std::to_string(pooling_type));
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
if (!parent_ctx->params.embedding) {
|
|
587
|
+
throw std::runtime_error("embedding disabled but required for reranking");
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
const llama_vocab * vocab = llama_model_get_vocab(parent_ctx->model);
|
|
591
|
+
std::vector<llama_token> query_tokens = common_tokenize(vocab, query, false, true);
|
|
592
|
+
|
|
593
|
+
scores.reserve(documents.size());
|
|
594
|
+
|
|
595
|
+
for (size_t i = 0; i < documents.size(); ++i) {
|
|
596
|
+
rewind();
|
|
597
|
+
embd = {};
|
|
598
|
+
|
|
599
|
+
const std::string & document = documents[i];
|
|
600
|
+
|
|
601
|
+
std::vector<llama_token> doc_tokens = common_tokenize(vocab, document, false, true);
|
|
602
|
+
|
|
603
|
+
std::vector<llama_token> rerank_tokens = format_rerank(vocab, query_tokens, doc_tokens);
|
|
604
|
+
|
|
605
|
+
llama_memory_clear(llama_get_memory(parent_ctx->ctx), false);
|
|
606
|
+
|
|
607
|
+
// Process the rerank input
|
|
608
|
+
try {
|
|
609
|
+
parent_ctx->params.prompt = tokens_to_str(parent_ctx->ctx, rerank_tokens.begin(), rerank_tokens.end());
|
|
610
|
+
initSampling();
|
|
611
|
+
loadPrompt({}); // No media paths for rerank
|
|
612
|
+
beginCompletion();
|
|
613
|
+
doCompletion();
|
|
614
|
+
|
|
615
|
+
// Get the rerank score (single embedding value for rank pooling)
|
|
616
|
+
float *data = llama_get_embeddings_seq(parent_ctx->ctx, 0);
|
|
617
|
+
if (data) {
|
|
618
|
+
scores.push_back(data[0]); // For rank pooling, the score is the first (and only) dimension
|
|
619
|
+
} else {
|
|
620
|
+
scores.push_back(-1e6f); // Default low score if computation failed
|
|
621
|
+
}
|
|
622
|
+
} catch (const std::exception &e) {
|
|
623
|
+
LOG_WARNING("rerank computation failed for document %zu: %s", i, e.what());
|
|
624
|
+
scores.push_back(-1e6f);
|
|
625
|
+
}
|
|
626
|
+
endCompletion();
|
|
627
|
+
|
|
628
|
+
// Clear KV cache again to prepare for next document or restore original state
|
|
629
|
+
llama_memory_clear(llama_get_memory(parent_ctx->ctx), false);
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
return scores;
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
std::string llama_cap_context_completion::bench(int pp, int tg, int pl, int nr)
|
|
636
|
+
{
|
|
637
|
+
if (is_predicting) {
|
|
638
|
+
LOG_ERROR("cannot benchmark while predicting", "");
|
|
639
|
+
return std::string("[]");
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
is_predicting = true;
|
|
643
|
+
|
|
644
|
+
double pp_avg = 0;
|
|
645
|
+
double tg_avg = 0;
|
|
646
|
+
|
|
647
|
+
double pp_std = 0;
|
|
648
|
+
double tg_std = 0;
|
|
649
|
+
|
|
650
|
+
// TODO: move batch into llama_cap_context (related https://github.com/mybigday/llama.rn/issues/30)
|
|
651
|
+
llama_batch batch = llama_batch_init(
|
|
652
|
+
std::min(pp, parent_ctx->params.n_ubatch), // max n_tokens is limited by n_ubatch
|
|
653
|
+
0, // No embeddings
|
|
654
|
+
1 // Single sequence
|
|
655
|
+
);
|
|
656
|
+
|
|
657
|
+
for (int i = 0; i < nr; i++)
|
|
658
|
+
{
|
|
659
|
+
llama_batch_clear(&batch);
|
|
660
|
+
|
|
661
|
+
const int n_tokens = pp;
|
|
662
|
+
|
|
663
|
+
for (int i = 0; i < n_tokens; i++)
|
|
664
|
+
{
|
|
665
|
+
llama_batch_add(&batch, 0, i, {0}, false);
|
|
666
|
+
}
|
|
667
|
+
batch.logits[batch.n_tokens - 1] = 1; // true
|
|
668
|
+
|
|
669
|
+
llama_memory_clear(llama_get_memory(parent_ctx->ctx), true);
|
|
670
|
+
|
|
671
|
+
const int64_t t_pp_start = llama_time_us();
|
|
672
|
+
if (llama_decode(parent_ctx->ctx, batch) != 0)
|
|
673
|
+
{
|
|
674
|
+
LOG_ERROR("llama_decode() failed during prompt", "");
|
|
675
|
+
}
|
|
676
|
+
const int64_t t_pp_end = llama_time_us();
|
|
677
|
+
|
|
678
|
+
llama_memory_clear(llama_get_memory(parent_ctx->ctx), true);
|
|
679
|
+
|
|
680
|
+
if (is_interrupted) break;
|
|
681
|
+
|
|
682
|
+
const int64_t t_tg_start = llama_time_us();
|
|
683
|
+
|
|
684
|
+
for (int i = 0; i < tg; i++)
|
|
685
|
+
{
|
|
686
|
+
llama_batch_clear(&batch);
|
|
687
|
+
|
|
688
|
+
for (int j = 0; j < pl; j++)
|
|
689
|
+
{
|
|
690
|
+
llama_batch_add(&batch, 0, i, {j}, true);
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
if (llama_decode(parent_ctx->ctx, batch) != 0)
|
|
694
|
+
{
|
|
695
|
+
LOG_ERROR("llama_decode() failed during text generation", "");
|
|
696
|
+
}
|
|
697
|
+
if (is_interrupted) break;
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
const int64_t t_tg_end = llama_time_us();
|
|
701
|
+
|
|
702
|
+
llama_memory_clear(llama_get_memory(parent_ctx->ctx), true);
|
|
703
|
+
|
|
704
|
+
const double t_pp = (t_pp_end - t_pp_start) / 1000000.0;
|
|
705
|
+
const double t_tg = (t_tg_end - t_tg_start) / 1000000.0;
|
|
706
|
+
|
|
707
|
+
const double speed_pp = pp / t_pp;
|
|
708
|
+
const double speed_tg = (pl * tg) / t_tg;
|
|
709
|
+
|
|
710
|
+
pp_avg += speed_pp;
|
|
711
|
+
tg_avg += speed_tg;
|
|
712
|
+
|
|
713
|
+
pp_std += speed_pp * speed_pp;
|
|
714
|
+
tg_std += speed_tg * speed_tg;
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
pp_avg /= nr;
|
|
718
|
+
tg_avg /= nr;
|
|
719
|
+
|
|
720
|
+
if (nr > 1) {
|
|
721
|
+
pp_std = sqrt(pp_std / (nr - 1) - pp_avg * pp_avg * nr / (nr - 1));
|
|
722
|
+
tg_std = sqrt(tg_std / (nr - 1) - tg_avg * tg_avg * nr / (nr - 1));
|
|
723
|
+
} else {
|
|
724
|
+
pp_std = 0;
|
|
725
|
+
tg_std = 0;
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
if (is_interrupted) llama_memory_clear(llama_get_memory(parent_ctx->ctx), true);
|
|
729
|
+
endCompletion();
|
|
730
|
+
|
|
731
|
+
char model_desc[128];
|
|
732
|
+
llama_model_desc(parent_ctx->model, model_desc, sizeof(model_desc));
|
|
733
|
+
return std::string("[\"") + model_desc + std::string("\",") +
|
|
734
|
+
std::to_string(llama_model_size(parent_ctx->model)) + std::string(",") +
|
|
735
|
+
std::to_string(llama_model_n_params(parent_ctx->model)) + std::string(",") +
|
|
736
|
+
std::to_string(pp_avg) + std::string(",") +
|
|
737
|
+
std::to_string(pp_std) + std::string(",") +
|
|
738
|
+
std::to_string(tg_avg) + std::string(",") +
|
|
739
|
+
std::to_string(tg_std) +
|
|
740
|
+
std::string("]");
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
void llama_cap_context_completion::processMedia(
|
|
744
|
+
const std::string &prompt,
|
|
745
|
+
const std::vector<std::string> &media_paths
|
|
746
|
+
) {
|
|
747
|
+
if (!parent_ctx->isMultimodalEnabled()) {
|
|
748
|
+
throw std::runtime_error("Multimodal is not enabled but image paths are provided");
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
// Delegate to the mtmd_wrapper method
|
|
752
|
+
parent_ctx->mtmd_wrapper->processMedia(
|
|
753
|
+
parent_ctx->ctx,
|
|
754
|
+
prompt,
|
|
755
|
+
media_paths,
|
|
756
|
+
parent_ctx->n_ctx,
|
|
757
|
+
parent_ctx->params.n_batch,
|
|
758
|
+
n_past,
|
|
759
|
+
embd,
|
|
760
|
+
context_full,
|
|
761
|
+
ctx_sampling
|
|
762
|
+
);
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
// Speculative decoding implementation
|
|
766
|
+
completion_token_output llama_cap_context_completion::nextTokenSpeculative() {
|
|
767
|
+
// Enable speculative mode
|
|
768
|
+
use_speculative = parent_ctx->isSpectulativeEnabled();
|
|
769
|
+
|
|
770
|
+
if (!use_speculative) {
|
|
771
|
+
// Fallback to regular token generation
|
|
772
|
+
return nextToken();
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
completion_token_output result;
|
|
776
|
+
|
|
777
|
+
// If we don't have drafted tokens, draft some
|
|
778
|
+
if (draft_tokens.empty()) {
|
|
779
|
+
draft_tokens = draftTokens(parent_ctx->speculative_samples);
|
|
780
|
+
n_drafted = draft_tokens.size();
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
// Try to verify and accept draft tokens
|
|
784
|
+
if (!draft_tokens.empty()) {
|
|
785
|
+
int accepted = verifyAndAcceptTokens(draft_tokens);
|
|
786
|
+
n_accepted += accepted;
|
|
787
|
+
|
|
788
|
+
if (accepted > 0) {
|
|
789
|
+
// Use the first accepted token
|
|
790
|
+
result.tok = draft_tokens[0];
|
|
791
|
+
draft_tokens.erase(draft_tokens.begin());
|
|
792
|
+
|
|
793
|
+
// Update context
|
|
794
|
+
embd.push_back(result.tok);
|
|
795
|
+
--n_remain;
|
|
796
|
+
num_tokens_predicted++;
|
|
797
|
+
|
|
798
|
+
has_next_token = parent_ctx->params.n_predict == -1 || n_remain != 0;
|
|
799
|
+
return result;
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
// If no tokens were accepted, fall back to regular sampling
|
|
804
|
+
draft_tokens.clear();
|
|
805
|
+
return nextToken();
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
std::vector<llama_token> llama_cap_context_completion::draftTokens(int n_draft) {
|
|
809
|
+
std::vector<llama_token> drafted;
|
|
810
|
+
|
|
811
|
+
// Check if draft model is available
|
|
812
|
+
if (!parent_ctx->draft_ctx || !parent_ctx->draft_model || !parent_ctx->isSpectulativeEnabled()) {
|
|
813
|
+
return drafted; // Return empty vector - will fallback to regular decoding
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
// Copy current context to draft model
|
|
817
|
+
// Note: KV cache copying may not be available in all llama.cpp versions
|
|
818
|
+
// For now, we'll skip this optimization and let the draft model generate from scratch
|
|
819
|
+
// This is still effective for speculative decoding
|
|
820
|
+
|
|
821
|
+
// Generate draft tokens using the smaller model
|
|
822
|
+
for (int i = 0; i < n_draft; i++) {
|
|
823
|
+
// Create batch with current context
|
|
824
|
+
llama_batch batch = llama_batch_init(1, 0, 1);
|
|
825
|
+
|
|
826
|
+
if (!embd.empty()) {
|
|
827
|
+
llama_batch_add(&batch, embd.back(), n_past + i, {0}, true);
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
// Decode with draft model
|
|
831
|
+
if (llama_decode(parent_ctx->draft_ctx, batch) != 0) {
|
|
832
|
+
llama_batch_free(batch);
|
|
833
|
+
break;
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
// Sample from draft model (using faster, simpler sampling)
|
|
837
|
+
const float temp = 0.8f; // Fixed temperature for draft
|
|
838
|
+
auto logits = llama_get_logits_ith(parent_ctx->draft_ctx, -1);
|
|
839
|
+
const int n_vocab = llama_vocab_n_tokens(llama_model_get_vocab(parent_ctx->draft_model));
|
|
840
|
+
|
|
841
|
+
// Simple sampling for draft model
|
|
842
|
+
std::vector<llama_token_data> candidates;
|
|
843
|
+
candidates.reserve(n_vocab);
|
|
844
|
+
|
|
845
|
+
for (int token_id = 0; token_id < n_vocab; token_id++) {
|
|
846
|
+
candidates.emplace_back(llama_token_data{token_id, logits[token_id], 0.0f});
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
llama_token_data_array candidates_p = {
|
|
850
|
+
candidates.data(),
|
|
851
|
+
candidates.size(),
|
|
852
|
+
-1,
|
|
853
|
+
false,
|
|
854
|
+
};
|
|
855
|
+
|
|
856
|
+
// Simple temperature sampling for draft model
|
|
857
|
+
for (int token_id = 0; token_id < n_vocab; token_id++) {
|
|
858
|
+
candidates[token_id].logit /= temp; // Apply temperature
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
// Sort by logit (simple greedy sampling for draft)
|
|
862
|
+
std::sort(candidates.begin(), candidates.end(),
|
|
863
|
+
[](const llama_token_data& a, const llama_token_data& b) {
|
|
864
|
+
return a.logit > b.logit;
|
|
865
|
+
});
|
|
866
|
+
|
|
867
|
+
llama_token token = candidates[0].id; // Take top token
|
|
868
|
+
drafted.push_back(token);
|
|
869
|
+
|
|
870
|
+
// Clean up
|
|
871
|
+
llama_batch_free(batch);
|
|
872
|
+
|
|
873
|
+
// Stop if we hit EOS
|
|
874
|
+
const llama_vocab * vocab = llama_model_get_vocab(parent_ctx->draft_model);
|
|
875
|
+
if (llama_vocab_is_eog(vocab, token)) {
|
|
876
|
+
break;
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
return drafted;
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
int llama_cap_context_completion::verifyAndAcceptTokens(const std::vector<llama_token> &draft_tokens) {
|
|
884
|
+
if (draft_tokens.empty() || !parent_ctx->ctx) {
|
|
885
|
+
return 0;
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
int accepted = 0;
|
|
889
|
+
|
|
890
|
+
// Verify each draft token against the main model
|
|
891
|
+
for (size_t i = 0; i < draft_tokens.size(); i++) {
|
|
892
|
+
// Create batch for verification
|
|
893
|
+
llama_batch batch = llama_batch_init(1, 0, 1);
|
|
894
|
+
|
|
895
|
+
if (!embd.empty()) {
|
|
896
|
+
llama_batch_add(&batch, embd.back(), n_past + accepted, {0}, true);
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
// Decode with main model
|
|
900
|
+
if (llama_decode(parent_ctx->ctx, batch) != 0) {
|
|
901
|
+
llama_batch_free(batch);
|
|
902
|
+
break;
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
// Get logits from main model
|
|
906
|
+
auto logits = llama_get_logits_ith(parent_ctx->ctx, -1);
|
|
907
|
+
const int n_vocab = llama_vocab_n_tokens(llama_model_get_vocab(parent_ctx->model));
|
|
908
|
+
|
|
909
|
+
// Sample from main model
|
|
910
|
+
std::vector<llama_token_data> candidates;
|
|
911
|
+
candidates.reserve(n_vocab);
|
|
912
|
+
|
|
913
|
+
for (int token_id = 0; token_id < n_vocab; token_id++) {
|
|
914
|
+
candidates.emplace_back(llama_token_data{token_id, logits[token_id], 0.0f});
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
llama_token_data_array candidates_p = {
|
|
918
|
+
candidates.data(),
|
|
919
|
+
candidates.size(),
|
|
920
|
+
-1,
|
|
921
|
+
false,
|
|
922
|
+
};
|
|
923
|
+
|
|
924
|
+
// Apply sampling from main model using common_sampler
|
|
925
|
+
llama_token main_token = common_sampler_sample(ctx_sampling, parent_ctx->ctx, -1);
|
|
926
|
+
|
|
927
|
+
// Accept if tokens match
|
|
928
|
+
if (main_token == draft_tokens[i]) {
|
|
929
|
+
accepted++;
|
|
930
|
+
common_sampler_accept(ctx_sampling, main_token, true);
|
|
931
|
+
} else {
|
|
932
|
+
// Reject and stop verification
|
|
933
|
+
break;
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
llama_batch_free(batch);
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
return accepted;
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
} // namespace capllama
|