OmniAICreator/Qiita-1.07M huggingface dataset:
Marpで作成したスライドをPDF出力する

# はじめに

Marp for VS Codeで作成したスライドをPDF出力する

# 手順

Markdownでスライドを作成し、三角のマークをクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3343142/c9c37e4c-3ca7-5978-f063-ecaf017180df.png)

`Export Slide Deck...`を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3343142/15ee11a8-6b0c-5d29-0b4d-ab94484a1fa1.png)

保存先を選択し、`Export`するとPDF形式で出力されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3343142/4c1a6846-f3a2-669c-dae8-0b8ab82d920d.png)

出力されたPDF

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3343142/0edff3a9-e604-e20e-38cf-86dd097a425a.png)
知財のあれこれをPythonで何とかする

１．ファミリを何とかする

特許には「ファミリ」というものがあります。
例えば１件の日本出願があればこれを元にして外国出願や分割出願を行えるようになっており、元出願、外国出願、分割出願らを人間の家族に例えてファミリ特許といっております。
ちょうど元の出願が山田太郎＝世帯主であればその家族、子供の山田花子、山田健太の３人で１家族というのと同じです。人間も特許もそれぞれ独立した個ですが、人間を家族単位で扱うように特許もファミリ単位で扱いたい場合があります。
しかしながら専用ツール無しで（Excelで）特許をファミリ単位で扱おうとすると結構煩わしい作業が伴います。今回は少しでもファミリの取り扱いを容易にできるような処理方法を紹介したいと思います。

２．今回やろうとしていること
今回やろうとしていることは
１．1つの要素の中に改行コードで区分されて含まれている家族一人一人を別の要素に分離する
２．分離している家族を世帯主でまとめて再度改行コードで区分された1つの要素に統合する

１．1つの要素の中に改行コードで区分されて含まれている家族一人一人を別の要素に分離する
の２つです

まず特許の「世帯主」の要素と「世帯主を含む家族」の要素が対応付けられた配列（リスト）が準備されているものとします。
「家族」一人一人は改行コードで区分されているものとします。
![famly.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3831931/b319fcd4-b503-3996-c205-6ed01f3de3e8.jpeg)

このリストを以下のプログラムで処理します
```python:qiita.py
fmlygr = [["JP1","JP1\r\nUS2\r\nEP3"],
          ["JP10","JP10\r\nJP11"]]
fmlylist = [[],[]]
index =0

for item in fmlygr:
    fmly = fmlygr[index][1].splitlines() #改行コードで分割しリストfmlyに代入
    for smpl in fmly:#家族ごとに複数の要素に分割
        fmlylist.append([fmlygr[index][0],smpl])
    index += 1
    
print(fmlylist)
```
以下のようなデータ形式になります。
![famly.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3831931/920a3fc4-a1cd-2d20-0596-fb80abd1aeba.jpeg)

上記プログラムでのポイントは「splitlines()」のコマンドです。このコマンドとその次の行のForループの組み合わせだけで家族の分離が簡単に実現できてしまいます。

２．分離している家族を世帯主でまとめて再度改行コードで区分された1つの要素に統合する

次のプログラムは1．のプログラム（家族を分離する）とは逆の処理（家族を統合する）になります。

```python:qiita2.py
import itertools
fmlylist =[["JP10", "JP11"], ["JP1", "EP3"], ["JP10", "JP10"],["JP1", "JP1"],["JP1", "US2"] ]
fmlygr = [[],[]]

for k, g in itertools.groupby(sorted(fmlylist, key=lambda x: x[0]), lambda x: x[0]):
    idg='\r\n'.join(x[1] for x in g) #改行コード（\r\n）で区分してjoinでまとめる
    fmlygr.append([k,idg])
    
print(fmlygr)
```
プログラムを実行すると、世帯主ごとに家族がまとまった形式に戻ります。
上記プログラムでのポイントは「世帯主のグループ化とソート」です。Pythonの機能であるイテレータツール（「itertools.groupby(sorted..」）の利用により世帯主のグループ化とソートの処理が非常に短いプログラムで実現できます。これもPythonの優れた機能の一つと思います。

３．おすすめの使い方
例えば何らかの特許を発見したとき、ファミリ特許も評価しないといけない場合、ファミリ特許を複数の要素に分離し、評価の情報を連結させた後、全ファミリ特許とその評価を同じエクセルの行に収める、といった処理が機械的にできるようになります。
（例えば以下のような形式にすることができる）
![famly.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3831931/593694f5-815e-3864-db18-a635cb111181.jpeg)

Pythonの優れた文字列処理機能をどう利用するかは知財業務の担当者にとって非常に研究しがいのあるテーマではないでしょうか。
以上何かのご参考になれば幸いです。
Marp スライド作成入門

# はじめに

Markdown形式でスライドを作成することができるMarpというものがあることを知り、実際に試してみます。

https://marp.app/

# Marp for VS Code

VS Codeの拡張機能をインストールします。

https://marketplace.visualstudio.com/items?itemName=marp-team.marp-vscode

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3343142/93882a88-ecc1-297f-aa06-e4f5b7815444.png)

以下の内容で新しいファイルを作成し、プレビューする

```Markdown:Usage
---
marp: true
---

# Your slide deck

Start writing!
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3343142/42ae5cb8-acde-0c23-65bd-09c831a0a9e9.png)

簡単に表示できました。

改ページは`---`を入れるようです。

```Markdown:改ページ
---
```

Markdown形式でスライド作成できるのは良いですね。今後は色々と試してみたいと思います。
データサイエンス・コミュニケーションの心得

## データサイエンスコミュニケーションとは？

### はじめに

近年、データサイエンスの重要性がますます高まり、多くの企業でデータサイエンティストが活躍していると思います。

しかし、データサイエンスは高度な専門知識や技術を必要とするだけでなく、少し特殊な状況になることが多いのかなと個人的に思っています。そこで、データサイエンスに携わる方々が意識すべきコミュニケーション、**データサイエンスコミュニケーション**（勝手に名付けました）について何本かに分けてまとめようかと思います。


### データサイエンスに限らず、報連相はビジネスの基本（当たり前だよね）

**報連相がビジネスの基本である理由**

**報連相**が**ビジネスの基本**である理由は、**以下の5つ**に分類できます。

**1. 意思決定の迅速化**

* 状況を常に把握することで、迅速な意思決定が可能になります。
* 意思決定の遅延は、**機会損失**や**コスト増加**につながる可能性があります。

**2. 組織全体の連携強化**

* 情報共有により、組織全体の連携が強化されます。
* チームワークの向上は、生産性やイノベーションの創出につながります。

**3. リスクの回避**

* 問題を早期に発見し、対応することができます。
* リスクを回避することで、損失や評判の低下を防ぐことができます。

**4. メンバーのモチベーション向上**

* 自分の仕事が重要視されていることを実感し、モチベーションが向上します。
* モチベーションの高いメンバーは、より良い成果を生み出すことができます。

**5. 円滑な業務遂行**

* 上記の4つの理由により、円滑な業務遂行が可能になります。
* 円滑な業務遂行は、**顧客満足度**や**収益向上**につながります。

と、いろいろな観点があると思いますが、個人的には4が結構重要な気がします。特にメンバーの立場であれば、自分の業務に意味があるのか、自分が成長しているのかを確認できるいい機会だと自分は思っています。
これらはいずれもデータサイエンス界隈に限らずすべてのビジネスにおいて基本的なことだと思っています。

では、コミュニケーションに関するデータサイエンス特有の側面はどんなものがあるでしょうか。

### データサイエンスの業務って、コミュニケーションの摩擦が起きやすい気がする

#### 理由1：情報の非対称性

データサイエンスプロジェクトでは、リーダーとメンバーの階層構造をもった形でプロジェクトが進むことが一般的だと思いますが、リーダーはより上流にかかわる業務に時間を割くので、実際の分析設計や集計・分析に関する細かい知識はメンバーのほうが詳しいことのほうが多かったです。

通常の職種でもこのような環境は発生しますが、その回数は圧倒的に多いなと感じています。

#### 理由2：個人のスキルセットが見づらく、できること/できないことが分かりづらい
個人的には非データサイエンス界隈から転職してかなりギャップがあったことです。

当然自分の上長からも自分のステータスが把握しづらいということなので、上長が自分のスキルを見誤ってしまい、コミュニケーションギャップが発生しやすい状況になります。

データサイエンスそのものが統計学・機械学習・プログラミングスキルなど多様な技術をもとにしているためしょうがないことですが、この辺は結構苦労しました。

逆に言うと、メンバー側からも上長のスキルが見えないので、この知識はあると思ってスキップしたら認識齟齬が起きた、使っている単語の意味が微妙に異なっていたなど、メンバー側の誤解も起きそう。

#### 理由3： 一人で分析/開発する時間が必要なので、二人三脚で進めづらい場面が多い

私は新卒で公務員をしていましたが、Aタスクの作業をしている最中にBタスクの進捗を求められ、ついでにCタスクのインプットを受けるといった同時並行的な報連相が多かったです。

このような進め方であれば会話量が増えるので、「ついでに〇〇についてなんですが・・・」と、会話の隙が結構あったので、報連相の難易度は比較的低かったです。（むしろリモートワークのせい？）

一方、データサイエンスのプロジェクトでは、クエリを書いたりコーディングしたり何かと一人で黙々と考えながら進める場面も多いと思います。

そんな時、多くの人は上長や他メンバーから頻繁に連絡が来てチャットで話しながら進めるという方法はあまり好まないでしょう。

最近ではリモートワークの普及もあり、進捗確認する側も「邪魔してないかな・・・」「細かくコメントしてパワハラだと思われたくない」といった気持ちから、メンバーへのこまめな連絡ができないという思いもありそうです。

#### 理由4： 伝えようと思ったら永遠に話せるほど周辺知識が関連している

これは何となくわかってもらえると思います。「これって細かいけど伝えたほうがいいのか？」みたいな情報がめちゃくちゃあります。

マストではないけど・・・みたいな内容が多いので、限られたレビュー時間で何を話せばいいのかを取捨選択することが難しいです。



### まとめ
ざっと考えてもこんな側面から、データサイエンス界隈って意外と報連相のハードルは高い気がします。
次の記事では、自分が工夫した報連相・コミュニケーションのポイントを書いていこうかと思います。
今日から始めるAngular！さくっと環境構築

# はじめに
Angulerの環境構築の手順について、解説します。

1. Angular CLIのインストール
2. 新しいプロジェクトの作成
3. プロジェクトの実行

# 前提条件

ngularプロジェクトを始める前に、以下のソフトウェアがインストールされていることを確認してください。

- Node.js (最新のLTSバージョン)
- npm (Node.jsに含まれています)

これらはAngular CLIとプロジェクトの依存関係管理に必要です。

# 1. Angular CLIのインストール
Angular CLIは、プロジェクトの作成、開発、ビルド、デプロイを効率化するためのツールです。コマンドラインで以下のコマンドを実行してインストールします。

```
npm install -g @angular/cli
```

このコマンドは、Angular CLIをグローバルにインストールし、どのディレクトリからでもアクセスできるようにします。

# 2. 新しいプロジェクトの作成
Angular CLIを使用して新しいプロジェクトを作成するには、次のコマンドを実行します。

```
ng new todo-app
```
このコマンドを実行すると、いくつかの質問が表示されます。これには、プロジェクト名やスタイルシートの形式などが含まれます。適切なオプションを選択してプロジェクトの設定を完了します。

# 3. プロジェクトの実行
プロジェクトディレクトリに移動し、以下のコマンドを実行してローカル開発サーバーを起動します。

```
cd todo-app
ng serve
```
デフォルトで `http://localhost:4200/` でアプリケーションが起動します。ブラウザでこのURLを開くと、作成したばかりのAngularアプリケーションが表示されます。

