[デザイン] 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

[LLM] Llama 3.1 × LoRA の流れ

Llama 3.1 × LoRA の流れ
ベースモデル読み込み(4bit量子化)
LoRA 設定(r=16 など)
指示データを用意(chat形式)
学習(300ステップくらい)
LoRA アダプタ保存(数十MB)
Base + LoRA で推論

これで 社内特化 LLM・商品説明特化 LLM・カスタマーサポート LLM

. 準備(必要なライブラリ)

Google Colab なら下記だけで準備OK:

!pip install transformers accelerate peft bitsandbytes datasets

2. ベースモデルを決める(例:Llama 3.1 8B)

軽くて実用的な LLama の OSS モデル:

meta-llama/Meta-Llama-3.1-8B

3. 学習データの形式

LoRA は「教師データ」が **指示形式(instruction format)」だと最も効果が出ます。

例:JSONL(1行1サンプル)
{“instruction”: “社内VPNの再接続方法を教えて”, “response”: “設定→ネットワーク→VPN→再接続ボタンを押すだけです。”}
{“instruction”: “見積書を再発行するには?”, “response”: “営業管理システムで案件番号を検索し、PDFを再生成できます。”}

例:ChatML 形式(最近はこちらが主流)
{
“messages”: [
{“role”: “user”, “content”: “返品の受付方法を教えて”},
{“role”: “assistant”, “content”: “返品受付画面で注文番号を入力し、ステータスを「返品受付」に変更します。”}
]
}

4. LoRA 設定(PEFT)
from peft import LoraConfig

lora_config = LoraConfig(
r=16, # Rank(一般的に 8 / 16)
lora_alpha=32,
lora_dropout=0.05,
bias=”none”,
task_type=”CAUSAL_LM”
)

5. モデル読み込み(4bit 量子化=QLoRA)

4bit QLoRA の標準書き方:

from transformers import AutoModelForCausalLM, AutoTokenizer
import torch

model_name = “meta-llama/Meta-Llama-3.1-8B”

model = AutoModelForCausalLM.from_pretrained(
model_name,
torch_dtype=torch.bfloat16,
quantization_config={“load_in_4bit”: True},
device_map=”auto”
)

tokenizer = AutoTokenizer.from_pretrained(model_name)
tokenizer.pad_token = tokenizer.eos_token

これで GPU 8GB でも Llama3.1-8B を微調整できる状態になります。

6. データセット読み込み
from datasets import load_dataset
dataset = load_dataset(“json”, data_files=”train.jsonl”)

7. 学習データの前処理(プロンプト生成)
def format_chat(example):
messages = example[“messages”]

text = tokenizer.apply_chat_template(
messages,
add_generation_prompt=False
)
return {“text”: text}

dataset = dataset.map(format_chat)

8. Trainer で LoRA 学習開始
from transformers import TrainingArguments, Trainer
from peft import get_peft_model

peft_model = get_peft_model(model, lora_config)

args = TrainingArguments(
output_dir=”llama-lora”,
per_device_train_batch_size=1,
gradient_accumulation_steps=16,
warmup_steps=10,
max_steps=300, # 100~500 で充分効果出る
learning_rate=2e-4,
fp16=True,
logging_steps=10,
save_steps=100,
)

def collate(batch):
return tokenizer(batch[“text”], padding=True, truncation=True, return_tensors=”pt”)

trainer = Trainer(
model=peft_model,
args=args,
train_dataset=dataset,
data_collator=collate
)

trainer.train()

9. 結果の保存(LoRA のみ数十 MB)
peft_model.save_pretrained(“lora-out”)

出力されるのは adapter_config.json / adapter_model.bin
→ 30〜100MB 程度で Llama 3.1 がカスタムモデルになります。

10. 推論(本番利用)
from peft import PeftModel

base = AutoModelForCausalLM.from_pretrained(model_name, device_map=”auto”)
model = PeftModel.from_pretrained(base, “lora-out”)

prompt = “社内VPNに接続できない時の対処方法は?”
inputs = tokenizer(prompt, return_tensors=”pt”).to(“cuda”)

output = model.generate(**inputs, max_new_tokens=200)
print(tokenizer.decode(output[0], skip_special_tokens=True))

[TTS] モデルのパラーメタファイルと設定ファイル

1. パラメータファイル (Model Checkpoint)
パラメータファイル(例:my_voice_model.pth)はバイナリデータなので中身をテキストで見ることはできませんが、概念的には以下のようなモデルの学習結果が数値の配列として格納されています。

項目概念的な内容役割
ジェネレーターの重み$W_G: [[0.12, -0.05, …], [0.99, 0.01, …], …]$音響特徴量から生の音声波形を生成するための数百万の数値。
エンコーダーの重み$W_E: [[-0.45, 0.22, …], [0.10, -0.87, …], …]$テキスト情報から音響特徴量を作り出すための数百万の数値。
話者埋め込みベクトル$V_{\text{speaker}}: [0.75, -0.11, 0.40, …]$このモデルが学習した**話者(声質)**を特徴づける固有の数値(声のDNAのようなもの)。

