this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Sync with monorepo

+85 -47
+2 -4
doc/add_example.mld
··· 1 1 {0 Tensor Addition} 2 2 3 - @x-ocaml.universe ./universe 4 - @x-ocaml.worker ./universe/worker.js 5 3 6 4 This notebook demonstrates basic ONNX Runtime inference in OCaml: 7 5 creating tensors, loading a model, and running addition. ··· 10 8 11 9 Load [onnxrt], [Note] (FRP), and the widget library: 12 10 13 - {@ocaml[ 11 + {@ocaml x[ 14 12 #require "onnxrt";; 15 13 #require "note";; 16 14 #require "js_top_worker-widget";; ··· 18 16 19 17 Load the ONNX Runtime JavaScript library into the worker: 20 18 21 - {@ocaml[ 19 + {@ocaml x[ 22 20 let () = 23 21 Js_of_ocaml.Js.Unsafe.meth_call 24 22 Js_of_ocaml.Js.Unsafe.global "importScripts"
+83 -43
doc/sentiment_example.mld
··· 1 1 {0 Sentiment Analysis} 2 2 3 - @x-ocaml.universe ./universe 4 - @x-ocaml.worker ./universe/worker.js 5 3 6 4 This notebook runs a DistilBERT sentiment analysis model entirely in 7 5 the browser using ONNX Runtime. It includes a vocabulary loader, ··· 11 9 12 10 Load [onnxrt], [Note] (FRP), and the widget library: 13 11 14 - {@ocaml[ 12 + {@ocaml x[ 15 13 #require "onnxrt";; 16 14 #require "note";; 17 15 #require "js_top_worker-widget";; 18 16 ]} 19 17 20 - {@ocaml[ 18 + {@ocaml x[ 21 19 let () = 22 20 Js_of_ocaml.Js.Unsafe.meth_call 23 21 Js_of_ocaml.Js.Unsafe.global "importScripts" ··· 191 189 Create int64 tensors (required by DistilBERT) and compute softmax 192 190 over logits: 193 191 194 - {@ocaml[ 192 + {@ocaml x[ 195 193 open Onnxrt 196 194 197 195 let make_int64_tensor (data : int array) (dims : int array) : Tensor.t = ··· 253 251 the quantized DistilBERT model. A status widget updates as loading 254 252 progresses: 255 253 256 - {@ocaml[ 254 + {@ocaml x[ 257 255 let max_length = 128 258 256 259 257 let vocab = ref None ··· 268 266 Style ("padding", "0.75em 1em"); 269 267 Style ("border-radius", "6px"); 270 268 Style ("font-family", "monospace"); 271 - Style ("background", "#f0f4f8"); 269 + Style ("border", "1px solid currentColor"); 270 + Style ("opacity", "0.8"); 272 271 ]; children = [Text msg] } 273 272 274 273 let () = ··· 289 288 let open Lwt.Syntax in 290 289 let* s = Session.create "model_quantized.onnx" () in 291 290 session := Some s; 292 - send_model_status "Ready! Edit the text below and click Analyze."; 291 + send_model_status "Model ready."; 293 292 Lwt.return_unit) 294 293 ]} 295 294 296 295 {1 Analyze Sentiment} 297 296 298 - Edit the sample text and click {b Run} to classify it. The result 299 - widget updates reactively when inference completes: 297 + Type or edit the text below — the model classifies it reactively 298 + via [Note] signals whenever you click {b Analyze}. 300 299 301 - {@ocaml exercise[ 300 + {@ocaml x[ 301 + let input_e, send_input = Note.E.create () 302 + let input_text = Note.S.hold 303 + "This movie was absolutely wonderful, I loved every minute of it!" 304 + input_e 305 + 302 306 let result_e, send_result = Note.E.create () 303 - let result_s = Note.S.hold "" result_e 307 + let result_s = Note.S.hold "Type something and click Analyze." result_e 304 308 305 - let result_view msg = 306 - let open Widget.View in 307 - if msg = "" then Element { tag = "div"; attrs = []; children = [] } 308 - else 309 - Element { tag = "div"; attrs = [ 310 - Style ("padding", "0.75em 1em"); 311 - Style ("border-radius", "6px"); 312 - Style ("font-family", "monospace"); 313 - Style ("font-size", "1.1em"); 314 - Style ("background", "#e8f5e9"); 315 - ]; children = [Text msg] } 316 - 317 - let () = 318 - Widget.display ~id:"sentiment-result" ~handlers:[] 319 - (result_view "") 320 - 321 - let _logr2 = Note.S.log 322 - (Note.S.map result_view result_s) 323 - (Widget.update ~id:"sentiment-result") 324 - let () = Note.Logr.hold _logr2 325 - ]} 326 - 327 - {@ocaml exercise run-on=click[ 328 - let text = "This movie was absolutely wonderful, I loved every minute of it!" 329 - 330 - let () = 309 + let analyze text = 331 310 match !vocab, !session with 332 311 | Some v, Some s -> 333 312 send_result "Running inference..."; ··· 351 330 let label, confidence = 352 331 if probs.(1) > probs.(0) then ("POSITIVE", probs.(1)) 353 332 else ("NEGATIVE", probs.(0)) in 354 - send_result (Printf.sprintf "%s (confidence: %.1f%%)" 355 - label (confidence *. 100.0)); 333 + let emoji = if label = "POSITIVE" then "👍" else "👎" in 334 + send_result (Printf.sprintf "%s %s (%.1f%% confident)" 335 + emoji label (confidence *. 100.0)); 356 336 Tensor.dispose input_ids_tensor; 357 337 Tensor.dispose attention_mask_tensor; 358 338 Tensor.dispose logits_tensor; 359 339 Lwt.return_unit) 360 340 | _ -> 361 341 send_result "Model not loaded yet — wait a moment and try again." 362 - ]} 363 342 364 - Edit the [text] variable above, click {b Run}, and the result will 365 - appear automatically. 343 + let input_view text = 344 + let open Widget.View in 345 + Element { tag = "div"; attrs = [ 346 + Style ("display", "flex"); 347 + Style ("flex-direction", "column"); 348 + Style ("gap", "0.75em"); 349 + ]; children = [ 350 + Element { tag = "textarea"; attrs = [ 351 + Property ("rows", "3"); 352 + Style ("width", "100%"); 353 + Style ("padding", "0.75em"); 354 + Style ("border-radius", "6px"); 355 + Style ("border", "1px solid currentColor"); 356 + Style ("font-size", "1em"); 357 + Style ("font-family", "inherit"); 358 + Style ("background", "transparent"); 359 + Style ("color", "inherit"); 360 + Style ("resize", "vertical"); 361 + Style ("opacity", "0.9"); 362 + Handler ("input", "text_changed"); 363 + ]; children = [Text text] }; 364 + Element { tag = "button"; attrs = [ 365 + Style ("padding", "0.5em 1.5em"); 366 + Style ("border-radius", "6px"); 367 + Style ("border", "1px solid currentColor"); 368 + Style ("background", "transparent"); 369 + Style ("color", "inherit"); 370 + Style ("font-size", "1em"); 371 + Style ("cursor", "pointer"); 372 + Handler ("click", "analyze"); 373 + ]; children = [Text "Analyze"] }; 374 + ] } 375 + 376 + let result_view result = 377 + let open Widget.View in 378 + Element { tag = "div"; attrs = [ 379 + Style ("font-family", "monospace"); 380 + Style ("padding", "0.75em 1em"); 381 + Style ("border-radius", "6px"); 382 + Style ("border", "1px solid currentColor"); 383 + Style ("opacity", "0.8"); 384 + ]; children = [Text result] } 385 + 386 + let () = 387 + Widget.display ~id:"sentiment-input" 388 + ~handlers:[ 389 + "text_changed", (fun v -> send_input (Option.value ~default:"" v)); 390 + "analyze", (fun _ -> analyze (Note.S.value input_text)); 391 + ] 392 + (input_view (Note.S.value input_text)) 393 + 394 + let () = 395 + Widget.display ~id:"sentiment-result" ~handlers:[] 396 + (result_view (Note.S.value result_s)) 397 + 398 + let _logr_input = Note.S.log input_text (fun _ -> ()) 399 + let () = Note.Logr.hold _logr_input 400 + 401 + let _logr_result = Note.S.log 402 + (Note.S.map result_view result_s) 403 + (Widget.update ~id:"sentiment-result") 404 + let () = Note.Logr.hold _logr_result 405 + ]}