2024年12月22日日曜日

dspy.ai で Azure 互換のカスタムエンドポイントを設定する方法

dspy.ai で Azure 互換のカスタムエンドポイントを設定する方法

概要

Azure の OpenAI 互換だがエンドポイントが異なる場合に dspy を使う方法を紹介します

環境

  • Python 3.11.3
  • dspy 2.5.43

サンプルコード

import dspy

lm = dspy.LM(
    "azure/gpt-4-32k",
    api_key="xxx",
    api_version="",
    api_base="https://your-api-endpoint/ai/chat-ai/gpt4",
)
dspy.configure(lm=lm)

result = lm("Say this is a test!", temperature=0.7)
print(result)

ポイント

  • モデルの prefix は azure/ から始めること
  • api_base に独自の Azure 互換エンドポイントを設定すること
  • api_version は空で OK

最後に

内部的には litellm のプロバイダを使っているので litellm の使い方がわかっていれば簡単に他のプロバイダも設定できると思います

参考サイト

2024年12月21日土曜日

faiss を使って文章の類似度計算をしてみる

faiss を使って文章の類似度計算をしてみる

概要

前回 文章を数値化し faiss にデータを保存しました
今回は実際に faiss に検索をかけて文章の類似度を計算して似ている文章を見つけたいと思います

環境

  • macOS 15.2
  • transformers 4.47.0
  • faiss-cpu 1.9.0-post1

コード全体

from torch import Tensor
from transformers import AutoModel, AutoTokenizer


# このaverage_pool関数はbertの出力結果ではよく使われる手法、何をしているかの詳細は以下の説明に記載
def average_pool(last_hidden_states: Tensor, attention_mask: Tensor) -> Tensor:
    last_hidden = last_hidden_states.masked_fill(~attention_mask[..., None].bool(), 0.0)
    return last_hidden.sum(dim=1) / attention_mask.sum(dim=1)[..., None]


# faissに保存する文章、この文章と類似度検索をする
input_texts = [
    "好きな食べ物は何ですか?",
    "どこにお住まいですか?",
    "朝の電車は混みますね",
    "今日は良いお天気ですね",
    "最近景気悪いですね",
    "最近、出かけていないので、たまには外で食事でもどうですか?",
]

# モデルとトークナイザの取得、日本語なので日本語に特化したモデルを使用
tokenizer = AutoTokenizer.from_pretrained("cl-tohoku/bert-base-japanese")
model = AutoModel.from_pretrained("cl-tohoku/bert-base-japanese")

# 文章の数値化
inputs = tokenizer(input_texts, padding=True, truncation=True, return_tensors="pt")

# 文章のベクトル化、768 次元のベクトル情報が取得できる (参考: https://github.com/cl-tohoku/bert-japanese)
outputs = model(**inputs)

# bert の結果を更によくするためのおまじない
embeddings = average_pool(outputs.last_hidden_state, inputs["attention_mask"])

# faiss で扱えるように numpy 配列に変換
embeddings_np = embeddings.cpu().detach().numpy()

# なぜか先頭でimportすると segmentation fault になるのでここで import
import faiss

# 次元数(768)で初期化
index_flat_l2 = faiss.IndexFlatL2(embeddings_np.shape[1])
# ベクトル情報を追加、6文章(vectors)登録される
index_flat_l2.add(embeddings_np)  # type: ignore

# クエリとなるテキストの定義、数値化、faiss 用ベクトル化
query_text = ["今日は晴れている"]
query_dict = tokenizer(
    query_text, max_length=512, padding=True, truncation=True, return_tensors="pt"
)
query_output = model(**query_dict)
query_embeddings = average_pool(
    query_output.last_hidden_state, query_dict["attention_mask"]
)
query_embeddings_np = query_embeddings.cpu().detach().numpy()

# 上位何件を取得するかの設定
k = 2

# 検索の実行
D, I = index_flat_l2.search(query_embeddings_np, k)  # type: ignore

# 結果の表示
for i in range(k):
    print(
        f"  Rank: {i+1}, Index: {I[0][i]}, Distance: {D[0][i]}, Text: '{input_texts[I[0][i]]}"
    )

今回追加した faiss で検索をする部分は以下です

# クエリとなるテキストの定義、数値化、faiss 用ベクトル化
query_text = ["今日は晴れている"]
query_dict = tokenizer(
    query_text, max_length=512, padding=True, truncation=True, return_tensors="pt"
)
query_output = model(**query_dict)
query_embeddings = average_pool(
    query_output.last_hidden_state, query_dict["attention_mask"]
)
query_embeddings_np = query_embeddings.cpu().detach().numpy()

# 上位何件を取得するかの設定
k = 2

# 検索の実行、結果はD(distance)とI(index)の情報が返ってくる
D, I = index_flat_l2.search(query_embeddings_np, k)  # type: ignore

# 結果の表示
for i in range(k):
    print(
        f"  Rank: {i+1}, Index: {I[0][i]}, Distance: {D[0][i]}, Text: '{input_texts[I[0][i]]}"
    )