ポイント: このファイルは、提供された音声データとテキストの関係を学習したニューラルネットワークの脳そのものです。

2. 設定ファイル

"train": {
    "log_interval": 200,
    "eval_interval": 1000,
    "seed": 1234,
    "epochs": 1000
  },
  "data": {
    "training_files": "filelists/train.txt",
    "validation_files": "filelists/val.txt",
    "max_wav_value": 32768.0,
    "sampling_rate": 24000  // 💡重要:音声の品質(サンプリングレート)
  },
  "model": {
    "inter_channels": 192,
    "hidden_channels": 192,
    "filter_channels": 768,
    "n_heads": 2,
    "n_layers": 6,
    "kernel_size": 3,
    "p_dropout": 0.1,
    "gin_channels": 256, // 💡話者埋め込みベクトルの次元
    "style_channels": 128 // 💡Style-Bert-VITS2のスタイル特徴量の次元
  },
  "speakers": {
    "speaker01": 0,
    "speaker02": 1
  } // 💡話者IDとモデル内でのインデックスの対応
}

https://github.com/litagin02/Style-Bert-VITS2
config.jsonと.pthのセット
https://huggingface.co/RinneAi/Rinne_Style-Bert-VITS2

設定ファイル config.json モデルの構造、サンプリングレートなどの設計情報を定義するテキストファイル。
パラメータファイル Rinne.safetensors 学習によって得られた**モデルの重み(パラメータ)**を格納したファイル。従来の.pthに代わり、安全性の高い.safetensors形式が使われることが増えています。
スタイル情報 style_vectors.npy Style-Bert-VITS2特有の、声の**スタイル(話し方、感情など)**の特徴を格納したファイル。

これらのファイル3点セットをダウンロードし、Style-Bert-VITS2の実行環境に配置することで、テキストから指定した声(この場合は「Rinne」)で音声を合成できるようになります。

なるほど〜、

[3D] BlendShape

BlendShape(ブレンドシェイプ)とは、3Dキャラクターの表情や口の動きなどの“変形”を作るための仕組みです。
アニメーション制作やゲーム、VTuberの顔モデルなどで非常によく使われます。

🔷 BlendShape の基本的な考え方
1つの3Dモデルに対して、
笑顔
怒り顔
口を「あ」形に開ける
目を閉じる
など、**形が変化した複数のモデル(ターゲット形状)**を用意します。

そして、アニメーション中に
「元の形」+「ターゲット形状の混合量(0〜1)」
でモデルの形が変わる仕組みです。
例:
“Smile” ブレンドシェイプを 0 → 1 にすると、だんだん笑顔になる
“Mouth Open” を 0.5 にすると、口が半分開く

🔷 なぜBlensShapeが使われるのか?
自然な表情の作りやすさ
骨(ボーン)だけでは難しい細かな変形が可能
リアルタイムで軽い処理(ゲーム・VTuber向き)
複数の表情を混ぜられる(笑いながら目を閉じるなども簡単)

🔷 具体例:口のBlendShape
例えば「口」に関係するBlendShapeには:
A(あ)
I(い)
U(う)
E(え)
O(お)

口角上げ
口すぼめ
ニコッと笑う

などがあり、MMD・VTuber・ゲーム顔アニメで使われています。

🔷 まとめ
BlendShape=“複数の形を混ぜて表情や口の形を変える仕組み”
ボーンのアニメと違い、メッシュ自体が変形するので、細かい顔表現に最適です。

[デザイン] 基本原則

デザインの基本原則は、**誰でもデザインが上手に見えるための「土台」**になるルールです。
センスに依存しないので、エンジニアでも非デザイナーでも、これを理解すれば UI の質が一気に上がります。

ここでは「UIデザインで最も重要な5つ」に絞って、例つき・実践的に説明します。

🎨 デザインの基本原則(UIデザイン版)
1️⃣ コントラスト(Contrast)

「違いを強調してメリハリをつける」こと。

✔ 良い例

重要なボタンだけ濃い色

タイトルは太字、大きめ

背景が薄い → テキストは濃い

✘ 悪い例

背景#FFFFFF に #F5F5F5 の薄いグレー文字

ボタンの色が全部同じでクリック先が分からない

テキストの階層がどれも同じ大きさ

使い方(Figma)

文字の「大・中・小」の階層をつける

Primary ボタンはブランドカラーで統一

余白でもコントラストを作れる(→後述)

2️⃣ 整列(Alignment)

「要素の位置を揃える」こと。
UIの「高級感」と「プロっぽさ」は整列で決まると言っても過がありません。

✔ 良い例

テキスト左揃え

アイコンと文字の中央揃え

