デザイン

これらは UI/UXデザインを学ぶうえで世界的に有名なメディア・研究機関 です。
プロのデザイナーが情報収集で必ず利用するレベルの定番です。

🌎 1. UX Collective(Medium の UX専門コミュニティ)

何か?

世界最大クラスの UX デザインに関するオンラインマガジン

Medium(ミディアム)というプラットフォーム内で運営されている

世界中のデザイナーが記事を投稿するコミュニティ

特徴

実務寄りの UX/UI ノウハウが多い

ケーススタディ(事例研究)が豊富

ライターが多いため、色んな視点の記事を読める

こんな記事が多い

UI改善のBefore/After

デザインプロセスの解説

ユーザーテストのノウハウ

AI × UX デザインの最新動向

こんな人に向いてる
✔ 実務で使える UX 思考を学びたいデザイナー
✔ 海外の最新トレンドを知りたい人

📘 2. Smashing Magazine(UI/UX・Web制作の専門オンライン雑誌)

何か?

Webデザイン・フロントエンド開発・UI/UXの記事を専門に扱う国際オンラインメディア

“Webデザインの古参メディア”として信頼度が高い

特徴

デザインだけでなく HTML/CSS/JS の実装寄り情報も強い

accessibility (アクセシビリティ) の記事がめちゃくちゃ多く質が良い

無料で読めるけど、質がプロ仕様

こんな記事が多い

UI/UX デザインのベストプラクティス

CSSレイアウトの高度なテクニック

アクセシビリティの実装

デザインシステム運用の深い話

こんな人に向いてる
✔ デザインだけでなく実装も理解したい人
✔ プロレベルの知識をインプットしたい人

🧠 3. Nielsen Norman Group(NN/g:UX研究の世界最高権威)

何か?

世界で最も有名な UX 研究機関

Jakob Nielsen と Don Norman が設立(デザイン界のレジェンド二人)

UX の“基礎理論はほぼ全部ここが作った”

特徴

記事は科学的エビデンスに基づいている(実験・調査データが豊富)

UI/UX の原則や法則の「公式」みたいな存在

UXトレーニングや資格が世界で使われている

こんな記事が多い

ユーザビリティの原則(10 Usability Heuristics)

インタラクションの心理学

UIパターンの研究結果

認知心理学に基づく UX 分析

こんな人に向いてる
✔ UXの理論をしっかり理解したい
✔ プロのUXリサーチを学びたい

🎯 実務デザイナーがよく言う例え
名称 役割 例えるなら
UX Collective 実務で役立つ UX の記事まとめ 現場のデザイナーが集まる知見共有コミュニティ
Smashing Magazine デザインと実装の専門媒体 デザインとフロントの専門雑誌
Nielsen Norman Group(NN/g) UX理論の世界最高権威 UXの教科書、研究論文
📌 もしあなたが学習中なら、こう使うと最速で伸びます
▼ 初級:UX Collective

→ “今すぐ使える UI/UX の知識” を吸収できる

▼ 中級:Smashing Magazine

→ デザインシステム、アクセシビリティ、フロント知識を強化

▼ 上級:Nielsen Norman Group

→ 認知心理学とユーザビリティの深い理解

Viseme(ビズィーム)→口形状の対応表

**Viseme(ビズィーム)**とは、
発音される音(phoneme:フォニーム)に対応する “口の形” のセットのことです。
つまり、音素(あ・い・う・え・お、ba、fa など)をアニメで表現するための口形状の対応表です。

🔷 Viseme とは何か?
アニメーションや3Dキャラで**リップシンク(口パク)**を作るとき、
音声のすべての音素ごとに口形状を作るのは大変です。

そこで、多くの音をまとめて
👉 「この音はだいたいこういう口の形」
という分類をしたものが Viseme(視覚的音素) です。

🔷 具体例:Viseme の対応表(例)
英語圏で一般的な Viseme 例:

音(Phoneme) Viseme(口形状)例 説明
A, AA, AH A(あ型) 口を縦に開く
I, EE I(い型) 口を横に引く
U, OO U(う型) 唇を前に突き出す
F, V F 下唇を噛む
B, P, M Closed(閉じる) 唇を閉じる
S, Z, T, D S(す型) 歯を軽く見せる
O O(お型) 丸く開ける

VTuber や VRChat、Unity、Blender のリップシンクでよく使われます。

🔷 なぜ Viseme が必要なのか?
音声には数十〜100以上の音素がありますが、
見た目の口の形は10種類前後にまとめられるためです。

これにより:
✔ BlendShape の数が減る(制作が楽)
✔ 音声 → Viseme の変換が簡単
✔ リアルタイム処理が軽く、VTuber に向いている
✔ アニメーションが自然に見える

🔷 日本語の場合は?
日本語のリップシンクでは **5母音(あ・い・う・え・お)+閉じ口(ん・ま行)**が基本です。
例:

日本語音素 Viseme(口形状)
あ行 A
い行 I
う行 U
え行 E
お行 O
ま・ぱ・ば 口を閉じる(Close)
🔷 まとめ

Viseme = フォニーム(音素)を視覚的な“口形状”にまとめたもの
リップシンクで

「どの音に対してどの口形状を使うか」
を定義したのが Viseme 対応表 です。

CNN / RNN / Transformer の違い

以下では CNN / RNN / Transformer の違いを、
「何が得意で、どう動くのか」を中心に分かりやすくまとめます。

