Livebook にファイルを投げると、データ処理や音声認識など、拡張子に応じたいい感じのコードを生成、提案してくれる

## はじめに

Livebook Launch Week 2 を自分でやってみるシリーズ

- Day1: [Smart Cell からのリモート接続](https://qiita.com/RyoWakabayashi/items/d2f19a674c261790d999)
- Day2: [Whisper による音声認識の新機能](https://qiita.com/RyoWakabayashi/private/4db05611945f3bba6e30)
- Day3: ファイルをドラッグ＆ドロップすると、扱うためのコードを自動生成する <- ここ
- Day4:
  - [データクラウド Snowflake に接続する](https://qiita.com/RyoWakabayashi/private/98db4a51c6a275541ec2)
  - [Microsoft SQL Server に接続する](https://qiita.com/RyoWakabayashi/private/ab1ce456eaa14b1da6f8)
- Day5: [Vim と Emacs のキーバインド](https://qiita.com/RyoWakabayashi/items/c95934c690d663918a8a)

Day 3 は Livebook のファイル統合です

https://news.livebook.dev/introducing-file-integration---launch-week-2---day-3-2HoFfa

Livebook にファイルをドラッグ＆ドロップすると、そのファイルを使うときのコードを勝手に生成してくれるようになる神機能です

実際に使ってみましょう

Livebook のはじめ方はこちら

https://qiita.com/RyoWakabayashi/items/dc82ad3ed866d58a8acf

## CSV ファイルの追加

### ファイル参照の追加

Livebook で新しいノートブックを開きます

左メニューのディレクトリーアイコン（Files）をクリックしましょう

![スクリーンショット 2023-11-06 9.29.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/8fa1e966-4f86-70ba-ef3d-2cb2cb4268f6.png)

FILES メニューが表示されます

+ Add file ボタンをクリックします

![スクリーンショット 2023-11-06 9.30.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/cf824761-9c9a-6a7a-e065-539d6767a678.png)

Add file モーダルが開きます

![スクリーンショット 2023-11-06 9.39.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/22569946-45eb-1162-13ef-f2bec806dcd1.png)

今回は Web 上から CSV を取得してみます

From URL タブをクリックします

:::note info
From URL タブをクリックしてもタブの色が変化しないのはバグだと思いますが、そのうち修正されるでしょう
:::

URL を入力すると、自動的に Name にファイル名が入力されます（変更可能です）

今回は私の GitHub リポジトリーから都道府県別人口構成の CSV ファイルを指定しました

https://github.com/RyoWakabayashi/elixir-learning/raw/main/livebooks/explorer/population_20211001.csv

![スクリーンショット 2023-11-06 9.34.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/dc6e7f20-3220-14a7-99b1-ea74ea0da6f1.png)

Add ボタンをクリックすると、 References にファイルが追加されました

![スクリーンショット 2023-11-06 9.44.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/29460351-a0b7-bbf8-db77-a62f1374cbad.png)

### CSV ファイルからのコード自動生成

追加されたファイルをノートブック上のセルの前後にドラッグ＆ドロップしてみましょう

![add_csv.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/0410b7d3-1bf5-b5ab-7b12-289d4f2925dd.gif)

Suggested actions というモーダルが開き、 CSV の場合、以下の選択肢が表示されます

- Create a dataframe
- Read file content

Create a dataframe を選択すると、追加の依存モジュールとして `kino_explorer`　をインストールして再起動するよう求められます

+ Add and restart をクリックすると、以下のように CSV を読み込んでデータフレームにする処理が追加されます

```elixir
df =
  Kino.FS.file_path("population_20211001.csv")
  |> Explorer.DataFrame.from_csv!()
```

また、セットアップセルには以下のコードが追加され、インストールが実行されます

```elixir
Mix.install([
  {:kino, "~> 0.11.0"},
  {:kino_explorer, "~> 0.1.11"}
])
```

インストールの完了後、 CSV 読み込みのセルを実行すると、データフレームが作成され、結果がテーブル形式で表示されます

![スクリーンショット 2023-11-06 9.50.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/44c14cc4-5e47-3dd5-5f61-0b210804daae.png)

通常は自分で Web からダウンロードする処理などをコードで記述しないといけません

しかし、 FILES メニューを使うことで、コード上はファイル名を指定するだけで CSV ファイルが読み込まれています

内部的には References で URL の参照だけを保持しており、セルの実行時、 Livebook が裏でデータをダウンロードしてくれています

### ノートブックの保存

この状態でノートブックを保存してみましょう

ノーブックの右下フロッピーアイコン（今の時代伝わるか不安）をクリックします

![スクリーンショット 2023-11-06 10.24.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/c20e4701-a74d-12c9-00ce-0fc61cfe3537.png)

適当なディレクトリーを選択し、適当な名前を付けて保存します

![スクリーンショット 2023-11-06 10.26.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/6fdf5928-9caf-22f3-c9a5-6620679e2239.png)

保存された `.livemd` ファイルは以下のような内容になっています

```markdown
<!-- livebook:{"file_entries":[{"name":"population_20211001.csv","type":"url","url":"https://github.com/RyoWakabayashi/elixir-learning/raw/main/livebooks/explorer/population_20211001.csv"}]} -->

# Untitled notebook
...
```

FILE メニューの References の内容がコメントで保持されており、 Livebook が内部的にここを参照して処理していることが分かります

参照情報ごと管理されるので、このファイルを共有すれば他の人も同じファイルを参照可能です

### ファイル添付

References にあるファイルの右ドロップダウンから `Move to attachments` をクリックします

![スクリーンショット 2023-11-06 9.56.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/df481609-db79-9cf6-a4d2-4de82cf981f7.png)

ファイルが Attachments の方に移動しました

![スクリーンショット 2023-11-06 9.59.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/3aef6c3f-0ceb-be5f-7c1d-7c7275875ed8.png)

この状態でノートブックを保存すると、 `.livemd` の内容は以下のように変化します

```markdown
<!-- livebook:{"file_entries":[{"name":"population_20211001.csv","type":"attachment"}]} -->

# Untitled notebook
```

`"type":"attachment"` で添付ファイル状態になっています

そして、 `.livemd` ファイルと同じディレクリー配下に `files` ディレクトリーが作成され、その中に `population_20211001.csv` が保存されました

```
.
├── sample.livemd
└── files
    └── population_20211001.csv
```

Attachments にすることで、使用するファイル自体をダウンロードして保存することができます

ファイル自体を Git 管理下に置きたい場合などはファイル添付を使用しましょう

## 音声ファイルの添付

今度は `.wav` の音声ファイルを追加し、ノートブックに投げてみます

すると、以下のようなモーダルが表示されます

![スクリーンショット 2023-11-06 10.36.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/663c5f4e-a1b5-e6d2-d70d-ffeba85e286a.png)

選択肢は以下の二つです

- Read file content
- Transcribe speech

勘の良い方はお気付きですね

下の Transcribe speech をクリックすると、以下のようなモーダルが表示され、 `kino_bumblebee` の追加と再起動を要求されます

![スクリーンショット 2023-11-06 10.36.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/d362b520-8c9c-1a0c-08da-3fe6bf3248ae.png)

+ Add and restart をクリックすると、以下のコードが追加されます

```elixir
# To explore more models, see "+ Smart" > "Neural Network task"

{:ok, model_info} = Bumblebee.load_model({:hf, "openai/whisper-tiny"})
{:ok, featurizer} = Bumblebee.load_featurizer({:hf, "openai/whisper-tiny"})
{:ok, tokenizer} = Bumblebee.load_tokenizer({:hf, "openai/whisper-tiny"})
{:ok, generation_config} = Bumblebee.load_generation_config({:hf, "openai/whisper-tiny"})
generation_config = Bumblebee.configure(generation_config, max_new_tokens: 100)

serving =
  Bumblebee.Audio.speech_to_text_whisper(model_info, featurizer, tokenizer, generation_config,
    chunk_num_seconds: 30,
    timestamps: :segments,
    stream: true,
    compile: [batch_size: 4],
    defn_options: [compiler: EXLA]
  )

path = Kino.FS.file_path("run.wav")
Kino.render(Kino.Text.new("(Start of transcription)", chunk: true))

for chunk <- Nx.Serving.run(serving, {:file, path}) do
  [start_mark, end_mark] =
    for seconds <- [chunk.start_timestamp_seconds, chunk.end_timestamp_seconds] do
      seconds
      |> round()
      |> Time.from_seconds_after_midnight()
      |> Time.to_string()
    end

  text = "\n#{start_mark}-#{end_mark}: #{chunk.text}"
  Kino.render(Kino.Text.new(text, chunk: true))
end

Kino.render(Kino.Text.new("\n(End of transcription)", chunk: true))
:ok
```

これは前回やった Whisper のコードです

https://qiita.com/RyoWakabayashi/private/4db05611945f3bba6e30

セットアップセルは以下のようになります

 ```elixir
 Mix.install(
  [
    {:kino, "~> 0.11.0"},
    {:kino_explorer, "~> 0.1.11"},
    {:kino_bumblebee, "~> 0.4.0"},
    {:exla, ">= 0.0.0"}
  ],
  config: [nx: [default_backend: EXLA.Backend]]
)
```

依存モジュールに `kino_bumblebee` と `exla` が追加され、 EXLA を使用するための設定も追加されています

## SQLite データベースファイルを追加する

SQLite は軽量なデータベース管理システムです

https://www.sqlite.org/index.html

データはデータベースファイル (.db) の中に保存されます

このデータベースファイルをノートブックに追加することができます

### サンプルデータベースの取得

公式チュートリアルにあるサンプルデータベースをダウンロードします

ダウンロードした chinook.zip を展開すると、 chinook.db が取得できます

### ノートブックへのデータベースファイルの追加

FILES メニューから chinook.db を追加し、ノートブックに投げてみます

すると、以下のようなモーダルが表示されます

![スクリーンショット 2023-11-06 10.52.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/e7c0f62e-9eb5-c442-2512-82de8c4d65d4.png)

選択肢は以下の二つです

- Describe SQLite database 
- Read file content

Describe SQLite database をクリックすると、 `kino_db` の追加と再起動を要求されます

+ Add and restart をクリックすると、以下のコードが追加されます

```elixir
database_path = Kino.FS.file_path("chinook.db")
{:ok, conn} = Kino.start_child({Exqlite, database: database_path})

Exqlite.query!(conn, "PRAGMA table_list", [])
```

また、セットアップセルには `kino_db` と `exqlite` が追加されます

データベース読込のセルを実行すると、以下のようにテーブル一覧が表示されます

![スクリーンショット 2023-11-06 10.57.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/5115a08c-7f60-2c56-ff29-3ee47334e3c0.png)

## Parquet ファイルの追加

Parquet　は効率的にデータを保存、検索するためのファイル形式です

https://www.databricks.com/jp/glossary/what-is-parquet

### Parquet ファイルの準備

先程 CSV ファイルを読み込んだ結果のテーブルから、データを Parquet 形式で出力しましょう

テーブル左上のエクスポートアイコンをクリックすると、出力形式がドロップダウンで表示されるので、 Parquet をクリックします

![スクリーンショット 2023-11-06 11.12.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/9edf5e30-1a98-7763-1779-76c4ec685b1c.png)

テーブルの内容が `DataFrame-1699236727025.parquet` というようなファイル名で出力されます

### Parquet ファイルの遅延読込

準備した `.parquet` ファイルを FILES メニューから追加し、ノートブックに投げてみます

すると、 CSV の場合と同じ選択肢が表示されます

- Create a dataframe
- Read file content

![スクリーンショット 2023-11-06 11.17.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/2f9d2041-cb44-6120-0438-acc165680596.png)

Create a dataframe をクリックすると、以下のコードが追加されます

```elixir
df =
  Kino.FS.file_spec("population_20211001.parquet")
  |> Explorer.DataFrame.from_parquet!(lazy: true)
```

実行結果は以下のようになり、 CSV と同様、データが一覧表示されます

![スクリーンショット 2023-11-06 11.21.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/32bef96e-a4a6-e47c-78b4-5c9a7f18ce58.png)

しかし、左上をよく見ると、 `Lazy - DataFrame` となっており、コードでも `lazy: true` を指定しています

これは遅延読込の指定です

巨大なデータの場合、最初から全量を読み込むのはメモリを圧迫して非効率です

条件による絞り込みや項目の選択を指定した後、必要な分だけを読み込めば良いはずです

Parquet 形式の場合、そのような遅延読込が可能なため、デフォルトで `lazy: true` が指定されています

### Parquet ファイルから読み込んだデータの変換

Data transform の Smart Cell を追加します

![スクリーンショット 2023-11-06 11.25.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/52040d46-0bb2-62bc-bd96-1b9c1fa0c96b.png)

すると、以下のようなフォームが表示されます

![スクリーンショット 2023-11-06 11.27.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/94779e53-6c64-43e0-cc60-aee2ce79dbbf.png)

以下のように入力してください

- Filter by: 都道府県(string)
- Operation: equal
- Value: 大分県

Evaluate をクリックすると、都道府県が大分県であるデータのみを抽出できます

![スクリーンショット 2023-11-06 11.29.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/b5290a7c-e7ff-fde1-b3ff-660e5aa61c5a.png)

このとき、遅延読込を指定していない場合、一旦 Parquet ファイルから全量読み込んでから、 Livebook 内で絞り込みを行います

遅延読込をしている場合、 Parquet から都道府県が大分県であるデータのみを読み込みます

後者の方がメモリを節約できることが分かるでしょう

## まとめ

Livebook の FILES メニューからファイルを追加することで、以下のようなメリットを得られます

- 拡張子毎にコードの提案を受けられる
- 遅延読込などの便利なオプションもデフォルトで提案してくれる
- ノートブックを共有するとき、一緒にファイルも共有できる

初心者でもすぐにデータ処理や AI モデルの実行ができるため、非常に便利な機能ですね