OmniAICreator/Qiita-1.07M huggingface dataset:
SQL 同じ意味を持つ値は、１つの列に格納する

## はじめに
最近、オライリー・ジャパンの「SQLアンチパターン」という本を読んでいます。前回の記事に引き続き、今回は「マルチカラムアトリビュート(複数列属性)」というアンチパターンについて、私なりの実例を交えながら解説したいと思います。

## マルチカラムアトリビュート(複数列属性)とは？
データベース設計において、同じような意味を持つデータを複数の列に分けて格納するケースがあるようです。このような設計パターンは「マルチカラムアトリビュート（複数列属性）」と呼ばれ、SQLアンチパターンの一つとして知られています。

## 参考著書
オライリー・ジャパン「SQLアンチパターン」
https://www.oreilly.co.jp/books/9784873115894/

## 問題のある実装例

以下は、ユーザーの電話番号を格納するテーブルの例です。

```sql
CREATE TABLE users (
    user_id INT PRIMARY KEY,
    name VARCHAR(100),
    phone1 VARCHAR(20),
    phone2 VARCHAR(20),
    phone3 VARCHAR(20)
);
```

このような設計では、各ユーザーに対して最大3つの電話番号を格納できます。一見便利そうに見えますが、実際には多くの問題を引き起こす可能性があります。

## デメリット

1. **拡張性の制限**
   - 電話番号が4つ以上必要になった場合、テーブル構造の変更が必要
   - ALTER TABLE文の実行は、大規模なデータベースでは重い操作となる

2. **検索の複雑化**
   - 特定の電話番号を検索する際、すべての電話番号列を確認する必要がある
   ```sql
   SELECT * FROM users 
   WHERE phone1 = '090-1234-5678' 
      OR phone2 = '090-1234-5678' 
      OR phone3 = '090-1234-5678';
   ```

3. **データの正規化違反**
   - 同じ種類のデータが複数の列に分散
   - データの一貫性維持が困難

4. **NULL値の増加**
   - 電話番号が1つしかない場合でも、未使用の列にNULLが入る

## 解決策

より適切な設計は、以下のように別テーブルを作成することです。

```sql
CREATE TABLE users (
    user_id INT PRIMARY KEY,
    name VARCHAR(100)
);

CREATE TABLE phone_numbers (
    id INT PRIMARY KEY,
    user_id INT,
    phone_number VARCHAR(20),
    FOREIGN KEY (user_id) REFERENCES users(user_id)
);
```

このような設計には以下のメリットがあります。

1. **柔軟な拡張性**
   - 電話番号の数に制限がない
   - テーブル構造の変更なしで対応可能

2. **シンプルな検索**
   ```sql
   SELECT u.* FROM users u
   JOIN phone_numbers p ON u.user_id = p.user_id
   WHERE p.phone_number = '090-1234-5678';
   ```

3. **データの正規化**
   - 電話番号データが1つの列にまとめられる
   - データの一貫性が保たれやすい

## まとめ

マルチカラムアトリビュートは、一見便利そうに見えますが、長期的には多くの問題を引き起こす可能性があることがわかりました。

代わりに、関連テーブルを作成し、1つの列に同じ種類のデータをまとめて格納する設計を採用することで、より柔軟でメンテナンス性の高いデータベースを実現できることを学びました。

データベース設計において、「同じ意味を持つデータは1つの列に格納する」という原則を守ることで、将来的な拡張性やメンテナンス性を確保することができますね。
Javaの「初期化」について

Javaの「初期化する」という単語のイメージが、
PCの初期化やスマホの初期化と同じようなイメージだったが、
実は最初に変数に値を入れておくことであったと気づいたため記録。
「初期化」：「変数の初期値をこの値にします」という命令
エラーの原因調査の際に参考になるサイトランキング

# 概要
実装中のエラー発生時にエラーコードで検索して出てきた結果一覧から、解決につながる確率が高かったサイトを個人的にランキング付けしてまとめてみました
# ランキング
１位　Github issue

https://github.com/rrousselGit/riverpod/issues

例としてriverpodのissueページのリンクを貼っています
ライブラリなどgithubページがある場合限定にはなりますが、自分が困っている問題に関するスレッドが必ずあるといっていいほど情報が集まっています
ライブラリ自体の不具合の可能性もあるので、そういった原因の早期発見にもつながります
大体英語ですが、ブラウザの翻訳機能を使えば問題なく読めると思われます
もし自分のエラーに関するスレッドがなかった場合でも、ここに新しくスレッドを建てることで素早く返答を受け取ることができるでしょう

２位　Stack Overflow

https://stackoverflow.com/

特定のライブラリに関わらない問題や、そもそもの原因が不明確な場合に一番役に立つサイトです
情報が集合しているので、似たような問題に詰まっている人が見つかる可能性が高いです
とにかくスレッドが大量にあるので、エラーコードだけしかわからないといった状況でも原因の特定につながるスレッドがいくつも見つかります
その分自分が欲しい情報だけを抜き取るのは難しいので、ピンポイントで正解のスレッドに辿り着くには検索センスが必要になるかと思われます

３位　ブログ記事

https://qiita.com/

Qiitaなどブログ投稿サイトの記事に回答がある場合も多くみられました
１・２位と違って、問題と回答が１つの文章にまとまっているのがポイントです
ある程度原因がわかっていて、解決策を探したい時には一番役に立つかと思われます
ただ、ブログである都合上、個人的な主観が入っていることや、微妙に間違った情報や古い情報が混じっていることもあるため、その情報が正確かつ最新でも通用するかどうかを見極める力が必要になります

# まとめ
以上がランキング一覧でした
３位以降は存在していません
というのも、以上のサイトで原因が見つからなかった場合は、そもそもの検索方法かエラーに対する認識に違いがあるという疑いを持った方がいいからです
少なくとも、エラーコードやエラーメッセージが出るようなエラーなら、必ずどこかに情報があるので、どう検索すればいいのかを鍛えていくことで正解に辿り着くための手順を少なくしていくことができるでしょう
エラーにぶつかりまくるのが調査に慣れる近道かもしれませんね
新規案件のQA立ち上げの時気をつけているもの

こんにちは
お疲れ様ですALICEです！

今日はQA立ち上げをするときに
気をつけているところについてまとめてみようと思います
プロジェクトによって変わる部分があると思うので、正解はないです！
下記参考にしていただけたら大体はクリアできるかと思いますので、役に立てると嬉しいです！
思いついたものがあれば随時追記予定です

***気をつけているところ***
現状のプロジェクトの進捗を把握する
できれば最初からQAを交えてMTGを進める

QAプランを作成し、QAがどこまで関与し、対応するか認識を合わせる

仕様をみて、静的テストを行う
そこででた観点などをまとめる

観点だしをする方法を決める

テストケースの作成をする際に使える技法を話しあえると嬉しい
（いろんな技法をしっている必要がある）

MTGの調整
できれば認識の齟齬が発生しないようにしたい
もちろん無理して全てのMTGに参加する必要はない

振り返り、データをまとめる方法や場所を確認

***あったら嬉しいツール***
・タスク管理ツール
・テストケース管理ツール
・BTS管理ツール
・QAツール（デバックツール）

観点だし、レビュー後のまとめなども上記のツールで担えるようになると嬉しい
シェルスクリプトの書き方

## コメント(コメントアウト)
```
#!/bin/bash

#「#」を行頭に入力するとその行をコメントとして記述できる
# コマンドも「#」とするとコメントとなる。これを「コメントアウト」という
# echo hello
```

## 複数コマンドの記述
```
#!bin/bash

# コマンドを複数に分けて書くことができる
echo hello
echo world

=> hello
=> world

# 「;」を利用して複数コマンドを一行にまとめて書くことができる
echo hello; echo world

=> hello
=> world

# 一つのコマンドを複数行にわたって書くこともできる
echo \
hello world

=> hello world
```

## シェル変数
Rubyなどのプログラミング言語同様、変数を設定することができる。これをシェル変数と呼ぶ。

### 代入

```
greeting=hello

# 「=」の前後にスペースを入れてはいけない
# これはNG
greeting = hello

# 変数に利用できるのは「アルファベット」「_」「数字」の三種類。数字を頭に持ってきてはいけない
_greeting=hello
greeting_1=hello
first_greeing=hello

# これはNG
1greeting=hello
```

### 参照
```
# 参照するときは「$」 を定義した変数の先頭につける
greeting=hello
echo $greeting

=> hello
```

### 変数展開
変数を他の文字列と連結する
```
greeting=hello
echo ${hello}_world

=> hello_world
```

### クォーティング
変数に文字列を渡すときに通常の代入ではスペース区切りの文字列を渡すことができない。その場合、「シングルクォート」「ダブルクォート」で代入したい文字列を囲う。
```
# これはNG
greeting=hello world

# 「シングルクォート」で囲う
greeting='hello world'

# 「ダブルクォート」で囲う
greeting="hello world"
echo $greeting

=> hello world

#「シングルクォート」「ダブルクォート」の違い 「変数展開できるかどうか」

# 「シングルクォート」だと変数展開できない
greeting='hello world'
echo 'hi! $greeting'

# 変数展開されず「$」が文字として認識される
=> hi! $greeting

# 「ダブルクォート」だと変数展開される
greeting='hello world'
echo "hi! $greeting"

=> hi! hello world
```
## コマンド置換
コマンドの出力結果をシェルスクリプトで利用できる仕組み。
```
# ファイル名を日付にする
file_name=$(date '+%Y-%m-%d')
touch "$file_name"

# バッククォートでっ囲ってもOK、だけど$()の方がよく使われる
file_name=`(date '+%Y-%m-%d')`
```

