Search

2026/08/18

Docker nginx+CertbotでLet's Encrypt証明書を複数ドメイン1本に統合し、自動更新する方法

Docker nginx+CertbotでLet's Encrypt証明書を複数ドメイン1本に統合し、自動更新する方法



1:要約

Dockerでnginxを運用しているVPSで、Let's Encryptの証明書が複数作成され、 どの証明書をnginxが利用しているのか分かりにくくなっていました。 また、Certbotによる証明書更新も自動化されておらず、証明書の期限切れが発生していました。

そこで今回は、複数のドメイン・サブドメインを 1つのLet's Encrypt証明書に統合し、 Docker版Certbotとsystemd timerを使って自動更新する構成に整理します。

この記事では例として、以下の4ドメインを利用します。

example.com
www1.example.com
www2.example.com
www3.example.com

最終的な構成は次のようになります。

Let's Encrypt
       ↑
       │ HTTP-01認証
       │
Docker nginx
       │
       ├─ /.well-known/acme-challenge/
       │
       ↓
/srv/web/certbot/www

Docker Certbot
       │
       ├─ 証明書管理名:example.com
       │
       └─ 4ドメインを1証明書で管理
              │
              ↓
/srv/web/certbot/conf

systemd timer
       │
       ↓
docker run certbot renew
       │
       ↓
更新成功時のみ nginx reload

ポイントは、Ubuntu本体にCertbotを追加インストールせず、 公式のDocker版Certbotに統一することです。 Certbotを二重管理しないため、後から見ても構成が分かりやすくなります。

3:内容

3-1.今回の構成

nginxとCertbotはDockerで動かし、証明書データだけをVPS上の永続ディレクトリに保存します。

/srv/web/certbot/
├── conf/
│   ├── live/
│   ├── archive/
│   └── renewal/
│
└── www/
    └── .well-known/
        └── acme-challenge/

役割は次の通りです。

  • /srv/web/certbot/conf:証明書、秘密鍵、Certbotの更新設定
  • /srv/web/certbot/www:Let's EncryptのHTTP-01認証で使用

nginxコンテナとCertbotコンテナから同じディレクトリを見ることで、 nginxを停止せずに証明書を更新できます。

3-2.Let's Encrypt証明書を複数ドメインで1本にする

Let's Encryptでは、1枚の証明書に複数のDNS名を含めることができます。

今回は次の4ドメインを1枚にします。

example.com
www1.example.com
www2.example.com
www3.example.com

Certbot上の管理名も、分かりやすく example.com に統一します。

最終的には次のようになります。

Certificate Name: example.com

Identifiers:
  example.com
  www1.example.com
  www2.example.com
  www3.example.com

サブドメインごとに証明書を作る必要がなければ、 このようにまとめた方が管理対象を減らせます。

3-3.nginxとCertbotのディレクトリ共有

nginxには、例えば次のようにマウントします。

- /srv/web/certbot/conf:/etc/letsencrypt
- /srv/web/certbot/www:/var/www/certbot

実際のマウント状態は次のコマンドで確認できます。

docker inspect nginx \
  --format '{{range .Mounts}}{{println .Source " -> " .Destination}}{{end}}'

例えば次のようになっていればOKです。

/srv/web/certbot/www  -> /var/www/certbot
/srv/web/certbot/conf -> /etc/letsencrypt

3-4.ACME challenge用のnginx設定

Let's EncryptのHTTP-01認証では、 HTTPの80番ポートから特定のURLへアクセスできる必要があります。

server {
    listen 80;
    listen [::]:80;

    server_name
        example.com
        www1.example.com
        www2.example.com
        www3.example.com;

    location ^~ /.well-known/acme-challenge/ {
        root /var/www/certbot;
        try_files $uri =404;
    }

    location / {
        return 301 https://$host$request_uri;
    }
}

通常のHTTPアクセスはHTTPSへリダイレクトしますが、 /.well-known/acme-challenge/ だけはCertbot用にHTTPでアクセス可能にします。

3-5.ACME challengeの疎通確認

証明書発行前に、テストファイルを作成します。

sudo mkdir -p /srv/web/certbot/www/.well-known/acme-challenge

echo 'certbot-test' | sudo tee \
  /srv/web/certbot/www/.well-known/acme-challenge/test.txt

各ドメインから確認します。

curl http://example.com/.well-known/acme-challenge/test.txt
curl http://www1.example.com/.well-known/acme-challenge/test.txt
curl http://www2.example.com/.well-known/acme-challenge/test.txt
curl http://www3.example.com/.well-known/acme-challenge/test.txt

すべてで次の文字列が返れば正常です。

certbot-test

この確認を先に行っておくと、Certbot実行時の認証失敗をかなり減らせます。

3-6.4ドメイン入り証明書を発行する

公式Certbot Dockerイメージを使います。

docker run --rm \
  -v /srv/web/certbot/conf:/etc/letsencrypt \
  -v /srv/web/certbot/www:/var/www/certbot \
  certbot/certbot certonly \
  --webroot \
  -w /var/www/certbot \
  --cert-name example.com \
  -d example.com \
  -d www1.example.com \
  -d www2.example.com \
  -d www3.example.com

成功すると、証明書は次の場所に作成されます。

/etc/letsencrypt/live/example.com/fullchain.pem
/etc/letsencrypt/live/example.com/privkey.pem

実ファイルはVPS側の /srv/web/certbot/conf に保存されているため、Certbotコンテナを削除しても証明書は残ります。

証明書一覧は次のコマンドで確認できます。

docker run --rm \
  -v /srv/web/certbot/conf:/etc/letsencrypt \
  certbot/certbot certificates

3-7.nginxを新しい証明書へ切り替える

4つのHTTPS serverで同じ証明書を指定します。

ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

nginx設定を確認します。

docker exec nginx nginx -t

正常ならreloadします。

docker exec nginx nginx -s reload

実際に読み込まれている証明書設定も確認できます。

docker exec nginx nginx -T 2>/dev/null \
  | grep -E 'server_name|ssl_certificate'

HTTPS通信も確認します。

curl -I https://example.com
curl -I https://www1.example.com
curl -I https://www2.example.com
curl -I https://www3.example.com

HTTPステータスが200以外でも、アプリケーション側が400や302を返している場合があります。 重要なのはSSL証明書エラーが発生していないことです。

3-8.古い証明書を整理する

過去に複数の証明書を作っている場合、 livearchiverenewal に古い設定が残っていることがあります。

まず一覧を確認します。

docker run --rm \
  -v /srv/web/certbot/conf:/etc/letsencrypt \
  certbot/certbot certificates

nginxが古い証明書を参照していないことを確認してから、 Certbot管理下の不要な証明書を削除します。

docker run --rm \
  -v /srv/web/certbot/conf:/etc/letsencrypt \
  certbot/certbot delete \
  --cert-name 古い証明書名 \
  --non-interactive

