package chatoyant
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>
OCaml-first LLM SDK with Melange-generated JavaScript
Install
dune-project
Dependency
Authors
Maintainers
Sources
chatoyant-v0.13.0.tbz
sha256=1f84c5229b2d58ec6264dd651a58f2686130afa6e91989f110aa7aaf10bba0f5
sha512=49142e122dbb44b03f7f27b52839492800332207d0efeacc7451173827c899a9b965b671a3d9028cc05250aaebbc6789d3815a6cf356f4319bc0c1b0454c68dd
doc/src/chatoyant.tokens/chunking.ml.html
Source file chunking.ml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166type options = { max_tokens : int; overlap : int; separator : string option } let trim = String.trim let split_on_substring ~separator text = if separator = "" then [ text ] else let separator_len = String.length separator in let text_len = String.length text in let rec find_from index = if index + separator_len > text_len then None else if String.sub text index separator_len = separator then Some index else find_from (index + 1) in let rec loop start acc = match find_from start with | None -> List.rev (String.sub text start (text_len - start) :: acc) | Some index -> let part = String.sub text start (index - start) in loop (index + separator_len) (part :: acc) in loop 0 [] let words text = text |> String.split_on_char ' ' |> List.map trim |> List.filter (( <> ) "") let default_segments text = text |> String.split_on_char '\n' |> List.concat_map words let segments ?separator text = match separator with | Some separator -> split_on_substring ~separator text |> List.map trim |> List.filter (( <> ) "") | None -> default_segments text let overlap_text text overlap_tokens = if overlap_tokens <= 0 then "" else let words = words text in let rec loop tokens acc = function | [] -> String.concat " " acc | word :: rest -> if tokens >= overlap_tokens then String.concat " " acc else let word_tokens = Token_estimate.estimate word in loop (tokens + word_tokens) (word :: acc) rest in loop 0 [] (List.rev words) let split_large_segment ~max_tokens ~overlap segment = let rec loop current current_tokens chunks = function | [] -> if trim current = "" then List.rev chunks else List.rev (trim current :: chunks) | word :: rest -> let token_count = Token_estimate.estimate (word ^ " ") in if current <> "" && current_tokens + token_count > max_tokens then let overlap = overlap_text current overlap in let next = if overlap = "" then word else overlap ^ " " ^ word in loop next (Token_estimate.estimate next) (trim current :: chunks) rest else let next = if current = "" then word else current ^ " " ^ word in loop next (current_tokens + token_count) chunks rest in loop "" 0 [] (words segment) let split_text ?(overlap = 0) ?separator ~max_tokens text = if text = "" then [] else if max_tokens <= 0 then [ text ] else if Token_estimate.estimate text <= max_tokens then [ text ] else let rec loop current current_tokens chunks = function | [] -> if trim current = "" then List.rev chunks else List.rev (trim current :: chunks) | segment :: rest -> let segment_tokens = Token_estimate.estimate segment in if segment_tokens > max_tokens then let flushed = if trim current = "" then chunks else trim current :: chunks in let large_chunks = split_large_segment ~max_tokens ~overlap segment in loop "" 0 (List.rev_append large_chunks flushed) rest else let added_tokens = current_tokens + segment_tokens + if current = "" then 0 else 1 in if current <> "" && added_tokens > max_tokens then let overlap_text = overlap_text current overlap in let next = if overlap_text = "" then segment else overlap_text ^ " " ^ segment in loop next (Token_estimate.estimate next) (trim current :: chunks) rest else let next = if current = "" then segment else current ^ " " ^ segment in loop next added_tokens chunks rest in loop "" 0 [] (segments ?separator text) let truncate_content ?(ellipsis = "...") ~max_tokens content = if content = "" then content else let tokens = Token_estimate.estimate content in if tokens <= max_tokens then content else let target_chars = int_of_float (floor (Float.of_int (String.length content) *. (Float.of_int (max 0 max_tokens) /. Float.of_int (max 1 tokens)) )) - String.length ellipsis in if target_chars <= 0 then ellipsis else let truncated = String.sub content 0 (min target_chars (String.length content)) in let last_space = try Some (String.rindex truncated ' ') with Not_found -> None in let truncated = match last_space with | Some index when Float.of_int index > Float.of_int target_chars *. 0.8 -> String.sub truncated 0 index | _ -> truncated in trim truncated ^ ellipsis let fit_messages ?(provider = Message_budget.Openai) ~max_tokens ?(reserve_for_response = 0) messages = Message_budget.fit ~provider ~max_tokens ~reserve_for_response messages let paginate_messages ?(provider = Message_budget.Openai) ~tokens_per_page messages = let rec loop current current_tokens pages = function | [] -> if current = [] then List.rev pages else List.rev (List.rev current :: pages) | message :: rest -> let message_tokens = Message_budget.estimate_message ~provider message in if current <> [] && current_tokens + message_tokens > tokens_per_page then loop [ message ] message_tokens (List.rev current :: pages) rest else loop (message :: current) (current_tokens + message_tokens) pages rest in loop [] 0 [] messages let estimate_chunk_count ~chunk_size text = if text = "" || chunk_size <= 0 then 0 else int_of_float (ceil (Float.of_int (Token_estimate.estimate text) /. Float.of_int chunk_size))
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>