最後に

faiss で文章の類似度計算をしてみました
文章の類似度を計算する手法はいろいろとありますが特に自分で何も計算することなく search するだけで勝手に似たような文章を持ってきてくれるので簡単に使えます

今回は IndexFlatL2 を使いましたが他にも「IndexFlatIP」「IndexHNSWFlat」などがあります
参考: https://github.com/facebookresearch/faiss/wiki/Faiss-indexes

データの規模やマシンスペックによって適宜切り替えれば OK です
使い方によって多少データの加工が必要ですがほぼ同じように使えます

流れとしては以下で可能だとわかりました

  • transformers で文章を数値化、ベクトル化
  • 結果を faiss に格納
  • クエリを作成し検索を実施

bert のテンソルベクトル情報を faiss で扱えるように numpy形式のベクトル情報に変換するところが少しクセがありますがそこ以外は数値化した情報をそのまま faiss に渡すだけなので簡単に使えました

また数値化する際に今回は cl-tohoku/bert-base-japanese を使いましたがモデルとトークナイザを変えるだけでも結果は変わってくるかなと思います

参考サイト

2024年12月20日金曜日

faiss に数値化したデータを保存する方法

faiss に数値化したデータを保存する方法

概要

前回 文章を数値化し faiss に保存可能なベクトル情報を計算しました
今回は faiss にベクトル情報を保存する方法を紹介します

環境

  • macOS 15.2
  • transformers 4.47.0
  • faiss-cpu 1.9.0-post1

コード全体

from torch import Tensor
from transformers import AutoModel, AutoTokenizer


# このaverage_pool関数はbertの出力結果ではよく使われる手法、何をしているかの詳細は以下の説明に記載
def average_pool(last_hidden_states: Tensor, attention_mask: Tensor) -> Tensor:
    last_hidden = last_hidden_states.masked_fill(~attention_mask[..., None].bool(), 0.0)
    return last_hidden.sum(dim=1) / attention_mask.sum(dim=1)[..., None]


# faissに保存する文章、この文章と類似度検索をする
input_texts = [
    "好きな食べ物は何ですか?",
    "どこにお住まいですか?",
    "朝の電車は混みますね",
    "今日は良いお天気ですね",
    "最近景気悪いですね",
    "最近、出かけていないので、たまには外で食事でもどうですか?",
]

# モデルとトークナイザの取得、日本語なので日本語に特化したモデルを使用
tokenizer = AutoTokenizer.from_pretrained("cl-tohoku/bert-base-japanese")
model = AutoModel.from_pretrained("cl-tohoku/bert-base-japanese")

# 文章の数値化
inputs = tokenizer(input_texts, padding=True, truncation=True, return_tensors="pt")

# 文章のベクトル化、768 次元のベクトル情報が取得できる (参考: https://github.com/cl-tohoku/bert-japanese)
outputs = model(**inputs)

# bert の結果を更によくするためのおまじない
embeddings = average_pool(outputs.last_hidden_state, inputs["attention_mask"])

# faiss で扱えるように numpy 配列に変換
embeddings_np = embeddings.cpu().detach().numpy()

# なぜか先頭でimportすると segmentation fault になるのでここで import
import faiss

# 次元数(768)で初期化
index_flat_l2 = faiss.IndexFlatL2(embeddings_np.shape[1])
# ベクトル情報を追加、6文章(vectors)登録される
index_flat_l2.add(embeddings_np)  # type: ignore

今回追加した faiss にデータを保存する部分は以下の3行です

# なぜか先頭でimportすると segmentation fault になるのでここで import
import faiss

# 次元数(768)で初期化
index_flat_l2 = faiss.IndexFlatL2(embeddings_np.shape[1])
# ベクトル情報を追加、6文章(vectors)登録される
index_flat_l2.add(embeddings_np)  # type: ignore

最後に

たったこれだけで faiss にベクトル情報を保存することができました
次回は faiss に保存した文章をもとにクエリとして与えた文章と似ている文章を探す処理を追加します

参考サイト

2024年12月19日木曜日

emacs に copilot.el をインストールする方法

emacs に copilot.el をインストールする方法

概要

copilot が無料になって誰でも使えるようになったので emacs の設定をしました

環境

  • macOS 15.2
  • emacs 29.4
  • node 20.17.0

準備

  • node のインストール
    • nvm でローカルだけ使えるようにしてそこで emacs を起動しても OK
  • editorconfig、jsonrpc のインストール
    • package-list-packages などで melpa からインストールすれば OK

copilot.el のインストール

最初に straight.el をインストールしています
そのあとで copilot.el をインストールしています
初回起動時はいろいろと clone するので少し時間がかかります