/etc/letsencrypt/live配下を単純にrmするのは避けます。

Certbotは livearchiverenewal を連動して管理しているためです。

ただし、過去の作業で live が消えているのに archiverenewal/*.conf だけが残った壊れた設定では、手動整理が必要になる場合があります。

作業前にはバックアップを取っておくと安全です。

sudo tar -czf /root/letsencrypt-backup.tar.gz \
  /srv/web/certbot/conf

3-9.Certbotの自動更新テスト

自動化する前に、実際には証明書を更新しない --dry-run を実行します。

docker run --rm \
  -v /srv/web/certbot/conf:/etc/letsencrypt \
  -v /srv/web/certbot/www:/var/www/certbot \
  certbot/certbot renew \
  --dry-run

正常なら次のようなメッセージが表示されます。

Congratulations, all simulated renewals succeeded

ここまで成功してから自動実行を設定するのが安全です。

3-10.systemd timerでCertbotを自動実行する

Docker版Certbotは、コンテナ自身がcronのように常駐して定期実行する構成ではありません。

そこでUbuntu側のsystemd timerを使って、 定期的にDocker版Certbotを起動します。

まずserviceを作ります。

sudo tee /etc/systemd/system/certbot-docker-renew.service > /dev/null <<'EOF'
[Unit]
Description=Renew Let's Encrypt certificates with Docker Certbot
Requires=docker.service
After=docker.service network-online.target
Wants=network-online.target

[Service]
Type=oneshot
RuntimeDirectory=certbot-renew

ExecStartPre=/usr/bin/rm -f /run/certbot-renew/renewed

ExecStart=/usr/bin/docker run --rm \
  -v /srv/web/certbot/conf:/etc/letsencrypt \
  -v /srv/web/certbot/www:/var/www/certbot \
  -v /run/certbot-renew:/run/certbot-renew \
  certbot/certbot renew \
  --deploy-hook "touch /run/certbot-renew/renewed"

ExecStartPost=/bin/sh -c 'if [ -f /run/certbot-renew/renewed ]; then echo "Certificate renewed - reloading nginx"; /usr/bin/docker exec nginx nginx -s reload; else echo "No certificate renewal - nginx reload not required"; fi'
EOF

このserviceでは、証明書が実際に更新された場合だけ nginx -s reload を実行します。

次にtimerを作ります。

sudo tee /etc/systemd/system/certbot-docker-renew.timer > /dev/null <<'EOF'
[Unit]
Description=Run Docker Certbot renewal twice daily

[Timer]
OnCalendar=*-*-* 03,15:00:00
RandomizedDelaySec=30m
Persistent=true
Unit=certbot-docker-renew.service

[Install]
WantedBy=timers.target
EOF

systemdへ設定を読み込ませます。

sudo systemctl daemon-reload

timerを有効化して、その場で開始します。

sudo systemctl enable --now certbot-docker-renew.timer

この例では1日2回、3時台と15時台にCertbotが更新チェックを行います。

毎回証明書を発行するわけではありません。 certbot renew が更新期限を判断し、更新が必要な場合だけ証明書を更新します。

3-11.自動更新の状態を確認する

timerの状態を確認します。

systemctl status certbot-docker-renew.timer --no-pager

次回実行時刻はこちらです。

systemctl list-timers --all | grep certbot

有効化状態も確認できます。

systemctl is-enabled certbot-docker-renew.timer
systemctl is-active certbot-docker-renew.timer

正常なら次のようになります。

enabled
active

timerを待たずにserviceだけ手動実行することもできます。

sudo systemctl start certbot-docker-renew.service

実行ログを確認します。

sudo journalctl \
  -u certbot-docker-renew.service \
  -n 100 \
  --no-pager

証明書を取得したばかりの場合は更新されないため、 次のような内容になるのが正常です。

Certificate not yet due for renewal
No certificate renewal - nginx reload not required

3-12.省保守化のポイント

今回の構成で重要なのは、Certbotや証明書の管理方法をできるだけ増やさないことです。

最終的には次の状態を目指します。

証明書
└─ example.com
   ├─ example.com
   ├─ www1.example.com
   ├─ www2.example.com
   └─ www3.example.com

Certbot
└─ Docker版のみ

認証方式
└─ webroot

定期実行
└─ systemd timer

Webサーバー
└─ Docker nginx

Ubuntuへ別のCertbotをインストールすると、 「OS版Certbot」と「Docker版Certbot」の2系統が存在することになります。

特別な理由がなければ、今回のようにDocker版Certbotだけに統一した方が、 数か月後に設定を見直したときにも理解しやすくなります。

また、証明書をサブドメインごとに分割すると、 renewal設定、証明書ファイル、期限確認対象も増えます。

同じサーバーで利用していて、同じタイミングで更新して問題ないドメインなら、 1枚の証明書へまとめることで保守対象を減らせます。

最終チェック用コマンド

# 証明書一覧
docker run --rm \
  -v /srv/web/certbot/conf:/etc/letsencrypt \
  certbot/certbot certificates

# 更新シミュレーション
docker run --rm \
  -v /srv/web/certbot/conf:/etc/letsencrypt \
  -v /srv/web/certbot/www:/var/www/certbot \
  certbot/certbot renew --dry-run

# nginxが使用している証明書
docker exec nginx nginx -T 2>/dev/null \
  | grep -E 'server_name|ssl_certificate'

# timer確認
systemctl list-timers --all | grep certbot

# 更新ログ
sudo journalctl \
  -u certbot-docker-renew.service \
  -n 100 \
  --no-pager

この構成にしておけば、通常の運用ではCertbotを手動で操作する必要はほとんどなく、 systemd timerが定期チェックし、必要なタイミングで証明書を更新できます。

2026/08/17

dockerとは起動失敗なく仮想環境を複数で作って、それぞれ繋げて便利に使うもの

docker使っているけど簡単に説明すると何?
起動するときに余計なこと考えずに失敗しなくて、
それぞれの仮想環境を複数で作って、
それぞれ繋げて便利に使うもの
みたいな感じ。(てきとう)

その分、必要なファイル容量は大きくなるし、
管理することも増えるよ
みたいなことも。(当てずっぽう)

調べたりAIにまとめてもらったものの備忘録です。


DockerでLaravelを動かす仕組み――nginx・PHP・PostgreSQL・Portainer・WUDの関係

Ubuntu VPS上でLaravelのWebアプリ、データベース、Docker管理画面、更新確認ツールを動かす構成を初心者向けに整理します。Laravelは通常のブラウザから利用でき、PortainerとWUDは管理者だけがブラウザで開ける構成です。

1. 全体構成

インターネット上のブラウザ
        │ HTTP / HTTPS
        ▼
Ubuntu VPS
└─ Docker Engine
   ├─ nginxコンテナ ─────── 公開窓口
   │        │ FastCGI
   │        ▼
   ├─ PHP-FPMコンテナ ──── Laravelを実行
   │        │
   │        ▼
   ├─ PostgreSQLコンテナ ─ データを保存
   ├─ Portainerコンテナ ── Docker管理画面
   └─ WUDコンテナ ─────── イメージ更新を確認

Docker Engineは1つだけです。nginx、PHP-FPM、PostgreSQL、Portainer、WUDは、同じDocker Engine上で動く別々のコンテナです。LaravelはPHP-FPMコンテナ内で実行されるアプリケーションです。

2. 各コンテナの役割

要素役割外部公開
nginxブラウザからのアクセスを受け、PHP処理をPHP-FPMへ渡す80・443番
PHP-FPMPHPを実行し、Laravelの処理結果をnginxへ返す公開しない
Laravel画面表示、ログイン、検索、データ処理などWebアプリ本体nginx経由
PostgreSQLLaravelが使うデータベース公開しない
Portainer CEDockerをGUIで確認・管理するlocalhostのみ
WUDDockerイメージの更新を検出するlocalhostのみ

3. ブラウザからアクセスする流れ

  1. ブラウザでLaravel用ドメインを開く
  2. VPSの80番または443番へ接続する
  3. nginxがリクエストを受ける
  4. PHP処理をPHP-FPMへ渡す
  5. Laravelが必要に応じてPostgreSQLへ接続する
  6. 処理結果がnginx経由でブラウザへ戻る
https://example.com
        ↓
VPSの443番
        ↓
nginx
        ↓
php:9000
        ↓
Laravel
        ↓
postgres:5432
ブラウザアクセスは可能です。 外部へ公開するのはnginxの80・443番だけです。PHPの9000番とPostgreSQLの5432番はDocker内部だけで利用します。

4. コンテナ同士の通信

同じDockerネットワークに接続したコンテナは、Composeのサービス名で通信できます。

  • nginxからPHPへ:php:9000
  • LaravelからPostgreSQLへ:postgres:5432

LaravelのDB_HOSTにはpostgresを指定します。PHPコンテナ内のlocalhostはPHPコンテナ自身を意味するためです。

5. 推奨ディレクトリ構成

/srv/
├─ laravel-app/
│  ├─ compose.yml
│  ├─ .env
│  ├─ docker/
│  │  ├─ nginx/default.conf
│  │  └─ php/Dockerfile
│  └─ src/
│     ├─ artisan
│     ├─ app/
│     ├─ public/
│     └─ storage/
└─ docker-management/
   └─ compose.yml

Laravel側と管理ツール側を別のComposeプロジェクトに分けます。それぞれでdocker compose up -dを実行すると、同じDocker Engine上へ追加されます。

6. Laravel側のCompose例

/srv/laravel-app/compose.ymlの基本例です。

name: laravel-app

services:
  nginx:
    image: nginx:alpine
    container_name: laravel-nginx
    restart: unless-stopped
    ports:
      - "80:80"
    volumes:
      - ./src:/var/www/html:ro
      - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
    depends_on:
      - php
    networks:
      - app-network

  php:
    build:
      context: ./docker/php
    container_name: laravel-php
    restart: unless-stopped
    working_dir: /var/www/html
    volumes:
      - ./src:/var/www/html
    environment:
      APP_ENV: production
      DB_CONNECTION: pgsql
      DB_HOST: postgres
      DB_PORT: 5432
      DB_DATABASE: laravel
      DB_USERNAME: laravel
      DB_PASSWORD: ${DB_PASSWORD}
    depends_on:
      postgres:
        condition: service_healthy
    networks:
      - app-network

  postgres:
    image: postgres:16-alpine
    container_name: laravel-postgres
    restart: unless-stopped
    environment:
      POSTGRES_DB: laravel
      POSTGRES_USER: laravel
      POSTGRES_PASSWORD: ${DB_PASSWORD}
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U laravel -d laravel"]
      interval: 10s
      timeout: 5s
      retries: 5
    networks:
      - app-network

volumes:
  postgres_data:

networks:
  app-network:

PostgreSQLにはportsを書いていないため、VPS外部から5432番へ直接接続できません。Composeと同じディレクトリの.envには、DB_PASSWORD=長いランダムなパスワードを設定します。

7. Portainer・WUD側のCompose例

/srv/docker-management/compose.ymlの例です。

name: docker-management

services:
  portainer:
    image: portainer/portainer-ce:2.39.6
    container_name: portainer
    restart: unless-stopped
    ports:
      - "127.0.0.1:9443:9443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - portainer_data:/data

  wud:
    image: getwud/wud:8.3.1
    container_name: wud
    restart: unless-stopped
    ports:
      - "127.0.0.1:3000:3000"
    environment:
      TZ: Asia/Tokyo
      WUD_WATCHER_LOCAL_CRON: "0 6 * * *"
      WUD_WATCHER_LOCAL_WATCHBYDEFAULT: "true"
      WUD_WATCHER_LOCAL_WATCHEVENTS: "false"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - wud_data:/store

volumes:
  portainer_data:
  wud_data:

PortainerとWUDはVPSの127.0.0.1だけに公開します。インターネットから直接は開けません。

8. nginx設定例

/srv/laravel-app/docker/nginx/default.confの基本例です。

server {
    listen 80;
    server_name example.com;
    root /var/www/html/public;
    index index.php index.html;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        include fastcgi_params;
        fastcgi_pass php:9000;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }

    location ~ /\.ht {
        deny all;
    }
}

fastcgi_pass php:9000;により、PHP処理をphpサービスへ渡します。

これはHTTPの基本例です。本番公開ではドメインを設定し、Let's EncryptなどでHTTPS化してください。

9. 起動方法

Laravel側

cd /srv/laravel-app
docker compose config
docker compose build
docker compose up -d
docker compose ps

管理ツール側

cd /srv/docker-management
docker compose config
docker compose pull
docker compose up -d
docker compose ps

全体は次で確認できます。

docker ps
docker compose ls

10. 管理画面へのブラウザアクセス

WindowsのPowerShellからSSHトンネルを開きます。

ssh -L 9443:127.0.0.1:9443 -L 3000:127.0.0.1:3000 ユーザー名@VPSのIPアドレス

SSH接続を開いたまま、ブラウザで次を開きます。

  • Laravel:https://取得したドメイン
  • Portainer:https://localhost:9443
  • WUD:http://localhost:3000

Laravelは一般利用者向けに公開し、PortainerとWUDはSSH接続できる管理者だけが利用します。

11. 更新とデータ管理

対象管理方法更新方法
UbuntuAPTセキュリティ更新は自動、通常更新は手動
Docker EngineAPTメンテナンス時間に手動
nginx・PHP・PostgreSQLWUDで検出Composeから手動
LaravelGitなどコード配備、Composer、マイグレーション
コンテナの状態Portainerログと稼働状態を確認
cd /srv/laravel-app
docker compose pull
docker compose build --pull php
docker compose up -d
docker compose ps
docker compose logs --tail 100

PostgreSQLデータはpostgres_dataボリューム、Portainer設定はportainer_data、WUD履歴はwud_dataに保存されます。

PostgreSQLの16から17のようなメジャーバージョン変更は単純なイメージ更新ではありません。事前バックアップとデータ移行が必要です。また、docker compose down -vはボリュームを削除するため、通常は使いません。

主な確認コマンド

docker ps
docker compose ls
docker system df
df -h /

cd /srv/laravel-app
docker compose logs --tail 100 nginx
docker compose logs --tail 100 php
docker compose logs --tail 100 postgres
docker exec laravel-nginx nginx -t
docker compose exec php php artisan about

12. まとめ

  • nginxがブラウザからのアクセスを受ける
  • PHP-FPMがLaravelを実行する
  • LaravelがPostgreSQLへデータを保存する
  • PortainerがDocker全体をGUIで見えるようにする
  • WUDがコンテナイメージの更新を確認する

Laravelはドメインから通常のブラウザで利用できます。PortainerとWUDはlocalhostだけに公開し、SSHトンネル経由でブラウザ表示します。これにより、Webアプリの公開とDocker管理画面の保護を両立できます。

Dockerでは、稼働中のコンテナを直接作り込むより、Composeファイル、Dockerfile、nginx設定、Laravelソース、環境変数を設計図として保ち、同じ構成を再現できる状態にすることが重要です。

2026/06/25

USD12払えば無料枠が1000リクエスト/日で案外使えるOpenRouterのレビュー

AIのことなのに文章にAI使っていないので、読みづらかったらすみません。
APIでのAIツールOpenRouterのご紹介&無料枠のレビュー。

OpenRouterには無料で使えるものあります。
無課金だと50リクエスト/日であまり使えないですが、
USD10以上のクレジットを買うと、1,000リクエスト/日まで増えます。
結構使えます。
VsCodeの拡張機能CLINEを使って数日間いろいろやってみた感想を書いていきます。

結論
基本的には制限が厳しいので全部作って系のバイブコーディングには使えません。
しかし、それなりに使えるので、CodexやClaude Codeの制限を抑えるための補助ツールとしていいかも、です。
メインにするには制限が強すぎて、途中で止まるのが多い。
案外使えるので、少人数で1時間に10回のリクエストをAPIで使うとか、
OCRするとか、文章要約には便利。
アプリへの組み込みも使えるな、と思います。

問題点
1)制限かかってすぐに停止する。対処必須。
2)利用規約に一部のデータ保存とあるので情報流出の危険があるのかも。

使えそうなモデル
下記ですが2026/06/25現在のもので、入替えがあります。
cohere/north-mini-code:free                       
nvidia/nemotron-3.5-content-safety:free           
nvidia/nemotron-3-nano-omni-30b-a3b-reasoning:free
nvidia/nemotron-3-nano-30b-a3b:free               
poolside/laguna-xs.2:free                         
poolside/laguna-m.1:free                          
google/gemma-4-31b-it:free                        
nvidia/nemotron-3-super-120b-a12b:free            
liquid/lfm-2.5-1.2b-instruct:free                 
openai/gpt-oss-120b:free                          
openai/gpt-oss-20b:free                           

おすすめモデル
openai/gpt-oss-20b:free、google/gemma-4-31b-it:freeが標準的で安定した出力で使えます。
cohere/north-mini-code:freeがコーディングではいいかもな感触です。

といっても・・・
Groqの無料枠を使ってしまいます。
無課金でもOKだし、FreeTier枠が案外大きい。
ほかサービスと比較して速度がとっても速い!
(推測でしかありませんが、無課金の無料枠なのでデータ流出もある程度は許容しながらのものではないかと思います。)
Groqのレビューは下記↓
https://nokoshitamono.blogspot.com/2026/02/whisperllm0ai-apigroq-cloud20262.html


最後の感想
AIは従量課金が拡大していくサービスですが、便利なので安く使いたい。
そういう用途ならOpenRouterも一つの選択肢だと思います。
ただし、無料なのでいつ終了するのか分かりません。
でも、何かのサービスでこういう課金+無料枠のサービスは続いていくのではと思います。
そう入ってもコーディングではClaudeが圧倒して強いな、と思います。


勝手におすすめの本
必須ではないですが、ゲーム開発するならこの本読むと深い理解に繋がる。
そして、ホイジンガのホモ・ルーデンスも読みたくなる。
(ホモ・ルーデンスまで読まなくてもいいと思う。
時間は逆ですが、カイヨワを先にがわかりやすい)






[

2026/03/12

Xiaomi POCOの日本語入力が激遅!?設定1つでスマホが爆速になった話【 POCO F7 HyperOS 3.0.6.0 】2026/03/12版

Xiaomi POCOの日本語入力が激遅!?設定1つでスマホが爆速になった話【 POCO F7 HyperOS 3.0.6.0 】2026/03/12版

Xiaomi POCO F7 12GB+256GBを買った。

楽天市場のセールで買った。

使っていて問題なし。

しかし、最初からずっと感じていたのが「日本語キーボードの表示が遅い」です。

ぬるっとしたから上がってくるのがだいぶ遅い。

日本語キーボードが下から上がる動作の遅さ加減がひどい。

「スペックは高いはずなのに、なぜ?」と思い調べた。

Snapdragon 8s Gen 4なのに・・・。

AIと一緒に原因を探して突き止めました。

とある設定を1個変更するだけでかなりとても劇的に改善しました。

POCO F7使ってる人全員に知ってほしいので方法を紹介します。


ちなみに、使用感をお伝えすると、問題なく使えるAndroidスマホです。

不満なし。特徴なし。たいていのことは何でもできる。

カメラのコントラストが強めかも、くらい。

Xiaomi POCO X7 Pro 8GB+256GBでもいいかもと思う。

値段の同じくらいなモデルは大差なしと思います。


アマゾンの値段比較:2026/03/12現在

Xiaomi POCO F7 12GB+256GB : 5.5万

Xiaomi POCO X7 Pro 8GB+256GB :4.8万

Xiaomi POCO F7 Pro 12GB+512GB :7.3万

なんならredmiでもいいのかも。

Xiaomi REDMI Note Pro 15 5G 8+256GB :5.0万



遅い原因は「アニメーション」

POCO(Xiaomi / HyperOS)はUIアニメーションが強めに設定されています。

そのため

  • キーボード表示

  • アプリ起動

  • 画面遷移

などが 実際より遅く感じることがあります。

・・・というか実際に遅い。

遅すぎます。


爆速になった設定

結論から言うとアニメーションをOFFにする、です。

これだけでした。


設定方法

① 設定
② デバイス情報
HyperOSバージョンを7回タップ

すると「開発者モードが有効になりました」と表示されます。

次に

設定>追加設定>開発者オプション

以下開発者オプションのだいぶ下の方で下記をOFFに変更

※x0.5でもいいかも。

  • ウィンドウアニメーションスケール

  • トランジションアニメーションスケール

  • アニメーター再生時間スケール


実際の変化

設定後はキーボード表示が爆速、です。

というのは言い過ぎで、今までが遅すぎただけです。

標準に戻りました。

同じような現象に悩まされているPOCO F7ユーザーにはとても、すごくおすすめです。


さらに軽くなるかもの設定

もう1つおすすめがあります。RAM拡張をOFFです。

設定>追加設定>メモリ拡張>OFF

これで動作が安定、発熱減少、バッテリー改善になることがあるらしい・・・。

実感はよくわからないです。


POCO F7 ユーザーにおすすめの設定

動作改善のおすすめの設定1個。

開発者オプションのアニメーションOFF、です。

さらに、RAM拡張OFFもやるといいのかも?

キーボードの遅さで困っている人はぜひ試してみてください。

2026/02/27

RackNerd Clubとは何?少し使っての感想。低価格な海外VPS。試験向けに良さそう【中身は本家RackNerd、年間5400円の4GBプランおすすめ】

RackNerd Clubとは何?少し使っての感想。低価格な海外VPS。試験向けに良さそう【中身は本家RackNerd、年間5400円の4GBプランおすすめ】

海外VPSで検索すると出てくるRackNerdClub。その「RackNerd Club」の特価ページ(セール常設のように見えるやつ)について、 Redditのレビューや自分使ってみた感想を書きました。

先に結論:中身はアメリカのサーバーRackNerdと同じ。Redditで評判も普通。個人開発・小規模運用なら“普通に使える”。docker+Laravelとか動かして普通に使えた。おすすめは3.5GB・4GB。





RackNerd Clubって何?(ざっくり)

RackNerd Clubは、RackNerdのセール(ディール)をまとめて見せている日本語セールページです。クリックすると本家の英語ページに行きます。
日本語>https://racknerd.club/ja/
本家>https://www.racknerd.com/

メモリ2.5GBで約USD20年間 3220円は安い。
使えるのだろうかと不安になる。
でもテストするなら、NTT Web arena Indigo で2GB月額814円とか日本の格安VPSが多数あるのでそれでいいやと思ってしまう。

↓普通すぎるけど聞かない会社なので手が出しにくいウェブサイト・・・





Redditで多い評価:まずは「価格が安い」

Redditで調べてみました。
Redditでは「定価で買うよりセールページを見るべき」という趣旨のコメントが多め。 Black Fridayセールの価格の安いページがいつでも契約できます。
そこがさらに変に思えて契約するのが難しい・・・。

良い評判まとめ:個人用途・学習用途・小規模なら「十分」「2年以上問題なし」

ポジティブ寄りの意見で多いのは次のタイプです。

  • 「学習用途・検証環境・個人サイトなら十分」
  • 「2年以上動いていて大きな問題はない」
  • 「遅い/気になる点があったが、相談したら移行対応してくれた」
  • 「サポートが返信してくれた(IPv6有効化、rDNSなど)」

実際のスレ例:

注意点まとめ:「本番は冗長化した方がいい」「当たり外れ(ばらつき)」系の声もある

一方で、ネガティブ寄り・注意喚起寄りの意見も一定数あります。代表的なのは次のタイプ。

  • 「パフォーマンスが徐々に落ちた(オーバーセル疑惑)」
  • 「packet loss / network slowdown があった」
  • 「CPU steal が気になる」
  • 「本番クリティカル用途の“単独運用”は避ける」(=バックアップや冗長化前提が安心)
  • 「昔使った時に落ちまくった」という体験談

実際のスレ例:

まとめると、Redditの空気感はだいたいこうです: 「安い。個人用途ならOK。ただし“絶対止めたくない本番”は、単騎運用にしない」

(ざっくり)スペックの見方:迷ったら4GB

RackNerdのセールは時期で表記が変わりますが、だいたい次のレンジで出てきます。 迷ったら4GBが一番バランス良いです。

目安プラン 向いている用途 体感コメント
1GB〜2GB 検証、軽いWeb、踏み台、超小規模 安いが、Docker複数やDB同居だと窮屈になりがち
3GB 小規模アプリ、軽いAPI、WordPress数本 コスパ良いが、あと一歩余裕が欲しくなることがある
4GB(おすすめ) Laravel + DB + Nginx、Docker運用、軽めのAI系 安定運用の“最低ライン”として選びやすい

Redditでも「学習・検証には良い」「本番は冗長化」という意見が多いので、 4GBで余裕を作りつつ、バックアップや移行手順を最初から整えるのが現実的です。

スペックはこの画像。
racknerdのHome>何でもいいのでOrder now>カート手前ページで左のCategories一覧見る>BlackFriday2025
4GBで年間USD29.98+消費税=USD33/年
年間5339円|月間444円/1USD=161.8のカード支払い手数料込みで計算




おすすめの使い方

  • 個人開発・社内ツールの検証環境(まず動かして学ぶ)
  • 小規模のWeb/API(落ちても致命傷にならない設計)
  • バックアップ前提の本番(スナップショット、外部バックアップ、別リージョン待機など)

使ってみたRackNerd 4GB

4GBをカード決済で契約。
ユーザー名とパスワードがメールで送られてきた。
linuxサーバーはconoha wingをsshで数年使ってるだけ。

コマンド集を読みながら、わからないことはチャッピー全投げ。
Ubuntu24.0のLAサーバー。
OSアップデート、ファイヤーウォール、SSH、sudoユーザ作ってroot禁止の基本設定のみ。docker+nginx+Laravelでサンプルページ表示。
CloudFlareでDNS設定で公開。httpsも。

私のレベルですが、ここまでササッと遅滞なく公開までできた。
難しいことやらないなら普通のサーバーなのだと思います。
cp、mvなどのコマンド忘れてたのが一番時間かかりました。
Ubuntuだとnanoエディタあるので初心者には楽。
チャッピー指示でroot禁止を言われて、sudoできないユーザーでログインして焦りました・・・。
※RackNerdマイページのVNCサービスでrootログイン可能なのでここから再設定かOS再インストール。


結論

RackNerd Clubは「RackNerdの日本語版のセールページ」。
Redditでも“安い、普通に使える”という声。

ただし、品質にばらつき混雑などのコメントもあるため、 重要サービスは単独運用にしないのが安心。

迷うなら、最初は4GB
心配ならもっと低価格な2.5GBプランとか。使ってみて試す。
おそらく普通に付ける海外品質のVPSサービスです。
レスポンス気にするならNTT Web arena、さくらVPS、カゴヤ、Conohaが間違いないと思います。
低価格でそれなりのRAM容量でやりたい!
サーバー学びたい。
小規模な社内向けアプリの初期段階とかならRackNerdもありと思います。
ただし、海外なので各種リスクは考えての運用を。

2026/02/23

WhisperもLLMも無料で試せる?0円でAI APIを使う方法:Groq Cloud無料枠の簡単レビュー 2026年2月版

Groq Cloudは無料で使える?実際にAPIを試してわかった無料枠と制限まとめ

AI APIは便利ですが、気になるのは料金です。

OpenAIやAnthropicは従量課金制。
テスト段階ではできるだけコストを抑えたいものです。

そこで試してみたのが「Groq Cloudの無料枠(Free Tier)」です。
https://groq.com/

今回は、実際にAPIを使ってみた経験をもとに、

  • 無料枠の内容
  • どこまで実用的か
  • 制限は厳しいのか

を整理します。

目次の前にさらっと結論!
1:APIなので低スペックPCでも使える。便利
2:テストでやってみるなら全然OK
3:0円で使えるので消費量みて従量のコストが体感できる。怖くない
4:OpenAI形式なので汎用性のあるAPIが覚えられる
5:使ってみるとgeminiよりも応答の速いGroqすごいと思う
6:whisperでも応答が速い。Groqすごい
7:Groqの従量課金は高くないのでGroq使い勝手いいかも
8:調子にのって使っていると制限で使えなくなる

テスト環境はCPUは10世代のIntel+メモリ16GBの5万くらいの中古ノート
アマゾンならこういうの>https://amzn.to/3MTlDUd
ちゃんと動く。
PCではPowershellでURLアクセスとテキスト処理のみ。

もう少ししっかりテストするなら10万以下のこういうので↓いいと思う。
GROQのAPI運用ならローカルのスペックはそんなにいらない。
メモリ16GBでいいと思う。



Groqは応答速度が非常に速い。でも、OpenAIのgpt-5-nanoはかなりコストが安い
gpt-5-nanoでも十分ならOpenAIでいいのかも。nanoでも精度は良い。

https://developers.openai.com/api/docs/pricing
gpt-5-nano $0.05/1M-input $0.40/1M-Output
(↑1Mトークンでどこまでやれるの?の体感をGroqで試してみてもいいかも。)
(llama-3.3-70b-versatile、gpt-oss-120bで、GPT-4に足りないくらいの精度らしい)

Groq Cloudとは

Groq Cloudは、高速推論に特化したAI APIサービスです。

対応モデルには以下のようなものがあります。

  • Llama系モデル
  • Whisper(音声文字起こし)
  • Vision対応モデル

特に特徴的なのは、推論速度の速さです。

体感としては、他のAPIよりもレスポンスが非常に速い印象があります。
開発時のストレスが少ないのは大きな利点です。

無料枠(Free Tier)の内容

2026年2月時点での無料枠の概要は以下の通りです。
多くはないですが試験するには十分と思います。

Groq Free Tier Limits
Model RPM RPD TPM TPD
allam-2-7b307K6K500K
groq/compound3025070KNo limit
groq/compound-mini3025070KNo limit
llama-3.1-8b-instant3014.4K6K500K
llama-3.3-70b-versatile301K12K100K
meta-llama/llama-4-maverick-17b-128e-instruct301K6K500K
meta-llama/llama-4-scout-17b-16e-instruct301K30K500K
meta-llama/llama-guard-4-12b3014.4K15K500K
meta-llama/llama-prompt-guard-2-22m3014.4K15K500K
meta-llama/llama-prompt-guard-2-86m3014.4K15K500K
moonshotai/kimi-k2-instruct601K10K300K
moonshotai/kimi-k2-instruct-0905601K10K300K
openai/gpt-oss-120b301K8K200K
openai/gpt-oss-20b301K8K200K
openai/gpt-oss-safeguard-20b301K8K200K
qwen/qwen3-32b601K6K500K
Token Cost Comparison (1M tokens)
Model Input (1M) Output (1M)
OPENAI gpt-5-nano $0.05 $0.40
Groq GPT OSS 120B 128k $0.15 $0.60
Model Capabilities
Model テキスト 画像 特長
allam-2-7b×軽量高速
groq/compound×複合推論
groq/compound-mini×軽量複合
llama-3.1-8b-instant×超高速
llama-3.3-70b-versatile×高精度
meta-llama/llama-4-maverick-17b-128e-instruct視覚対応
meta-llama/llama-4-scout-17b-16e-instruct視覚高速
meta-llama/llama-guard-4-12b×安全判定
meta-llama/llama-prompt-guard-2-22m×入力検査
meta-llama/llama-prompt-guard-2-86m×高精検査
moonshotai/kimi-k2-instruct×長文強い
moonshotai/kimi-k2-instruct-0905×改良版
openai/gpt-oss-120b×大規模
openai/gpt-oss-20b×軽量版
openai/gpt-oss-safeguard-20b×安全特化
qwen/qwen3-32b×多言語

リクエスト制限

多くのモデルで 30リクエスト/分(RPM)

1日のリクエスト上限

モデルごとに異なります。

例:

  • llama-3.1-8b-instant → 約14,000回/日
  • llama-3.3-70b → 約1,000回/日

トークン制限

  • 1分あたり 6,000〜70,000トークン(モデルによる)
  • 1日あたり 100,000〜500,000トークン(モデルによる)

Whisper(音声API)

音声処理には時間ベースの制限があります。

例:

  • 1時間あたり 約120分の音声処理
  • 1日あたり 約8時間分

実際に使ってみた感想

テキスト処理

ブログ整形、OCR結果の整形、要約などは十分実用的です。
無料枠でも日常的なテスト用途には問題ありません。

Whisper文字起こし

2時間を超えるm4aファイルも、分割すれば対応可能です。
業務テスト用途としては十分な性能です。

注意点

  • 商用利用する場合は必ず利用規約を確認すること
  • 無料枠は予告なく変更される可能性があること
  • 同時実行数には制限があること

無料枠は実用レベルか

結論としては、開発・検証用途なら十分実用レベルです。

特に以下の用途には向いています。

  • OCR後のテキスト整形
  • Whisper文字起こし
  • 社内ツール開発
  • 小規模な自動化

本格運用の前段階としては非常に使いやすいサービスです。

まとめ

Groq Cloudは、無料枠でも十分に実用的なAI APIサービスです。

開発段階で従量課金を避けたい場合や、 まずは試してみたいという方には特におすすめできます。

といっても、OpenAIのAPIもとても高額な料金ではないので、 まずはやってみたい方ならいいかも。
Groqの反応速度は使い勝手よしです。


さらっとテストコード

<#
Get-Weather-Groq.ps1
- Open-Meteoで今日の天気(実データ)を取得
- Groq (llama-3.3-70b-versatile) に渡して「詳しく説明」させる
必要:
  $env:GROQ_API_KEY にAPIキーを設定
例:
  $env:GROQ_API_KEY="gsk_...."
  .\Get-Weather-Groq.ps1 -City "東京" -Language "ja"
#>

param(
  [Parameter(Mandatory=$false)][string]$City = "東京",
  [Parameter(Mandatory=$false)][string]$Language = "ja",
  [Parameter(Mandatory=$false)][string]$Timezone = "Asia/Tokyo",
  [Parameter(Mandatory=$false)][string]$Model = "llama-3.3-70b-versatile"
)

$ErrorActionPreference = "Stop"

# --- 0) Groq API Key ---
$apiKey = $env:GROQ_API_KEY
if ([string]::IsNullOrWhiteSpace($apiKey)) {
  throw "環境変数 GROQ_API_KEY が未設定です。例: `$env:GROQ_API_KEY='gsk_...'`"
}

# --- 1) 都市名 -> 緯度経度(Open-Meteo Geocoding) ---
$geoUrl = "https://geocoding-api.open-meteo.com/v1/search?name=$([uri]::EscapeDataString($City))&count=1&language=$Language&format=json"
$geo = Invoke-RestMethod -Uri $geoUrl -Method Get

if (-not $geo.results -or $geo.results.Count -eq 0) {
  throw "都市 '$City' の緯度経度が見つかりませんでした。別の表記で試してください。"
}

$place = $geo.results[0]
$lat = $place.latitude
$lon = $place.longitude
$resolvedName = $place.name
$admin = @($place.admin1, $place.country) -join ", "

# --- 2) 今日の天気(Open-Meteo Forecast) ---
# 取得項目(必要なら増やしてOK)
$meteoUrl = "https://api.open-meteo.com/v1/forecast" +
  "?latitude=$lat&longitude=$lon" +
  "&timezone=$([uri]::EscapeDataString($Timezone))" +
  "&forecast_days=1" +
  "&hourly=temperature_2m,apparent_temperature,precipitation_probability,precipitation,weathercode,windspeed_10m,windgusts_10m,winddirection_10m,relativehumidity_2m" +
  "&daily=weathercode,temperature_2m_max,temperature_2m_min,precipitation_sum,precipitation_probability_max,windspeed_10m_max,windgusts_10m_max,sunrise,sunset"

$wx = Invoke-RestMethod -Uri $meteoUrl -Method Get

# --- 3) Groq に「今日の天気を詳しく」説明させる ---
$today = (Get-Date).ToString("yyyy-MM-dd")
$system = @"
あなたは日本の天気解説の専門家です。
ユーザーが提供する天気APIのJSON(Open-Meteo)を根拠に、推測で補完せず、データに基づいて「今日の天気」を詳しく説明してください。
出力は日本語。読みやすい箇条書き中心。最後に「外出アドバイス」を短く付けてください。
"@

$user = @"
場所: $resolvedName ($admin)
日付: $today
次のOpen-Meteo JSONを解析して、今日の天気を詳しく解説してください。

--- OPEN-METEO JSON ---
$($wx | ConvertTo-Json -Depth 12)
"@

$endpoint = "https://api.groq.com/openai/v1/chat/completions"

$body = @{
  model = $Model
  messages = @(
    @{ role="system"; content=$system },
    @{ role="user"; content=$user }
  )
  temperature = 0.2
  top_p = 1
  max_tokens = 1200
} | ConvertTo-Json -Depth 10

$headers = @{
  "Authorization" = "Bearer $apiKey"
  "Content-Type"  = "application/json"
}

$res = Invoke-RestMethod -Method Post -Uri $endpoint -Headers $headers -Body $body
$text = $res.choices[0].message.content

# --- 4) 表示 ---
"=== 今日の天気(Groq解説)==="
$text

ページ上部へ戻る

2026/01/25

CPUでOCR処理:LightOnOCR-2-1B

PythonでのOCR処理。EasyOCRでやってました。

【2025年12月版】Windows で EasyOCR と Poppler を利用して PDF を OCR する手順
https://nokoshitamono.blogspot.com/2025/12/202512windows-easyocr-poppler-pdf-ocr.html

LightOnOCR-2-1Bでもやってみました。

EasyOCRは高速処理。
LightOnOCR-2-1Bはそれなりに時間がかかるけど、段組みの認識は強い。
CPUでも動くので使えるかも。
WikipediaのページをOCR処理した結果







モデルはどっかにダウンロードする
git lfs install
git clone https://huggingface.co/lightonai/LightOnOCR-2-1B c:/llamamodels/LightOnOCR-2-1B

あとは各ライブラリをpipでインストール。
pip checkで過不足ない感じにすれば動くはず。
torchはCUDA対応にすればGPU使えますが、CPUだけでも動きます。


# python lightonocr_local.py test.jpg --out result.txt
# python lightonocr_local.py book.pdf --pages 1,2,5-12

import argparse
import io
import os
from pathlib import Path
from typing import List, Optional, Tuple

import torch
from PIL import Image

# PDF対応(任意)
try:
    import pypdfium2 as pdfium
except Exception:
    pdfium = None

from transformers import LightOnOcrForConditionalGeneration, LightOnOcrProcessor

MODEL_PATH = r"c:/models/LightOnOCR-2-1B"

IMAGE_EXTS = {".png", ".jpg", ".jpeg", ".webp", ".bmp", ".tif", ".tiff"}


def pick_device() -> Tuple[str, torch.dtype]:
    """
    LightOnOCR公式例に合わせて:
      - mps -> float32
      - cuda -> bfloat16(対応しないGPUなら float16 に切替推奨)
      - cpu -> float32
    """
    if torch.backends.mps.is_available():
        return "mps", torch.float32
    if torch.cuda.is_available():
        # bf16 が怪しい場合は float16 に変更してください
        return "cuda", torch.bfloat16
    return "cpu", torch.float32

def resolve_device_and_dtype(device_arg: str, dtype_arg: str, force_fp16: bool) -> Tuple[str, torch.dtype]:
    """
    CLI指定に基づいて device と dtype を安全に確定する。
    device_arg: auto|cpu|cuda|cuda:0|cuda:1|mps
    dtype_arg : auto|fp32|fp16|bf16
    """
    # --- device 決定 ---
    if device_arg == "auto":
        if torch.backends.mps.is_available():
            device = "mps"
        elif torch.cuda.is_available():
            device = "cuda"
        else:
            device = "cpu"
    else:
        device = device_arg

    # --- device 実在チェック ---
    if device.startswith("cuda"):
        if not torch.cuda.is_available():
            raise RuntimeError("CUDAが利用できません。--device cpu を指定してください。")
        if device != "cuda":
            # cuda:0 のような形式
            try:
                idx = int(device.split(":")[1])
            except Exception:
                raise RuntimeError("CUDA指定は cuda または cuda:0 の形式で指定してください。")

            if idx < 0 or idx >= torch.cuda.device_count():
                raise RuntimeError(f"{device} は存在しません。CUDAは {torch.cuda.device_count()}枚です。")

    if device == "mps" and not torch.backends.mps.is_available():
        raise RuntimeError("MPS が利用できません。")

    # --- dtype 決定 ---
    if dtype_arg == "auto":
        if device.startswith("cuda"):
            dtype = torch.float16 if force_fp16 else torch.bfloat16
        else:
            dtype = torch.float32
    else:
        mp = {"fp32": torch.float32, "fp16": torch.float16, "bf16": torch.bfloat16}
        if dtype_arg not in mp:
            raise ValueError("--dtype は auto|fp32|fp16|bf16 のいずれかです")
        dtype = mp[dtype_arg]

    # MPSはfp32が安全(fp16/bf16で不安定になりやすい)
    if device == "mps":
        dtype = torch.float32

    return device, dtype



def load_images_from_path(path: Path, page_spec: str = "") -> List[Image.Image]:
    """
    path が:
      - 画像ファイル: 1枚
      - フォルダ: 画像を全列挙
      - PDF: 各ページをレンダして画像化(pypdfium2必須)
    """
    if path.is_dir():
        imgs = []
        for p in sorted(path.rglob("*")):
            if p.suffix.lower() in IMAGE_EXTS:
                imgs.append(Image.open(p).convert("RGB"))
        return imgs

    if path.suffix.lower() in IMAGE_EXTS:
        return [Image.open(path).convert("RGB")]

    if path.suffix.lower() == ".pdf":
        if pdfium is None:
            raise RuntimeError("PDFを処理するには `pip install pypdfium2` が必要です。")

        pdf_data = path.read_bytes()
        pdf = pdfium.PdfDocument(pdf_data)

        page_indices = parse_page_range(page_spec, len(pdf))

        images = []
        for i in page_indices:
            page = pdf[i]
            pil_img = page.render(scale=2.77).to_pil()
            images.append(pil_img.convert("RGB"))

        return images

    raise ValueError(f"未対応の入力です: {path}")

def parse_page_range(spec: str, total_pages: int) -> List[int]:
    """
    ページ指定文字列を 0-based index のリストに変換
    """
    if not spec:
        return list(range(total_pages))

    pages = set()

    for part in spec.split(","):
        part = part.strip()

        if "-" in part:
            start, end = part.split("-", 1)

            start_i = int(start) - 1 if start else 0
            end_i = int(end) - 1 if end else total_pages - 1

            start_i = max(start_i, 0)
            end_i = min(end_i, total_pages - 1)

            for i in range(start_i, end_i + 1):
                pages.add(i)
        else:
            i = int(part) - 1
            if 0 <= i < total_pages:
                pages.add(i)

    return sorted(pages)



@torch.inference_mode()
def ocr_image(
    model: LightOnOcrForConditionalGeneration,
    processor: LightOnOcrProcessor,
    image: Image.Image,
    device: str,
    dtype: torch.dtype,
    max_new_tokens: int = 1024,
) -> str:
    """
    Transformersの公式モデルカードにある会話テンプレ方式でOCRする。 :contentReference[oaicite:2]{index=2}
    """
    conversation = [
        {
            "role": "user",
            "content": [
                {"type": "image", "image": image},
            ],
        }
    ]

    inputs = processor.apply_chat_template(
        conversation,
        add_generation_prompt=True,
        tokenize=True,
        return_dict=True,
        return_tensors="pt",
    )

    # floatテンソルだけ dtype を当て、他は device のみ移動
    inputs = {
        k: (v.to(device=device, dtype=dtype) if v.is_floating_point() else v.to(device))
        for k, v in inputs.items()
    }

    output_ids = model.generate(**inputs, max_new_tokens=max_new_tokens)
    generated_ids = output_ids[0, inputs["input_ids"].shape[1] :]
    text = processor.decode(generated_ids, skip_special_tokens=True)
    return text.strip()


def main():
    ap = argparse.ArgumentParser()
    ap.add_argument("input", help="画像ファイル / 画像フォルダ / PDF のパス")
    ap.add_argument("--max_new_tokens", type=int, default=1024)
    ap.add_argument("--out", default="", help="出力テキスト保存先(未指定なら標準出力)")
    ap.add_argument("--page_sep", default="\n\n--- PAGE ---\n\n", help="複数ページの区切り")
    ap.add_argument("--force_fp16", action="store_true", help="CUDA時に fp16 を強制(bf16で不安定なら)")
    ap.add_argument("--pages", default="", help="PDFページ範囲(例: 1-5, 3-, -10, 1,3,5-7)※PDFのみ有効")
    ap.add_argument("--model", default="", help="HF model id or local path(未指定ならコード内の MODEL_PATH を使用)")

    # ★追加(GPU切替)
    ap.add_argument("--device", default="auto", help="実行デバイス: auto | cpu | cuda | cuda:0 | cuda:1 | mps")
    ap.add_argument("--dtype", default="auto", help="精度: auto | fp32 | fp16 | bf16(cuda以外はfp32推奨)")

    args = ap.parse_args()
    model_path = args.model if args.model else MODEL_PATH
    
    
    # ★追加(GPU切替)
    device, dtype = resolve_device_and_dtype(args.device, args.dtype, args.force_fp16)
    print(f"[INFO] device={device} dtype={dtype}")

    model = LightOnOcrForConditionalGeneration.from_pretrained(
        model_path,
        torch_dtype=dtype,
        local_files_only=True,
    ).to(device)

    processor = LightOnOcrProcessor.from_pretrained(
        model_path,
        local_files_only=True,
    )

    images = load_images_from_path(in_path, args.pages)
    if not images:
        raise RuntimeError("処理できる画像が見つかりませんでした。")

    texts: List[str] = []
    for idx, img in enumerate(images, start=1):
        print(f"[INFO] OCR {idx}/{len(images)} ...")
        txt = ocr_image(
            model=model,
            processor=processor,
            image=img,
            device=device,
            dtype=dtype,
            max_new_tokens=args.max_new_tokens,
        )
        texts.append(txt)

    final_text = args.page_sep.join(texts)

    if args.out:
        out_path = Path(args.out)
        out_path.write_text(final_text, encoding="utf-8")
        print(f"[INFO] saved: {out_path}")
    else:
        print(final_text)


if __name__ == "__main__":
    main()

2025/12/16

データSIMが使えるようになるまで1時間くらいかかるときもある


50GBのデータSIMカードをamazonで購入。
設定どおりにAndroid、iPhoneに挿して、10分20分待っても通信できず。。。
やり方わからずに発売元にも聞いてみた。
説明をしたりと、だいたい1時間くらい経過したらいつのまにか通信できるようになってた。
10分くらい待つ、とは聞いたことあったけど電波弱いと時間が必要かもと思います。

TORA様のSIMは通信速度も良かったです。
50GBも使えます。

eSIMと物理SIMがあるけど、端末やスマホを替えるかもしれないなら
物理SIMのほうが便利。
一つの端末で使い切りならeSIMの方が便利で少し安い。
30GBで3000円しないなら、たくさん使いそうなときだけeSIMで使えばいいのかもと思う。


360日で50GBが5,000円しないなら、サブ端末はこういうのでいいかも。
あとはWIFIを使うなど。
5000/12 =417円/月。



[