![スクリーンショット 2024-07-06 14.24.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3536873/a0526bee-5706-8eeb-7ae1-4a32ba2bc81a.png)

# おわりに
これで、基本的なAngularプロジェクトのセットアップが完了しました。
次回はさまざまな機能を追加して、TODOアプリを作ってみたいと思います！
毎回忘れるディレクトリごとの容量を調査するコマンド

毎回忘れてしまうので、備忘録として記載します。
ディレクトリごとに容量を調べたい時に使うやつ

## コマンド

```bash
du -d 1 -h
```

## 結果
```bash
479M	./node_modules
4.0K	./prisma
 40M	./.next
  0B	./.mise
8.0K	./public
1.1M	./.git
4.0K	./.vscode
132K	./src
520M	.
```
【個人開発】「最小の時間で最大の学習効果を生む新しい記憶アプリ」を作成しています！

### アプリ概要

![スクリーンショット 2024-07-06 13.57.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/465409/4f49c5b6-4a7d-1e31-d384-c85224653fe2.png)

学習アプリ「RecallNote（リコールノート）」は、スマホだけで、誰でもオリジナルのノートとテストが作成できるアプリです。最新の学習科学に基づくテスト機能により、短時間で効率的に学習を進めることができます。

## 開発者のプロフィール

**砥嶋 勇希**

エンジニア。Ruby on Railsを用いた転職活動用ポートフォリオの制作をサポートをしている。バックエンド担当。

**赤松 汰輝**

和歌山大学B4。社会情報学を専攻。個人開発アプリで複数の賞を獲得。フロントエンド担当。

**宮森 航流**

大阪大学大学院修士1年生。モチベーションの脳科学を研究中。開発はできないが、企画・コンセプト担当。この記事の作成者。

## 開発のきっかけ

「RecallNote」の開発は、高校生のプログラミング学習を支援するボランティア活動で出会った3人が、学習科学[^1]とITを活用して、より多くの人々の効率的な学びをサポートしたいという思いから始まりました。
　　
NPOで高校生と関わってきた経験を通じて、多くの中高生が「自分は勉強ができない」と感じている原因は、効果的な勉強法を知らないことだと気づきました。科学的な学習法に基づいて学べば、誰でも効率的に学習でき、「自分は勉強できるかも」と自信を持つことで、未来を切り開けると考えています。

　　
特に、このアプリは記憶の定着に有効な「テスト効果」[^2]という学習科学の知見をベースにしています。これは、単に本を読み返すよりも、内容を思い出すことで記憶が何倍も定着するというものです。
　　
多くの人が参考書を何度も読んだり、同じ単語を書いて覚えようとしますが、それよりも自分でテストする方が効率的です。このアプリでは簡単にオリジナルテストを作成でき、科学的に効果が認められている方法で学ぶことができます。
　　
[^1]: 「学習科学」とは、人々がどのように学ぶか、効果的な学習環境をどのように設計するかについて研究する学際的な分野です。心理学、教育学、認知科学、情報科学、神経科学などの知見を取り入れ、学習のプロセスを理解し、改善を目指しています。

[^2]:テスト効果とは、テキストを読み返すよりも、その内容を思い出すことで記憶がより強化される現象です。100年以上前に心理学の領域で発見され、多くの学習材料で再現されています。しかし、教育現場ではあまり知られていないのが現状です。

## 解決したい問題
- 単語帳や問題集は丸暗記で覚えてしまって、試験になると思い出せない
　　
- 復習するのがついつい後回しになって、いつも同じ問題を間違えてしまう
　　
- 先生の講義ノートだけで授業が進んだり、参考書や問題集がない分野の勉強をしているから、演習の機会に乏しく知識が定着しない


## アプリの詳細

### 想定ユーザー

**テスト勉強のやり方に困っている中高生・大学生** 
- ノートにまとめる、教科書を何度も読む、音読するなど、どの方法が良いか分からない
- 色々な勉強法を知っているけど、成績は上がっていない

**資格勉強などで、限られた時間で効率よく学習したい社会人** 
- 仕事から帰って難しい参考書を読むのはしんどい
- 休日に一気に勉強しても平日に忘れてしまう

### 機能


**ノートの作成** 
- 単語帳や問題集は丸暗記で覚えてしまって、試験になると思い出せない
→オリジナルクイズがランダムに出題されるので、繰り返し利用することで本番でも使える知識が定着します
　　
- 復習するのがついつい後回しになって、いつも同じ問題を間違えてしまう
→正答率や学習タイミングに応じて、学習科学の観点から最適な復習のタイミングで問題を出題するので、苦手も克服できます
　　
- 先生の講義ノートだけで授業が進んだり、参考書や問題集がない分野の勉強をしているから、演習の機会に乏しく知識が定着しない
→手書きのノートがあれば写真を撮るだけでオリジナルクイズが作成できます

### イメージ画面
![スクリーンショット 2024-07-06 13.57.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/465409/537299f9-e37b-ee04-57f9-e1641f921e32.png)


## 今後について
「RecallNote」は現在、開発を進めている段階です。10月末のリリースを目指しているので、続報をお待ちください！感想やコメントも大歓迎です！コメント欄、Google Form（匿名可能）またはDiscordにご参加いただき、コメントいただけると幸いです！
ここまで読んでいただき、ありがとうございました！！

**Google Form**
https://docs.google.com/forms/d/1VLSrZZEbGJl7CsiegzbvJr4hUKE8aaFPwBvn3O4Kwns/edit?hl=ja

**Discord**
参加はこちらから
→https://discord.gg/vG4aer7P7C
フロントエンドからバックエンドへのAPI連携: localhostの問題とhost.docker.internalを使用した解決策

# localhostではなく、host.docker.internalでアクセスする
最近、ローカルPC上でdocker composeを使用して、Next.jsで構築したフロントエンドとGolangで構築したバックエンドAPIを、それぞれ独立したDockerコンテナで開発していました。
ここで、フロントエンドからバックエンドのAPI実行時に、localhostを使用してもうまく接続できないという問題に直面しました。

調査の結果、コンテナ内のlocalhostはコンテナ自身を指すため、他のコンテナやホストマシン上のサービスにアクセスできないことが原因だと判明しました。そこで出会ったのがhost.docker.internalです。

コンテナ内のlocalhostがコンテナ自身を指すため、他のコンテナやホストマシン上のサービスにアクセスできないという問題があります。
そんな時に便利なのが**host.docker.internal**です。

# localhostがコンテナ内部を指す問題
コンテナ内でlocalhostを使用すると、それはコンテナ自身を指します。
つまり、コンテナ内で http://localhost:8080 にアクセスしても、ホストマシン上で実行されているサービスには到達できません。
これは、各コンテナが独立したネットワーク環境を持っているためです。

例えば、バックエンドのコンテナAPIサーバーがlocalhost:8080で実行されていて、フロントエンドのコンテナからそのAPIサーバーにアクセスしようとしても、http://localhost:8080 では接続できないことがあります。
コンテナ内のlocalhostはコンテナ自身を指すため、コンテナ内部に存在しないサービスへアクセスしようとしていることになります。

# host.docker.internalの役割
host.docker.internalは、この問題を解決するための特殊なDNS名です。
コンテナ内でhost.docker.internalを使用すると、ホストマシン上で実行されているサービスにアクセスすることができます。
つまり、先ほどの例で、コンテナ内のフロントエンドからAPIサーバーにアクセスする場合、http://localhost:8080 の代わりに http://host.docker.internal:8080 を使用することで、ホストマシン上のAPIサーバーに到達できます。

# 使用方法
コンテナ内からホストマシン上のサービスへアクセスする際に、localhostの代わりにhost.docker.internalを使用します。

添付画像では、`NEXT_PUBLIC_API_URL=http://localhost:8080`と`NEXT_PUBLIC_API_URL=http://host.docker.internal:8080`の二つが存在します。
今回、`NEXT_PUBLIC_API_URL=http://host.docker.internal:8080`の設定をすることで、事象が解消しました。
![スクリーンショット 2024-07-06 14.22.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/263017/698f6618-e30e-6292-fa2e-d3c2ccc71616.png)

エラー: NEXT_PUBLIC_API_URL=http://localhost:8080
![スクリーンショット 2024-07-06 14.24.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/263017/640550a9-6c9a-1a71-76de-5b35bbe6fafe.png)

成功: NEXT_PUBLIC_API_URL=http://host.docker.internal:8080
![スクリーンショット 2024-07-06 14.25.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/263017/9b69a90f-52cb-e906-64e4-54e25f34430d.png)