要素の開始位置が1列のガイドに沿っている

✘ 悪い例

テキストが微妙にズレている

ボタンの幅がバラバラ

カードの余白が整っていない

使い方(Figma)

Option + Click で整列ツール

Layout Grid を ON(8pt/4pt)

Auto Layout を使えばほぼズレない

3️⃣ 反復(Repetition)

「同じルールを繰り返す」こと。

✔ 良い例

ボタンの丸みは全て 8px

同じ色・フォントを繰り返す

カードUIのパターンを統一

✘ 悪い例

あるページだけボタンの角丸が違う

フォントが3種類以上ある

余白ルールがバラバラ

使い方(Figma)

Color Style / Text Style を使う

Auto Layout で間隔を固定(8/12/16 など)

Components と Variants で統一感を出す

4️⃣ 近接(Proximity)

「意味が近いものは近くに、違うものは離す」。

✔ 良い例

タイトルと説明文を近づける

セクションごとにまとまっている

ボタン → 前後の要素と十分な距離

✘ 悪い例

タイトルと関係ないテキストが近くにある

セクションの境目が分からない

使い方(Figma)

Auto Layout の「Padding / Gap」で距離を一定に

セクションごとに余白を大きくつける
→ 例:同じグループ「16px」、違うセクション「32px」

5️⃣ 余白(Whitespace)

「空間はデザインの一部」。
優れたデザインほど余白が広い。

✔ 良い例

ボタンの内側がしっかり余白

セクションの外側に大きな余白

縦の間隔を揃える(例:8/16/24)

✘ 悪い例

全部の要素がぎゅうぎゅう

見出しと本文が近すぎる

カードが狭くて読みにくい

使い方(Figma)

Auto Layout の「Padding」「Gap」を積極的に使う

余白にも階層を作る(例:8 → 小、16 → 中、32 → 大)

📘 これらを使って「良いUI」はこう作る
Before(悪い例)

フォントサイズが全部同じ

ボタンの色がバラバラ

余白が不揃い

テキストがズレている

After(良い例)

タイトル → 24px / Bold

本文 → 16px

ボタン → Primary Color

余白 → 16/32 で統一

整列 → Auto Layout + Grid

🎯 最重要ポイント(覚えるだけで UI が変わる)

1. 大事なものは大きく&濃く(コントラスト)
2. 全部きっちり揃える(整列)
3. 同じルールを繰り返す(反復)
4. 近い意味のものはくっつける(近接)
5. 迷ったら余白を増やす(Whitespace)

[iOS] Video Upload

import SwiftUI
import PhotosUI

struct ContentView: View {
    @State private var selectedItem: PhotosPickerItem?
    @State private var selectedImage: UIImage?
    @State private var selectedVideoURL: URL?

    var body: some View {
        VStack(spacing: 20) {

            // 選択 UI
            PhotosPicker(selection: $selectedItem,
                         matching: .any(of: [.images, .videos])) {
                Text("画像・動画を選択")
                    .padding()
                    .background(Color.blue)
                    .foregroundColor(.white)
                    .cornerRadius(8)
            }

            // 選択した画像があれば表示
            if let image = selectedImage {
                Image(uiImage: image)
                    .resizable()
                    .scaledToFit()
                    .frame(height: 200)
            }

            // 選択した動画の URL を表示
            if let url = selectedVideoURL {
                Text("動画URL: \(url.lastPathComponent)")
                    .font(.caption)
            }

            // アップロードボタン
            Button("アップロード") {
                upload()
            }
            .padding()
            .background(Color.green)
            .foregroundColor(.white)
            .cornerRadius(8)
        }
        .onChange(of: selectedItem) { newValue in
            Task {
                await loadSelectedItem()
            }
        }
        .padding()
    }

    // 画像 / 動画を読み込む
    func loadSelectedItem() async {
        guard let item = selectedItem else { return }

        // 画像読み込み
        if let data = try? await item.loadTransferable(type: Data.self),
           let image = UIImage(data: data) {
            self.selectedImage = image
            self.selectedVideoURL = nil
            return
        }

        // 動画読み込み
        if let url = try? await item.loadTransferable(type: URL.self) {
            self.selectedVideoURL = url
            self.selectedImage = nil
            return
        }
    }

    // アップロード処理
    func upload() {
        if let image = selectedImage {
            print("📤 画像アップロード: \(image)")
        }

        if let url = selectedVideoURL {
            print("📤 動画アップロード: \(url)")
        }
    }
}

VS codeでClaude Codeを使ってみる

Claude Codeにコードを生成させる
VS Codeの画面左側にあるClaudeアイコンをクリックして、Claude Codeのサイドバーを開きます。

サイドバー下部のチャット入力欄に、次のプロンプトを入力します。

「Pythonで、コンソールに ‘Hello World’ と出力するコードを書いてください。」

なるほど、こういうことか!