Magnus having a pint of bitters in a London pub

Colophon

Essential tools: Hugo PaperMod theme Visual Studio Code Obsidian DigitalOcean App Platform AI is used as an assistant. I’m doing the writing, but with help (usually in the form of proof reading or helping with structure). I bounce around between a variety of tools. Claude - Often integrated with other tools like vscode, Obsidian, AnythingLLM. AnythingLLM Ollama Open WebUI ChatGPT - Largely Claude is replacing this. But I still use it some.

An illustration of Pete the octopus, a friendly purple octopus mascot, sitting on top of a computer monitor. The monitor displays a chat interface with colorful text bubbles, representing a tech-themed concept. Surrounding Pete are floating elements like HTML and CSS code snippets, chat bubbles, and subtle digital design patterns. The background features a vibrant gradient with soft tech-inspired geometric shapes, creating a creative and engaging atmosphere.

renderchat shortcode - Open WebUI chats in Hugo sites

Introduction Since I’m using AI to help me more quickly brain dump my non-linear thoughts into a more readable format, I thought it would sometimes be handy to display Open WebUI chats in Hugo sites. This is where the renderchat shortcode comes in. Installation To use the renderchat shortcode, you can do this by creating a file in your site, layouts/shortcodes/renderchat.html, and adding the following code: {{/* renderchat.html */}} {{ $file := .Get "file" }} {{ if eq $file "" }} <p>No chat log file specified.</p> {{ return }} {{ end }} {{ $jsonResource := .Page.Resources.GetMatch $file }} {{ if not $jsonResource }} <p>Could not find the chat log file: {{ $file }}</p> {{ return }} {{ end }} {{ $json := $jsonResource | transform.Unmarshal }} {{ if not $json }} <p>Failed to parse the chat log JSON file.</p> {{ return }} {{ end }} {{ range $json }} <div class="chat-log"> <h2 class="chat-title">{{ .title }}</h2> <div class="chat-messages"> {{ $messages := slice }} {{ range .chat.history.messages }} {{ $messages = $messages | append . }} {{ end }} <!-- Create a map of messages by ID --> {{ $messageMap := dict }} {{ range $messages }} {{ $messageMap = merge $messageMap (dict (printf "%s" .id) .) }} {{ end }} <!-- Render root messages --> {{ range (where $messages "parentId" "==" nil) }} {{ template "renderMessageWithChildren" dict "message" . "map" $messageMap }} {{ end }} </div> </div> {{ end }} {{/* Recursive template to render messages */}} {{ define "renderMessageWithChildren" }} {{ $message := .message }} {{ $map := .map }} <!-- Render current message --> <div class="chat-message {{ $message.role }}"> <strong>{{ if eq $message.role "user" }}User{{ else }}{{ $message.model }}{{ end }}:</strong> <div style="white-space: pre-wrap;">{{ $message.content }}</div> </div> <!-- Render children recursively --> {{ range $message.childrenIds }} {{ $child := index $map . }} {{ template "renderMessageWithChildren" dict "message" $child "map" $map }} {{ end }} {{ end }} Now we’ll need CSS code. My theme will load any CSS that I put in assets/css/extended/ so I added a file in there called renderchat.css. Here’s the CSS code for the chat log: ...

Watercolor-style digital painting of a modern Mac laptop on a sleek desk surrounded by abstract AI-themed elements, with subtle travel-related items like a passport and an airplane toy in a minimalist pastel background.

Local AI Assistant on Mac

Introduction I’m writing this just before hopping on a long trans-atlantic flight. I’m not betting on the in-flight WiFi being very good, so I’m taking the time to get a local AI assistant running on my laptop. I think many travelers will be interested in setting something like this up, so I’d like to take the time to document a lot of how I’m doing this… and hopefully make it easier for others to get it going. ...