# まとめ
コンテナ内のlocalhostがコンテナ自身を指すことによって、他のコンテナやホストマシン上のサービスにアクセスできないという問題があります。
host.docker.internalを使用することで、この問題を解決し、コンテナ内からホストマシン上で実行されているサービスにアクセスすることができます。
ぜひ、host.docker.internalを活用して、コンテナとホストマシン間のシームレスな連携を実現してください。
生成AIアプリ開発プラットフォーム「Dify」の実力検証！～Qiita記事まとめ～ 


近年、ChatGPTをはじめとする生成AIが急速に発展し、私たちの生活や仕事のあり方を変えようとしています。そんな中、 **生成AIアプリを簡単に開発できるプラットフォーム「Dify」** が注目を集めています。

Difyは、コードを書かずに、視覚的に操作できるインターフェースで、誰でも簡単に生成AIアプリを開発できるのが特徴です。特に、複雑なワークフローも直感的に設計できるため、開発効率が大幅に向上します。

今回は、Qiitaに投稿された**Difyの実力検証記事**を参考に、Difyでどんなことができるのか、その可能性を探ってみましょう。

### Qiitaに見るDify活用事例

Qiitaには、実際にDifyを使って様々なアプリを開発した事例が多数投稿されています。

**1. チャットボット開発**