📌 3つのモデルの根本的な違い
モデル 仕組みの特徴 得意分野 苦手分野
CNN (Convolutional Neural Network) 画像の局所パターンを畳み込みで抽出 画像認識・特徴抽出 長距離関係(文脈の長期依存)
RNN (Recurrent Neural Network) 時系列を「1ステップずつ」処理 音声・時系列・短い文の生成 並列化が苦手、長距離依存が苦手(勾配消失)
Transformer Attentionで全要素を同時に見て関係を学ぶ 文章理解・生成・翻訳、画像生成 計算量がデカい(特に長い入力)
🔍 1. CNN:画像を理解するのが得意
▪ 特徴
畳み込み(Convolution) によって「周辺の局所的なパターン」を抽出する。
階層が深くなるほど「輪郭 → パーツ → 物体 → 構造」と抽象度が上がる。

▪ 得意なもの
画像分類
物体検出
セグメンテーション
画像の特徴抽出(Encoder)

▪ 弱点
長距離の関係が苦手
→ 画像の遠い部分の関係性を理解するのが難しい。

🔍 2. RNN:時系列を「順番に読む」
▪ 特徴
データを「前 → 次へ」連続的に処理する。
内部に“状態(メモリ)”を持ち、それを次のステップに渡しながら学習。
LSTM / GRU など改良版もある。

▪ 得意なもの
音声やセンサーなど“時間で並んだデータ”
短い文章の生成
時系列予測
▪ 弱点
並列化できない → 遅い
長距離依存の学習が苦手(勾配消失問題)
大規模言語モデルにはスケールしにくい

🔍 3. Transformer:Attentionで全体を見る
▪ 特徴
「入力の全部の位置が、全部の位置を注視できる」
→ Self-Attention(自己注意) で長距離依存を捉えるのが得意。
並列計算できるので 大規模化しやすい。
▪ 得意なもの
大規模言語モデル(GPT, BERT)
文章生成・翻訳
画像生成(拡散モデルの中や Vision Transformer)
音声生成

マルチモーダル(テキスト+画像など)
▪ 弱点
入力長に対して計算量が O(n²) と重くなりやすい
(最近は対策モデルも多い:Longformer、FlashAttention など)

🧠 たとえで説明すると…
■ CNN
近くのピクセルを見て「これは目だ」「これは毛だ」と特徴を抜き取るカメラのフィルター。

■ RNN
文章を一文字ずつ読み進める人。
前の単語を覚えているけど、長い文になると忘れがち。

■ Transformer

文章のすべての単語を並べて、一瞬で「どことどこが関係しているか」を分析できる人。

✔ まとめ
CNN → 画像の「局所パターン」を得意
RNN → 時系列を「順番に」処理
Transformer → Attentionで「全体の依存関係」を捉える
必要なら「数学的な違い」や「Attention の図解」、「各モデルのコード例(PyTorch)」も作れます!

[TTS] Tacotron2とは

🎤 Tacotron2とは?
Tacotron2 は Google が開発した「自然な音声を生成するTTSモデル」 で、
Neural TTS(ニューラルTTS)を大きく前進させた代表的な音声生成モデルです。

✔️ Tacotron2 の特徴(ざっくり)
テキスト → メルスペクトログラムを生成するモデル
WaveGlow / WaveRNN などの vocoder と組み合わせて音声に復元
人間の声に近い自然な抑揚(プロソディ)が得られる
End-to-End(前処理が少ない)

🎛 Tacotron2 の構造(これが最重要)
Tacotron2 は大きく 2つの部分 に分かれています。
① Acoustic Model(文章 → Melスペクトログラム)
② Vocoder(Melスペクトログラム → 音声波形)

① Acoustic Model(Tacotron2本体)
内部構造:
Encoder(文章を特徴ベクトルに変換)
テキストを文字単位でEmbedding
Convolution + LSTM
Attention(位置を揃える)
テキストとメルスペクトログラムの対応を学習
Location-Sensitive Attention で「読み飛ばし」を防止
Decoder(Melスペクトログラム生成)
RNNベース

1フレームずつメルスペクトログラムを生成
→ Tacotron2はテキストを“メル画像”に変換する装置

② Vocoder(WaveGlow / WaveRNN など)
Tacotron2はメルスペクトログラムまでしか作らないので、
これを波形に変えるのが Vocoder の役割。
有名な組み合わせ:
Acoustic Vocoder
Tacotron2 WaveGlow
Tacotron2 WaveRNN
Tacotron2 HiFi-GAN
🎧 Tacotron2 が使うメルスペクトログラムの特徴

80次元 Mel
22,050Hz サンプリング
対数変換(log-mel)
hop=256, win=1024
これらは ほぼすべての NeuraI TTS の標準仕様 になりました。

🔍 Tacotron2 がすごかった理由
✔️ 1. 文章のリズム(韻律)が自然
Attentionにより、
「どこを読んでいるか」を内部で推定することで
自然な抑揚を作れるようになった。

✔️ 2. End-to-Endなので音質が高い
従来:
形態素解析
音素列変換
音響モデル
デュレーションモデル
vocoder
→ Tacotron2は中間を自動学習

✔️ 3. WaveGlowと組み合わせて高品質な音声
従来のvocoder(Griffin-Lim等)は粗い音質だったが
WaveGlowで劇的に改善。