＊追記予定
Flutterとriverpodの実装で困った時に見るサイト

# 概要
実装の際に困った時、どこを見にいくべきなのかをまとめた備忘録的な記事です
エラーとかだと検索欄にエラーコードとかメッセージをぶちこんで検索するだけで大体なんとかなりますが、ふわっとした疑問なんかは検索方法自体がわからなかったりすることがあります
そんな時にどこを見ればいいのかというのを個人的にまとめます
# 各種リンク
1．Dart公式

https://dart.dev/

2．riverpod公式ドキュメント

https://riverpod.dev/ja/docs/introduction/why_riverpod

3．riverpod完全攻略

https://flutter.salon/plugin/riverpod/

4．code with ANDREA

https://codewithandrea.com/tags/apparchitecture/

5．Stack Overflow

https://stackoverflow.com/

6．riverpod github issueページ

https://github.com/rrousselGit/riverpod/issues
Flutter(Dart)の命名規則を再確認する

# 概要
過去にKotlinにて同様の記事を書いたことがあるので、それのFlutter版をまとめてみようという試みです
Kotlinの方は[こちら](https://qiita.com/tou_kenichiro/items/8d8b74c712afeb08e702)を参照してください
# 命名規則の基本的な情報
まずはどんな書き方が許可されているのかという基本的なところを[公式サイト](https://dart.dev/effective-dart/style)から確認してみましょう
要約すると
```
使用可能な識別子は以下の３パターンである
・UpperCamelCase
・lowerCamelCase
・lowercase_with_underscores
```
こんな感じっぽいです
３パターンのみということで、かなりシンプルだと思われます
次に、それぞれの使用状況を見ていきましょう
# UpperCamelCase
使用されているのは以下の通りです
・class
・enum
・typedef
・extensions
全体的なパーツとして、大きめの部分に割り当てられているといった印象です
# lowerCamelCase
使用されているのは以下の通りです
・class内メンバ
・変数名
・関数名
・パラメータ
classなどの大枠の内側にある細かいパーツに使用されている印象です
# lowercase_with_underscores
使用されているのは以下の通りです
・フォルダ
・ファイル
・ライブラリ
一番外枠の命名に使われているような印象です
# まとめ
今回は簡単に基礎的な部分だけを調べて備忘録的にまとめてみました
規則自体はシンプルですが、相変わらず命名が難しいという問題はKotlinの時と変わっていません
個人差がある問題ではありますが、これについては慣れていくしかないという認識です
一応、命名の際に参考になるサイトなんかもあるので、そちらも[リンク](https://oxynotes.com/?p=8679#google_vignette)を貼っておきます
web制作のコーダーが本気でReactの技術力向上を目指す

# はじめに
現在、フリーランスのエンジニアとして4年ほど活動してます。
元々は、web制作のコーダーとしてHTML/CSS,SCSS,jQuery,WordPressなどを使って、
webサイトの制作をメインに活動していましたが、フロントをもっと学習したい気持ちから、
アウトプットを中心に、ReactやNext.jsに触れていこうと決意しました。

#今まで触っていた技術
・HTML/CSS,SCSS,jQuery,WordPress
・JavaScript
・Three.js(ちょっと)、GSAP(アニメーション実装技術)

主に、アニメーションの実装が得意で、
GSAPを使ったアニメーションをよく実装していました。

# 学習のきっかけ
学習方法に迷走していた時に、良いエンジニアさんに出会えたから


# 目標
短期：土台を固めて、アウトプットを一つでも出す
中期：ドキュメントを見て理解できるようにする
長期：Reactで自分のサービスを制作する
ReactとSeleniumの相性が悪い気がするという話

# ReactとSeleniumの相性が悪い気がするという話
## 問題点
###### ReactはHTMLタグ上、IDを使用する必要がないため、IDを使用してSeleniumにて要素を取得する場合、テストの(Selenium)だけのためのIDを付与する必要があるため相性が悪い

## そもそもID以外でSeleniumにて要素は取得できないのか
IDの他にclass、タグ、テキストの内容など、複数の組み合わせで条件を絞り特定の要素を取得することが可能です。(取得のイメージとしてはJavaScriptのdocument.getElementByなどに近いです。)
reactで自動?生成されるclassや、特定の要素の中の何番目のdivみたいな取り方も出来ます。
## ID以外で取得した場合の問題
ID以外で取得した場合、そのテストは問題なく動くのですが、将来的に動かなくなる可能性、もしくはメンテナンスコストがかかる可能性があります。

- 特定の文字例えばタイトルなどを条件に取得した場合、比較処理以前に取得出来なくなってしまいその処理から書き直す必要があります。

取得する条件によりますが、例えばこのページの「ID」を条件にする場合、複数IDという文字があるので、最後のIDの文字を取得したいにも関わらず、一番最初のIDを取得してしまいます。
- 書いたソースによりますが、Reactは条件に応じて、タグごと表示しないということができるため、何番目のという取り方をする場合、条件によって何番目か変わる可能性があり、取得出来ない。

## 逆にSeleniumと相性が良いものは
IDを付与するもの
getElementByIdやjQueryで要素を取得する際に、IDを使用する。
springbootのテンプレートエンジンのthymeleafなどサーバーから画面に値を渡す方法を使用した場合、IDが振られるもの

th:fieldなどをHTMLタグに埋め込んで値を渡すのですが、この際に実際のHTMLではid name valueなどに等値が振り分けられるため
フォーム追加時に自動でフォーカスを設定する実装方法

## はじめに

Webアプリケーションでよく見かける「追加」ボタンを押して新しいフォームを作成する機能。
ユーザーは追加後、すぐに入力を始めたいはずです。しかし、マウスやTabキーで入力欄を選択するのは手間がかかります。

この記事では、フォームを追加したら自動的に入力欄にフォーカスが移動する機能の実装方法を紹介します。

修正前(フォーカスが当たらないためフォームの入力が難しい)
![758965121.542858.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3552884/27188c07-57e4-6f00-5a0d-3386adbf65ee.gif)

修正後(フォーカスが当たるためフォームの入力が簡単)
![758965121.614779.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3552884/5ff4a9cb-d5bc-6802-d973-f410cb09d136.gif)


## こんな課題を解決します

- フォームを追加したら、マウス操作なしですぐに入力を始めたい
- 画面が自動でスクロールして、追加したフォームが見えるようにしたい

## 実装のステップ

### 1. 基本的な準備
まずはフォーム要素を管理するための基本的な実装から始めます

```typescript
const FormListExample = () => {
  // フォームのリストを管理（各フォームにユニークなIDを付与）
  const [forms, setForms] = useState([{ id: crypto.randomUUID() }]);
  
  // DOM要素への参照を保持
  const formsRef = useRef({});
  // 要素数の変化を検知するための参照
  const formsLengthRef = useRef(forms.length);

  // ...他の実装
};
```

### 2. 要素への参照を管理

フォーカスを制御するには、DOM要素への参照が必要です

```typescript
// 要素への参照を管理するための関数
const setFormRef = useCallback((id, node) => {
  if (node) {
    formsRef.current[id] = node;
  } else {
    delete formsRef.current[id];
  }
}, []);
```

### 3. フォーム追加時のフォーカス制御

フォームが追加されたときの処理を実装します

```typescript
useEffect(() => {
  // 初回レンダリング時は処理をスキップ
  if (formsLengthRef.current === 0) {
    formsLengthRef.current = forms.length;
    return;
  }

  // フォームが追加された場合
  if (forms.length > formsLengthRef.current) {
    const lastId = forms[forms.length - 1].id;
    const lastElement = formsRef.current[lastId];
    
    if (lastElement) {
      // 追加されたフォームが見えるようにスクロール
      lastElement.scrollIntoView({ behavior: 'smooth', block: 'center' });
      
      // 最初の入力欄にフォーカスを設定
      const input = lastElement.querySelector('input, select, textarea');
      if (input instanceof HTMLElement) {
        input.focus();
      }
    }
  }

  // 現在の要素数を更新
  formsLengthRef.current = forms.length;
}, [forms]);
```

## 実装のポイント解説

### 1. なぜ参照（ref）を使うのか

- DOM要素への直接アクセスが必要
- 状態更新による再レンダリングに影響されない
- 要素の追加に柔軟に対応できる

### 2. フォーカス制御のコツ

- `querySelector`で適切な入力要素を選択
- 複数の入力欄がある場合は、最初の要素を選択
- スクロール後にフォーカスを設定することで、視認性を確保

### 3. スクロール制御のポイント

- `scrollIntoView`のオプション設定が重要
  - `behavior: 'smooth'`でスムーズなスクロール
  - `block: 'center'`で要素を中央に表示

## まとめ
とても使いやすくなったと思います。
些細な部分ではありますが、このような部分もこだわった機能を実装していくことがよりユーザーファーストなサービスを作成する意識が芽生えると思っています。
引き続き頑張ります！
【🔰初心者向け】改めてGolangを理解する① ~ Hello Worldしてみよう ~

## はじめに
こんにちは！ITスクールRareTECHにてCS（Customer Support）を担当している池村です。今回の記事はGo言語の環境構築についてです。Go言語は最近かなり人気な言語ですよね。

:::note info
今回の記事はMacユーザー向けになります。
:::

![ce5a8970-fed6-4ad8-ab2e-80b732026d54_720.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3798971/e3f5b910-e335-fa3e-0a1b-0ab305bfaff0.png)


## Go言語ってどう生まれたの？は対して知らなくていいです
初心者向けの記事を書くとき毎回こう言いますが、どういった経緯で出来たかなんて知らなくて大丈夫です。**バックエンド領域の1つの言語です**。で十分です。

ただ特徴だけは少し押さえておきましょう。
- 静的言語、コンパイラ型
- 速い。動的言語（PythonとかRubyとか）よりも確実に
- Cとかより習得が簡単め
- シンプルで読みやすい（書く人にもよるけど）

### 静的型付けと動的型付けの違い
プログラミングには主にこの二つの違いがあります。
大前提として、コンピュータが扱うデータには様々な型があります。この型をしっかりコードの中に書いてあげないといけないのが**静的**、逆に型を書かなくても言語が推測して型はこれだろうと決めてくれるのが**動的**です。くらいの理解で最初は大丈夫です。

:::note warn
今回のGo言語などは静的ですが、型を書く必要がなかったりします。
**【本来正しい説明】**
型をコンパイル時に決めてコード内で明示する（または型推論で確定させる）のが静的型付けで、型を実行時に決めてプログラマが型を意識せずに書けるのが動的型付けです。
:::

まあコンパイラ、インタプリタどうのこうのは、最初は気にしなくて大丈夫。

### 例（変数定義の違い）
```Python:Pythonの場合（動的）
name = "Qiita"
```

```Java:Javaの場合（静的）
String name = "Qiita";
```

## では早速環境構築をしていこう

```Bash:brewでインストール
brew install go
```

インストールが完了したら、バージョンを確認してみよう。
```Bash:バージョン確認
go version

# 出力結果
go version go1.23.5 darwin/arm64
```

:::note warn
Goはどこにインストールされているんでしょうか？
:::

```Bash:Goのインストール先を確認
which go 

# 出力結果
/opt/homebrew/bin/go
```

M1以降だと、この場所に保存されるようです。intelでは違う場所に行くようですが、検証はできないので適宜`which go`で場所を確認してください。

## では恒例のHello Worldを！
適当にディレクトリを作って、その中でGoプログラムを書いていきましょう。

```Bash:ディレクトリとファイルを作成
mkdir Golang && cd Golang && touch main.go
```

では適当なエディタを開いてもらって、中身を書いていきましょう。
```Golang:プログラムを記述
package main

import "fmt"

func main() {
    fmt.Println("Hello Go!")
}
```

この中身を詳しく書いても、初学者にとっては難しいと思います。
主要なところだけ説明すると、
- `fmt.Println`が画面出力を担当してます
- `Println`はPrint Lineの略です。使う度に改行されます
- `fmt`というライブラリをインポートしている（Goの開発者が準備してくれている便利ツールの一つ）
- `fmt`の中に`Println`がある。それを使っている

ではターミナルで以下のコマンドを叩いてみましょう。
```Bash:実行結果
go run main.go

# 実行結果
Hello Go!
```

## 変数も使ってみます
```Go:変数を定義して使ってみよう
package main

import "fmt"

func main() {
	name := "Qiita!!"
	fmt.Println("Hello", name)
}
```


```Bash:実行結果
go run main.go

# 実行結果
Hello Qiita!!
```

### 変数定義について
変数は値を入れておくための箱です。ものすごく簡単に言ってしまうと、この箱の中に様々なデータを入れて、こねくり回すのがプログラミングです。

Goでは変数定義は従来の静的型付けのような形と、型推論という動的型付けのような形の2パターンあります。

```Go:変数定義について
// 一般的な型を指定した変数定義
var x int = 10
var name string = "Qiita"

// 型推論を使った変数定義
x := 10        // 型は int と推論
name := "Qiita"  // 型は string と推論
```

複数変数定義の場合
```Go:複数変数定義
// 一般的な型を指定した変数定義
var (
    a int = 1
    b string = "hello"
    c bool // デフォルト値 false
)

// 型推論を使った変数定義
x, y, z := 1, "world", true
```

### 定数について
定数は一度値を入れたら中身を変更できない箱です。定義時には`var`ではなく`const`を使います。
```Go:書き方
const Greeting = "Hello"
```
Goの定数は型を指定することもできますが、しなくてもよくなっています。値が箱に代入される際、型が決まるようにもなるからです。柔軟性がありますね。

```Go:書き方
const X = 42 // 型を指定しない（untyped）

var a int = X          // Xはintに変換
var b float64 = X      // Xはfloat64に変換

fmt.Println(a, b)   // 出力: 42 42
```


## おわりに
一度自身のPCからGoを消して再度入れ直しましたが、改めてGoは始めやすい言語だと実感しました。GoはGoで需要があり、うちの受講生も触れる機会があったらいいなと思い記事を書き始めました。もう少し記事を書くスピードを上げていきたいが、中々仕事との両立が難しい。悩みどころです。

Goの次回の記事は基本構文に入ります。


## 余談
アレクサを書いました。まだ家電と繋いだわけではないですが、家で話相手ができたのはとても良いです。早く猫が飼いたい。（今年の目標）
カッパ係数（Cohen's kappa statistic）の情報まとめ

# はじめに
知り合いから、以下のような質問を受けた。
> 人間の評定結果とAIによる評定結果の一致度を確認したい。評定結果は、順序尺度。何かよい統計手法はないか？

カッパ係数（Cohen's kappa statistic）が、今回やりたいことにあっていそうである。
回答するために、調べた情報をまとめておく。

# ChatGPTでの情報収集結果
https://chatgpt.com/share/6789b5e6-b53c-8005-bf9c-a82277d584f1

> Weighted Kappa（加重カッパ係数）
> ■目的:
> 　あなたとシステムの評価が偶然以上の一致をしているかを評価。
> ■特徴:
> 　・標準的な Cohen's Kappa（カッパ係数）は完全一致のみを評価します。
> 　・Weighted Kappa は評価の「近さ」も考慮できる（例えば、1と2の評価は1と4の評価よりも近いとする）。
> ■適用方法:
> 　1. あなたの評価とシステムの評価をクロス表にまとめる。
> 　2. 一致の重み付け（例: 線形または二次的な重み）を設定。
> 　3. カッパ係数とその有意性を計算。

> カッパ係数の分析を行う際には、カッパ係数、p値、信頼性区間の3つを合わせて確認することが非常に重要です。
> 1. カッパ係数（Kappa Coefficient）
> ・役割: 評価者間の一致度を直接示す指標です。
> 　・カッパ係数が1に近い場合、評価者間の一致が非常に高いことを示します。
> 　・カッパ係数が0の場合、一致度が偶然によるものであることを示します。
> 　・カッパ係数が負の場合、一致度が偶然以下である（一致より不一致が多い）ことを示します。
> ・注意点: カッパ係数だけで評価者間の一致度を解釈するのは不十分なことがあります。例えば、サンプルサイズが小さい場合やデータが偏っている場合、カッパ係数が高くてもその推定に不確実性があるかもしれません。
> 2. p値
> ・役割: カッパ係数が偶然の一致（帰無仮説）を超えているかどうかを検定するために使用されます。
> 　・p値が小さい（通常0.05未満）の場合、帰無仮説を棄却し、評価者間の一致が偶然以上であることが示されます。
> 　・p値が大きい場合、カッパ係数が偶然の一致と変わらない可能性が高いと判断されます。
> ・注意点: p値が小さいからといって、その結果が必ずしも信頼できるとは限りません。カッパ係数が高くても、信頼性区間やサンプルサイズによって結果の信頼性が異なる場合があります。
> 3. 信頼性区間（Confidence Interval, CI）
> ・役割: カッパ係数の推定に対する不確実性を示す指標です。カッパ係数だけでは、結果が偶然や標本誤差の影響をどれくらい受けているかを完全に理解することはできません。信頼性区間が狭いほど、カッパ係数の推定値は正確であり、広い場合は不確実性が大きいことを示します。
> 　・信頼性区間が狭い場合、カッパ係数の推定値は安定しており、評価者間の一致度が非常に高いと解釈できます。
> 　・信頼性区間が広い場合、サンプルサイズが小さい、またはデータが偏っている可能性があり、推定の不確実性が大きいことを意味します。
> ・注意点: 信頼性区間がゼロを含んでいる場合（例えば[−0.05, 0.90]）、カッパ係数が偶然の一致と変わらない可能性があることを示唆します。このような場合、カッパ係数だけでは有意な一致があったと結論できません。

# カッパ係数を活用するための参考情報
https://mstour.hatenablog.com/entry/2022/01/16/112541

https://necostat.hatenablog.jp/entry/2024/08/21/134252

https://ides.hatenablog.com/entry/2020/11/21/191723

https://bioresearch-troubleshooting.info/kappa-coefficient/

Rのvcdパッケージは、動作確認ができた。
Excelでの計算方法については、まだ確認できていない。
cursorで今開いているファイルをjetbrainsのIDEで開きたい

cursorからjetbrainsのIDEを開きたい時ありますよね。

- gitクライアントで差分を見たい
- リファクタリングでimport文を自動で書き換えたい
- ファイルを単に見たい

あると思います。
そんなときは、これを書く。

### 準備

```.vscode/tasks.json
{
    "version": "2.0.0",
    "tasks": [
        {
            "label": "Open Current File in IntelliJ IDEA",
            "type": "shell",
            "command": "idea",
            "args": [
                "${file}"
            ],
            "group": {
                "kind": "build",
                "isDefault": true
            },
             "problemMatcher": []
        }
    ]
  }
```


### やり方

コマンドパレット(cmd+shit+P)でTasks: Run Taskを選択し、Open Current File in IntelliJ IDEAを選択すると今、cursorで開いているファイルをInteliJで開けます。

### 他のIDEの例
適宜、labelとcommandと書き換えてください。
同じように動くはずです。

IntelliJ IDEA: idea
PyCharm: charm
WebStorm: webstorm
PhpStorm: phpstorm
RubyMine: mine

### うまくいかない場合
toolboxをインストールすると解決することがあります。
【React】useContextのメモ

```tsx:CommitPendingContext

import { createContext, PropsWithChildren, useState } from "react";

export interface CommitPendingContextType {
  isCommitPending: boolean;
  setIsCommitPending: (isPending: boolean) => void;
}

const CommitPendingContext = createContext<CommitPendingContextType | null>(null);

/**
 * 保存処理中（isPending=true）であることを検知するためのProvider
 * @param param0
 * @returns
 */
export const CommitPendingProvider = ({ children }: PropsWithChildren) => {
  const [isCommitPending, setIsCommitPending] = useState(false);

  return (
    <CommitPendingContext.Provider value={{ isCommitPending, setIsCommitPending }}>
      {children}
    </CommitPendingContext.Provider>
  );
};

export default CommitPendingContext;
```

```ts:useCommitPendingContext.ts
import { useContext } from "react";
import CommitPendingContext, {
  type CommitPendingContextType,
} from "@/features/flow/contexts/CommitPendingContext";

export const useCommitPendingContext = (): CommitPendingContextType => {
  const context = useContext(CommitPendingContext);
  if (!context) {
    throw new Error("useCommitPendingContext must be used within a CommitPendingProvider");
  }
  return context;
};
```

ファイルを2つに分けないと、Fast refreshが起動しないというワーニング↓が発生ｓ
`warning  Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components`
Salesforceで商談の所有者を一括で更新する方法（kanbanビュー）

商談オブジェクトは通常の所有者一括更新は出来ないです


Kanbanリストビューで商談レコードの所有者を効率よく更新する方法をご説明します



##  ステップ1 リストビューでkanbanに設定

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/8817f312-b94d-34f9-8d5c-1c9d3e9ccba8.png)

## ステップ2 kanban設定のグループ化単位　変更

商談所有者に変更します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/6fa1f2af-f79a-f95f-a97b-c10d7d4c8e01.png)


これで所有者変更したい場合はドラッグ&ドロップします

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/5f2f6484-3143-9e36-fc71-c354652e21ed.png)