* **[Make DifyでLINEボットを作る](https://qiita.com/cog1t0/items/00a9e608925578e0cf44)**
    - LINE BotとDifyを連携させて、質問応答や情報提供を行うチャットボットを開発。
    - Make（旧Integromat）と組み合わせることで、LINE以外のサービスとの連携も可能に。

**2. Webスクレイピング+情報要約**

* **[話題のローコードツール「Dify」で生成AIアプリを作ってみよう！](https://qiita.com/minorun365/items/4c5dba1de7977c386249)**
    - Google検索とGPTを組み合わせ、ユーザーの質問に対してWebから情報を取得し、要約して回答するアプリを開発。
    - SerpAPIを使ってGoogle検索をAPI化し、Difyのワークフローで処理を自動化。

**3. 社内ナレッジベース検索**

* **[Dockerで構築したDifyを利用しノーコードでRAGのチャットボットを作る](https://qiita.com/sey323/items/8921bb767e2b0656f1cc)**
    - 特定のドキュメントをRAG（Retrieval-Augmented Generation）に登録し、その内容に関する質問に回答できるチャットボットを開発。
    - Qiita CLIのREADMEを例に、Dockerを用いたローカル環境でのDify構築とRAG実装を紹介。

**4. プロンプトエンジニアリング**

* **[Anthropic Generate a promptとDifyの組み合わせがAI活用を加速する](https://qiita.com/tregu148/items/bba83bfcc098362209d3)**
    - AnthropicのGenerate a prompt機能で生成したプロンプトをDifyで活用し、高精度なAIアプリ開発を実現。
    - ビジネスプラン自動生成チャットボットを例に、プロンプト生成とDifyの連携による効率的な開発を紹介。

### Difyの可能性

これらの記事から、Difyは以下のような可能性を秘めていることがわかります。

- **幅広いユースケース**: チャットボット開発、Webスクレイピング、RAG、プロンプトエンジニアリングなど、様々な用途に活用可能。
- **高い拡張性**: API連携や外部ツールとの統合により、さらに複雑な処理や高度な機能を実現可能。
- **迅速な開発**: ノーコード開発により、従来よりも短期間でAIアプリのプロトタイプを作成し、検証可能。

### まとめ

Difyは、生成AIアプリ開発のハードルを大幅に下げ、誰でも簡単にAIを活用したサービスを開発できる画期的なプラットフォームです。Qiitaの記事に見られるように、すでに多くの開発者がDifyを使って様々なアプリを開発し、その可能性を実証しています。

生成AIは私たちの生活やビジネスを大きく変える可能性を秘めています。Difyのようなツールを活用することで、私たちもその変化を加速させることができるでしょう。

Difyは進化を続けており、今後も新しい機能が追加される予定です。ぜひ、Difyを試してみて、あなた自身のアイデアを形にしてみてください。
公式 Pi 7" Touchscreen Display element14(旧verRaspberry pi 用ディスプレイ)とRaspberry pi 5を繋げるためには

公式 Pi 7" Touchscreen Display element14とRaspberry pi 5では対応するFPCケーブル(カメラケーブル)のピン数が異なります。公式 Pi 7" Touchscreen Display element14は15ピン対応、Raspberry pi 5は22ピン対応となっています。

そのため、※別途15ピンから22ピンにつなげることが出来るFPCケーブルを購入する必要があります。
本例では秋月電子通商で販売されている
Raspberry Pi 5用DSIケーブル(ディスプレイ用) FPC 15-22pin 200mm (販売コード 129334) 
URL: https://akizukidenshi.com/catalog/g/g129334/  を用いております。


※旧バージョンのRaspberry pi は15ピン対応なので変換ケーブルは不必要です。

参考としてFPCケーブル、ジャンパーの接続後の図を下記に示します。
【接続例】
![KIMG0297.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3827595/af295ee2-792b-6ab6-b6a7-1b7942d4e492.jpeg)

Raspberry pi 5側のジャンパー線接続位置
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3827595/f1c4c30f-f5d7-02ae-5cff-ddf3cb686200.png)
左が赤、右が黒のジャンパーです。


【正常に起動した場合の画面】
![KIMG0302.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3827595/50abfe53-9182-9f83-989a-d27287710887.jpeg)


【公式ケースに入れた場合】
![KIMG0300 (1).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3827595/56144f04-1427-116a-975f-1b9fe599e1a2.jpeg)



[ディスプレイが正常に動作しない際の対処法]
事象1:Raspberry pi5起動後、10秒待ってもディスプレイが白く光ることすらない。
 原因1:ジャンパー線の断線、ジャンパー線の接続位置が誤っている。
 ![KIMG0299.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3827595/168d7700-59f1-1ac1-4836-972fdd5418ad.jpeg)
ロガーやテスターを持っている方は5Vの電圧が出ているか確認してみてください。

事象2:Raspberry pi5起動後、ディスプレイは白く光るが映像が映らない、映像が乱れる。
 原因2:FPCケーブルきちんと接続されていない、FPCケーブルの破損。


私のようにRaspberry pi 5用ディスプレイが見つからず困っている方の助けになれば
幸いです。
Goでトランザクション処理をやってみる

## はじめに
タイトルどおり、Goでトランザクションを張って処理を実行してみます。

## コード

ポイントは、defer tx.Rollback()で、ロールバックを予約しておくことです。
こうしておくことで、処理がコケたときに自動でロールバックが実行されるようになりますし、エラーハンドリング内でロールバックの記述漏れが発生することがなくなります。
コミット後は、ロールバックは実行されないのでこれでOKです。

```go
package main

import (
	"database/sql"
	"fmt"
	"log"
	"os"

	_ "github.com/go-sql-driver/mysql"
)

var (
	dbUser     = os.Getenv("DB_USER")
	dbPassword = os.Getenv("DB_PASSWORD")
	dbDatabase = os.Getenv("DB_NAME")
	dbConn     = fmt.Sprintf("%s:%s@tcp(127.0.0.1:3306)/%s?parseTime=true", dbUser, dbPassword, dbDatabase)
)

func main() {
	db, err := sql.Open("mysql", dbConn)
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	// トランザクションを開始する
	tx, err := db.Begin()
	if err != nil {
		log.Fatal(err)
	}
	defer tx.Rollback()

	// トランザクション内でクエリを実行する
	_, err = tx.Exec("INSERT INTO users (name, email) VALUES (?, ?)", "TEST TEST", "test@example.com")
	if err != nil {
		log.Fatal(err)
	}

    _, err = tx.Exec("INSERT INTO users (name, email) VALUES (?, ?)", "TEST TEST", "test@example.com")
	if err != nil {
		log.Fatal(err)
	}

	// トランザクションをコミットする
	err = tx.Commit()
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println("トランザクションが正常に完了しました")
}
```

## 動かしてみる

```zsh
go run main.go

トランザクションが正常に完了しました
```

## 参考
- [詳解Go言語Webアプリケーション開発](https://www.amazon.co.jp/%E8%A9%B3%E8%A7%A3Go%E8%A8%80%E8%AA%9EWeb%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E9%96%8B%E7%99%BA-%E6%B8%85%E6%B0%B4%E9%99%BD%E4%B8%80%E9%83%8E-ebook/dp/B0B62K55SL)
ffmpegの使い方：シェルスクリプトで一括処理の応用編

ffmpegのバッチ処理のファイルをまとめてみた

まず前提として
デスクトップに「Input」フォルダと「Output」フォルダが作ってあり
Inputフォルダに変換したい複数の動画ファイルがぶっ込んであって
Outputフォルダは空にする

下記のスクリプトをターミナルで実行すると、Inputフォルダの動画が変換されてOutputフォルダに出力される

基本編はこちら

https://qiita.com/HXYoUGZ/items/960d9bb4e61c55ab9bbc

FFmpegに関して

https://ja.wikipedia.org/wiki/FFmpeg

# コーデックをHEVC(H.265)に変換する

```sh:convert2hevc.sh
#!/bin/sh

INDIR=~/Desktop/Input/
OUTDIR=~/Desktop/Output/

for FILE in ${INDIR}*
do
  FILENAME=`basename "${FILE}"`
  OUTPATH=$OUTDIR$FILENAME
  ffmpeg -i "${FILE}" -c:v hevc -tag:v hvc1 "${OUTPATH%.*}.mp4"
done
```

https://atmarkit.itmedia.co.jp/flinux/rensai/linuxtips/437delfileext.html

https://qiita.com/osw_nuco/items/a5d7173c1e443030875f

# 黒を透明にしてhapコーデックにする

```sh:convertblack.sh
#!/bin/sh

INDIR=~/Desktop/Input/
OUTDIR=~/Desktop/Output/

for FILE in ${INDIR}*
do
  FILENAME=`basename "${FILE}"`
  OUTPATH=$OUTDIR$FILENAME
  ffmpeg -i "${FILE}" -vf colorkey=0x000000:0.01:0.15 -vcodec hap -an -format hap_alpha "${OUTPATH%.*}.mov"
done
```

# 青を透明にしてhapコーデックにする

```sh:convertblue.sh
#!/bin/sh

INDIR=~/Desktop/Input/
OUTDIR=~/Desktop/Output/

for FILE in ${INDIR}*
do
  FILENAME=`basename "${FILE}"`
  OUTPATH=$OUTDIR$FILENAME
  ffmpeg -i "${FILE}" -vf colorkey=0x0000ff:0.01:1 -vcodec hap -format hap_alpha -an "${OUTPATH%.*}.mov"
done
```

# 緑を透明にしてhapコーデックにする

```sh:convertgreen.sh
#!/bin/sh

INDIR=~/Desktop/Input/
OUTDIR=~/Desktop/Output/

for FILE in ${INDIR}*
do
  FILENAME=`basename "${FILE}"`
  OUTPATH=$OUTDIR$FILENAME
  ffmpeg -i "${FILE}" -vf colorkey=0x00ff00:0.01:1 -vcodec hap -format hap_alpha -an "${OUTPATH%.*}.mov"
done
```

# hapコーデックにエンコードする

```sh:convert2hap.sh
#!/bin/sh

INDIR=~/Desktop/Input/
OUTDIR=~/Desktop/Output/

for FILE in ${INDIR}*
do
  FILENAME=`basename "${FILE}"`
  OUTPATH=$OUTDIR$FILENAME
  ffmpeg -i "${FILE}" -vcodec hap -pix_fmt yuv420p -an "${OUTPATH%.*}.mov"
done
```

# 動画の拡大縮小

動画の横幅(width)を 1280 にする。高さ(height)はアスペクト比を維持して自動で設定する

```sh:convertsize.sh
#!/bin/sh

INDIR=~/Desktop/Input/
OUTDIR=~/Desktop/Output/

for FILE in ${INDIR}*
do
  FILENAME=`basename "${FILE}"`
  OUTPATH=$OUTDIR$FILENAME
  ffmpeg -i "${FILE}" -vf scale=1280:-1 "${OUTPATH%.*}.mp4"
done
```
Gitでファイルを無視する方法の選択肢と使い所について

Gitでファイルやディレクトリを無視する方法には、いくつかの選択肢があります。それぞれの方法の違いと使い所についてまとめたいと思います。

### 目次

- [`~/.config/git/ignore`を利用する場合](#configgitignoreを利用する場合)
- [`.gitignore`を利用する場合](#gitignoreを利用する場合)
- [`.git/info/exclude`を利用する場合](#gitinfoexcludeを利用する場合)


## まとめ

|| `~/.config/git/ignore` | `.gitignore` | `.git/info/exclude` |
|-|-|-|-|
| 適用範囲 | グローバル (すべてのリポジトリに適用)| リポジトリごとに適用 | リポジトリごとに適用 |
| ファイルの場所 |ユーザーのホームディレクトリ | リポジトリのルートディレクトリ | リポジトリの`.git`ディレクトリ内 |
| 影響範囲 | ユーザーの環境のみ | チーム全体（リポジトリを共有する全員）| ユーザーの環境のみ |
| コミット| コミットされない | コミットされる | コミットされない |
| 使い所 | 個人的な環境設定ファイルやメタデータ | プロジェクト全体の無視したいもの | 一時的または個人的なもの |
| 具体例 | `.DS_Store`, エディタの設定ファイル | `node_modules`, `.env`, `dist`フォルダ| デバッグ用の一時ファイル |


## ~/.config/git/ignoreを利用する場合

- 特徴
  - ユーザーのホームディレクトリに存在し、グローバルな設定として全てのリポジトリに適用されます。
  - ユーザーごとの設定なので、他の開発者には影響しません。
- 使い所
  - 個人的な開発環境に依存するファイルを無視したい場合
    - 例: 自分が利用しているエディタの設定ファイルなど
  - 全てのリポジトリで共通して無視したいファイルがある場合
    - 例: DS_Storeのようなメタデータファイル

:::note info
自分は`~/.gitignore_global`で同様の設定をしていたのですが、`~/.config/git/ignore`がデフォルトのようです。
https://zenn.dev/qnighy/articles/1a756f2857dc20

`~/.gitignore_global`で無視していたものを`~/.config/git/ignore`で管理し直す場合は、既存のcore.excludesfileの設定を削除する必要があります。

```bash
# 現在の設定を確認
git config --global --get core.excludesfile
# .gitignore_globalの場所が表示される

# 現在の設定を削除
git config --global --unset core.excludesfile

# 設定が削除されたことを確認
git config --global --get core.excludesfile
# 何も表示されなければ削除成功
```

これで`~/.config/git/ignore`の内容が反映されるようになります。


:::


## .gitignoreを利用する場合

- 特徴
  - リポジトリごとに存在し、プロジェクトのルートディレクトリに配置されます。
  - .gitignore自体はリポジトリにコミットされるため、他の開発者とも共有されます。  
- 使い所
  - プロジェクト全体で無視するファイルやディレクトリを指定したい場合
    - 例: envやnode_modulesやdistファイルなど
  - 無視する内容をチームで共有する必要がある場合

.gitignore自体はGit管理されます。
もし自分のメモ用のファイルを無視する場合、以下のように.gitignoreに追記するとそれが差分として現れてしまいます。

``` .gitignore
memo.txt
```
```diff
+ memo.txt
```

このように自分用のファイルを無視する際、
他の開発者に影響は与えたくないが、グローバルな設定にするほどではないという場合は次の方法が使えます。

## .git/info/excludeを利用する場合

- 特徴
  - 各リポジトリの.gitディレクトリの中に存在します。
  - .git/info/excludeはリポジトリにコミットされない他、他の開発者には影響しません。
- 使い所
  - 特定のリポジトリで一時的に無視したいファイルやディレクトリがある場合
  - ignoreする内容をチームで共有する必要がない場合

この方法であれば他の開発者に影響を与えることなく任意のファイルを無視することができます。

## 最後に

Gitでファイルを無視する方法はそれぞれ特徴と使い所があります。

個人的にどの方法にするかは以下の基準で考えています。
・プロジェクトに関係するもの → .gitignoreで管理
・個人の環境に関係するのもの → ~/.config/git/ignoreで管理
・そのプロジェクトに関係するもので自分にしか関係のないもの → .git/info/excludeで管理

以上、今回紹介した方法を活用して快適なGit運用に活かしていただけると幸いです。

## 参考
https://docs.github.com/ja/get-started/getting-started-with-git/ignoring-files

https://git-scm.com/docs/gitignore
【Prisma】npx prisma migrate dev実行時、「Can't reach database server at `localhost:3306`」というエラーを解決

# 環境

```
command                | version
--------------------------------------------------------------------------
wsl --version          | WSL バージョン: 2.2.4.0
docker --version       | Docker version 26.1.4, build 5650f9b
docker compose version | Docker Compose version v2.27.1-desktop.1
npm --version          | 10.7.0
node --version         | v20.15.0
mysql --version        | mysql  Ver 8.0.38 for Linux on x86_64
mysql -u root -p${PW}  | Server version: 8.0.38 MySQL Community Server
```

# エラー詳細

バックエンド用コンテナとDBコンテナを使用している。下記コマンドをバックエンド用コンテナから実行したとき、下記のエラーメッセージが表示された。

- エラーが発生したコマンド

```shell
npx prisma migrate dev --name init
```

- エラーメッセージ

```
root@9d2e635a5c67:/app# npx prisma migrate dev --name init
Environment variables loaded from .env
Prisma schema loaded from prisma/schema.prisma
Datasource "db": MySQL database "sample" at "localhost:3306"

Error: P1001: Can't reach database server at `localhost:3306`

Please make sure your database server is running at `localhost:3306`.
root@9d2e635a5c67:/app#
```

- prisma.schema

```prisma.schema
generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "mysql"
  url      = "mysql://root:root@localhost:3306/sample"
}

model User {
  id    Int    @id @default(autoincrement())
  name  String
  email String @unique
}
```

# 解決方法

- prisma.schema の URL を `localhost` ではなく docker-compose.yml に記載したサービス名とする

```diff:prisma.schema
generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "mysql"
-  url      = "mysql://root:root@localhost:3306/sample"
+  url      = "mysql://root:root@db:3306/sample"
}

model User {
  id    Int    @id @default(autoincrement())
  name  String
  email String @unique
}
```

```docker-compose.yml
...
...
services:
  db:
    build: ./db
    ports:
      - '3306:3306'
```

# 参考資料

https://github.com/prisma/prisma/discussions/21666#discussioncomment-8721583
【Laravel】softDeleteでリレーション先のレコードも削除したい

タイトルのとおりですが、今回は論理削除時の話です。
物理削除は記事最後の「番外」部分に書いております。

## やりたいこと
親テーブル => companies（会社）
子テーブル　=> postings（投稿）

例えば「A社」を削除したら、「A社」が登録している投稿も一緒に削除したい

## 結論

子テーブルのモデルに`withTrashed()`を加えるだけです。

app/Models/Posting.php
```php
// リレーション部分だけ抽出
public function company()
{
    return $this->belongsTo(Company::class)->withTrashed();
}
```
これでやりたいことが実現できます。
めちゃくちゃ便利ですね…

他にもModel内でbootメソッドを使用してやる方法もあるようですが、違いについてはまだ調べてないです…
もしわかったら別途記事にするかもしれません。

## 番外

ちなみに物理削除で同じことをしたい場合には、マイグレーションファイルの外部キーを設定する際に、以下のようにonDeleteなどを記述します。

```php
$table->foreignId('company_id')
    ->constrained()
    ->onUpdate('cascade')
    ->onDelete('cascade');
```

以上です。
CSV 連絡先を Android 携帯に転送する理由と最適なソリューション

<p>ユーザー、企業、その他のドメイン向けのアプリケーションでは、ファイル形式として CSV が広く使用されています。たとえば、Android ユーザーの多くは、電話の連絡先を CSV ファイルに保存しています。Samsung Galaxy S20、S10、S10+、S10e、またはその他の新しい Android スマートフォンを受け取った場合はどうなりますか? または、Android デバイスから誤って連絡先を消去しましたか? 連絡先は、PC など他の場所に保存されている CSV ファイルから Android デバイスにインポートする必要があります。では、CSV 連絡先を Android にインポートする最も速い方法は何でしょうか? この投稿には、優れた答えがあります。</p>
<h2><strong>Android への CSV 連絡先転送が必要な理由は何ですか?</strong></h2>
<p>CSV 連絡先を PC から Android フォンに転送する理由はいくつかあります。これは以前にも述べましたが、もう一度言及することが重要です。最も一般的な原因は次のとおりです。</p>
<ul>
    <li>ユーザーは、紛失を防ぐために定期的にコンピュータのデータをバックアップすることが予想されます。</li>
    <li>CSV は PC 上の連絡先の一般的なバックアップ ファイルであるため、誤ってスマートフォンで連絡先を消去したり紛失したりした場合に備えて、CSV 形式の連絡先を PC から Android スマートフォンにインポートできます。</li>
    <li>新しい Android スマートフォンに切り替える場合は、以前の Android スマートフォンから連絡先をインポートする必要があります。</li>
    <li>データの移動は、特にデータが多い場合は、誰もやりたくない作業です。</li>
</ul>
<h2><strong>CSV から vCard または VCF への自動変換</strong></h2>
<p><strong>Softaken Windows 用 </strong><a target="_blank" rel="noopener noreferrer" href="https://www.softaken.com/jp/csv-vcard"><strong>CSV から vCard へのコンバーター</strong></a> を使用すると、CSV ファイルを Android デバイスと互換性のある VCF 形式に簡単に変換できます。変換を完了するには、以下の手順を実行します。</p>
<ul>
    <li>ソフトウェアを Windows コンピューターにインストールすることが最初のステップです。</li>
    <li>インストール後、ソフトウェアを起動し、iPhone に送信する CSV ファイルを選択します。</li>
    <li>これにより、CSV ファイルの連絡先フィールドを完全に表示してマッピングし、必要に応じて開くことができます。</li>
    <li>マッピング オプションは、ウィザードの右上にあります。</li>
    <li>VCF ファイルを保存するには、出力フォルダーに移動します。</li>
    <li>変換プロセスを開始するには、出力場所を選択して [今すぐ変換] ボタンをクリックします。</li>
</ul>
<p><strong>すべての VCF ファイルを収集したら、USB コードまたは G ドライブを使用して、それらをコピーして Android スマートフォンの内部メモリに貼り付けます。</strong></p>
<ul>
    <li>Android デバイスで連絡先を追加します。</li>
    <li>Android ガジェットで連絡先アプリを開きます。</li>
    <li>画面の右上隅にある 3 つのドットのアイコンをクリックします。</li>
    <li>[設定] または [連絡先の管理] を選択します。</li>
    <li>次に、vCard ファイルをインポートするには、[連絡先のインポート/エクスポート] メニューで [インポート] &gt; [内部ストレージ] &gt; [電話] を選択します。</li>
    <li>Android デバイスに連絡先がインポートされます。</li>
    <li>別のモデルの Android スマートフォンでこの手順を実行すると、手順が少し変わる場合があります。</li>
</ul>
<h3><strong>Android 向けの無料 CSV 連絡先インポート戦略の評価</strong></h3>
<p>Gmail アカウントを利用して CSV 連絡先を Android モバイル デバイスに移動することは、2 番目の手法を利用するよりもはるかに便利なようです。CSV から Android への連絡先の直接インポートは、必要な手順が多いため時間がかかります。プログラムをダウンロードし、ファイルを何度もインポートおよびエクスポートする必要があります。少し奇妙に感じます。Gmail を使用している場合は、この方法で使用しないでください。</p>
<p>CSV 連絡先を Android にインポートする簡単で効果的な方法は、Gmail アカウントを使用することです。CSV 連絡先を Android デバイスにインポートするだけであれば、問題は簡単に解決できます。ただし、連絡先の詳細の変更など、一部のアクティビティはサポートされていません。この場合、追加のツールを使用する必要がある場合があります。</p>
<p>Android スマートフォンで連絡先をより柔軟に処理したり、Android 連絡先を CSV ファイルにエクスポートしたりするには、Softaken の CSV から VCF へのコンバーター ツールを使用します。このツールもはるかに信頼性が高くなっています。</p>
<p>PC では、Android 連絡先の追加、変更、削除もできます。 Android から PC に連絡先をエクスポートする場合でも、Android に連絡先をインポートする場合でも、ニーズを満たすことができます。これらの優れた品質は他に類を見ないものです。これらの戦術を皆さんにお伝えしたいと思います。CSV 連絡先を Android デバイスにインポートする際に問題が発生している場合は、これらの手順が非常に役立ちます。</p>
Juliaを起動したら，いつもすること...

Julia を起動するたびに実行する一連のプログラムや設定を指定するには、`startup.jl` ファイルを編集する方法があります。`startup.jl` は、Julia が起動する際に自動的に読み込まれるスクリプトファイルです。このファイルに必要な設定やプログラムを書いておくことで、毎回手動で設定する手間を省くことができます。

### 手順:

1. **`startup.jl` ファイルの場所:**
   - ファイルは通常、ユーザーのホームディレクトリの `.julia/config` フォルダ内にあります。フルパスは以下のようになります：
     - **Windows:** `C:\Users\<ユーザー名>\.julia\config\startup.jl`
     - **macOS/Linux:** `/Users/<ユーザー名>/.julia/config/startup.jl` または `/home/<ユーザー名>/.julia/config/startup.jl`

2. **ファイルが存在しない場合:**
   - `startup.jl` ファイルが存在しない場合は、新しく作成します。テキストエディタで以下のディレクトリにファイルを作成します。

3. **`startup.jl` ファイルに設定を記述:**
   - 例えば、毎回特定のパッケージを使用する場合やカスタム関数を定義したい場合は、以下のように記述します：
     ```julia
     # startup.jl

     # パッケージの使用
     using Pkg
     Pkg.activate("path/to/your/project")

     # よく使うパッケージのインポート
     using DataFrames
     using Plots

     # カスタム関数の定義
     function greet()
         println("Welcome to Julia!")
     end

     greet()
     ```

### 注意点:

- `startup.jl` ファイルに書かれたコードは、Julia を起動するたびに実行されるため、実行に時間がかかる重い処理や副作用があるコードは避けるべきです。
- 万が一 `startup.jl` に記述したコードにエラーがある場合、Julia の起動時にエラーメッセージが表示されることがあります。エラーを避けるために、事前にコードをテストしておくと良いでしょう。

これで、Julia を起動するたびに自動的に設定やプログラムを実行することができます。
テンソルの定義と例

## テンソル とは
データを表現するためのデータを表現するための数学的な構造。
テンソルは、スカラー（単一の数値）、ベクトル（一次元配列）、行列（二次元配列）を一般化したもので、多次元配列を表現できる。


### 定義と具体例
- 0次元テンソル

    - 単一の数値。いわゆるスカラー
    例：5とか30とか<br><br>
    
- 1次元テンソル
    - 一次元配列。つまりベクトル
    例：[1, 2, 3]とか<br><br>

- 2次元テンソル

    - 二次元配列。つまり行列
例：[[1, 2],
　　[3, 4]]<br><br>

- 高次元テンソル（3次元以上）:

    - 三次元以上の配列。
    例：　　[[[1, 2], [3, 4]],
    　　　　[[5, 6], [7, 8]]]

と、どんどん次元が増えていく......


## テンソルで表現されたデータ
### 1. 画像データのテンソル表現
画像データは通常、ピクセル値を格納する多次元テンソルとして表現される。
画像の各ピクセルは、明るさや色の情報を持っている。

- **グレースケール画像**
グレースケール画像は、各ピクセルが0から255までの強度を持つ単一の値で表現される。これは2次元テンソルで表される。<br>
例: 28x28ピクセルのグレースケール画像。このテンソルの形状は (高さ, 幅) 。
```
[
  [0, 25, 50, ..., 200],
  [30, 60, 90, ..., 210],
  ...
]
```



- **RGBカラー画像**
カラー画像は、各ピクセルが複数のチャネルを持つ多次元テンソルで表される。通常、RGB（赤、緑、青）の3つのチャネルがある。
例：28x28ピクセルのカラー画像。幅×高さ×3のテンソル
このテンソルの形状は (高さ, 幅, チャネル数) 。例では (28, 28, 3)。
```
[
  [[255, 0, 0], [128, 128, 128], [0, 255, 0], ..., [255, 255, 0]],  # 最初の行
  [[0, 0, 255], [64, 64, 64], [255, 0, 255], ..., [0, 255, 255]],  # 2行目
  ...
]
```
   
### 2. テキストデータのテンソル表現
テキストデータは、単語や文字を数値やベクトルに変換し、それをテンソルとして処理することが多い。言語モデルで出てくるパラメータ数とテンソルは全然別物なので注意。<br><br>

- **ワンホットエンコーディング**
各単語を語彙（ボキャブラリー）内のインデックスにマッピングし、ワンホットベクトルに変換する。
例: 「猫はかわいい」という文を ["猫", "は", "かわいい"] とし、語彙サイズが10の場合。このテンソルの形状は (単語数, 語彙サイズ)
```
[
  [1, 0, 0, 0, 0, 0, 0, 0, 0, 0],  # "猫"
  [0, 1, 0, 0, 0, 0, 0, 0, 0, 0],  # "は"
  [0, 0, 1, 0, 0, 0, 0, 0, 0, 0]   # "かわいい"
]
```
- **単語埋め込み（ワードエンベディング）**
各単語を固定次元のベクトルにマッピングする方法。埋め込み層を通じて、各単語は意味的に類似した単語と近くなるように配置される。
例: 「猫はかわいい」という文を3次元の埋め込みベクトルで表現。このテンソルの形状は (単語数, 埋め込み次元数) 。
```
[
  [0.1, 0.2, 0.3],  # "猫"
  [0.4, 0.5, 0.6],  # "は"
  [0.7, 0.8, 0.9]   # "かわいい"
]
```

- **シーケンスデータとしての表現**
RNNやTransformerなどのモデルで使用するために、テキストはシーケンスデータとして表現されます。各単語やトークンはインデックスで表され、それがバッチとしてテンソルに格納されます。
例: バッチ内の2つの文、「猫はかわいい」と「犬もかわいい」をインデックスで表現。このテンソルの形状は (バッチサイズ, シーケンス長) 。
```
[
  [1, 2, 3, 0],  # "猫はかわいい" （0はパディング）
  [4, 5, 3, 0]   # "犬もかわいい"
]
```



### 3. 音声データのテンソル表現
音声データはテンソルとして、次のような形で表現される。

- **時系列データとしての音声データ**
音声データは基本的に時系列データ。音声信号は、時間の関数として変化する連続的な振幅の変化を記録したもの。これをデジタル形式で扱うために、サンプリングレート（通常は1秒間にサンプリングする回数）で離散的なデータに変換する。<br><br>

- **1次元テンソルとしての表現**
最も単純な形式では、音声データは1次元のテンソル（ベクトル）として表現される。例えば、1秒間の音声を16kHzのサンプリングレートで記録した場合、その1秒間の音声は16,000個のサンプル値として表現される。
例：1秒間の音声信号を16kHzでサンプリングした場合
```
[0.1, 0.3, -0.2, 0.4, ..., -0.1]  # 長さ16,000の1次元テンソル
```

- **短時間フーリエ変換（STFT）による2次元テンソルとしての表現**
音声データを周波数領域で分析するために、短時間フーリエ変換（STFT）を適用する。これによって時間-周波数平面にマッピングされる2次元テンソルが得られる（スペクトログラム）。
例:　　このテンソルの形状は (時間窓数, 周波数ビン数)
```
[
  [1.2, 0.5, 0.1, ...],  # 時間t1における各周波数の強度
  [0.9, 0.4, 0.3, ...],  # 時間t2における各周波数の強度
  ...
]
```

- **メルスペクトログラムとしての表現**
人間の聴覚の特性に基づいて、周波数ビンをメル尺度に変換したメルスペクトログラムもよく使用される。これも2次元テンソル。
例:　　このテンソルの形状も (メル周波数ビン数, 時間窓数) 。
```
[
  [0.8, 0.6, 0.3, ...],  # メル周波数ビン1における各時間窓の強度
  [0.7, 0.5, 0.4, ...],  # メル周波数ビン2における各時間窓の強度
  ...
]
```

- **マルチチャネル音声データとしての表現**
ステレオ録音や複数のマイクを使用する場合、各チャネルごとにテンソルが存在し、それらをまとめて表現することもある。これにより、3次元テンソルが得られる。
例: ステレオ音声データを16kHzでサンプリングした場合
　このテンソルの形状は (チャネル数, サンプル数) 。
```
[
  [0.1, 0.3, -0.2, ..., -0.1],  # 左チャネルの1次元テンソル
  [0.2, 0.4, -0.1, ..., 0.0]    # 右チャネルの1次元テンソル
]
```

## まとめ
テンソルは構造の名前。
データをテンソルとして表現する方法は複数ある。
これらを使い分けて、さまざまなタスクを効果的に処理しよう💪
なぜパッケージ管理ツールを使わないのか? pipでの手動管理はもうやめよう

Pythonのパッケージ管理と言えば、まず思い浮かぶのはpipです。
pipは非常に強力なツールで、パッケージのインストールやアップデートをシンプルに行えます。
しかし、プロジェクトが大きくなるにつれて、依存関係の管理や仮想環境の維持が難しくなります。
そこで登場するのがパッケージ管理ツールです。
以下に、pip単体での管理と、PoetryやPipenv、Ryeのようなパッケージ管理ツールを使う場合の違いやメリットを挙げてみます。

## pip とパッケージ管理ツールを使った場合の違い

1. **依存関係の自動管理**:
   - **pip**: 依存関係の手動管理が必要です。複数のパッケージが異なるバージョンの同じライブラリを必要とする場合、手動で調整する必要があります。
   - **パッケージ管理ツール**: 依存関係を自動で解決してくれます。例えば、Poetryなら`poetry.lock`、Pipenvなら`Pipfile.lock`、Ryeなら`requirements.lock`を使って依存関係のバージョンを固定し、一貫性のある環境を維持し、開発メンバー間の環境、開発環境と本番環境などの環境で差異がうまれることを防ぎます。

2. **仮想環境の簡単な管理**:
   - **pip**: `venv`や`virtualenv`を使って仮想環境を手動で作成・管理する必要があります。
   - **パッケージ管理ツール**: 仮想環境の作成と管理が簡単にできます。

4. **ロックファイルの生成**:
   - **pip**: 手動でrequirementsファイルを作成し、更新する必要があります。
   - **パッケージ管理ツール**: 自動でロックファイルを生成・更新し、依存関係のバージョンを固定します。これにより、異なる環境間での一貫性を保つことができます。

5. **ビルドとパッケージング**:
   - **pip**: パッケージのビルドや公開は手動で行う必要があります。
   - **パッケージ管理ツール**: PoetryやRyeなどはビルドやパブリッシングの機能も持っており、一連の作業を簡単に行えます。

6. **統合されたフォーマッタとLinter**:
   - **pip**: フォーマッタやLinterは別途インストールし、設定する必要があります。
   - **パッケージ管理ツール**: Ryeはruffと統合されていて、フォーマッタやLinterもシームレスに利用できます。

7. **Pythonのバージョン管理**:
   - **pip**: Pythonのバージョン管理は手動で行う必要があります。例えば、pyenvを使って複数のPythonバージョンをインストールし、切り替える作業が必要です。
   - **パッケージ管理ツール**: PoetryやPipenv、Ryeは、プロジェクトごとにPythonのバージョンを指定でき、必要なバージョンを自動でインストールしてくれます。これにより、プロジェクト間でのバージョンの一貫性を保つことが容易になります。

8. **本番環境での動作保証**:
   - **pip**: ライブラリ管理がうまくできないと、開発環境で動いたものが本番環境で動かないという問題が発生することがあります。特に依存関係やバージョンの不一致が原因でトラブルになることが多いです。
   - **パッケージ管理ツール**: ロックファイルを使って依存関係のバージョンを固定することで、開発環境と本番環境の違いを最小限に抑えることができます。これにより、「本番環境で動かない」問題を防ぐことができます。

以上のように、パッケージ管理ツールを使うことで、依存関係の管理が楽になり、仮想環境の作成・管理も簡単になります。
また、プロジェクトの一貫性を保つためのロックファイルの自動生成やPythonのバージョン管理も大きなメリットです。
Pythonのプロジェクトを効率的に進めたいなら、これらのツールを活用するのが賢明です。

パッケージ管理ツールの比較については以下にまとめていますので、参考にしてください。

https://qiita.com/owayo/items/142ac770d1a007e764a9
Icebergとは何かについて理解していきたい

# 1.Data Cloud Summit 2024 にて Iceberg Table が GA された

結構大々的にData Cloud Summit2024にてGAの発表がありました。

私自身、Icebergを使ったことがないので、なんのこっちゃと思っていたので
実際に調べてみました。

Icebergを理解するためにはまず、データレイクハウスと言うものを理解しておく必要があります。

前段で先にまとめておくと
Icebergはデータレイクハウスを利用するために用いるもの。

データレイクハウスを使用するには、csvなどのファイルフォーマットだけでは使用できない。（スキーマ情報などが不足）

そこで、Icebergテーブルを用いて
データのスキーマ情報やパーティショニング情報を格納するもの。

そのデータレイクハウスの分析エンジンとして、
snowflakeと言うものがあります。

簡単に、説明しましたがここから細かく探っていきたいと思います。

# 2.データレイクハウスとは

これは聞いたことがある人いるかもしれません。
S3などに格納されている実物のデータをそのまま分析したい時に
使用します。

その際に、テーブルフォーマットを扱うことで、データ型だったり、パーティショニングを解析してくれます。

# 3.テーブルフォーマットとは

テーブルフォーマットというのは、あるデータセットが1つのテーブルとして表現できるように、ファイルの管理方式を定めます。

テーブルフォーマットはクエリ実行において、主に2つの大きな役割を果たしています。

1つ目は、どのファイルがテーブルのデータを構成しているかに答えることです。2つ目は、そのファイルがどのように読み書きできるかに答えることです。そのためには、パーティショニングやスキーマ定義など、メタデータの管理も必要になります。


データ自体はAvroやParquetなどの列思考データフォーマットで格納します。

IceBergが登場する前は

Delta Table / Hive format などが存在していました。

IceBurgは、テーブルフォーマットに仲間入りしたと言うことです。

# 3.1　なぜIcebergが優れているのか？

今前までデファクトスタンダードとなっていた
Hive Formatを例にしてみると、

テーブルの管理に使われるパーティションやスキーマなどのメタデータの変更、照会はHive Metastoreというサーバーを介して行われます。

Hive Metastoreのバックエンドでは、メタデータがRDBMS（Relational DataBase Management System）に保存されます。

そのため、クエリなどが多い場合
そのRDBMSにアクセスが集中してしまい、結果としてボトルネックになるという問題点がありました。

IceBergでは、テーブル情報がファイルによって管理されているため、Hive Metastoreと違いRDBMSがなく

個々別々のファイルで管理されているので、そのような問題が解消されたと言う例がありました。

https://logmi.jp/tech/articles/325336

# 4.IceaBergのアーキテクチャ

詳しく書くよりもこちらを参考にするとよさそうです。笑
自分もまだ全て見切れていないので、個人的に解釈完了したらまた記事にしたいと思います。


https://zenn.dev/kevinrobot34/articles/snowflake-iceberg-introduction
[Python]リスト内包表記について

## はじめに
こんにちは！
今回も、備忘録を兼ねて。

プログラミングをしていると、もっと効率的にコードを書きたくなることがあります。

Pythonのリスト内包表記は、そんなときに役に立つテクニックです。
forループを使った処理を、より短く読みやすく記述することができます。

それでは、基本から見ていきましょう。

## リスト内包表記の基本

リスト内包表記は、**新しいリストを作成** するための簡潔な方法です。
基本的な構文は以下の通りです。

```python
[式 for 変数 in イテラブルオブジェクト]
```

* **式:** 各要素に対して適用する式
* **変数:** イテラブルオブジェクトの各要素を格納する変数
* **イテラブルオブジェクト:** リストやタプルなど、要素を順番に取り出せるオブジェクト

簡単な例を見てみましょう。

```python
# 1から10までの数のリストを作成
numbers = [i for i in range(1, 11)]
print(numbers)  # 出力: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

# 文字列のリストから、各文字列の先頭を大文字にした新しいリストを作成
words = ["apple", "banana", "cherry"]
capitalized_words = [word.capitalize() for word in words]
print(capitalized_words)  # 出力: ['Apple', 'Banana', 'Cherry']
```

## 条件式を使ったリスト内包表記

リスト内包表記では、`if`文を使って要素を抽出したり、条件に応じて処理を分岐させたりすることができます。

### 条件に合う要素のみを抽出

```python
# 偶数のみを抽出
even_numbers = [i for i in range(1, 11) if i % 2 == 0]
print(even_numbers)  # 出力: [2, 4, 6, 8, 10]
```

### 条件に応じて異なる処理を実行

```python
# 偶数なら2倍、奇数なら3倍
numbers = [i * 2 if i % 2 == 0 else i * 3 for i in range(1, 6)]
print(numbers)  # 出力: [3, 4, 9, 8, 15]
```


## ネスト構造を使ったリスト内包表記

リスト内包表記はネストさせることも可能です。
例えば、二次元リストを作成する場合などに便利です。

```python
# 二次元リストを作成
matrix = [[i * j for j in range(1, 4)] for i in range(1, 4)]
print(matrix) 
# 出力: [[1, 2, 3], [2, 4, 6], [3, 6, 9]]
```

## リスト内包表記のメリット

### 簡潔なコード

forループに比べて、リスト内包表記を使うことでコードを簡潔に書くことができます。

### 処理の効率性

リスト内包表記は、forループに比べ、処理速度が速い場合があります。

## まとめ

今回は、Pythonのリスト内包表記について、基本から解説しました。

リスト内包表記を使いこなすことで、より簡潔で効率的なコードを書くことができます。

みなさんも一緒に頑張りましょう！
LeetCode挑戦日記：Day29

# はじめに

最近、業務で実装する時間よりも資料作成やレビューをする時間が多くなってきました。
このままでは自身のコーディング能力が落ちそうで怖いので、LeetCodeを始めてみました。

自身の学習の記録 & LeetCodeに興味のある人が挑戦しやすいように、記事に残していきます。
このような競技プログラミングをした経験がないので、ひよってEasyからやっていきます...

# [Medium] 2095. Delete the Middle Node of a Linked List

リンクリストの`head`が与えられたとき、中央のノードを削除し、修正されたリンクリストの`head`を返してください。

サイズ`n`のリンクリストの中央のノードは、0ベースのインデックスを使用して開始から`⌊n / 2⌋`番目のノードです。
ここで、`⌊x⌋`は`x`以下の最大の整数を表します。

例えば、`n`が`1`,`2`,`3`,`4`,`5`の場合、中央のノードはそれぞれ`0`,`1`,`1`,`2`,`2`番目のノードです。

## 素直に解いてみる

### 考え方

1. `n`を求める
1. `head[n/2 - 1].next`を`head[n/2 + 1]`にする

### コーディング

```typescript
function deleteMiddle(head: ListNode | null): ListNode | null {
    let length = 1;
    let node = head;
    while ((node !== null) && (node.next !== null)) {
        length++;
        node = node.next;
    }

    if ((length === 0) || (length === 1)) {
        return null;
    }

    const deleteNode = Math.floor(length / 2);

    let i = 0;
    node = head;
    while ((node !== null) && (node.next !== null)) {
        if (i === (deleteNode - 1)) {
            node.next = node.next.next ?? null;
            break;
        }
        node = node.next;
        i++;
    }

    return head;
};
```

### 結果

Runtime：580ms
Beats 77.56%

Memory：91.54MB
Beats 36.01%

## 他の人の解法

### 考え方

1. 1つずつリンクリストを辿る`slow`と2つずつリンクリストを辿る`fast`を用意
1. `fast`がリンクリストの最後に辿り着いたとき、`slow`を削除する

### コーディング

```typescript
function deleteMiddle(head: ListNode | null): ListNode | null {
    if (!head.next) return null;
    let slow = head;
    let fast = head;
    let prev = null;
    while (fast && fast.next) {
        prev = slow;
        slow = slow.next;
        fast = fast.next.next;
    }
    prev.next = slow.next;
    return head;
};
```
Monobrick完全に理解した

Monobrickの簡単な操作説明と機能の紹介です。~~Monobrickは起動もそこそこ早く、操作性もそこそこ悪くなくといったあまり決め手にならないOSな気がします。~~
メリットについてはこちらの記事をご覧ください。

https://qiita.com/SASNEWS/items/fca28cb057aeef07c727

# 操作説明
最初の最初は下の表を見ながら操作してみてください。
| 操作 | 動作 |
| - | - |
| 選択 | 上下 |
| 決定 | 中央 |
| 戻る | エスケープ |
| 入力 | 上下左右中央 |
| 強制終了 | エスケープ + 中央 長押し |

ボタンの数が6個しかないので、わからないときはすべて押してみて探ってください。

# サンプルプログラムを動かす
MonoBrickにはサンプルプログラムがいくつか用意されています。
「Programs」を選択すると、プログラムがリストになっています。
例として「MenuExample」を選択して、「Run program」を押すと実行されます。
EV3の画面でサンプルのメニュー表示がされると思います。

他のサンプルもプログラム名から予想がつく思うので、センサーを接続しつついろいろ実行してみると面白いです。
# 機能紹介
### Programs
サンプルプログラムと自分で書いたプログラムが置かれる場所です。
様々なプログラムを実行してみましょう。
### WiFi Connection
Wifiの設定ができます。接続方法するにはWifiドングルが必要です。

### Settings
設定ができますが、設定項目が少ないのであまり触ることはないと思います。

### Information
MonoBrickのバージョンが書いてあります。
ここでIPアドレスの確認ができます。

### Check for Updates
Wifiに接続している場合に限り、アップデートが確認できます。
もう更新されていないOSなので、アップデートは永遠とこないと思います。

### Shutdown
シャットダウンできます。

# 注意事項
実行されているプログラムを強制終了する手段がありません。
各プログラムの中に停止用のコードがないとプログラムが終了できないのです。
プログラムが停止できなくなったときは左上+中央を長押ししてOS自体を強制終了ください。
MySQL環境で論理削除をやってみる

# はじめに
論理削除を勉強したので備忘録も兼ねて本記事を作成しました。
DBからのデータの削除方法として、論理削除と物理削除があります。
本記事では論理削除がどういったものかMySQL環境でクエリを使用し実際に試しながら確認していきます。


# 論理削除とは？
論理削除とはDBからデータを完全に削除する代わりに、そのデータを `削除済み` とマークする削除方法の事。
データは削除しないのでDB上にデータは存在しますが、任意の削除フラグを用いて対象のデータは削除されているもの判断します。


:::note info

**物理削除とは？**：DBから完全にデータを削除するデータの復元が不可能な削除方法
:::


# メリデメ
- メリット：
 データの復元が容易なところ。DB上からデータを消していないので、データを復元し過去のデータを参照できる。

- デメリット：
物理削除しないためデータはDB上に残り続け、その分DBの容量を取ってしまうところ。また、データを取得する際に削除フラグをクエリに加える必要がでてくるため、クエリの複雑化が考えられます。


# 論理削除をやってみる

実際にMySQL環境でクエリを使ってデータの論理削除をやってみます。
DBのテーブルに削除フラグ( `is_deleted` )のカラムを設けたテーブルを作成してみます。
`is_deleted` が `1` または `true` の場合に削除済みとみなします。

```sql
-- 例: テーブル定義
CREATE TABLE users (
    id INT PRIMARY KEY,
    name VARCHAR(100),
    email VARCHAR(100),
    is_deleted BOOLEAN DEFAULT FALSE
);
```

INSERTでデータをいくつかテーブルに追加します。

```sql
INSERT INTO users (name, email) VALUES ('tarou', 'tarou@example~~');
INSERT INTO users (name, email) VALUES ('Bob', 'Bob@example~~');
INSERT INTO users (name, email) VALUES ('hogesan', 'hogesan@example~~');
```

**テーブルの状態**

| id | name    | email             | is_deleted |
|----|---------|-------------------|------------|
| 1  | tarou   | tarou@example~~   | FALSE      |
| 2  | Bob     | Bob@example~~     | FALSE      |
| 3  | hogesan | hogesan@example~~ | FALSE      |



`tarou`のデータだけis_deleted フラグを TRUE に設定し削除フラグを更新します。

```sql
UPDATE users SET is_deleted = TRUE WHERE name = 'tarou';
```
**テーブルの状態**

| id | name    | email             | is_deleted |
|----|---------|-------------------|------------|
| 1  | tarou   | tarou@example~~   | TRUE       |
| 2  | Bob     | Bob@example~~     | FALSE      |
| 3  | hogesan | hogesan@example~~ | FALSE      |


論理削除されたデータを確認します。
論理削除したデータを復元する際には、UPDATEで再度更新します。

```sql
SELECT * FROM users WHERE is_deleted = TRUE;
```

| id | name  | email           | is_deleted |
|----|-------|-----------------|------------|
| 1  | tarou | tarou@example~~ | TRUE       |

論理削除されていないデータを表示します。

```sql
SELECT * FROM users WHERE is_deleted = FALSE;
```

| id | name    | email             | is_deleted |
|----|---------|-------------------|------------|
| 2  | Bob     | Bob@example~~     | FALSE      |
| 3  | hogesan | hogesan@example~~ | FALSE      |


今回は削除フラグとしてTRUE、FALSEを使用しましたが、他にも削除フラグとしてデータを論理削除した日付を削除フラグとして記録するやり方もあるようです。
Python パッケージ管理ツール比較: Poetry vs Pipenv vs Rye

Pythonの開発環境を整えるうえで、パッケージ管理ツールの選択は非常に重要です。
今回は、3つのツール - Poetry、Pipenv、Ryeを比較してみます。

https://python-poetry.org/

https://pipenv.pypa.io/en/latest/

https://rye.astral.sh/

## 比較表

| 項目 | Poetry | Pipenv | Rye |
|------|--------|--------|-----|
| 実装言語 | Python | Python | Rust |
| 依存関係の管理 | ✅ | ✅ | ✅ |
| ビルドツール | ✅ (`poetry build`) | ❌ | ✅ (`rye build`) |
| ライブラリのアップデート | ✅ (`poetry update`) | ✅ (`pipenv update`) | ✅ (`rye sync --update-all`) |
| フォーマッタ | ❌ (外部ツール統合可) | ❌ (外部ツール統合可) | ✅ (ruffでの`rye fmt`) |
| Linter | ❌ (外部ツール統合可) | ❌ (外部ツール統合可) | ✅ (ruffでの`rye lint`) |
| 仮想環境管理 | ✅ | ✅ | ✅ |
| ロックファイル | `poetry.lock` | `Pipfile.lock` | `requirements.lock` |
| パッケージング | ✅ (`poetry build`) | ❌ | ✅ (`rye build`) |
| パブリッシング | ✅ (`poetry publish`) | ❌ | ✅ (`rye publish`) |
| ツール自身のアップデート | ✅ (`poetry self update`) | ✅ (`pip install --upgrade pipenv`) | ✅ (`rye self update`) |
| 最終リリース | 1.8.3 (2024-05-08) | 2023.9.1 (2023-09-01) | 0.35.0 (2024-06-24) |

## 詳細比較

### 実装言語

PoetryとPipenvはPythonで書かれていますが、Ryeは高速な実行を目指してRustで開発されています。

### 依存関係の管理

3つのツールすべてが依存関係の管理を行います。
Poetryは`pyproject.toml`ファイルを使用し、Pipenvは`Pipfile`を使用します。
Ryeも`pyproject.toml`を使用しますが、より柔軟な設定が可能です。

### ビルドツール

PoetryとRyeはパッケージのビルド機能を内蔵していますが、Pipenvにはこの機能がありません。
Poetryは`poetry build`コマンドを使用し、Ryeも`rye build`コマンドを提供します。

### ライブラリのアップデート

すべてのツールがライブラリのアップデート機能を提供しています。
Poetryは`poetry update`コマンドを使用し、Pipenvは`pipenv update`コマンド、Ryeは`rye sync`コマンドを持っています。

### フォーマッタとLinter

PoetryとPipenvは直接フォーマッタやLinterを内蔵していませんが、外部ツールとの統合が可能です。
一方、Ryeはruffによるフォーマッタ、Linterが標準で統合されています。

### その他の特徴

- 仮想環境管理：3つのツールすべてが仮想環境の管理が可能です。
- ロックファイル：依存関係の正確なバージョンを記録するためのロックファイルを生成します。
- パッケージング：PoetryとRyeはパッケージングとPyPIへの公開機能を提供しますが、Pipenvにはこの機能がありません。
- ツール自身のアップデート：3つのツールすべてが自身のアップデート機能を持っています。(pipenvのみpipでアップデート)
- 最終リリース日：Ryeは新しいツールということもあり開発が活発です。Poetryも定期的に更新されています。

## まとめ

どのツールが最適かは、プロジェクトのニーズや開発スタイルによって異なります。
Poetry、Ryeは依存関係管理からパッケージング、パブリッシングまで幅広くカバーしており、特にPyPIへの公開を考えている場合に便利です。
Pipenvはシンプルな依存関係管理と仮想環境の統合に強みがありますが、ビルドやパブリッシング機能はありません。

RyeはRustで書かれているため、高速な動作が期待でき、さらにフォーマッタやLinterの統合も魅力です。
[Python] 関数定義の基本と使い方

## はじめに
こんにちは！
今回も、備忘録を兼ねて。

Pythonでコードを書くとき、処理をまとめたり、再利用したりするために関数を使いますよね。
関数は、特定の処理に名前を付けたもので、必要な時に呼び出して使うことができます。

それでは、基本から見ていきましょう。

## 関数定義の基本

Pythonで関数を定義するには、`def`キーワードを使います。基本的な構文は以下の通り。

```python
def 関数名(引数1, 引数2, ...):
  """
  関数の説明（ドキュメンテーション文字列）
  """
  # 関数で行う処理
  
  return 戻り値 
```

* **関数名:** 関数に付ける名前。分かりやすい名前を付けましょう。
* **引数:** 関数に渡す値。複数の引数を指定する場合はカンマで区切ります。
* **ドキュメンテーション文字列:** 関数の説明を記述します。省略可能です。
* **処理:** 関数が行う処理を記述します。インデントを付けて記述します。
* **戻り値:** 関数の実行結果として返す値。`return`文で指定します。省略可能です。

簡単な関数定義の例を見てみましょう。

```python
def greet(name):
  """
  挨拶をする関数
  """
  print(f"こんにちは、{name}さん！")

greet("やました")  # 出力: こんにちは、やましたさん！
```

## 引数について

### 引数のデフォルト値

関数定義時に、引数にデフォルト値を設定しておくことができます。
デフォルト値が設定された引数は、関数呼び出し時に値が渡されかった場合に、デフォルト値が使用します。

```python
def greet(name="ゲスト"):
  """
  挨拶をする関数
  """
  print(f"こんにちは、{name}さん！")

greet()       # 出力: こんにちは、ゲストさん！
greet("やました")  # 出力: こんにちは、やましたさん！
```

### 可変長引数

関数定義時に引数の数を固定せずに、任意の数の引数を受け取れるようにしたい場合があります。
そのような場合には、アスタリスク（`*`）を使って可変長引数を定義します。

```python
def sum_all(*args):
  """
  すべての引数の和を返す関数
  """
  total = 0
  for num in args:
    total += num
  return total

print(sum_all(1, 2, 3))        # 出力: 6
print(sum_all(10, 20, 30, 40)) # 出力: 100
```

可変長引数はタプルとして扱われます。
タプルについては [こちら](https://qiita.com/yam_dev/items/d3385c39878c351d0320) を参照してください。

## 戻り値について

### 複数の値を返す

Pythonの関数は、複数の値を返すことができます。

```python
def calculate(x, y):
  """
  xとyの和と積を返す関数
  """
  sum_xy = x + y
  product_xy = x * y
  return sum_xy, product_xy

s, p = calculate(3, 4)
print(f"和: {s}, 積: {p}") # 出力: 和: 7, 積: 12
```

## 関数をより便利に使う

### lambda式を使った無名関数

簡単な処理を行う関数を、その場で定義したい場合には、`lambda`式を使うと便利です。`lambda`式を使うと、関数定義を1行で書くことができます。

```python
# lambda式を使った無名関数
square = lambda x: x ** 2 

print(square(5)) # 出力: 25
```

### 関数を引数として渡す

Pythonでは、関数を別の関数の引数として渡すことができます。

```python
def apply_operation(func, x, y):
  """
  渡された関数にxとyを引数として渡して実行する
  """
  result = func(x, y)
  return result

def add(x, y):
  return x + y

def multiply(x, y):
  return x * y

print(apply_operation(add, 3, 5))      # 出力: 8
print(apply_operation(multiply, 3, 5)) # 出力: 15
```

## まとめ

今回は、Pythonの関数の基本的な定義方法から、引数、戻り値、そして応用的な使い方まで解説しました。

私もまだまだ勉強中ですが、関数の使い方を理解し、より効率的な開発を行いましょう！
[Dify] v0.6.10以降ではメール送信失敗するようになったから調査した話



## はじめに

Difyをバージョン0.6.10へのアップデート後にメール送信機能が突然失敗するようになりました。この記事では、問題の発見から解決までの調査プロセスをここに残します。
Difyのメールの設定はこちらで残しています。

https://qiita.com/hudebakononaka/items/1885f3e38bfee8b93db8

## 問題の発見

Dify v0.6.10へのアップデート直後、それまで正常に機能していたメール送信機能が動作しなくなりました。エラーログを確認したところ、以下のエラーメッセージが表示されていました：

```
SSLError: [SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:1007)
```

このエラーは、SSL/TLS接続の確立に問題があることを示唆しています。

## エラーの分析

`WRONG_VERSION_NUMBER`エラーは通常、クライアントとサーバーが異なるプロトコルバージョンを使用しようとしている場合に発生します。具体的には：

1. クライアントがSSL/TLS接続を試みているのに対し、サーバーが非暗号化接続を期待している。
2. あるいは、クライアントとサーバーが互換性のないSSL/TLSバージョンを使用しようとしている。

このエラーは、接続方法が突然変更されたことをと推測できますね。

## 初期調査

1. SMTPサーバーの設定（ホスト、ポート、認証情報）が正しいことを再確認しました。
2. ネットワーク接続に問題がないことを確認しました。
3. ファイアウォールの設定に変更がないことを確認しました。

これらの基本的なチェックでは問題の原因が特定できませんでした。

## コードの詳細調査

問題の原因を特定するため、Dify v0.6.10のソースコードの変更点を調査しました。すると、`api/libs/smtp.py`ファイルに変更があることがわかりました。

### 変更の詳細（api/libs/smtp.py）:

```diff_python 
    def send(self, mail: dict):
        smtp = None
        try:
            smtp = smtplib.SMTP(self.server, self.port, timeout=10)
-           if self._use_tls:
-                smtp.starttls()
+           if self.use_tls:
+               if self.opportunistic_tls:
+                    smtp = smtplib.SMTP(self.server, self.port, timeout=10)
+                    smtp.starttls()
+                else:
+                   smtp = smtplib.SMTP_SSL(self.server, self.port, timeout=10)
+            else:
+                smtp = smtplib.SMTP(self.server, self.port, timeout=10)
            if self.username and self.password:
                smtp.login(self.username, self.password)
```

新しく `self.opportunistic_tls` というパラメータが導入されて、TLS使用時の接続ロジックに変更がありますね。


## 解決策


v0.6.9以前と同じような方法でメール送信を行う場合、`opportunistic_tls` パラメータを `True` に設定しないといけません。
これは環境変数で設定できるので以下に変更しておきましょう。

```
SMTP_OPPORTUNISTIC_TLS: 'true'
```


## 最後に
以下の時にうまくできる方法はわかっていないので知っている人がいれば教えて欲しいです。
```
SMTP_OPPORTUNISTIC_TLS: 'false'
```