; for copilot (with straight)
(defvar bootstrap-version)
(let ((bootstrap-file
       (expand-file-name
        "straight/repos/straight.el/bootstrap.el"
        (or (bound-and-true-p straight-base-dir)
            user-emacs-directory)))
      (bootstrap-version 7))
  (unless (file-exists-p bootstrap-file)
    (with-current-buffer
        (url-retrieve-synchronously
         "https://raw.githubusercontent.com/radian-software/straight.el/develop/install.el"
         'silent 'inhibit-cookies)
      (goto-char (point-max))
      (eval-print-last-sexp)))
  (load bootstrap-file nil 'nomessage))

(use-package copilot
  :straight (:host github :repo "copilot-emacs/copilot.el" :files ("*.el"))
  :ensure t)

copilot サーバのインストール

M-x copilot-install-server で node が起動しサーバのインストールと起動が始まります

node で書かれておりバックグラウンドで npm が起動し copilot-node-server がインストールされます
執筆時点ではバージョンは 1.27.0 でした

copilot-install-server というバッファに「Comint finished at Thu Dec 19 14:44:17」という感じで表示されれば OK です

copilot へのログイン

M-x copilot-login を実行します

  • ワンタイムコードが発行されるのでコピーします
  • https://github.com/login/device にアクセスします、アクセスするブラウザは copilot を使う Github アカウントでログインしているブラウザを使います
  • コピーしたコードを入力し認証します

下のような画面が表示されればあとは許可すれば OK です

emacs 側には「Authenticated as GitHub user username.」と表示されれば OK です

使ってみる

適当に Python ファイルなどを開いてみましょう
M-x copilot-mode で起動します
自動で copilot-mode にする場合は以下を追加します

(add-to-list 'copilot-major-mode-alist '("python" . "python"))

上記がうまく動作しない場合は以下でも OK です

(add-hook 'python-mode-hook 'copilot-mode)

copilot によって補完された候補を入力するには M-x copilot-accept-completion を実行します
これをショートカットキーに登録しておいてもいいかなと思います

うまく補完してくれない場合には M-x copilot-diagnose を実行して copilot events バッファにエラーログが出ていないか確認しましょう

最後に

emacs + copilot の設定をしてみました
無料だと制限があるのでそのうち制限に引っかかって使えなくなるかなと思います

勝手にガンガン補完してくれるので慣れるまで結構かかるかもしれませんが慣れれば便利なのかもしれません

参考サイト

faiss を使うための準備として文章を数値化する方法

faiss を使うための準備として文章を数値化する方法

概要

前回 transformers を使って文章を数値化する方法を紹介しました
今回は数値化した情報を faiss で使えるように更に加工します

faissは文章の類似度を検索するツールです
過去に LangChain で使っていますが今回は faiss 単体で使ってみました

この記事では文章を数値化する部分だけを紹介しています
基本的には参考サイトにあるコードを動かしているだけですが事前学習済モデルなどが異なっています

環境

  • macOS 15.2
  • transformers 4.47.0

コード全体

最後の embeddings が faiss に保存するための通知情報です

from torch import Tensor
from transformers import AutoModel, AutoTokenizer


# このaverage_pool関数はbertの出力結果ではよく使われる手法、何をしているかの詳細は以下の説明に記載
def average_pool(last_hidden_states: Tensor, attention_mask: Tensor) -> Tensor:
    last_hidden = last_hidden_states.masked_fill(~attention_mask[..., None].bool(), 0.0)
    return last_hidden.sum(dim=1) / attention_mask.sum(dim=1)[..., None]


# faissに保存する文章、この文章と類似度検索をする
input_texts = [
    "好きな食べ物は何ですか?",
    "どこにお住まいですか?",
    "朝の電車は混みますね",
    "今日は良いお天気ですね",
    "最近景気悪いですね",
    "最近、出かけていないので、たまには外で食事でもどうですか?",
]

# モデルとトークナイザの取得、日本語なので日本語に特化したモデルを使用
tokenizer = AutoTokenizer.from_pretrained("cl-tohoku/bert-base-japanese")
model = AutoModel.from_pretrained("cl-tohoku/bert-base-japanese")

# 文章の数値化
inputs = tokenizer(input_texts, padding=True, truncation=True, return_tensors="pt")

# 文章のベクトル化、768 次元のベクトル情報が取得できる (参考: https://github.com/cl-tohoku/bert-japanese)
outputs = model(**inputs)

# bert の結果を更によくするためのおまじない
embeddings = average_pool(outputs.last_hidden_state, inputs["attention_mask"])

# faiss で扱えるように numpy 配列に変換
embeddings_np = embeddings.cpu().detach().numpy()

説明

コード内のコメント以外で詳細に説明したほうがいい部分について説明します

average_pool 関数について

average_pool 関数は bert の出力結果を数値化する際によく使われる関数です
おまじないだと思ってもいいかなと思います
以下に軽く説明文を記載しておきます

この関数が使われる理由
1. 文全体の特徴量を作るため
BERTの出力 last_hidden_states は各トークンごとの特徴量を提供します。
文分類タスクなど、文全体を1つの特徴ベクトルで表現したい場合、このような平均プーリング処理がよく使われます。

2. パディングを無視して正しい平均を計算するため
文の長さは入力によって異なるため、パディングが挿入されます。
パディングを無視して、実際のトークンのみを対象にした平均を計算することで、モデルの性能を向上させます。
last_hidden = last_hidden_states.masked_fill(~attention_mask[..., None].bool(), 0.0)
attention_mask[..., None] を使ってマスクの次元を増やし、last_hidden_states に適用可能な形にします。
~attention_mask により、attention_mask が0(パディング)の部分を True に反転させます。
masked_fill を使い、attention_mask が0の位置の特徴量をゼロに置き換えます。
結果として、実際のトークンに対応する特徴量のみが残ります。
last_hidden.sum(dim=1)
各トークン(sequence_length次元)ごとの特徴量を足し合わせます。
パディング部分はゼロに置き換えられているため、実際のトークンの特徴量だけが合計されます。
attention_mask.sum(dim=1)[..., None]
attention_mask.sum(dim=1) は、各文の実際のトークン数を計算します(1 の数を合計)。
次元を合わせるために [..., None] で形状を (batch_size, 1) に変形。
最終的に、トークンの特徴量の合計をトークン数で割り、**トークンごとの平均特徴量(文全体の特徴量)**を計算します。

最後の変換について

簡単に言えば faiss 上で動作させるための変換です

embeddings_np = embeddings.cpu().detach().numpy()
以下の変換を行う理由:

.cpu(): GPU上のテンソルをCPU上に移動する。
.detach(): 計算グラフからテンソルを切り離す(推論時にメモリを節約)。
.numpy(): NumPy形式に変換し、後続の処理や保存で利用可能にする。

最後に

transformers でベクトル化した情報を faiss で使える形式に変換しました
次回は実際に faiss にデータを保存し類似度検索する部分を実装します

参考サイト

2024年12月18日水曜日

transformers の BertJapaneseTokenizer を使って日本語をトークナイズする基本

transformers の BertJapaneseTokenizer を使って日本語をトークナイズする基本

概要

過去に transfomers の pipeline を使ってみました
今回はシンプルに日本語をトークナイズ(数値化)する機能を使ってみます
この仕組みは LLM におけるツールやユースケースなどどのケースでも使われる基本的な使い方になります

環境

  • macOS 15.2
  • Python 3.11.10
    • transformers 4.47.0

準備

  • pipenv install transformers torch torchvision fugashi unidic-lite "numpy<2"

transformers 4.47.0 が numpy 2.0 以上に対応していないので注意です

サンプルコード

import torch
from transformers import AutoModel, AutoTokenizer

# Bert用の日本語モデルをダウンロード
bertjapanese = AutoModel.from_pretrained("cl-tohoku/bert-base-japanese")
tokenizer = AutoTokenizer.from_pretrained("cl-tohoku/bert-base-japanese")

# 解析する文章の設定
line = "吾輩は猫である。"

# トークナイズ(数値化)する、テンソル
inputs = tokenizer(line, return_tensors="pt")

# トークナイズされた情報を確認する
print(tokenizer.decode(inputs["input_ids"][0]))

# おまけ: 特徴量の抽出(last_hidden_stateとpooler_outputの取得)
# これらは更に与えた文章の類似度検索や分類に使える
outputs = bertjapanese(**inputs)

複数の文章を与える

import torch
from transformers import AutoModel, AutoTokenizer

# Bert用の日本語モデルをダウンロード
bertjapanese = AutoModel.from_pretrained("cl-tohoku/bert-base-japanese")
tokenizer = AutoTokenizer.from_pretrained("cl-tohoku/bert-base-japanese")

# 解析する文章の設定
lines = [
    "吾輩は猫である。",
    "名前はまだない",
]

# トークナイズ(数値化)する、テンソル
inputs = tokenizer(lines, padding=True, truncation=True, return_tensors="pt")

# トークナイズされた情報を確認する
print(tokenizer.decode(inputs["input_ids"][0]))
print(tokenizer.decode(inputs["input_ids"][1]))

# おまけ: 特徴量の抽出(last_hidden_stateとpooler_outputの取得)
# これらは更に与えた文章の類似度検索や分類に使える
outputs = bertjapanese(**inputs)

最後に

ここで数値化した情報やベクトル情報は更に類似度検索や分類器に与えられて次の処理に利用されます

次回はこれらのデータを使って分類器を実行する方法を紹介します

参考サイト

2024年12月17日火曜日

Rlogin で多段 ssh する方法

Rlogin で多段 ssh する方法

概要

ProxyJump や ProxyCommand 的なことはできないっぽいので localhost にポートフォーワードしてそれをプロキシして次のサーバにつなぐのが主流なようです

なのでサーバ側でローカルポートフォーワードを許可していない場合には何か別の方法を模索する必要があります

環境

  • Rlogin 2.29.1

踏み台となるマシンの登録

ファイル -> サーバに接続 -> 新規で登録します

サーバー

  • エントリー(上) -> 好きな名前の設定
  • ホスト名 -> 踏み台マシンのIP
  • TCPポート -> 踏み台マシンのsshポート
  • ログインユーザ名 -> 踏み台マシンにログインするユーザ名
  • パスワード or パスフレーズ -> 踏み台マシンにログインするパスワード

あとは鍵などが必要であれば鍵を設定してください

サーバー(プロトコル)

サーバー -> プロトコル -> ポートフォーワード -> 新規で設定します

  • Listened -> Local Proxy Server
  • Host -> localhost
  • Port -> 10001 (空いてそうで競合しなさそうな localhost のポートならどこでもOK)

ポイントは踏み台に ssh した上で更に localhost の windows にポートフォーワードする設定もする点です

実際にsshするマシンの登録

ファイル -> サーバに接続 -> 新規で登録します

サーバ

  • エントリー(上) -> 好きな名前の設定
  • 前接続先(下) -> 先ほど登録した踏み台マシンの名前
  • ホスト名 -> sshするマシンのIP
  • TCPポート -> sshするマシンのsshポート
  • ログインユーザ名 -> sshするマシンにログインするユーザ名
  • パスワード or パスフレーズ -> sshするマシンにログインするパスワード

異なるのは踏み台マシンを「前接続先」とやらに設定する点です

プロキシ設定

サーバー -> プロキシ設定で設定します
先ほどの踏み台マシンで localhost にポートフォーワードしたポートをプロキシに設定します

  • Select Proxy Protocol -> SOCKS5
  • Proxy Server Address -> localhost
  • Socket Port -> 10001

動作確認

あとはサーバー接続の一覧から実際にsshするマシンを選択すれば踏み台->sshするマシンの順番で認証などが聞かれるので認証すればsshできるはずです

なおターミナルを閉じるときに localhost にポートフォーワードしたプロセスも閉じるように聞かれるので一緒に閉じましょう

同じような感じで踏み台が複数ある場合はその分だけローカルにポートフォーワードして次のマシンには踏み台の順番にプロキシを設定すれば 3,4段と多段の ssh もできるかなと思います

最後に

踏み台マシンがsshのポートフォーワードを許可していない場合にはどうすればいいのだろうか

踏み台マシンに nc などがあれば ProxyCommand が使えるが Rlogin で ProxyCommand 的なことはできるのだろうか

また ssh -W でも ssh 的には多段 ssh を実施できるが結局 ProxyCommand が必要になるので厳しそう

幸いにも Rlogin は日本人の開発者っぽいので最悪自分で開発すればいいのだと思う

参考サイト

2024年12月12日木曜日

Gitlab CI でデプロイジョブが古くて実行できない場合の対処方法

Gitlab CI でデプロイジョブが古くて実行できない場合の対処方法

概要

再度 force push してあげます

環境

  • Gitlab 17.5.2

エラー詳細

This job requires a manual action

This deployment job does not run automatically and must be started manually, but it's older than the latest deployment, and therefore can't run.

こんな感じで古いデプロイジョブは実行できなくなっています

対策その1

対象のブランチの HEAD から再度パイプラインを手動で実行してあげれば OK です
ただブランチのパイプラインなどの場合 workflow ルールで手動実行できないケースがあるのでその場合は以下の対策を試してください

対策その2

ブランチであれば一つコミットを打ち消して再度 push すれば OK です

  • git reset HEAD^
  • git add .
  • git commit -m "Re commit"
  • git push -u origin feature/branch_name

これで再度ブランチからパイプラインが作成されるのでそこからデプロイすれば OK です

最後に

古いデプロイジョブでも実行可能にするオプションがあるっぽいのでそれをオンにしても OK ですが間違って最新版以外をデプロイしまう可能性があるので注意しましょう

2024年12月11日水曜日

Gitlab CI でリトライする方法

Gitlab CI でリトライする方法

概要

retry を使います

環境

  • Gitlab 17.5.2

.gitlab-ci.yml

この場合は2回リトライするので3回目で失敗して終了します

stages:
  - test

failure_test:
  stage: test
  retry:
    max: 2
    when: script_failure
  image:
    name: python:3.12.8-alpine3.21
  script:
    - python error.py

最後に

タイミングにより失敗するジョブなどに使えます

参考サイト

2024年12月10日火曜日

GIGOオンクレ橋渡しメモ

GIGOオンクレ橋渡しメモ

とにかく20手以内に取れるようになることが大事かなと思います
20手をすぎると強制終了モード(アシスト状態)になります
初期もしくは途中からで10手以内で取れるようになればだいぶ上手かなと思います
ビビらず攻めるのが大事です

タテハメにするかヨコハメにするか決める

  • どちらでもとにかく深くハメていくことを考える
  • GIGOオンクレではどちらも有効
  • タテハメのほうが早いイメージはあるが状況ヨコハメのほうが簡単なケースもある
  • 自分はヨコハメのほうが好き

左右アームどちらか寄せの三角形狙い

  • タテでもヨコでも使える
  • カメラをヨコから見て三角形があればそこにアームを寄せて入れてズリズリと角度をつけていくイメージ
  • V型でどちらの三角形も狙える場合は動く方を見つけてそちらを重点に攻める
    • 動く方によってタテ、ヨコを切り替えていく

ハマっていない方の角狙い

  • 三角が動かない場合に使う
  • 手前がハマって奥が上にある場合は奥の左右どちらかの角をアームを寄せて持ち上げるイメージ
  • 奥を持つことで手前がはまっていくが単純に持ち上げてハマりが浅くなることがあるので注意
  • 三角形がダメでかつ三角形がある場合は浮いている方の角と対象の角をアームを寄せて取ってみると動きがあるかも
  • しっかり角が取れればクリティカルヒットもある一方で個人的には三角取りよりも事故る可能性は高いイメージ
  • あと単純に箱が大きいのと筐体の丸み問題がありすべって角自体取るのが難しい一手だと思う

バー停止からの弾き

  • かなり難しいが三角形に入れても動きがないときに有効
  • ギリギリアームを寄せてバー停止しその反動で本体に爪を当てて当てた方向に動かしていくイメージ
  • とめがけに近いがバー停止させるのがポイント
  • 何とかして動きが欲しい場合の秘密兵器的な一手として覚えておくといいかもしれない

左右アームどちらか寄せの下角狙い

  • 以下にも記載しているがあまりやらない一手
  • 使う場合はハマっている方に三角形がなく、いわゆるバーに箱が設置してしまっている状態、そのときに動きを出したいために使う
  • どちらかアームを寄せて下角を取ることで上にひっぱり上げて無理やりそこに三角形を作る感じ
  • ヨコでもタテでも使えるが自分はタテのときにやることが多い

逆タテハメのアーム寄せ手前角集中攻め

  • これでハマったらとめがけ的な
  • 逆タテの場合筐体すべらせ下角持ちずりあげができる形だがそこから進まないパターンが多い
  • その場合は手前角の方が動きが出そうな場合がある

フィニッシュ、決まり手を考える

  • 一番好きなのは「とめがけ」
  • GIGOオンクレの場合タテでもヨコでもとめがけが使える印象
  • 浮いている方を押してもう片方のアームで下角を引っ張るイメージ
  • タテハメの場合はかなりアームの場所がシビアなので難しいが使える
    • たまにアームの寄せが甘く浮いてる方を抑えられずアームが下に抜けてしまい角を取ってしまう事故もある
    • それでも繰り返していけば確実に取れるフィニッシュだと思う

個人的にあまり使わない手順

  • 両アーム使ってのハマっているほうにアームを入れてズリあげる
  • GIGOオンクレの場合筐体の丸みを活かして箱に本体をすべらせてアームを下に入れてひっぱり上げるテクがある
  • 簡単かつ誰でもできる一方で運要素が強いのと何より攻略している感がないので使わない
  • どうしても動かない場合にはパルプンテ的な要素で使うのはありかも

その他

  • 何をするにしても真ん中を取るよりかはどちらかのアームを寄せたほうが動きはあるイメージ
  • もしかしたら初手のみBCが使えるかも
  • SP の違いによる台の調整は基本ないと思ってはいるがそれは中の人しかわからない
    • アームの開きはどの SP でも同じ
    • アームの強さや捻じればもしかしたら SP によって細かく調整されているかも
    • このあたりはやってみないと何とも
  • この手法はGIGOのオンクレでしか使えない気がする
    • 特にフィニッシュのとめがけはリアルな筐体(UFO10など)+いろいろなフィギュアの箱の形状だとできるケースが限られます
    • ハメるまでの三角取りもリアル店舗だと使えないことが多い、加工制限などで
    • なのでGIGOオンクレでの技術はあくまでもGIGOオンクレだけで通じる技術だと思ったほうがいいかなと思います
    • お店の傾向、筐体、箱の形、重心の違いなど鑑みて自分はそう感じています
  • ネットワークごしにプレイするので通信環境は必ず良いところでやることをおすすめします
    • ためにプレイ中に通信が切れて次のプレイヤーに進んじゃないことがある
    • カメラの切り替えができなくなり詰む
    • 自分はそうですがスマホではなくできればラップトップなどでプレイしたほうが安全です
    • またラップトップ環境でも多少のラグがあるのでラグもしっかり考慮してアームを移動しましょう
  • 側面はまりの設置は詰みかな

最後に

GIGOのオンクレはアシストがあるのでそれ頼みで行くのもありですがやっぱり自分で取れるようになると取れたときのうれしさは格段に違うかなと思います

2024年12月5日木曜日

Github Actions の外向けの IP を調べる方法

Github Actions の外向けの IP を調べる方法

概要

/meta API を使います

環境

  • Github API 2022-11-28
  • curl 8.11.0

コマンド

トークンは Github のページから取得してください
IPv4 および IPv6 アドレスが含まれています

curl -L \     
  -H "Accept: application/vnd.github+json" \
  -H "Authorization: Bearer ghp_xxxxx" \
  -H "X-GitHub-Api-Version: 2022-11-28" \
  https://api.github.com/meta | jq '.actions'

最後に

執筆時点で 4888 個もあったが本当なのだろうか

2024年12月4日水曜日

Bookmarklet で jQuery を使う方法

Bookmarklet で jQuery を使う方法

概要

もしページ内ですでに読み込まれている場合はそのまま使えます
読み込んでいない場合はブックマークレット側で読み込めば使えるようになります

環境

  • Chrome 131.0.6778.86

ブックマークレット

javascript:(function() {
    if (!window.jQuery) {
        let script = document.createElement('script');
        script.src = 'https://code.jquery.com/jquery-3.6.0.min.js';
        script.type = 'text/javascript';
        script.onload = runBookmarklet;
        document.getElementsByTagName('head')[0].appendChild(script);
    } else {
        runBookmarklet();
    }
    function runBookmarklet() {
        alert('jQuery バージョン: ' + $.fn.jquery);
    }
})();

最後に

他のライブラリも同じ仕組みで読み込めると思います
バージョンなどは面倒ですが直接書き込むしかないです

2024年12月3日火曜日

サイト内の画像だけを抽出し表示するブックマークレット

サイト内の画像だけを抽出し表示するブックマークレット

概要

上からずらっと表示します

環境

  • Chrome 131.0.6778.86

ブックマークレット

javascript:(function() {
    const images = Array.from(document.querySelectorAll('img'));
    if (images.length === 0) {
        alert('画像が見つかりませんでした');
        return;
    }
    document.body.innerHTML = '';
    document.body.style.margin = '0';
    document.body.style.padding = '0';
    document.body.style.backgroundColor = 'black';
    images.forEach(img => {
        const newImg = document.createElement('img');
        newImg.src = img.src;
        newImg.style.display = 'block';
        newImg.style.margin = '10px auto';
        newImg.style.maxWidth = '90%';
        newImg.style.height = 'auto';
        document.body.appendChild(newImg);
    });
    alert(`${images.length} 個の画像を表示しました`);
})();

最後に

画像だけシンプルに表示したい場合に使えます
スタイルも全部解除するのでどんなページにも使えるはずです

2024年12月2日月曜日

GIGOのオンクレでプレイ中のプライズのみ表示するブックマークレット

GIGOのオンクレでプレイ中のプライズのみ表示するブックマークレット

概要

ブックマークレットを紹介します
DOM が変わった場合は適宜クラス名などを変更してください

環境

  • Chrome 131.0.6778.86

ブックマークレット

javascript:(function() {
    const targetUlClass = 'prizes__list';
    var allListItems = document.querySelectorAll(`ul.${targetUlClass} > li`);
    allListItems.forEach(function(li) {
        var spans = li.querySelectorAll('span');
        var hasTargetBackground = false;
        spans.forEach(function(span) {
            var bgColor = window.getComputedStyle(span).backgroundColor;
            if (bgColor === 'rgb(255, 226, 108)') {
                hasTargetBackground = true;
            }
        });
        if (hasTargetBackground) {
            li.style.display = '';
        } else {
            li.style.display = 'none';
        }
    });
    var highestIntervalId = setInterval(() => {}, 1000);
    for (var i = 0; i <= highestIntervalId; i++) {
        clearInterval(i);
    }
})();

最後に

ページのリロードする API のコールも停止しているので適宜手動でリロードしてください

2024年11月29日金曜日

GoogleSpreadSheetで月ごとに色を分ける方法

GoogleSpreadSheetで月ごとに色を分ける方法

概要

特定のカラムで日時を管理している場合に月ごとにセルの色を変更する方法を紹介します
条件付き書式ではできないので GoogleAppScript を使います

環境

  • GoogleSpreadSheet (2024/11/29時点)
  • GoogleAppScript (2024/11/29時点)

特定の色に変更する方法

事前に30色分(30ヶ月分)用意しています
何度実行しても同じ色になるようにしています

B2 カラムで日時を管理している想定です
B2 カラムの1行目はヘッダで2行目から日時データの想定です
B2 カラムの日時はフォーマットが Date になっていることが条件です

function colorRowsByMonth() {
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
  const lastRow = sheet.getLastRow(); // シート内の最終行を取得
  const range = sheet.getRange(2, 2, lastRow - 1, 1); // B列の2行目から最終行まで取得
  const values = range.getValues(); // データを2次元配列で取得
  const colors = {}; // 月ごとの色を保持するオブジェクト
  const colorPalette = getLargeFixedColorPalette(); // 固定された30色の薄い色パレット
  let paletteIndex = 0;

  for (let i = 0; i < values.length; i++) { // ヘッダーをスキップ
    const date = values[i][0]; // 日時が入力されているカラム (A列の場合)
    if (date instanceof Date) { // 日付形式か確認
      const monthKey = Utilities.formatDate(date, Session.getScriptTimeZone(), "yyyy/MM");
      // 月ごとの色を設定(未登録なら新しい色を割り当て)
      if (!colors[monthKey]) {
        colors[monthKey] = colorPalette[paletteIndex % colorPalette.length];
        paletteIndex++;
      }
      // B2から下に行の背景色を設定
      sheet.getRange(i + 2, 2, 1, 1).setBackground(colors[monthKey]);
    }
  }
}

// 固定された30個の薄い色のパレットを生成する関数
function getLargeFixedColorPalette() {
  return [
    "#FFCCCC", "#FFEECC", "#FFFFCC", "#CCFFCC", "#CCE5FF",
    "#CCCCFF", "#FFCCE5", "#FFE4B5", "#D8BFD8", "#B0E0E6",
    "#F0E68C", "#E6E6FA", "#F5DEB3", "#FFDAB9", "#F0FFF0",
    "#FFF0F5", "#FFFACD", "#E0FFFF", "#FAFAD2", "#D3D3D3",
    "#FFC0CB", "#B0C4DE", "#ADD8E6", "#DDA0DD", "#D9F2E6",
    "#F2E2D2", "#F5F5DC", "#FBE5D6", "#EBF4FA", "#FAEBD7"
  ];
}

月分だけ色を用意する方法

例えば 2024/01 と 2025/01 は同じセルの色にしたい場合などはこちらを使います
こちらの方法は12色準備すれば OK なので色の追加などは不要です

function colorRowsByMonth() {
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
  const lastRow = sheet.getLastRow(); // シート内の最終行を取得
  const range = sheet.getRange(2, 2, lastRow - 1, 1); // B列の2行目から最終行まで取得
  const values = range.getValues(); // データを2次元配列で取得
  const monthColors = getMonthColors(); // 月ごとの色を取得

  for (let i = 0; i < values.length; i++) { // ヘッダーをスキップ
    const date = values[i][0]; // 日時が入力されているカラム (A列の場合)
    if (date instanceof Date) { // 日付形式か確認
      const month = date.getMonth(); // 月を取得(0: 1月, 11: 12月)
      const color = monthColors[month]; // 月に対応する色を取得
      // B2から下に行の背景色を設定
      sheet.getRange(i + 2, 2, 1, 1).setBackground(color);
    }
  }
}

// 1月から12月までの固定色を返す関数
function getMonthColors() {
  return [
    "#FFCCCC", // 1月 - 薄い赤
    "#FFEECC", // 2月 - 薄いオレンジ
    "#FFFFCC", // 3月 - 薄い黄色
    "#CCFFCC", // 4月 - 薄い緑
    "#CCE5FF", // 5月 - 薄い青
    "#CCCCFF", // 6月 - 薄い紫
    "#FFCCE5", // 7月 - 薄いピンク
    "#FFE4B5", // 8月 - 薄いベージュ
    "#D8BFD8", // 9月 - 薄いモーブ
    "#B0E0E6", // 10月 - 薄い水色
    "#F0E68C", // 11月 - 薄いカーキ
    "#E6E6FA"  // 12月 - 薄いラベンダー
  ];
}

最後に

レコードが増えたら再度 GAS を実行する必要があるのが不便です
(条件付き書式でもできる方法があるのだろうか)

2024年11月27日水曜日

chrome のブックマークレットでボタンを押したあとにinputに値を入力しイベントを強制発火する方法

chrome のブックマークレットでボタンを押したあとにinputに値を入力しイベントを強制発火する方法

概要

テキスト入力用のフォームなどにイベントが設定されてある場合はブックマークレットでは強制的にイベントを発火させる必要があります

環境

  • macOS 15.1.1
  • Google Chrome 131.0.6778.86

ブックマークレット(js)

javascript:(function(){
    var button = document.querySelector('input.pc-tab__hidden-input[type="checkbox"][name="pnav-group"]');
    if (button) {
        button.click();
    } else {
        alert('ボタンが見つかりません');
        return;
    }
    setTimeout(function() {
        var input = document.getElementById('search-text');
        if (input) {
            input.value = 'スイカゲーム';
            var event = new Event('input', { bubbles: true });
            input.dispatchEvent(event);
        } else {
            alert('入力フィールドが見つかりません');
        }
    }, 500);
})();

chrome への登録

あとは chrome のブックマークへ上記 Javascript を登録すれば OK です

最後に

ブックマークレットは対象のURLを開いてから実行する必要があるので注意してください

ブックマークレットだけで特定の URL を開いた上で JavaScript を実行することは難しいようです

ボタンを押してからテキストフィールドに入力するまでに0.5秒待っていますが画面がうまく動作しない場合は値を調整してください

2024年11月26日火曜日

nvm 自身を更新する方法

nvm 自身を更新する方法

概要

Homebrew の場合は brew update でいいですが curl でインストールスクリプトを使ってインストールした場合は再度 curl を叩く必要があります

環境

  • nvm 0.40.1

コマンド

  • curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash

バージョンの部分はアップデートしたい最新バージョンにしてください

最後に

nvm 自身に update コマンドはないようです
バージョンを調べるのは少し面倒ですがこれが公式のようです

参考サイト