Display a TensorBoard instance in a Colab output frame. The Colab VM is not directly exposed to the network, so the Colab runtime provides a service worker tunnel to proxy requests from the end user's browser through to servers running on the Colab VM: the output frame may issue req
(port, height, display_handle)
| 311 | |
| 312 | |
| 313 | def _display_colab(port, height, display_handle): |
| 314 | """Display a TensorBoard instance in a Colab output frame. |
| 315 | |
| 316 | The Colab VM is not directly exposed to the network, so the Colab |
| 317 | runtime provides a service worker tunnel to proxy requests from the |
| 318 | end user's browser through to servers running on the Colab VM: the |
| 319 | output frame may issue requests to https://localhost:<port> (HTTPS |
| 320 | only), which will be forwarded to the specified port on the VM. |
| 321 | |
| 322 | It does not suffice to create an `iframe` and let the service worker |
| 323 | redirect its traffic (`<iframe src="https://localhost:6006">`), |
| 324 | because for security reasons service workers cannot intercept iframe |
| 325 | traffic. Instead, we manually fetch the TensorBoard index page with an |
| 326 | XHR in the output frame, and inject the raw HTML into `document.body`. |
| 327 | |
| 328 | By default, the TensorBoard web app requests resources against |
| 329 | relative paths, like `./data/logdir`. Within the output frame, these |
| 330 | requests must instead hit `https://localhost:<port>/data/logdir`. To |
| 331 | redirect them, we change the document base URI, which transparently |
| 332 | affects all requests (XHRs and resources alike). |
| 333 | """ |
| 334 | import IPython.display |
| 335 | |
| 336 | shell = """ |
| 337 | (async () => { |
| 338 | const url = new URL(await google.colab.kernel.proxyPort(%PORT%, {'cache': true})); |
| 339 | url.searchParams.set('tensorboardColab', 'true'); |
| 340 | const iframe = document.createElement('iframe'); |
| 341 | iframe.src = url; |
| 342 | iframe.setAttribute('width', '100%'); |
| 343 | iframe.setAttribute('height', '%HEIGHT%'); |
| 344 | iframe.setAttribute('frameborder', 0); |
| 345 | document.body.appendChild(iframe); |
| 346 | })(); |
| 347 | """ |
| 348 | replacements = [ |
| 349 | ("%PORT%", "%d" % port), |
| 350 | ("%HEIGHT%", "%d" % height), |
| 351 | ] |
| 352 | for k, v in replacements: |
| 353 | shell = shell.replace(k, v) |
| 354 | script = IPython.display.Javascript(shell) |
| 355 | |
| 356 | if display_handle: |
| 357 | display_handle.update(script) |
| 358 | else: |
| 359 | IPython.display.display(script) |
| 360 | |
| 361 | |
| 362 | def _display_ipython(port, height, display_handle): |