📘 Tacotron2 の処理フロー(図)
Text → Encoder → Attention → Decoder → Mel-spec
Mel-spec → Vocoder → Audio(WAV)

🧪 Pythonでの実行例(PyTorch)
※ NVIDIA の公式実装を利用した例
import torch
from tacotron2.model import Tacotron2
from denoiser import Denoiser

# モデル読み込み
checkpoint_path = “tacotron2_statedict.pt”
model = torch.load(checkpoint_path)[‘state_dict’]

# 入力テキスト
text = “こんにちは、これはTacotron2のテストです。”

# 1) テキスト → メルスペクトログラム
mel = tacotron2(text)

# 2) vocoder (WaveGlow)
audio = waveglow.infer(mel)

# 保存
torchaudio.save(“output.wav”, audio, 22050)

実際にはモデルファイルが必要ですが、
構造としてはこのように Mel → Audio の2段階です。

✔️ 要点まとめ
項目 内容
モデル名 Tacotron2
種類 Acoustic Model(テキスト→メル)
Vocoderが必要か 必要(WaveGlow等)
長所 抑揚が自然、高品質
短所 生成速度が遅い・Attentionの不安定性

[LLM] 推論コスト最適化

LLM(大規模言語モデル)の推論コスト最適化は、モデルの選択・技術的最適化・利用方法の工夫という複数の側面からアプローチできます。推論コストは主に使用するトークン数と計算リソース(GPUなど)の使用量に依存します。

主な最適化の手法は以下の通りです。
💡 モデルとアーキテクチャの最適化
1. 軽量なモデルの活用
モデルサイズの最適化:
より軽量なオープンソースLLMや、特定のタスクに特化した小規模なモデルを選択することで、必要な計算リソースとメモリ使用量を削減し、推論コストを大幅に抑えることができます。
蒸留(Knowledge Distillation):

**高性能な大規模モデル(教師モデル)の知識を、より小さなモデル(生徒モデル)**に転移させることで、高い性能を保ちつつ、推論コストを削減します。

2. 量子化(Quantization)
モデルのパラメータを表現するのに必要なビット数を減らす(例:32ビット浮動小数点数から8ビット整数へ)ことで、モデルのサイズを縮小し、メモリ帯域幅の要求を下げます。これにより、GPUメモリの使用量を削減し、推論の高速化とコスト削減につながります。

⚙️ 技術的な推論処理の最適化
3. KVキャッシュの最適化
トランスフォーマーモデルは、新しいトークンを生成するたびに、過去のトークンのKeyとValueを再計算する必要があります。これをメモリにキャッシュし再利用することで、計算コストを削減します。

Paged Attentionなどの技術でKVキャッシュのメモリ管理を効率化し、より大きなバッチサイズでの処理(スループット向上)を可能にします。

4. 推論インフラ・リソースの効率化
バッチ処理(Batching): 複数のリクエストをまとめて同時に処理することで、GPUの使用率を最大化し、全体のスループットを向上させます。

投機的デコーディング(Speculative Decoding): 小さくて高速なモデルで次のトークン候補を予測し、それを大規模モデルでまとめて検証することで、デコードのレイテンシ(応答時間)を大幅に短縮します。

GPUリソースの管理:

オンプレミスまたはクラウド(AWS, GCPなど)のGPUリソースについて、利用しない時間帯はインスタンスを停止するなど、使用状況に応じた適切なスケーリングを行うことで無駄なコストを削減します。

📝 利用方法・プロンプトの最適化
5. プロンプトの最適化
トークン使用量の削減:

LLM APIを利用する場合、入力・出力のトークン数が課金対象となるため、プロンプトを簡潔に保つことが直接的なコスト削減につながります。

短いプロンプトで適切な回答が得られるよう、プロンプトの設計を工夫します。

キャッシングの活用:
同じ質問や計算結果に対する過去の回答をキャッシュし、再利用することで、LLMへの不要なAPIリクエストや再計算を防ぎます。

6. RAG(検索拡張生成)の活用
RAGは、質問に関連する情報(ナレッジベースなど)を検索し、その情報をプロンプトに含めてLLMに入力する手法です。

これにより、LLMが大量の知識を記憶する必要がなくなり、軽量なモデルでも特定のタスクで高い精度を達成しやすくなります。

LLMの計算負荷を検索システムに分散させることで、結果的に推論コストを削減できます。

[LLM] Dify Pluginの作り方

# Difyプラグインのデプロイ方法

## デプロイ方法は3つあります

### 1. 🏪 Marketplaceから公開(公式配布)
### 2. 🔗 GitHubリポジトリから配布
### 3. 📦 ローカルファイルとして配布

## 前提条件

### Dify CLIツールのインストール

プラグインをパッケージ化するには、Dify CLIツールが必要です。

#### macOS/Linuxの場合(Homebrew)

“`bash
brew tap langgenius/dify
brew install dify

# インストール確認
dify version
“`

#### Windows/Linux/macOSの場合(バイナリ)

