Skip to content

Blog

Transcribe videos with google colab and openai whisper

Google colab provides powerful GPUs with 12G of VRAM even at free tier. I foud this very useful to first generate srt files of chinese youtube videos and then translate the chinese srt files into english srt files.

Sample ffmpeg command to extract audio from video

ffmpeg -i input.webm -vn -acodec libmp3lame -ab 192k output.mp3

First visit https://colab.research.google.com/

File
    > New notebook in Drive

Set the runtime type

Runtime
    > Change runtime type

Select python3 as interpreter and t4 gpu as hardware accelator

1749153964.png

Each code bock below is inserted by pressing the +Code button in the UI first and then entering the text. Lines that beings with ! is run in the os shell environment, while the rest are run in the selected interpreter (here python3). After typing in each code blocks, press the run button:

1749139785.png

The codeblocks (run in sequence)

!pip install openai-whisper
from google.colab import files
uploaded = files.upload() # (1)
  1. Click on Choose Files, navigate to and select file.
filename = list(uploaded.keys())[0] # (1)
print(f"Uploaded file: {filename}")
  1. This is done to print the name of the uploaded file so that we can copy it easily. We use this later.
!whisper '狠甩F-15一條街!傳中國無偵-7開掛升空嚇壞日本寶寶 美軍也呆了!【#環球大戰線】20250605-P2 葉思敏 蔡正元 鄭繼文 聶建中 [aK6jyS2GkhU].mp3'
    \   --output_format srt --language zh --model turbo # (1)

Note

  1. Replace "狠甩F-15一條街!傳中國無偵-7開掛升空嚇壞日本寶寶 美軍也呆了!【#環球大戰線】20250605-P2 葉思敏 蔡正元 鄭繼文 聶建中 [aK6jyS2GkhU].mp3" with the name of the file you uploaded
  2. Replace zh with the spoken language in the video
files.download("狠甩F-15一條街!傳中國無偵-7開掛升空嚇壞日本寶寶 美軍也呆了!【#環球大戰線】20250605-P2 葉思敏 蔡正元 鄭繼文 聶建中 [aK6jyS2GkhU].srt")

Note

  1. The generated srt file has the same name but different srt as extension.

Translate with google translate

At https://translate.google.com, in Documents tab you see that google ony supports .docx, .pdf, .pptx, .xlsx. To work around this i had libreoffice open this file and save it as .docx. Surprisingly it took less than a second for google to translate this. I downloaded the file and changed the extension to srt.

1749152901.png

Configuration management with mkdocs and pymdownx.snippets

I believe this is a better way to manage your config files than uploading them to github. With this approach all you need to do is sync your configs file into the config folder within the root of your mkdocs site. They can easily be embedded as snippets in markdown files with appropriate syntax highlighting and contents of these config files also turn up in site search.

Here's an example:

$ mkdocs new vectorspace.xyz
$ cd vectorspace.xyz
$ nvim mkdocs.yml # (1)
$ mkdir configs
$ cp ~/.zshrc configs/
$ nvim docs/index.md # (2)
  1. look down further for mkdocs.yml
  2. look down further for index.md
mkdocs.yml
1
2
3
site_name: My Docs
markdown_extensions:
  - pymdownx.snippets # (1)
  1. For pydownx extension, you need to install python-pymdown-extensions on archlinux
docs/index.md
# Welcome to MkDocs

For full documentation visit [mkdocs.org](https://www.mkdocs.org).

## Commands

* `mkdocs new [dir-name]` - Create a new project.
* `mkdocs serve` - Start the live-reloading docs server.
* `mkdocs build` - Build the documentation site.
* `mkdocs -h` - Print help message and exit.

## Project layout

    mkdocs.yml    # The configuration file.
    docs/
        index.md  # The documentation homepage.
        ...       # Other markdown pages, images and other files.

```zsh
--8<-- "configs/.zshrc"
```

Here I've just added:

```zsh
--8<-- "configs/.zshrc"
```

... to the end of the autogenerated docs/index.md file when you first create a site. Check the results of this by:

# Inside the directory that contains the mkdocs.yml file
mkdocs serve -a 127.0.0.1:9000

see the results for yourself at 127.0.0.1:9000

pydownx is just one of the many awesome extensions developed by github id facelessuser. Check out more at their site: https://facelessuser.github.io/pymdown-extensions/

How to think about flutter layouts

Let's be real specific here. Note the following specific question and the specific answer.

Question: What determines the size of a widget in flutter?
Answer: The widget can size itself however it wants but it is limited by the constraints imposed by its immediate parent widget. Widgets might also change their behavior entirely when it receives no constraints/is unconstrained. For instance, when a Column receives fixed constraints, like 0.0 <= h <= 100.3 and 0.0 <= w <= 958, it will try to assume the maximum height it can: 100.3. It chooses only enough width to fit its widest child, within the constraints ofcourse. But when the Column widget receives unbounded constraints, it no longer sets its height to the maximum it can, which is rational since the maximum would be infinity under unbounded constraints.

In a typical layout we create which starts with a Column (or Row), it receives fixed constraints and chooses to be biggest it can along its main axis. So a Column fills out the whole screen. This is what I mean by a typical layout:

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: Scaffold(
        appBar: AppBar(title: Text('Layout study')),
        body: const MyHomePage(),
      ),
    );
  }
}

class MyHomePage extends StatelessWidget {
  const MyHomePage({super.key});

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Text('Hello There'),
      ],
    );
  }
}

Our layout process for the app stars from the Column. Look at devtools to see what the layout looks like, pay attention to the constraints Column receives and what it decides its size is gonna be.

1732826833.png

You can see it choose the maximum of height from the the constraint and just enough width to fit the child Text widget.

Also note here that the child of this Column receives unconstrained height. We can exploit this fact by having one of the child widget take infinite height. As I mentioned earlier, when a Column receives unbounded height, it tries to do the rational next best thing, to be tall enough to fit its children. What happens if one those children say it wants to be too taller beyond the height of screen:

Column(
  children: [
    Container(
      width: 100,
      height: 5000,
      color: Colors.blue,
    ),
  ],
)
Now we get the classic overflow error. This is what we see in devtools:

1732829021.png

And this on the display:

1732829047.png

Look at the layout as shown in flutter inspector again and note that Column passes definite constraints width-wise to the child. So it has no problem rendering this despite the widget trying to set its width to something larger than the screen.

Column(
  children: [
    Container(
      width: 5000,
      height: 100,
      color: Colors.blue,
    ),
  ],
)