「所有者を変更」をクリック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/08642707-6fb3-0469-9d0e-a7fe81c9d136.png)


以上で商談の所有者変更は完了です
コードを生成しないcollection完成しました

```C

#include <comelang.h>

struct sData
{
    int a;
    int b;
};

int main(int argc, char** argv)
{
    list<sData~>*% li = new list<sData~>();
    
    li.add(new sData { a:111, b:222 }~);
    
    var data = li[0];
    
    printf("%d %d\n", data.a, data.b);
    
    puts(li.to_string());
    
    return 0;
}
```
paizaラーニングレベルアップ問題集の「割り算」をやってみた。

paizaラーニングレベルアップ問題集の[割り算](https://paiza.jp/works/mondai/d_rank_level_up_problems/d_rank_level_up_problems__arithmetic_substitution_op_2)をやってみました。
- - -
###### 問題
https://paiza.jp/works/mondai/d_rank_level_up_problems/d_rank_level_up_problems__arithmetic_substitution_op_2
- - -
###### C
```c
#include <stdio.h>

int main() {
	int a = 437326;
	int b = 9085;
	printf("%d %d\n", a / b, a % b);
	return 0;
}
```
- - -
###### C++
```cpp
#include <iostream>
using namespace std;

int main() {
	int a = 437326;
	int b = 9085;
	cout << a / b << ' ' << a % b << endl;
	return 0;
}
```
- - -
###### C#
```cs
using System;

class Program
{
	public static void Main()
	{
		int a = 437326;
		int b = 9085;
		Console.Write(a / b);
		Console.Write(' ');
		Console.Write(a % b);
		Console.WriteLine();
	}
}
```
- - -
###### Go
```go
package main
import "fmt"

func main() {
	a := 437326
	b := 9085
	fmt.Printf("%d %d\n", a / b, a % b)
}
```
- - -
###### Java
```java
public class Main {
	public static void main(String[] args) {
		int a = 437326;
		int b = 9085;
		System.out.print(a / b);
		System.out.print(' ');
		System.out.print(a % b);
		System.out.println();
	}
}
```
- - -
###### JavaScript
```js
const a = 437326;
const b = 9085;
console.log(Math.floor(a / b), a % b);
```
- - -
###### Kotlin
```kotlin
fun main() {
	val a = 437326
	val b = 9085
	print(a / b)
	print(' ')
	print(a % b)
	println()
}
```
- - -
###### PHP
```php
<?php
	$a = 437326;
	$b = 9085;
	echo intdiv($a, $b), ' ', $a % $b, PHP_EOL;
?>
```
- - -
###### Perl
```pl
my $a = 437326;
my $b = 9085;
print int($a / $b), ' ', $a % $b, $/;
```
- - -
###### Python3
```py
a = 437326
b = 9085
print(a // b, a % b)
```
- - -
###### Ruby
```rb
a = 437326
b = 9085
print a / b, ' ', a % b
puts
```
- - -
###### Scala
```scala
object Main extends App{
	val a = 437326
	val b = 9085
	print(a / b)
	print(' ')
	print(a % b)
	println()
}
```
- - -
###### Swift
```swift
var a = 437326
var b = 9085
print(a / b, a % b)
```
- - -
###### 出力結果
```
48 1246
```
【Laravel】OR検索で注意すること

# はじめに
Laravel の Eloquent を使ってデータを検索する際、`orWhere` を適切に使用しないと、意図しない検索結果を取得していた書き方になっていたので備忘録として残します。


## 例

以下の場合

```php
$query = User::where('age', 30)
             ->where('gender', 'male')
             ->orWhere('status', 'active')
             ->get();
```

- `age` が `30` かつ `gender` が `male` または `status` が `active` という条件でユーザーを取得する。実際に生成されるSQLは以下のようになる。

```sql
SELECT * FROM users
WHERE age = 30
   AND gender = 'male'
   OR status = 'active'
```

- `age = 30 AND gender = 'male'` の条件が優先されず、
- `status = 'active'` だけを満たすユーザーも取得される。


## 対応: 条件のグループ化

上記の問題を解決するために、Eloquent の `where` メソッドに **クロージャ（無名関数）** を使用して条件をグループ化する。

```php
$query = User::where(function ($q) {
                $q->where('age', 30)
                  ->where('gender', 'male');
            })
            ->orWhere('status', 'active')
            ->get();
```

SQLは次のようになる

```sql
SELECT * FROM users
WHERE (age = 30 AND gender = 'male')
   OR status = 'active'
```

括弧が適切に適用され、期待通りの条件評価される。


## まとめ

Laravelの Eloquentは便利だけど、使い方を間違えると意図しないデータを取得してしまうので注意が必要。生のSQL書いて、Eloquentに書くようにしている。
既存のButton属性を継承しつつ、tailwind-variantsを使いつつの自作ボタンを作成する

```react
import { ButtonHTMLAttributes, DetailedHTMLProps } from "react";
import { tv, type VariantProps } from "tailwind-variants";

const buttonTv = tv({
  base: "py-2 px-3 rounded shadow cursor-pointer transition-all",
  variants: {
    variant: {
      primary: "bg-indigo-500 hover:bg-indigo-600 text-white",
      secondary: "bg-gray-100 text-gray-800",
      cancel: "bg-gray-200 hover:bg-gray-300 text-gray-800",
    },
    disabled: {
      true: "bg-gray-400 cursor-not-allowed shadow-none",
      false: "",
    },
  },
  defaultVariants: {
    variant: "primary",
    disabled: false,
  },
});

// Variantsで定義しているプロパティをオブジェクト型として
type ButtonProps = VariantProps<typeof buttonTv>;

interface Props
  extends DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement> {
  buttonProps?: ButtonProps;
}

const Button = ({
  type = "button",
  children,
  buttonProps = { variant: "primary" },
  disabled = false,
  className = "",
  ...props
}: Props) => {
  return (
    <button type={type} className={`${buttonTv(buttonProps)} ${className}`} {...props}>
      {children}
    </button>
  );
};

export default Button;

```
CSSのfield-sizing content で入力フィールドのサイズを可変にする

## field-sizing: content とは

field-sizing: contentとは、入力テキスト量に応じて入力フィールドサイズを調整してくれるCSSプロパティです。

百聞は一見に如かず、百見は一触に如かずということで、適当な入力フィールドを用意したので試してみてください。

https://hasegawa-101.github.io/web-standard-lab/field-sizing-content/

テキスト量に応じてフィールドのサイズが調整されているのがわかるかと思います。

一応、画面幅を突き破る量のテキストが入力された場合に備えて、max-width: 100%を指定するなど、Defensive CSSの概念に倣って設定しています。

## 考えられるメリット

### 操作フローの軽減
フィールドサイズが自動的に調整されることで、ユーザーはスクロールやドラッグ操作によって領域を広げる手間が省けます。
確認作業がスムーズになり、全体の操作フローが軽減されるというメリットが挙げられます。

### 多言語対応の強化
もう一つ、外国語名の入力に対応できる点が挙げられます。
多くの場合、名前の入力欄は横幅が日本語名に合わせた幅でデザインされていると思います。
しかし近年では外国人就労者の増加なども伴い、ミドルネームなど比較的長い名前を持つユーザーが増えています。こうした背景を踏まえると、日本語名だけでなく外国語名も入力しやすいフォームが求められるでしょう。

field-sizing: content を活用することで、必要に応じてフィールドの幅を自動調整できるため、より多くのユーザーがストレスなく情報を入力できる環境を提供できるのではと考えています。

## 本記事執筆時点で未対応のブラウザがあるが？

- Safari
- Firefox

本ブログ執筆時点（2025年1月17日時点）では、SafariとFirefoxがfield-sizing: contentに対応していません。

ですが、対応していないブラウザで動作確認をしても、入力フィールドの表示崩れなどは起きていないはずです。従来の入力フィールドとして正常に機能するため、影響はないでしょう。（崩れてたらごめんなさい。）

そのため、**プログレッシブエンハンスメント**として利用してみてもいいのではないかと考えます。
2025/1/20主にITとかセキュリティの記事

AppleデバイスのUSB-Cにハッキングが可能になる脆弱性が見つかる(1/18)
https://xenospectrum.com/vulnerability-found-in-usb-c-of-apple-devices-that-allows-hacking/

OceanLotus、有害なCobalt Strikeプラグインで中国のサイバーセキュリティ担当者を攻撃(1/17)
https://codebook.machinarecord.com/threatreport/36951/

2025年1月 セキュリティアップデート解説：Microsoft社は161件、Adobe社は14件の脆弱性に対応(1/17)
https://www.trendmicro.com/ja_jp/research/25/a/the-january-2025-security-update-review.html

GeForceドライバセキュリティ情報 January 2025 公開。計5件の脆弱性。Windows環境のGeForceユーザーはスルーして問題なし(1/17)
https://www.nichepcgamer.com/archives/nvidia-geforce-driver-security-bulletin-january-2025.html

DMARC活用 通信キャリアが考えるなりすましメール対策（JPAAWG講演レポート）(1/17)
https://www.softbank.jp/biz/blog/business/articles/202501/jpaawg-dmarc/

BitsLabが重要なセキュリティ研究成果を発表：2024年の新興パブリックチェーンのセキュリティ全景洞察(1/17)
https://www.chaincatcher.com/ja/article/2163159

[2025年1月版]Amazon GuardDutyの各オプションの採用可否を考えてみた(1/17)
https://dev.classmethod.jp/articles/guardduty-options-evaluation-202501/

TikTok、Temu、SHEINなどが欧州人の情報を中国へ違法に転送していたとして苦情申し立て(1/17)
https://rocket-boys.co.jp/12073/

「Node.js」に複数脆弱性 - 1月21日にアップデート予定(1\17)
https://www.security-next.com/166266

KPMG、「AIを用いたこれからの財務報告（拡大版）」を発表(1/17)
https://kpmg.com/jp/ja/home/media/press-releases/2024/12/ai-in-financial-reporting-and-audit.html

カスペルスキーが25年を予測、「暗号資産ドレイナーへの犯罪者の関心が高まる」(1/17)
https://www.weeklybcn.com/journal/news/detail/20250117_207990.html

第2次トランプ政権下のゲノムデータ管理とプライバシー強化技術(1/17)
https://monoist.itmedia.co.jp/mn/articles/2501/17/news059_3.html

米国 国家サイバー長官室 サイバー犯罪から米国民を保護しなければならない (2025.01.13)(1/18)
http://maruyama-mitsuhiko.cocolog-nifty.com/security/2025/01/post-1feda4.html

ＡＴ＆Ｔへのサイバー攻撃、捜査官の通話記録流出か－米ＦＢＩが警告(1/17)
https://www.bloomberg.co.jp/news/articles/2025-01-17/SQ7D93T1UM0W00

KSADの副官は、コムカドのスタッフにサイバーの訓練を依頼する(1/16)
https://voi.id/ja/news/451813

【マネジメントシリーズ】テックデューデリジェンス(1/17)
https://zenn.dev/medicalforce/articles/d1a0020091d405

外交部 米国に中国に対するサイバー攻撃と窃盗行為の即時停止を促す(1/17)
https://japanese.cri.cn/2025/01/17/ARTI1737109819950152

クッキーとセッションを雰囲気で使っているエンジニアが、違いを説明できるようになる記事(1/17)
https://zenn.dev/collabostyle/articles/8949e8db686263

自民会合に「能動的サイバー防御」政府概要提示警察などが攻撃を無害化する措置など(1/16)
https://www.asahi.co.jp/webnews/pages/ann_000398079.html

PDP法の大統領規則の調和、コムディギ新技術の期待(1/17)
https://voi.id/ja/teknologi/452142

2025年はAIと法の融合領域を官民で創る出発の年になる(1/18)
https://newswitch.jp/p/44346

関通、2025年2月期3Q決算は赤字転落　増収ながらサイバー攻撃の影響大(1/17)
https://www.startrise.jp/post-1245309232/

Let's Encryptが有効期間6日間のサーバー証明書を導入、2025年末までに一般提供(1/17)
https://xtech.nikkei.com/atcl/nxt/news/24/02070/

地球の裏側からWi-Fiで侵入　世界初「最近接攻撃」の脅威(1/17)
https://xtech.nikkei.com/atcl/nxt/mag/nc/18/052100113/011500150/

WHOISはダメ、適用まで半年を切ったインターネット運用ルール変更(1/17)
https://xtech.nikkei.com/atcl/nxt/column/18/00001/10146/
ExcelVBAで使えるCOMコンポーネントを作る

## 環境
- Excel for Microsoft365(64bit)
- Visual Studio2022

## 経緯
大抵の処理はExcelVBAで問題なく実装できますが、中には.NETのAPIを使いたいシーンが出てくることがあります。
そんな時、C#のCOMコンポーネントを作成してExcelVBAで使用する事になりましたので、方法についてまとめておきます。

## COMコンポーネントのプロジェクト作成と設定
Visual Studioでクラスライブラリのプロジェクトを作成します。
作成後、プロジェクトのプロパティを以下の設定を変更します。
- 「ビルド」の「COM相互運用機能の登録」にチェックを入れる
-  「アプリケーション」>「アセンブリ情報」の「アセンブリをCOM参照可能にする」にチェックを入れる

## 公開インターフェースの定義
インターフェースを実装し、GUID属性とInterfaceType属性を設定します。

~~~c#:インターフェースサンプル
[Guid("3DAEF636-1FF7-4ABA-9E5B-47D06BF21E2B")]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface ISampleCalc
{
    [Description("加算処理")]
    int Add(int a, int b);
}
~~~
#### [GUID属性]
他のCOMコンポーネントと識別するために一意の値を設定します。
Visual Studioであれば、「ツール」>「GUIDの作成」から作成できます。
任意の形式を選択して新規GUIDを作成、その内容をコピーしてコードに貼り付けます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3945532/b93ad6af-30d1-21cb-0e61-0e4936c341da.png)