1. [Dify Plugin CLI Tool リリースページ](https://github.com/langgenius/dify-plugin-daemon/releases)からバイナリをダウンロード
2. ダウンロードしたファイルに実行権限を付与(macOS/Linux)

“`bash
chmod +x ./dify-plugin-darwin-arm64
mv ./dify-plugin-darwin-arm64 ./dify
“`

3. グローバルに使用する場合は `/usr/local/bin` に移動

“`bash
sudo mv ./dify /usr/local/bin/
“`

## 📦 ステップ1: プラグインのパッケージ化

プラグインプロジェクトのディレクトリで以下のコマンドを実行します:

“`bash
# プラグインディレクトリに移動
cd /path/to/your/plugin

# プラグインをパッケージ化
dify plugin package
“`

これにより、`.difypkg` ファイルが生成されます。
例: `weather_plugin-0.0.1.difypkg`

### パッケージング時の注意点

– `manifest.yaml` にバージョン情報が正しく記載されているか確認
– `requirements.txt` に必要な依存関係がすべて記載されているか確認
– プラグインコードにエラーがないか確認

## 🚀 ステップ2: デプロイ方法を選択

### 方法1: ローカルファイルとしてアップロード(最も簡単)

これが最も簡単で、開発・テスト段階に最適な方法です。

#### 手順:

1. **Difyの管理画面にアクセス**
– Difyプラットフォームにログイン
– 右上の「Plugins」をクリック

2. **プラグインをアップロード**
– 「+ Install plugin」ボタンをクリック
– 「INSTALL FROM」→「Local Package File」を選択
– 生成した `.difypkg` ファイルを選択してアップロード

3. **プラグインのインストール**
– アップロード後、自動的にインストールが開始されます
– インストールが完了すると、Workspaceで使用可能になります

#### メリット:
– ✅ 最も簡単で素早い
– ✅ レビュー不要
– ✅ 社内・チーム内での配布に最適
– ✅ テスト環境に最適

#### デメリット:
– ❌ ファイルを手動で配布する必要がある
– ❌ 一般公開されない

### 方法2: GitHubリポジトリから配布

オープンソースプロジェクトや、バージョン管理が必要な場合に推奨されます。

#### 手順:

1. **GitHubリポジトリを作成**

“`bash
# GitHubで新しいリポジトリを作成
# 例: https://github.com/your-username/dify-weather-plugin
“`

2. **プラグインコードをプッシュ**

“`bash
git init
git add .
git commit -m “Initial commit: Weather plugin”
git remote add origin https://github.com/your-username/dify-weather-plugin.git
git push -u origin main
“`

3. **GitHubリリースを作成**

“`bash
# パッケージ化
dify plugin package

# GitHubのUIでリリースを作成
# 1. GitHubリポジトリ → Releases → Create a new release
# 2. Tag: v0.0.1(manifest.yamlのバージョンと一致させる)
# 3. Title: Weather Plugin v0.0.1
# 4. .difypkg ファイルをアセットとしてアップロード
“`

4. **Difyからインストール**

– Dify管理画面 → Plugins → + Install plugin
– 「INSTALL FROM」→「GitHub」を選択
– リポジトリURL(またはリポジトリ名)を入力
– 例: `your-username/dify-weather-plugin`
– インストール実行

#### メリット:
– ✅ バージョン管理が容易
– ✅ オープンソース化できる
– ✅ GitHubのリリース機能を活用可能
– ✅ 公式レビュー不要

#### デメリット:
– ❌ リポジトリの作成とリリース手順が必要

### 方法3: Dify Marketplaceで公開(公式)

多くのユーザーに使ってもらいたい場合や、公式プラグインとして配布したい場合。

#### 手順:

1. **プラグインの準備**

“`bash
# プラグインをパッケージ化
dify plugin package
“`

2. **プライバシーポリシーの作成**

`PRIVACY.md` ファイルを作成し、プラグインのプライバシーポリシーを記載します。

“`markdown
# Weather Plugin Privacy Policy

## Data Collection
This plugin does not collect any personal information.

## External APIs
This plugin makes requests to weather APIs…
“`

3. **manifest.yaml にプライバシーポリシーへのパスを追加**

“`yaml
privacy:
en_US: ./PRIVACY.md
ja_JP: ./PRIVACY_JP.md
“`

4. **dify-pluginsリポジトリをフォーク**

“`bash
# GitHubでフォーク
https://github.com/langgenius/dify-plugins
“`

5. **プラグインを配置**

“`bash
# フォークしたリポジトリをクローン
git clone https://github.com/YOUR_USERNAME/dify-plugins.git
cd dify-plugins

# 組織ディレクトリとプラグインディレクトリを作成
mkdir -p your-organization/weather_plugin

# ソースコードと.difypkgファイルをコピー
cp /path/to/your/plugin/* your-organization/weather_plugin/
cp /path/to/weather_plugin-0.0.1.difypkg your-organization/weather_plugin/

# README.mdを作成(連絡先情報とリポジトリURLを含める)
“`

6. **Pull Requestを作成**

“`bash
git add .
git commit -m “Add Weather Plugin v0.0.1”
git push origin main

# GitHubでPull Requestを作成
# PRテンプレートに従って記入
“`

7. **レビュー待ち**

– Difyチームがコードレビューを実施
– 承認されるとmainブランチにマージ
– 自動的にMarketplaceに公開されます

#### メリット:
– ✅ 公式Marketplaceに掲載
– ✅ 信頼性が高い
– ✅ 多くのユーザーにリーチ可能
– ✅ ワンクリックインストール

#### デメリット:
– ❌ 公式レビューが必要(時間がかかる)
– ❌ プライバシーポリシーなど追加ドキュメントが必要

## 🔧 デバッグ方法(リモートデバッグ)

開発中は、リモートデバッグ機能を使うと便利です。

### 手順:

1. **Dify管理画面でデバッグキーを取得**

– Plugins → デバッグアイコンをクリック
– デバッグキーとリモートサーバーアドレスを取得

2. **プラグインプロジェクトで.envファイルを設定**

`.env.example` をコピーして `.env` を作成:

“`bash
cp .env.example .env
“`

`.env` ファイルを編集:

“`bash
INSTALL_METHOD=remote
REMOTE_INSTALL_HOST=debug.dify.ai # または localhost(Docker環境の場合)
REMOTE_INSTALL_PORT=5003
REMOTE_INSTALL_KEY=****-****-****-****-****
“`

3. **プラグインを起動**

“`bash
python -m main
“`

4. **リアルタイムでテスト**

– コードを編集
– 保存すると自動的に反映される
– Difyの管理画面でプラグインが使用可能になる

## 📝 更新・再デプロイ

### ローカルファイルの場合:

1. バージョン番号を更新(`manifest.yaml`)
2. 再度パッケージ化: `dify plugin package`
3. 新しい `.difypkg` をアップロード

### GitHubの場合:

1. バージョン番号を更新(`manifest.yaml`)
2. 再度パッケージ化: `dify plugin package`
3. 新しいGitHubリリースを作成
4. 新しい `.difypkg` をリリースに添付

### Marketplaceの場合:

1. バージョン番号を更新(`manifest.yaml`)
2. 再度パッケージ化: `dify plugin package`
3. 新しい `.difypkg` ファイルのみをPRとして提出
4. README.mdに破壊的変更を記載

## ⚠️ トラブルシューティング

### 署名検証エラーが出る場合

Marketplace以外のプラグインをインストールする場合、署名検証を無効化する必要があります。

Docker環境の場合、`.env` ファイルに追加:

“`bash
FORCE_VERIFYING_SIGNATURE=false
“`

### オフライン環境でのインストール

オフライン環境では、依存関係を含めた完全なパッケージを作成する必要があります。

“`bash
# dify-plugin-repackaging ツールを使用
git clone https://github.com/langgenius/dify-plugin-repackaging.git
cd dify-plugin-repackaging

# Python 3.12+をセットアップ
./plugin_repackaging.sh local ./your-plugin.difypkg

# 出力されたオフライン対応パッケージをインストール
“`

## 🎉 まとめ

**開発・テスト段階**: ローカルファイル または リモートデバッグ
**チーム内配布**: ローカルファイル
**オープンソース公開**: GitHub
**公式配布**: Marketplace

それぞれの用途に応じて、最適なデプロイ方法を選択してください!

手動でアップロードできるようになるのね。なるほど。

[デザイン] UIデザインパターン集

1. ナビゲーション(Navigation)
■ グローバルナビ(Top Navigation)
サイト全体のメインメニュー。
企業サイト・SaaS プロダクトで一般的。

■ サイドバー(Left Navigation)
情報量の多いサービス(管理画面、ダッシュボード)。
アイコン+ラベルが定番。

■ ハンバーガーメニュー(Hamburger Menu)
モバイルでメニューを隠すときの定番。
デスクトップでは避ける傾向が強い。

■ タブ(Tabs)
ページ切り替えやカテゴリ分けに利用。
水平タブ・垂直タブがある。

■ パンくずリスト(Breadcrumb)
ユーザーの現在地を示すために使う。

🔍 2. 検索・フィルタリング(Search & Filtering)
■ 検索バー(Search Bar)
オートコンプリート、検索候補などと組み合わせて UI が強化される。

■ 高度なフィルター(Advanced Filters)
EC、求人、管理画面で多用。
項目をアコーディオンで折りたたむのが一般的。

■ ソート(Sort)
並び替え:価格順、更新順など。

■ ファセットナビゲーション(Faceted Navigation)
ECサイトの定番。
複数の属性で絞り込む(価格・ブランド・サイズなど)。

📄 3. コンテンツ表示(Content Display)
■ カード(Card)
画像+タイトル+説明+ボタンの構成が一般的。
SNS・EC・ギャラリーで多用。

■ リスト(List)
テーブルより軽く、モバイルで定番。

■ テーブル(Data Table)
管理画面で最重要のUI。
ソート・フィルタ・ページネーションと組み合わせる。

■ グリッド(Grid)
写真、商品一覧、カテゴリ一覧など。

📝 4. 入力フォーム(Form Patterns)
■ ラベル+入力欄(Form Row)
横並び・縦並びの2パターン。

■ プレースホルダー入力(Floating Label / Placeholder)
マテリアルデザインに多い(入力時にラベルが浮き上がる)。

■ ステップフォーム(Step Form / Wizard)
入力内容が多いときにステップで分割。

■ バリデーション(Inline Validation)
入力中にリアルタイムでエラー表示。

⚠ 5. アラート・通知(Feedback)
■ トースト(Toast)
右上に一時表示される通知。
成功・エラー・警告など。

■ スナックバー(Snackbar)
画面下部に表示される短めの通知(モバイルによくある)。

■ モーダル(Modal)
重要な操作の確認などに使う。
頻用しすぎると UX が悪化。

■ バナー(Banner / Alert Bar)
ページ全体に関わるお知らせに使用。

💬 6. コミュニケーション(Messaging)
■ チャットUI(Chat Bubbles)
LINE・Messenger のような会話形式。

■ コメント欄(Comments)
SNS・ブログ・ナレッジツールなど。

🗃 7. データ可視化(Analytics / Dashboard)
■ カード型 KPI(Metric Cards)
数字+アイコン+前日比など。

■ チャート(Charts)
棒グラフ、折れ線、ドーナツ、ヒートマップなど。

■ テーブル+アクション(Data Table + Actions)
編集・削除・詳細などの操作がつく。

🎛 8. アクション(Actions)
■ プライマリーボタン(Primary Button)
最も重要なアクション。色で差別化。

■ セカンダリーボタン(Secondary)
補助的なアクション。

■ スピードダイヤル(Speed Dial / Floating Action Button)
モバイルで追加ボタンなどを浮かせて表示。

■ コンテキストメニュー(Context Menu)
右クリックや「…」メニュー。

🎚 9. 状態管理(States)
■ ローディング(Loading / Skeleton)
スケルトンやスピナーで読み込みを見せる。

■ エンプティステート(Empty State)
データがないときの説明+行動ボタン。

■ エラーステート(Error State)
404、500、フォームエラーなど。

🎨 10. ヒーローセクション(Hero Section)
LPやトップページの第一印象を作る。
タイトル・説明・CTA・ビジュアルの組み合わせ。

textToImageとdeeplearning

text-to-image(テキストから画像生成)では、Deep Learning が 文章の理解 → 画像の生成 までのすべての工程に使われています。代表的な仕組みを分かりやすくまとめます。

🌟 text-to-image における Deep Learning の使われ方
1. テキストを理解する(テキストエンコーダ)

入力された文章を数値ベクトルに変換するために Transformer(例:BERT、CLIP の Text Encoder) が使われます。

文章の「意味」や「スタイル」「関係性」を理解し、生成モデルに渡せる形にします。

2. 画像を生成する(拡散モデル or GAN など)

現在主流は 拡散モデル(Diffusion Models) です。

Stable Diffusion

DALL·E

Midjourney(内部構造は非公開だが拡散系と言われる)

📌 拡散モデルの流れ

ランダムノイズからスタート

「ノイズを少しずつ取り除いて画像に近づける」トレーニングを大量データで学習

テキストの意味を反映しながらノイズを除去して最終画像を生成

この「ノイズ除去」のステップを学習するのに Deep Learning(U-Net + Attention)が使われます。

3. テキストと画像を対応づける(クロスアテンション)

画像を作る時に
「文章のどの単語が、画像のどの部分に対応するか」
を学習する仕組みが必要です。

これに使われているのが Cross-Attention(クロスアテンション)

例:「a red cat sitting on a table」

“red”→猫の色

“cat”→動物の形

“table”→背景
といった対応を画像生成中に参照します。

4. 大規模データでの事前学習(Foundation Models)

text-to-image モデルは、
画像+キャプション(説明文) の巨大データセットで事前に学習されます。

これにより、

物体

スタイル

質感

写真の構図
などを深層学習が「理解」できるようになります。

🧠 全体構造まとめ
[テキスト] → Transformer(テキスト理解)
→ ベクトル
→ Diffusion Model(画像生成:U-Net + Cross-Attention)
→ [画像]

🔍 一言でまとめると

text-to-image は、
「テキスト理解 × ノイズから画像を作る技術 × アテンション」
を組み合わせた Deep Learning の応用です。

[Claude]契約リスク自動分析&要約ツール

"""
契約リスク自動分析&要約ツール - Webアプリケーション
Gradioを使用したユーザーインターフェース
"""

import gradio as gr
from contract_analyzer import ContractAnalyzer
import os
import json


def analyze_contract_pdf(pdf_file):
    """
    契約書PDFを分析する関数
    Args:
        pdf_file: アップロードされたPDFファイル
    Returns:
        分析結果のテキスト
    """
    if pdf_file is None:
        return "PDFファイルをアップロードしてください。"

    try:
        # 分析器を初期化(初回のみ時間がかかる)
        analyzer = ContractAnalyzer()

        # PDFファイルのパスを取得
        pdf_path = pdf_file.name

        # 契約書を分析
        result = analyzer.analyze_contract(pdf_path)

        # 平易な要約を生成
        summary = analyzer.generate_plain_summary(result)

        # 詳細情報をJSON形式で追加
        detailed_json = json.dumps(result, ensure_ascii=False, indent=2)

        # 結果を組み合わせて返す
        output = f"{summary}\n\n" + "="*50 + "\n"
        output += "\n【詳細情報(JSON形式)】\n"
        output += detailed_json

        return output

    except Exception as e:
        return f"エラーが発生しました: {str(e)}\n\n詳細: {type(e).__name__}"


def create_demo():
    """Gradioデモを作成"""

    with gr.Blocks(title="契約リスク自動分析ツール") as demo:
        gr.Markdown(
            """
            # 契約リスク自動分析&要約ツール

            ## 機能
            - **PDF契約書のアップロード**: 契約書PDFを簡単にアップロード
            - **AI自動分析**: Hugging Face LLMを使用して自動分析
            - **リスク抽出**: リスク条項を自動検出
            - **義務抽出**: 義務事項を明確化
            - **期限管理**: 重要な期限・納期を抽出
            - **平易な要約**: 専門用語を避けた分かりやすい説明

            ## 使い方
            1. 下のボックスに契約書PDF(日本語または英語)をアップロード
            2. 「分析開始」ボタンをクリック
            3. 数秒~数十秒で分析結果が表示されます

            **⚠️ 注意**: 初回実行時は、AIモデルのダウンロードに数分かかる場合があります。
            """
        )

        with gr.Row():
            with gr.Column():
                pdf_input = gr.File(
                    label="契約書PDF",
                    file_types=[".pdf"],
                    type="filepath"
                )
                analyze_btn = gr.Button("分析開始", variant="primary", size="lg")

            with gr.Column():
                output_text = gr.Textbox(
                    label="分析結果",
                    lines=30,
                    max_lines=50,
                    show_copy_button=True
                )

        # ボタンクリック時の処理
        analyze_btn.click(
            fn=analyze_contract_pdf,
            inputs=[pdf_input],
            outputs=[output_text]
        )

        gr.Markdown(
            """
            ---
            ### システム情報
            - **使用モデル**:
              - 要約: facebook/bart-large-cnn
              - テキスト生成: google/flan-t5-base
            - **処理時間**: 通常5〜30秒(モデル読み込み済みの場合)
            - **対応言語**: 日本語、英語

            ### ヒント
            - PDFのテキストが抽出可能である必要があります(画像のみのPDFは非対応)
            - より正確な分析のため、契約書は明瞭な文章で記載されている必要があります
            - 大きなファイルの場合、処理に時間がかかることがあります
            """
        )

    return demo


if __name__ == "__main__":
    print("契約リスク自動分析ツールを起動中...")
    print("ブラウザが自動的に開きます...")

    demo = create_demo()

    # アプリケーション起動
    demo.launch(
        share=False,  # 公開リンクを生成しない(ローカルのみ)
        server_name="0.0.0.0",  # すべてのネットワークインターフェースでリッスン
        server_port=7860,
        show_error=True
    )
"""
契約リスク自動分析ツール - コア機能
PDFから契約書を読み込み、Hugging Face LLMを使用してリスク分析を実行
"""

import PyPDF2
from typing import Dict, List
from transformers import pipeline
import re


class ContractAnalyzer:
    """契約書分析クラス"""

    def __init__(self, model_name: str = "facebook/bart-large-cnn"):
        """
        初期化
        Args:
            model_name: 使用するHugging Faceモデル名
        """
        print(f"モデルを読み込み中: {model_name}")
        # 要約用のパイプラインを初期化
        self.summarizer = pipeline("summarization", model=model_name)

        # テキスト生成用のパイプライン(リスク分析用)
        # より軽量なモデルを使用
        try:
            self.text_generator = pipeline(
                "text2text-generation",
                model="google/flan-t5-base"
            )
        except:
            # フォールバック: 要約モデルを使用
            self.text_generator = self.summarizer

    def extract_text_from_pdf(self, pdf_path: str) -> str:
        """
        PDFファイルからテキストを抽出
        Args:
            pdf_path: PDFファイルのパス
        Returns:
            抽出されたテキスト
        """
        try:
            with open(pdf_path, 'rb') as file:
                pdf_reader = PyPDF2.PdfReader(file)
                text = ""
                for page in pdf_reader.pages:
                    text += page.extract_text() + "\n"
                return text
        except Exception as e:
            raise Exception(f"PDF読み込みエラー: {str(e)}")

    def extract_risk_clauses(self, text: str) -> List[str]:
        """
        リスク条項を抽出
        Args:
            text: 契約書テキスト
        Returns:
            リスク条項のリスト
        """
        risk_keywords = [
            "損害賠償", "違約金", "解除", "終了", "責任", "義務",
            "禁止", "制限", "罰則", "ペナルティ", "補償",
            "liability", "penalty", "termination", "obligation",
            "prohibited", "restricted", "damages", "breach"
        ]

        # 文章を分割
        sentences = re.split(r'[。\.\n]', text)
        risk_clauses = []

        for sentence in sentences:
            sentence = sentence.strip()
            if not sentence:
                continue
            # リスクキーワードを含む文章を抽出
            if any(keyword in sentence.lower() for keyword in risk_keywords):
                risk_clauses.append(sentence)

        return risk_clauses

    def extract_obligations(self, text: str) -> List[str]:
        """
        義務条項を抽出
        Args:
            text: 契約書テキスト
        Returns:
            義務条項のリスト
        """
        obligation_patterns = [
            r"(甲|乙|当事者|受注者|発注者|契約者)(?:は|が).*(?:しなければならない|する義務|する責任)",
            r"shall\s+.*",
            r"must\s+.*",
            r"obligated to\s+.*"
        ]

        sentences = re.split(r'[。\.\n]', text)
        obligations = []

        for sentence in sentences:
            sentence = sentence.strip()
            if not sentence:
                continue
            for pattern in obligation_patterns:
                if re.search(pattern, sentence, re.IGNORECASE):
                    obligations.append(sentence)
                    break

        return obligations

    def extract_deadlines(self, text: str) -> List[str]:
        """
        期限・日付を抽出
        Args:
            text: 契約書テキスト
        Returns:
            期限に関する条項のリスト
        """
        deadline_patterns = [
            r"\d{4}年\d{1,2}月\d{1,2}日",
            r"\d{1,2}日以内",
            r"\d+(?:日|週間|ヶ月|年)(?:以内|前|後|まで)",
            r"期限|締切|納期|有効期限",
            r"\d{4}-\d{2}-\d{2}",
            r"within\s+\d+\s+(?:days|weeks|months|years)",
            r"deadline|due date|expiration"
        ]

        sentences = re.split(r'[。\.\n]', text)
        deadlines = []

        for sentence in sentences:
            sentence = sentence.strip()
            if not sentence:
                continue
            for pattern in deadline_patterns:
                if re.search(pattern, sentence, re.IGNORECASE):
                    deadlines.append(sentence)
                    break

        return deadlines

    def summarize_text(self, text: str, max_length: int = 150) -> str:
        """
        テキストを要約
        Args:
            text: 要約するテキスト
            max_length: 要約の最大長
        Returns:
            要約されたテキスト
        """
        if not text or len(text.strip()) == 0:
            return "(テキストが空です)"

        # テキストが短すぎる場合はそのまま返す
        if len(text) < 100:
            return text

        try:
            # 長すぎるテキストは分割
            chunk_size = 1024
            if len(text) > chunk_size:
                text = text[:chunk_size]

            summary = self.summarizer(
                text,
                max_length=max_length,
                min_length=30,
                do_sample=False
            )
            return summary[0]['summary_text']
        except Exception as e:
            # エラー時は先頭部分を返す
            return f"要約エラー: {str(e)}\n\n元のテキスト(抜粋):\n{text[:300]}..."

    def analyze_contract(self, pdf_path: str) -> Dict:
        """
        契約書を総合的に分析
        Args:
            pdf_path: PDFファイルのパス
        Returns:
            分析結果の辞書
        """
        print("PDF読み込み中...")
        text = self.extract_text_from_pdf(pdf_path)

        print("リスク条項を抽出中...")
        risk_clauses = self.extract_risk_clauses(text)

        print("義務条項を抽出中...")
        obligations = self.extract_obligations(text)

        print("期限情報を抽出中...")
        deadlines = self.extract_deadlines(text)

        print("要約を生成中...")
        # 全体の要約
        overall_summary = self.summarize_text(text[:2000], max_length=200)

        # リスク条項の要約(上位5件)
        risk_summary = []
        for clause in risk_clauses[:5]:
            try:
                summary = self.summarize_text(clause, max_length=100)
                risk_summary.append(summary)
            except:
                risk_summary.append(clause[:150] + "...")

        result = {
            "全体要約": overall_summary,
            "リスク条項": {
                "件数": len(risk_clauses),
                "主要なリスク": risk_clauses[:10],  # 上位10件
                "要約": risk_summary
            },
            "義務条項": {
                "件数": len(obligations),
                "主要な義務": obligations[:10]
            },
            "期限・納期": {
                "件数": len(deadlines),
                "主要な期限": deadlines[:10]
            },
            "リスクレベル": self._calculate_risk_level(
                len(risk_clauses),
                len(obligations),
                len(deadlines)
            )
        }

        return result

    def _calculate_risk_level(
        self,
        risk_count: int,
        obligation_count: int,
        deadline_count: int
    ) -> str:
        """
        リスクレベルを計算
        Args:
            risk_count: リスク条項数
            obligation_count: 義務条項数
            deadline_count: 期限条項数
        Returns:
            リスクレベル(高/中/低)
        """
        total_score = risk_count * 2 + obligation_count + deadline_count * 1.5

        if total_score > 50:
            return "高 - 詳細な法的レビューを推奨"
        elif total_score > 20:
            return "中 - 重要条項の確認を推奨"
        else:
            return "低 - 標準的な契約書"

    def generate_plain_summary(self, analysis_result: Dict) -> str:
        """
        平易な言葉で分析結果を要約
        Args:
            analysis_result: analyze_contractの結果
        Returns:
            平易な要約文
        """
        summary_lines = []
        summary_lines.append("=== 契約書分析結果 ===\n")

        summary_lines.append(f"【総合リスクレベル】{analysis_result['リスクレベル']}\n")

        summary_lines.append(f"\n【全体要約】\n{analysis_result['全体要約']}\n")

        summary_lines.append(f"\n【リスク条項】({analysis_result['リスク条項']['件数']}件検出)")
        if analysis_result['リスク条項']['主要なリスク']:
            summary_lines.append("主な注意点:")
            for i, risk in enumerate(analysis_result['リスク条項']['主要なリスク'][:5], 1):
                summary_lines.append(f"  {i}. {risk}")

        summary_lines.append(f"\n【義務事項】({analysis_result['義務条項']['件数']}件検出)")
        if analysis_result['義務条項']['主要な義務']:
            summary_lines.append("主な義務:")
            for i, obligation in enumerate(analysis_result['義務条項']['主要な義務'][:5], 1):
                summary_lines.append(f"  {i}. {obligation}")

        summary_lines.append(f"\n【期限・納期】({analysis_result['期限・納期']['件数']}件検出)")
        if analysis_result['期限・納期']['主要な期限']:
            summary_lines.append("重要な期限:")
            for i, deadline in enumerate(analysis_result['期限・納期']['主要な期限'][:5], 1):
                summary_lines.append(f"  {i}. {deadline}")

        return "\n".join(summary_lines)


if __name__ == "__main__":
    # テスト用
    analyzer = ContractAnalyzer()
    print("契約リスク分析ツールが初期化されました")
# 契約リスク自動分析&要約ツール - 必要パッケージ

# PDF処理
PyPDF2>=3.0.0

# Hugging Face Transformers(LLM)
transformers>=4.35.0
torch>=2.0.0
sentencepiece>=0.1.99

# Webインターフェース
gradio>=4.0.0

# データ処理
numpy>=1.24.0