1 module llama.vocab;
2 
3 import llama.llama;
4 
5 // Drop const for C APIs that don't take const vocab pointer.
6 private llama_vocab* mutableVocab(const(llama_vocab)* vocab) @trusted @nogc nothrow
7 {
8     return cast(llama_vocab*) vocab;
9 }
10 
11 /// Split `text` into tokens. Returns a GC-allocated slice.
12 llama_token[] tokenize(const(llama_vocab)* vocab, const(char)[] text,
13                        bool addSpecial = true, bool parseSpecial = true) @trusted
14 {
15     if (text.length == 0) return null;
16     auto v = mutableVocab(vocab);
17     int n = -llama_tokenize(v, text.ptr, cast(int) text.length, null, 0, addSpecial, parseSpecial);
18     if (n <= 0) return null;
19     auto tokens = new llama_token[](n);
20     int result = llama_tokenize(v, text.ptr, cast(int) text.length,
21                                 tokens.ptr, cast(int) tokens.length, addSpecial, parseSpecial);
22     return result < 0 ? null : tokens[0 .. result];
23 }
24 
25 /// The string piece for a single token.
26 string tokenToString(const(llama_vocab)* vocab, llama_token token) @trusted
27 {
28     char[256] buf;
29     int n = llama_token_to_piece(mutableVocab(vocab), token, buf.ptr, cast(int) buf.length, 0, true);
30     return n < 0 ? null : buf[0 .. n].idup;
31 }
32 
33 /// Decode a token sequence back into text.
34 string detokenize(const(llama_vocab)* vocab, const(llama_token)[] tokens,
35                   bool removeSpecial = false, bool unparseSpecial = false) @trusted
36 {
37     if (tokens.length == 0) return "";
38     auto v = mutableVocab(vocab);
39     int bufSize = cast(int)(tokens.length * 8 + 64);
40     char[] buf = new char[](bufSize);
41     int n = llama_detokenize(v, tokens.ptr, cast(int) tokens.length,
42                              buf.ptr, cast(int) buf.length, removeSpecial, unparseSpecial);
43     if (n < 0)
44     {
45         buf = new char[](-n + 1);
46         n = llama_detokenize(v, tokens.ptr, cast(int) tokens.length,
47                              buf.ptr, cast(int) buf.length, removeSpecial, unparseSpecial);
48         if (n < 0) return "";
49     }
50     return buf[0 .. n].idup;
51 }
52 
53 llama_token bosToken(const(llama_vocab)* vocab) @trusted @nogc nothrow { return llama_vocab_bos(mutableVocab(vocab)); } /// BOS token.
54 llama_token eosToken(const(llama_vocab)* vocab) @trusted @nogc nothrow { return llama_vocab_eos(mutableVocab(vocab)); } /// EOS token.
55 llama_token eotToken(const(llama_vocab)* vocab) @trusted @nogc nothrow { return llama_vocab_eot(mutableVocab(vocab)); } /// EOT (end-of-turn) token.
56 llama_token nlToken (const(llama_vocab)* vocab) @trusted @nogc nothrow { return llama_vocab_nl (mutableVocab(vocab)); } /// Newline token.
57 llama_token padToken(const(llama_vocab)* vocab) @trusted @nogc nothrow { return llama_vocab_pad(mutableVocab(vocab)); } /// Padding token.
58 llama_token sepToken(const(llama_vocab)* vocab) @trusted @nogc nothrow { return llama_vocab_sep(mutableVocab(vocab)); } /// Sentence separator token.
59 
60 // Fill-in-the-Middle special tokens.
61 llama_token fimPreToken(const(llama_vocab)* vocab) @trusted @nogc nothrow { return llama_vocab_fim_pre(mutableVocab(vocab)); } /// FIM prefix token.
62 llama_token fimSufToken(const(llama_vocab)* vocab) @trusted @nogc nothrow { return llama_vocab_fim_suf(mutableVocab(vocab)); } /// FIM suffix token.
63 llama_token fimMidToken(const(llama_vocab)* vocab) @trusted @nogc nothrow { return llama_vocab_fim_mid(mutableVocab(vocab)); } /// FIM middle token.
64 llama_token fimPadToken(const(llama_vocab)* vocab) @trusted @nogc nothrow { return llama_vocab_fim_pad(mutableVocab(vocab)); } /// FIM padding token.
65 llama_token fimRepToken(const(llama_vocab)* vocab) @trusted @nogc nothrow { return llama_vocab_fim_rep(mutableVocab(vocab)); } /// FIM repo token.
66 llama_token fimSepToken(const(llama_vocab)* vocab) @trusted @nogc nothrow { return llama_vocab_fim_sep(mutableVocab(vocab)); } /// FIM separator token.
67 
68 /// Vocabulary type as int (compare to `LLAMA_VOCAB_TYPE_*` constants).
69 int vocabType(const(llama_vocab)* vocab) @trusted @nogc nothrow
70 {
71     return cast(int) llama_vocab_type(mutableVocab(vocab));
72 }
73 
74 /// Raw text piece for a token (pointer into model memory; do not free).
75 const(char)* tokenText(const(llama_vocab)* vocab, llama_token token) @trusted @nogc nothrow
76 {
77     return llama_vocab_get_text(mutableVocab(vocab), token);
78 }
79 
80 /// Log-probability score stored for a token in the vocab.
81 float tokenScore(const(llama_vocab)* vocab, llama_token token) @trusted @nogc nothrow
82 {
83     return llama_vocab_get_score(mutableVocab(vocab), token);
84 }
85 
86 /// Token attribute flags (control, normal, byte, etc.).
87 llama_token_attr tokenAttr(const(llama_vocab)* vocab, llama_token token) @trusted @nogc nothrow
88 {
89     return llama_vocab_get_attr(mutableVocab(vocab), token);
90 }
91 
92 /// True if the token is a control token (not renderable text).
93 bool isControl(const(llama_vocab)* vocab, llama_token token) @trusted @nogc nothrow
94 {
95     return llama_vocab_is_control(mutableVocab(vocab), token);
96 }
97 
98 /// True if the token signals end of generation.
99 bool isEog(const(llama_vocab)* vocab, llama_token token) @trusted @nogc nothrow
100 {
101     return llama_vocab_is_eog(mutableVocab(vocab), token);
102 }