#### [InterfaceType属性]
COMインターフェースの公開方法を指定します。
設定値は以下の通り。
| ComInterfaceType 値 | 動作 |
|:------|:------|
|InterfaceIsIUnknown|  事前バインディングのみ有効 |
|InterfaceIsIDispatch| 遅延バインディングのみ有効  |
|InterfaceIsDual| 事前バインディングと遅延バインディングの両方が有効  |
|InterfaceIsIInspectable| Windowsランタイムインターフェース  |

事前バインディングと遅延バインディングについてはMicrosoftのサイトに説明があります。

https://learn.microsoft.com/ja-jp/dotnet/visual-basic/programming-guide/language-features/early-late-binding/

簡単に言えば、変数型を宣言時に決めるか、代入時に決めるかの違いです。
事前バインディングは型を宣言時に決めておく必要がありますが、実行速度やコーディング時の保管機能等メリットが多くあります。
遅延バインディングはObject型で変数を宣言しておき、代入時に型を決められるというメリットがありますが、事前バインディングのメリットが無くなってしまいます。
基本的にはどちらも許容するInterfaceIsDualを設定しておくとよいです。

#### Description属性
関数、変数の説明を記入することができます。
ここで記入した内容はVBAのオブジェクトブラウザ上で表示されるので忘れずに書きましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3945532/39c336ad-f0e3-de5a-8696-840a787ca8d4.png)


