🪻 distributed transcription service thistle.dunkirk.sh
at main 139 lines 3.8 kB view raw view rendered
1# Thistle 2 3> [!IMPORTANT] 4> This is crazy pre-alpha and is changing really rapidly. Stuff should stabilize eventually but probably not for a month or two. 5 6```bash 7. 8├── public 9├── src 10│ ├── components 11│ ├── pages 12│ └── styles 13└── whisper-server 14 ├── main.py 15 ├── requirements.txt 16 └── README.md 17 189 directories, 3 files 19``` 20 21## What's this? 22 23Thistle is a transcription service I'm building for Cedarville's startup competition! I'm also using it as an opportunity to become more familar with web components and full stack applications. 24 25## How do I hack on it? 26 27### Development 28 29I'm just running this locally for now but getting started is super straightforward. 30 31```bash 32bun install 33bun dev 34``` 35 36Your server will be running at `http://localhost:3000` with hot module reloading. Just edit any `.ts`, `.html`, or `.css` file and watch it update in the browser. 37 38### Transcription Service 39 40Thistle requires a separate Whisper transcription server for audio processing. Set it up in the `whisper-server/` directory: 41 42```bash 43cd whisper-server 44./run.sh 45``` 46 47Or manually: 48 49```bash 50cd whisper-server 51pip install -r requirements.txt 52python main.py 53``` 54 55The Whisper server will run on `http://localhost:8000`. Make sure it's running before using transcription features. 56 57### Environment Setup 58 59Copy `.env.example` to `.env` and configure: 60 61```bash 62cp .env.example .env 63# Edit .env to set WHISPER_SERVICE_URL=http://localhost:8000 64``` 65 66The tech stack is pretty minimal on purpose. Lit components (~8-10KB gzipped) for things that need reactivity, vanilla JS for simple stuff, and CSS variables for theming. The goal is to keep the total JS bundle as small as possible. 67 68## How does it work? 69 70The development flow is really nice in my opinion. The server imports HTML files as route handlers. Those HTML files import TypeScript components using `<script type="module">`. The components are just Lit web components that self-register as custom elements. Bun sees all this and bundles everything automatically including linked images or assets from the public directory. 71 72```typescript 73// src/index.ts - Server imports HTML as routes 74import indexHTML from "./pages/index.html"; 75 76Bun.serve({ 77 port: 3000, 78 routes: { 79 "/": indexHTML, 80 }, 81 development: { 82 hmr: true, 83 console: true, 84 }, 85}); 86``` 87 88```html 89<!-- src/pages/index.html --> 90<!DOCTYPE html> 91<html lang="en"> 92 <head> 93 <link rel="stylesheet" href="../styles/main.css" /> 94 </head> 95 <body> 96 <counter-component></counter-component> 97 <script type="module" src="../components/counter.ts"></script> 98 </body> 99</html> 100``` 101 102```typescript 103// src/components/counter.ts 104import { LitElement, html, css } from "lit"; 105import { customElement, property } from "lit/decorators.js"; 106 107@customElement("counter-component") 108export class CounterComponent extends LitElement { 109 @property({ type: Number }) count = 0; 110 111 static styles = css` 112 :host { 113 display: block; 114 padding: 1rem; 115 } 116 `; 117 118 render() { 119 return html` 120 <div>${this.count}</div> 121 <button @click=${() => this.count++}>+</button> 122 `; 123 } 124} 125``` 126 127Oh last two points. Please please please use standard commits for my sanity and report any issues to [the tangled repo](https://tangled.org/dunkirk.sh/thistle) 128 129<p align="center"> 130 <img src="https://raw.githubusercontent.com/taciturnaxolotl/carriage/master/.github/images/line-break.svg" /> 131</p> 132 133<p align="center"> 134 &copy 2025-present <a href="https://github.com/taciturnaxolotl">Kieran Klukas</a> 135</p> 136 137<p align="center"> 138 <a href="https://github.com/taciturnaxolotl/thistle/blob/main/LICENSE.md"><img src="https://img.shields.io/static/v1.svg?style=for-the-badge&label=License&message=O'Saasy&logoColor=d9e0ee&colorA=363a4f&colorB=b7bdf8"/></a> 139</p>