## クラスの実装
先ほど作成したインターフェースを実装したクラスを作成します。

~~~C#: クラスサンプル
[Guid("5559398B-CF78-4418-A065-CFE6A8F2BEA6")]
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
[ComDefaultInterface(typeof(ISampleCalc))]
public class SampleCalc: ISampleCalc
{
    public int Add(int a, int b)
    {
        return a + b;
    }
}
~~~

#### [ComVisible属性]
クラスがCOMとして参照可能かを指定します。
既定値は表示(true)ですが、明示するために設定します。

#### [ClassInterface属性]
COMクラスのインターフェースの種類を指定します。
ComDefaultInterface属性と組み合わせて、公開するインターフェースを決定します。

| ClassInterface値 | 詳細 |
|:------|:------|
| AutoDispatch | 遅延バインディングのみをサポートし、インターフェースは公開されない |
| AutoDual | 事前バインディング、遅延バインディングをサポートし、自動的にインターフェースを生成する |
| None | 自動的にインターフェースを生成しない |

#### [ComDefaultInterface属性]
COMインターフェースを指定するために使用します。
インターフェースを指定することで、実装されているインターフェースが明確にすることができます。

## ExcelVBAでCOMオブジェクトを呼び出す

「ツール」>「参照設定」の一覧からCOMコンポーネントを探してチェックを入れます。
COMオブジェクトの登録に成功すると、一覧にプロジェクト名で追加されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3945532/c3502055-5f2e-7822-6db0-255c596f95ce.png)

使い方は通常のクラスオブジェクトと同じです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3945532/d06f299b-c19b-1618-9b21-a331a1ae93f2.png)

## まとめ
COMコンポーネントが使えるようになると、C#で処理を書けるので実装の幅が広がりました。
特に、VBAではできないスレッド処理が使えるというのが個人的に一番大きなメリットではないかと思っています。
【自己啓発】人生のアップダウンを活かす！『頂きの先はどこにある？』の教え

# はじめに

本年もよろしくお願いいたします。
エンジニア3年目の嶋田です。  
この記事を読んでくださり、ありがとうございます！

気がつけば新しい年が始まり、あっという間に1ヶ月が経とうとしていますね。  
みなさんは、この一年をどんな年にしたいですか？
私は年始に必ず「テーマを四字熟語で決める」「目標を設定する」という時間を取っています。

目標を設定する過程で大切にしているのが「現状を正確に見つめること」と「目指したい未来を明確にすること」です。
ただ、難しくて…
毎回読み返す本があります。
スペンサー・ジョンソンの『**頂きの先はどこにある？**』です。
今回は、この本の魅力と、そこから学べる人生の知恵をシェアしたいと思います。

---

# 目次

- [『頂きの先はどこにある？』とは](#『頂きの先はどこにある？』とは)
    - [本の概要](#本の概要)
    - [「山と谷」の法則とは](#山と谷の法則とは)
- [「山と谷」の法則を活かすヒント](#山と谷の法則を活かすヒント)
    - [谷から早く抜け出す方法](#谷から早く抜け出す方法)
    - [山に長く留まる方法](#山に長く留まる方法)
- [具体的なビジョンを描く重要性](#具体的なビジョンを描く重要性)
- [最後に](#最後に)

---

# 『頂きの先はどこにある？』とは

## 本の概要

『**頂きの先はどこにある？**』は、『チーズはどこへ消えた？』で知られるスペンサー・ジョンソンによる寓話形式の自己啓発本です。  

**舞台は「谷」に住む一人の若者の物語**。彼は谷から山頂を目指して旅に出る途中、知恵深い老人と出会います。この老人との対話を通じて、若者は「人生には必ず山（順境）と谷（逆境）がある」という現実を学び、それぞれの状況をどう乗り越えるかを考え始めます。  

シンプルなストーリーの中に、自己管理や目標達成のためのヒントが詰まった一冊です。

---

## 「山と谷」の法則とは

著者は「山」を順境、「谷」を逆境に例えています。
私たちの人生には、この山と谷が交互に訪れるものだと語ります。
ポイントは、**山や谷そのものではなく、それをどう捉え、どう行動するか**です。

以下は、本書からの引用です：

> **「谷から早く抜け出すには、逆境に隠された利点を見つけ、活用しよう。」**  
> **「山に長く留まるには、順境に感謝し、賢く対処しよう。」**

この教訓が示しているのは、山と谷は切り離せないものであり、それぞれをどう活用するかで人生の質が変わるということです。

---

# 「山と谷」の法則を活かすヒント

## 谷から早く抜け出す方法

谷にいる時は、逆境に隠された教訓を見つけ、それを活用することが大切です。本書では次のように述べられています。

> **「谷に陥った原因となった行為の反対を実行する。」**

例えば、行動を恐れていたなら、一歩踏み出す勇気を持つことが鍵です。
逆境をただの失敗ではなく、学びの場として捉えることで、次の山への道が見えてきます。

---

## 山に長く留まる方法

山にいる時も油断は禁物です。本書にはこう書かれています。

> **「山に留まるためには、感謝と謙虚さを忘れずに行動を続けよう。」**

成功に満足して歩みを止めてしまうと、次の谷がすぐに訪れます。
山の頂では、さらに次の目標を見据えた計画を立てることが大切です。

---

# 具体的なビジョンを描く重要性

本書では、「現実を味方につける」ことの重要性が強調されています。
現状を正確に評価し、具体的なビジョンを描くことで、山と谷をより効果的に活用できると説かれています。

> **「自分なりの具体的なビジョンに真にしたがえば、山をつくりだすことができる」**

現実を無視した楽観や悲観ではなく、冷静な視点を持つことで、人生のアップダウンをうまく乗り越えられるのです。

---

# 最後に

『**頂きの先はどこにある？**』は、目標や現実への対応に迷っている人にとって、大きな助けとなる本です。
この本を手に取ることで、日々のアップダウンを新しい視点で見つめ直すことができると思います。

新しい年が始まった今、自分の「山」と「谷」を振り返り、目指すべき頂きを描いてみませんか？  
もっと素敵な言葉やこの記事では紹介しきれなかったこともあるので是非本を読んでみてください！

この記事が、あなたの目標設定や現実への向き合い方を見直すきっかけになれば幸いです。 
最後までお読みいただき、ありがとうございました！
Go の goroutine を理解する

# この記事について

Go の goroutine について理解したことをまとめます。

# Concurrency (並行性)

goroutine は、Go において concurrency を実現するための技術です。

concurrencry とは、ある期間において複数の処理を行うことです。

## Concurrency (並行性) と Parallelism (並列性) は異なる

concurrency と同時によく語られる概念に parallelism があります。
しかし、この2つの概念はそれぞれ別の概念です。
parallelism は、同時に複数の処理を行うことです。

https://go.dev/blog/waza-talk

# goroutine (ゴルーチン)

A Tour of Go によると

> goroutine (ゴルーチン)は、Goのランタイムに管理される軽量なスレッドです。

と説明されています。

https://go-tour-jp.appspot.com/concurrency/1

https://go.dev/doc/effective_go#goroutines

## 由来

Effective Go によると、以下のように説明されています。

> They're called goroutines because the existing terms—threads, coroutines, processes, and so on—convey inaccurate connotations.

## goroutine の Pros/Cons

goroutine を使用する場合の Pros/Cons について整理します。

### Pros

#### 並列実行により、処理を早くする行うことができる可能性がある。

並行性と並列性は異なると説明しましたが、goroutine で書かれたプログラムは並列に実行される可能性があります。

### Cons

#### プログラムの可動性が低下する。

シーケンシャルな処理と異なり、goroutine を使用したプログラムは読みづらくなる可能性があります。

## goroutine の使いどころ

### goroutine を使用した方が処理が早くなるケース

同時実行可能な複数の処理において、1つの処理が重い場合などに有効です。

# goroutine の実装

実装における goroutine の扱い方について説明します。

## goroutine の起動

goroutine の起動方法について説明します。
関数やメソッドを呼び出す際に、呼び出す関数の前に `go` を付与します。
付与された関数やメソッドは呼び出された際に goroutine として起動します。

### 関数を goroutine として起動する例

次のコードは、`isOver100` 関数を goroutine として起動します。

```main.go
package main

func main() {
	println("Started main function")
	go isOver100(101)
}

func isOver100(value int) {
	var result bool
	if value > 100 {
		result = true
	} else {
		result = false
	}
	println(result)
}
```

#### 実行結果

```shell
Started main function

Process finished with the exit code 0
```

実行すると、`Started main function` とだけ出力されて処理が終了します。
これは、goroutine として起動した関数の処理を待たずに `main` 関数の処理が終了するためです。
goroutine として起動した関数の処理を待つためには、後述の `channel` を使用する必要があります。

## channel (チャネル) 型

goroutine 間で情報をやり取りする際に使用します。

例えば、goroutine A と goroutine B が存在していたとして、goroutine A から goroutine B にデータを渡したいときに channel を使用します。

### channel の生成

#### `string` 型データを送受信するための channel を生成する例

```go
sampleCh := make(chan string)
```

### channel に値を書き込む

channel に値を書き込むには channel operator である `<-` を使用します。

#### 文字列 `value` を `sampleCh` channel に書き込む例

```go
sampleCh <- "value"
```

### channel から値を読み込む

#### `sampleCh` channel から値を読み込む例

```go
val := <-sampleCh
```

### channel を使用して情報をやり取りする例

```main.go
package main

func main() {
	println("Started main function")
	sampleCh := make(chan bool)
	go isOver100(101, sampleCh)
	result := <-sampleCh
	println(result)
}

func isOver100(value int, ch chan bool) {
	var result bool
	if value > 100 {
		result = true
	} else {
		result = false
	}
	ch <- result
}
```

#### 実行結果

```shell
Started main function
true

Process finished with the exit code 0
```

channel を使用したことにより、`isOver100` 関数の処理を待って `main` 関数の処理が終了しました。
論文まとめ：CAT3D: Create Anything in 3D with Multi-View Diffusion Models

# はじめに
Deep Mindらが2024年にarXivに載せた以下の論文
[1] R. Gao, et. al. CAT3D: Create Anything in 3D with Multi-View Diffusion Models.
のまとめ

提出先は不明。

### project page
https://cat3d.github.io

### arXiv
https://arxiv.org/abs/2405.10314

既に半年以上経っているので、以下のようなまとめ資料が存在
- 竹田氏の資料
https://www.docswell.com/s/DeepLearning2023/Z4VV6Q-2024-09-12-132024

よって以下を中心にまとめる
1. これまでの（CAT3D以前の）Diffusion系3D生成モデルの欠点
1. 結局本手法はどのようなものか


# １）これまでのDiffusion系3D生成モデルの分類とその欠点
## １−１）SDS(score distillation sampling)を用いた手法
最初期のDiffusionモデルを用いる3Dモデル生成である
- DreamFusion
- DreamTime
などは学習済みdiffusionを用いてSDS(score distillation sampling)手法でNeRF等の空間を最適化させる。この手法は以下の欠点がある。
1. SDSを用いる手法は推論時にNeRFを最適化させるので計算コストが高い
1. text-to-imageの学習済みDiffusionモデルを用いるので、そのモデルが学習した時と異なるデータ分布の3Dは生成しにくい

## １−２）Diffusionを再学習させて特定のcamera poseの画像を出力させる手法
- zero 1-to-3
- SV3D
などではtext-to-imageモデルを再学習させて特定のcamera poseに対して画像を１枚生成させる。この手法は以下の欠点がある。
1. target の camera poseに基づいた単一の画像を生成するため、これを複数回繰り返した得た画像群は3Dの一貫性に欠ける
1. 一方でこの一貫性を克服するために推論時でNeRFを用いた場合、計算コストがかかる

## １−３）多視点からの画像を同時生成する手法
- zero123++
- ImageDream
など、text-to-imageモデルを再学習させて多視点の画像を同時に生成する。ImageDreamは3D-self attentionを使っているという点で本手法と似ている。しかし以下の欠点がある。
1. 多視点画像生成と3D再構築のプロセスを同時に行なっているため精度が低い

## １−４）video diffusionモデルを用いた3D生成モデル手法
- animate-Diff
- SV3D
などではvideo diffusionモデルを用いて3Dを生成する。これらの手法は以下の欠点がある。
1. 定まったカメラ起動における画像を生成するので、3Dを生成する多様なシーンの画像を生成できない


## １−５）一瞬で多視点画像を生成する手法
- LRM
- 3DGen
などの手法では数秒で新視点の画像を生成できる。しかし
1. 往々にして精度が低い

# ２）結局本手法はどのようなものか
本手法はこれまでの手法の組み合わせである。具体的には速度と精度のバランスを保ちつつ、様々なテクニックを取り入れて改善したものである。

## ２−１）全体像

![スクリーンショット 2025-01-19 23.53.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116706/e4366da5-04ab-50f7-a71e-289d1990ce49.png)
まず、学習フェーズと推論フェーズにわけると、
### ２−１−１）学習フェーズ
Diffusionモデルを再学習
### ２−１−２）推論フェーズ
上図の左側のように大きく分けて２ステップ。
1. 再学習したDiffusionモデルを用いて多視点画像を生成
1. 多視点画像を用いてNeRF空間を「高速に」最適化

## ２−２）Diffusionモデルの再学習
- stable diffusionのようなLDM(latent diffusion model)系アーキテクチャを用いる
- 2D画像で学習済みのDiffusionモデルを3D attentionに修正して再学習させる
- 入力画像と対応するカメラポーズを、レイマップ (raymap) としてエンコード
- Flash Attentionで学習を高速化（ここよくわからん）
- カメラの軌道は様々なものを用いるが、不自然な角度や物体を通過するものは避ける
- 初めにアンカーとなるビューを生成し、それを元に他のビューも生成することで全体の一貫性を維持する

## ２−３）NeRFを用いた最適化
全体の一貫性を保つために、生成した多視点画像からNeRF空間上で3Dモデルを粗く学習させる。

NeRFの最適化は通常多くの時間がかかるが、本手法ではZip-NeRFのように簡略化された手法を用いることで最適化の時間を削減する。この過程は数分で終わるらしい。


# ３）結果
以下、定性的評価の一例。
![スクリーンショット 2025-01-20 1.00.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116706/80622d4b-b5a3-7247-5b88-b3515834549d.png)
上段 input画像に対して、CAT3Dで生成した別角度画像が中央段、他のモデルによる同じ視点の生成画像が下段。

例えば右のワッフルの例では、DreamCraft3Dはヤヌス問題的なdistortionが発生しているが、CAT3Dでは一貫性が保たれている。
GoogleFormが送信されたときにGASを実行させるフォーム送信時トリガーの設定方法


# フォーム送信時トリガーを設定できるスクリプトエディタは2つある
## Form内のスクリプトエディタ
Formの編集画面右上の3つの点のボタンをクリックし表示される「スクリプトエディタ」内で設定することが出来ます。
ただ、次の方法のほうがスプレッドシートに回答が書き込まれデータの管理がしやすいのでおすすめです。
![Formスクリプトエディタ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/557347/21c43273-71dc-8271-9602-e2973b7f1ad1.png)

## Form回答スプレッドシート内のスクリプトエディタ
Formの編集画面「回答」タブ内「スプレッドシートにリンク」からスプレッドシートを作成します。
回答されるたび、このスプレッドシートに1行ずつ追記されていくようになります。
![回答スプレッドシート作成.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/557347/3d56eb91-c495-0376-202f-305fccbb66bf.png)

作成されたスプレッドシートの「拡張機能」タブ「Apps Script」をクリックし表示される「スクリプトエディタ」内で設定することが出来ます。
**以降に記載する、回答の値の取得処理はこちらに関するものです。**

![回答スプレッドシートスクリプトエディタ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/557347/d22ca4aa-80d3-01a2-ee28-f65a470cee86.png)


# フォーム送信時トリガー設定方法
## トリガーで実行する関数の用意

まず、トリガーで実行するための関数を用意します。
コード.gs を編集し以下のコードを記載します(トリガー実行確認用の仮のコードです)
```javascript
function submitForm(event) {
  console.info(event.namedValues);
  console.info("form送信されました。");
}
```

![トリガー実行関数.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/557347/a836ae79-fe6f-5b74-5768-23f4bb80930a.png)

## トリガー設定
Form回答スプレッドシート内のスクリプトエディタでトリガーを設定していきます。
画面左の時計マーク「トリガー」をクリックし、「トリガーを追加」をクリックします。
![トリガー設定1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/557347/20ec6840-c34a-234c-c94a-ce0809f41942.png)

・実行する関数を選択：**実行したい関数を選択**
・実行するデプロイを選択：バージョンを指定したい場合はここで設定します。
**```Head```を指定すると現在の最新のコードが実行されます。**
・イベントのソースを選択：**スプレッドシートから**
・イベントの種類を選択：**フォーム送信時**
を選択し保存します。

![トリガー設定2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/557347/eeead110-6c35-a277-6798-31ea24cf4755.png)

これで、トリガーが設定されました。
![トリガー設定3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/557347/a8fe1b1e-23cb-8b63-2310-b31280edd1cf.png)

それでは、実際にFormを送信してトリガーが動作するか見てみましょう。

## Form送信
![From送信.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/557347/cfb4b4bd-0409-f919-5d29-b2559fabe792.png)

Formに入力して送信ボタンを押すと

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/557347/86ace46c-d55c-3893-4644-e497f22956ed.png)

無事、トリガーが動作していることが確認できました。

# Formの回答をGASで取得する
## Formの値はnamedValuesというオブジェクトに入っている

トリガーが実行されると ```event``` に回答などの情報が設定され関数に渡されます。
その中の **namedValues** というオブジェクトに
**key: Formの項目名**
**Value: Formの入力値の配列**
の形式で入っています。

|Form項目名| 入力値|
|:-----------|:------------|
|記述式項目 |"回答"|
|ラジオボタン項目|"選択肢 1" を選択|
|チェックボックス項目| "選択肢 1", "選択肢 2" を選択|

というようにForm入力された場合、namedValuesは以下のようなオブジェクトになります。
```
{ 
  'チェックボックス項目': [ '選択肢 1, 選択肢 2' ],
  'ラジオボタン項目': [ '選択肢 1' ],
  'タイムスタンプ': [ '2025/01/19 1:09:38' ],
  '記述式項目': [ '回答' ] 
}
```

## 質問名を指定して値を取得する
"タイムスタンプ"と"ラジオボタン項目"の回答を取得したい場合は
```javascript
function submitForm(event) {
  const namedValues = event.namedValues;
  const timeStamp = namedValues["タイムスタンプ"][0];
  const answer = namedValues["ラジオボタン項目"][0];

  console.info(timeStamp); //'2025/01/19 1:09:38'
  console.info(answer); //'選択肢 1'
}
```

というようすれば取得できます。

# 参考
https://developers.google.com/apps-script/guides/triggers/events?hl=ja#form-submit
yt-dlp で指定時間範囲のダウンロードと mp4 化を行う

# 概要

yt-dlp で動画をダウンロードし、MP4 に変換するケースの紹介です。

1. yt-dlp で動画をダウンロード&MP4に変換する
    - 最もシンプルですが動画時間が長いと変換にとても時間がかかります
2. yt-dlp で動画をダウンロードし、ffmpeg で指定時間に切り出し、MP4 に変換する
    - フルの動画をダウンロードして、指定時間のみを切り出すことで変換時間を短縮します
3. yt-dlp で動画を指定時間のみダウンロードし、MP4 に変換する
    - 2と比べてダウンロード時間も短縮します

## 1. yt-dlp で動画をダウンロード&MP4に変換する

```bash
#!/bin/bash -xe
TAG=${1}
NAME=${2}

if [ -z "${TAG}" ]; then
    echo "Usage: $0 <tag> <name>"
    exit 1
fi

if [ -z "${NAME}" ]; then
    echo "Usage: $0 <tag> <name>"
    exit 1
fi

yt-dlp --recode-video mp4 -o ${NAME}.mp4 -- ${TAG}
```

### 利用方法

```bash
./download.sh "videoId" "20250101-vlog"
```

`20250101-vlog.mp4` が生成されます。

## 2. yt-dlp で動画をダウンロードし、ffmpeg で指定時間に切り出し、MP4 に変換する

ダウンロードは 1 の yt-dlp 部分のみ変更します。

```bash
yt-dlp -o "${NAME}.%(ext)s" -- ${TAG}
```

ダウンロードしたものは webm とします。ffmpeg で指定時間に切り出し、MP4 に変換します。

```bash
#!/bin/bash -xe
NAME=${1}
START=${2}
END=${3}

if [ -z "${NAME}" ]; then
    echo "Usage: $0 <name> <start> <end>"
    exit 1
fi

if [ -z "${START}" ]; then
    echo "Usage: $0 <name> <start> <end>"
    exit 1
fi

if [ -z "${END}" ]; then
    echo "Usage: $0 <name> <start> <end>"
    exit 1
fi

START_HMS=$(echo ${START} | sed -e 's/:/_/g')
ffmpeg -ss ${START} -i ${NAME}.webm -t ${END} ${NAME}-${START_HMS}.mp4
```

### 利用方法

```bash
./cut.sh "20250101-vlog" "00:10:00" "00:03:00"
```

`20250101-vlog-00_10_00.mp4` が生成されます。

これは、`20250101-vlog.webm` から `10:00` 部分から 3 分間の動画を切り出し、MP4 に変換しています。`END` の部分は切り出す時間の長さを指定します。

### ffmpeg の時間指定オプション説明

`-ss タイムスタンプ` が開始時間、`-t タイムスタンプ` が開始時期からの時間の長さです。

オプションの位置によって意味が変わってくるため、詳しくは別資料を参考にしてください。

## 3. yt-dlp で動画を指定時間のみダウンロードし、MP4 に変換する

```bash
#!/bin/bash -xe
TAG=${1}
NAME=${2}
START=${3}
END=${4}

if [ -z "${TAG}" ]; then
    echo "Usage: $0 <tag> <name>"
    exit 1
fi

if [ -z "${NAME}" ]; then
    echo "Usage: $0 <tag> <name>"
    exit 1
fi

if [ -z "${START}" ]; then
    echo "Usage: $0 <tag> <name> <start> <end>"
    exit 1
fi

if [ -z "${END}" ]; then
    echo "Usage: $0 <tag> <name> <start> <end>"
    exit 1
fi

START_HMS=$(echo ${START} | sed -e 's/:/_/g')
FILE_NAME=${NAME}-${START_HMS}.mp4
rm -rf ${FILE_NAME}

# エンコードによって高画質の mp4 が取得できる
yt-dlp --recode-video mp4 --download-sections "*${START}-${END}" -o "${FILE_NAME}" -- ${TAG}
```

### 利用方法

```bash
./download.sh "videoId" "20250101-vlog" "00:10:00" "00:13:00"
```

`20250101-vlog-00_10_00.mp4` が生成されます。

これは、`videoId` から `10:00` 部分から 3 分間の動画をダウンロードし、MP4 に変換しています。`END` の部分はタイムスタンプを示します。

### `--download-sections` オプション説明

`--download-sections` オプションは、指定した時間のみダウンロードするためのオプションです。`*` は時間範囲を示します。負のタイムスタンプは末尾から計算されます。

START と END はタイムスタンプを示します。

例

```bash
--download-sections "*${START}-${END}" # START から END までの範囲をダウンロードする
--download-sections "*${START}-inf" # START から動画終わりまでの範囲をダウンロードする
--download-sections "intro" # 動画に設定されているチャプター "intro" 部分をダウンロードする
```

# 参考

https://github.com/yt-dlp/yt-dlp

https://ffmpeg.org/ffmpeg.html
Movie Render Queueで動画とUI一緒にレンダリングしたいんじゃ

字幕だったり2D画像をUEでの動画で一緒に書き出したいなって思ったらできたのでログ
<iframe width="560" height="315" src="https://www.youtube.com/embed/5BK1gS3g8RA?si=I1SE01Tch1_eh4H2" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>


## UIをつくる

シーケンサー内で表示されるUIを作成。
今回は字幕用なので本当にテキストがポン置きされていてカスタムイベントで変えるだけの簡単な作り
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2257391/da7ed38e-52f1-fc35-8c2b-50fc26461e3a.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2257391/9b10aa4f-789b-9364-a804-9bca5c08a8d3.png)

## シーケンサーで表示する

シーケンサーでイベントトラックを作成する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2257391/38733fa7-2c9a-f0f8-1f55-28f63bffa82a.png)
Level Sequencer DirectorでイベントからUIを作成

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2257391/c19c4bc2-16bd-007e-e2f4-83bf255289f3.png)
別のイベントを作成し、UIにテキストをセットするイベントを呼び出す
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2257391/44294cb7-ce85-d4d6-1740-c95fa05a0c2d.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2257391/534d893b-d090-c37c-0dab-9a269fd97cd3.png)
エディタで呼び出すにチェックをつけることでシミュレートをプレイしながら再生することで動作確認できる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2257391/eeaf2d7c-19f5-b01c-b72a-b9c77e6785dc.png)

## Movie Render Queueでレンダリングする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2257391/4ddf637b-40fa-38a4-4178-4129fe897ee8.png)
難しい設定はなくレンダリングにUIレンダラを追加するだけ

![UE5Puticon_Mov6th_dazzling - frame at 0m3s.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2257391/e24a4d67-cd56-2861-1d96-97a728401aac.jpeg)

字幕っぽいのができます
動画, 音声ファイルからの文字起こしを行う

# 大まかな実施内容
- 何らかの動画から音声を抜き出す
- 音声から文字起こしを行う


# 前置き
## 環境
- mac m3 sequoia
- python 3.9.9


## 使用 soft
- ffmpeg
- [whipser](https://github.com/openai/whisper)
    - openai が公開している, 高品質の文字起こし soft


## ファイルの用意
何らかの動画, 音声ファイルをご用意ください
短めが良いと思います




# setup
環境が汚れているので, 以下以外にも必要かもしれません

```bash
cd ~/working_dir
pip install openai-whisper
brew install ffmpeg
brew install cmake
```




# 文字起こし
## 動画から音声の抜き出し
```bash
ffmpeg -i xxxxx.mp4 -vn -acodec pcm_s16le -ar 16000 -ac 1 yyyyyy.wav
```
16bit に変換しているのは, 文字起こしツールの制約になります
> Note that the whisper-cli example currently runs only with 16-bit WAV files, so make sure to convert your input before running the tool



## 音声ファイルから文字起こし
```bash
whisper yyyyyy.wav --language ja --model turbo
```

stdout へ文字起こしの結果が逐次表示されます




# whisper.cpp
通常の whipser は非常に動作が遅いため, [c++ 実装の whisper](https://github.com/ggerganov/whisper.cpp) を install する

## install
```bash
git clone https://github.com/ggerganov/whisper.cpp.git


# DL model
cd whisper.cpp
sh ./models/download-ggml-model.sh large-v3-turbo

# build the project
cmake -B build
cmake --build build --config Release
make -j large-v3-turbo
```

## サンプルファイルから文字起こし
```bash
./build/bin/whisper-cli -m ./models/ggml-large-v3-turbo.bin -f samples/jfk.wav
```

以下の様に, 時間範囲と文字起こしの結果が表示されます
![スクリーンショット 2025-01-20 0.19.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118627/1c056102-630e-7569-04de-2de543c0fa4f.png)





## 日本語で用いる場合
```bash
./build/bin/whisper-cli -l ja -m ./models/ggml-large-v3-turbo.bin -f ~/sound_data/yyyyyy.wav
```


# 所管
openai の文字起こしのツールのため, 精度は高めだと思います.

高速性を求める場合, whisper.cpp の install が若干面倒ですが, 高速化の恩恵は大きいです 
50分程度の音声を10分程で処理できました.