ortの灰ログ

人狼のことや技術のことや日々雑感

ロールをプレイ!というサイトを作った

この記事は

ロールをプレイ!というサイトを作ったので技術面のほうを書いておく

x.com

技術要素

https://github.com/h-orito/chat-role-play-graphql

それぞれ選定理由は「無料か少額でできる範囲で、勉強がてら使いたいものを使う!」といういつも通りのやつ

所感

  • Oracle Cloud無料枠がつよつよ&backendをGoで実装しているのもありGraphQLのqueryレスポンスが超早い
  • backendもfrontendもDBもk8sに載せているのでSSR(=内部通信)が超早い
  • k8sに載せているものも増えてきたのでメモリが足りるのかわからないが、スケールアップも可能といえば可能
    • コンテナ化しているのでやばくなってもCloud Runとかに切り替えられそう
  • 画像アップロードがあるが相当流行らない限りCloudflare r2無料枠は超えないので無料で運用できそうで良い

今後のTwitter連携機能について

この記事は

2023/02/09をもってTwitter API v1.1/v2の無料アクセスがなくなり、有料アクセスのみとなるそうです(利用者でなく、開発者が支払うものです)。
マスク氏の別ツイートでは$100/月~との情報もありました。
私の個人開発webサービスは一部でTwitter連携を利用しているため、
影響範囲と今後の対応予定について記載しておきます。

影響範囲

赤字部分は2023/02/04修正

各所から公式に問い合わせした結果、認証まわりについては今回の無料終了範囲に含まれていないようです。
したがって、有料APIを使用しない場合、それぞれ以下が影響範囲となります。

Scenario Tuker

  • ログイン認証にTwitterを利用しているが、無料終了範囲に含まれないため影響なし
  • 以下の機能はv2 APIを利用しているため、2/9より使用不可能
    • 公開範囲が「フォロワーのみ」「相互フォロワーのみ」の感想を閲覧する際、閲覧できるかの判定
    • ユーザー一覧での検索条件「Twitterでフォローしている人に絞る」
    • シナリオ詳細での通過記録検索条件「Twitterでフォローしている人に絞る」

FIREWOLFLASTWOLF

  • ログイン認証にTwitterを利用しているが、無料終了範囲に含まれないため影響なし
  • その他もv1.1/v2 APIを利用していないため、2/9時点では影響なし

HOWLING WOLF

  • ログイン認証にTwitterを利用しているが、無料終了範囲に含まれないため影響なし
  • 村作成や村開始時の自動ツイートにAPIを利用しているため、2/9より停止

WOLF MANSION

  • 村作成や村開始、エピローグ時の自動ツイートにAPIを利用しているため、2/9より停止

それ以外のサービス

TwitterAPIを利用していないので、影響はありません。

対応予定

ざっくりいうと、

  • 個人開発の無料サービスで$100/月は支払っていられないので、v1.1/v2 API利用機能を閉じていきます(2/9まで予定)
  • Twitterの最近の動向を見ていると、ログイン認証もいつまでもつかわからないので、可能な限りGoogle連携など他の手段に切り替えたり、事前に紐付けを行えるようにします

Scenario Tuker

  • v2 API利用機能を閉じる
    • 公開範囲が「フォロワーのみ」「相互フォロワーのみ」の感想は「自分のみ」に強制変更
  • Twitter連携でログインした状態で追加でGoogle連携認証も行えるようにする
    • これにより、万が一Twitterログイン認証が不可能になっても、Google連携で同アカウントにログインできるようになる

HOWLING WOLF、FIREWOLF、LASTWOLF

  • Twitter連携でログインした状態で追加でGoogle連携認証(もしくはメールアドレス・パスワード認証)も行えるようにする
    • これにより、万が一Twitterログイン認証が不可能になっても、Google連携で同アカウントにログインできるようになる

その他

  • 人狼のほうはid/pass方式にしたいんだけどfirebase authを使っていると実装がかなり面倒そうなのでおそらく他にする
  • ただでさえ忙しいのにこういう後ろ向きな開発はとてもつらい
  • Twitterならそう簡単に使えなくならないやろ、と思っていたここ数年の自分を殴りたい
  • ですます調とかであるとか体言止めとか混在しているけど直す気がおきないのでこのまま投稿することにする

iOS16でFirebase authが通らなくなった問題の対応備忘録

事象

iOS16の各種ブラウザやMacOS SafariからFirebase authenticationの signInWithRedirectgetRedirectResult するとユーザー情報が取得できず null が返される

対応方法概要

サードパーティのストレージ アクセスをブロックするブラウザーでの壊れたリダイレクト サインインを軽減する  |  Firebase
の軽減策 #3の通り対応する

原因調査

ぐぐっていたら
Login to Firebase does not work on Safari 16.1 beta · Issue #6716 · firebase/firebase-js-sdk · GitHub
これに行き着いた。これやん。

リプライの
https://github.com/firebase/firebase-js-sdk/issues/6716#issuecomment-1320593233
ここから
サードパーティのストレージ アクセスをブロックするブラウザーでの壊れたリダイレクト サインインを軽減する  |  Firebase
これに行き着いた。
引用すると、

サードパーティのストレージ アクセスをブロックするブラウザーでは機能しません

.

認証フローがアプリ ドメインに戻ると、サインイン ヘルパー ドメインブラウザー ストレージにアクセスします。この軽減策と次の (コードを自己ホストするための) 軽減策により、ブラウザーによってブロックされるクロスオリジン ストレージ アクセスが排除されます。

とのこと。iOS16やMacOS Safariが先に厳しくなったのね。

対応内容

  • Nuxt2でFirebase authenticationのTwitter認証を利用
  • Netlifyにデプロイしている

自分のアプリでやっていることとしてはこんな感じなので、

アプリ側の設定

軽減策#3のやつ。
https://<app domain>/__/auth/ から https://<project>.firebaseapp.com/__/auth/ にproxyしてあげる必要がある(リダイレクトではダメ)ので、
Nuxt2の場合

static/_redirects

/__/auth/* https://<project>.firebaseapp.com/__/auth/:splat 200

を設定して再デプロイ。

Netlify側の設定

軽減策#1前半のやつ。
自分の場合 appDomain はNetlifyのEnvironment variablesで設定しているので、
環境変数appDomain にあたる内容を

<project>.firebaseapp.com から <app domain> に変更(して再デプロイ)

Twitter側の設定

軽減策#1後半のやつ。
Twitter Developer Portalで連携しているアプリの設定を開き User authentication settings Edit → App infoCallback URI / Redirect URLhttps://<app domain>/__/auth/handler を追加(既存のと変更でも良いかも)

以上。これでiOS16でも動作するようになった。

備考

軽減策#2の signInWithPopup() でも良いはずだが、
自分の場合はPWA対応もしているため、これは使えなかった。
(PWAだとsignInWithPopupが動作しない)

Stable Diffusion試してみたメモ

記事概要

話題の「GitHub - CompVis/stable-diffusion」で遊んでみる

日本語の解説記事とかも充実しているので参考にしたサイトをメモするだけになりそう

環境構築

PC環境

参考記事

画像生成AI「Stable Diffusion」をローカル環境で実行する - パソコン関連もろもろ

WSLからGPUを使えるようにする

上記記事を参考に構築して実行してみると

RuntimeError: Found no NVIDIA driver on your system. Please check that you have an NVIDIA GPU and installed a driver from http://www.nvidia.com/Download/index.aspx

と出た。
調べたところWindows10の場合はOS versionが21H2でないとWSL上でGPUを使えない模様。
(winverで調べたところ21H2だった)

参考: Enable NVIDIA CUDA on WSL 2 | Microsoft Docs

諸般の事情でまだWindows11にしたくないので、書いてある通り21H2をインストール。

蛇足
ぐぐるNVIDIA公式が出てきてWindows Insider Programに参加して適切なOS buildにすると書いてあるが、
今それをやるとWindows11に誘導されるだけなので、2022/8現在はMicrosoftに書いてある通り21H2にするのが良さそう

実行

sampleのを実行してみる

$ python3 scripts/txt2img.py --prompt "a photograph of an astronaut riding a horse" --plms --ckpt sd-v1-4.ckpt --n_samples 1
Your samples are ready and waiting for you here:
outputs/txt2img-samples

Enjoy.

やったぜ。

Cloudflare r2試してみる備忘録

yusukebe.com

この記事を見て、ええやん無料枠で色々やれるし試してみよう!と思ったので試してみた
(ほぼ書いてくださっているとおりに進めたらできたのであまり書くことはない。神。)

サイトを見ながらやったこと

  • cloudflare登録して
  • r2を使えるようにして
    • 2022/05時点ではr2のページから進んでいくとクレカ登録が通らなかった
    • 設定画面から先にクレカを登録しておくことで解決
  • wranglerをインストールして
    • 画面で案内があるので特に詰まるところはないと思う
  • bucketを作って
  • workerを作成して
  • これでworker経由でr2に画像アップロード/表示する準備が整ったはず

以下は、それ以外にやってみたことを記載

Webアプリケーションから画像アップロードしてみる

Nuxt3からアップロードしてみる
こんな感じにすればアップロードできた
(inputまわりは省略、Nuxtあまり関係ないかも)

export const upload = async (imageFile: File): string => {
  const reader = new FileReader()
  reader.readAsDataURL(imageFile)
  await new Promise<void>((resolve) => (reader.onload = () => resolve()))
  // data:${mimeType};base64,${base64EncodedFile} が得られる
  const dataurl = reader.result as string
  const res = await useFetch(
    `${worker_base_url}/upload`,
    {
      method: 'PUT',
      body: {
        // base64部分のみを抽出
        body: dataurl.replace(/data:.*\/.*;base64,/, '')
      }
    }
  )
  const path = (res.data as Ref<string>).value
  return `${worker_base_url}/${path}`
}

ただしこれでlocalhostからアップロードするとCORSエラーとなるので、

worker側でCORS許可

workerのindex.tsに以下を追加する

app.use('*', cors())

https://github.com/honojs/hono を利用しているので簡単に設定できた
ローカルで試したので全許可しているが、本番で利用するときは↓あたりを参考にして調整すれば良さそう

github.com
https://developers.cloudflare.com/workers/examples/cors-header-proxy/

要はOPTIONSのリクエストで 'Access-Control-Allow-Origin': '*' になっているので
本番環境のドメインにしてあげれば良いはず。

おまけ

無料枠がかなり大きいので個人サイトなら十分使い倒せるのではないかと思う
2022/05時点でざっくり以下のようになっていた

R2

  • 10GB
  • 更新系1,000,000回/月
  • 取得系10,000,000回/月

worker

Microsoft Translator使ってみた備忘録

翻訳APIの無料枠あるし、応用すれば自動で人狼の再翻訳村とかできるんじゃね?という思いつきで使ってみた
2022/5現在、月200万文字まで無料っぽい。

https://azure.microsoft.com/ja-jp/free/

ここからアカウント作成
登録完了したらクイックスタートセンターを開く
上部検索でTranslatorで検索して「Cognitive Services | Translator」を開く
いい感じに登録してキーを確認

Microsoft Translator APIを使ってみた - Qiita
Microsoft Azure Cognitive Services テキスト翻訳とは - Azure Cognitive Services | Microsoft Docs

このあたりを参考に叩けばok
情報量なさすぎるけどそのくらい簡単にできたよ、ということで。

WOLF MANSIONで翻訳者の能力を受けると、
発言した内容をランダム言語に翻訳→再度日本語訳して発言されるようにできた。

全員デフォでこの状態になる「再翻訳村」もできるなぁと思ったのだけど、
月200万文字までだとワンチャン超えそうだなと思ったので一旦封印。

あと、翻訳精度が高すぎて、昔と比べてあまり面白い文章に変わらないという難点が。
(翻訳精度高いのはいいことなんだけども)

おまけのざっくりKotlinコード

private fun fromJa(str: String, language: String): String {
    val builder = UriComponentsBuilder.fromUriString(baseUrl)
    val uri = builder.queryParam("api-version", "3.0")
        .queryParam("from", "ja")
        .queryParam("to", language)
        .toUriString()
    return call(uri, str)
}

private fun toJa(str: String, language: String): String {
    val builder = UriComponentsBuilder.fromUriString(baseUrl)
    val uri = builder.queryParam("api-version", "3.0")
        .queryParam("from", language)
        .queryParam("to", "ja-Jpan")
        .toUriString()
    return call(uri, str)
}

private fun call(uri: String, str: String): String {
    val requestEntity = RequestEntity
        .post(URI(uri))
        .header("Ocp-Apim-Subscription-Key", key)
        .header("Ocp-Apim-Subscription-Region", "japaneast")
        .header("Content-Type", "application/json; charset=UTF-8")
        .body(listOf(TranslatorBody(str)))
    val restTemplate = RestTemplate()
    val response = restTemplate.exchange(requestEntity, Array<TranslatorResponse>::class.java)
    return response.body?.firstOrNull()?.translations?.firstOrNull()?.text ?: str
}

data class TranslatorBody(
    val Text: String
)

@JsonIgnoreProperties(ignoreUnknown = true)
data class TranslatorResponse(
    val translations: List<TranslatorResponseContent>
) {
    @JsonIgnoreProperties(ignoreUnknown = true)
    data class TranslatorResponseContent(
        val text: String
    )
}

WSL2 x Nuxt3 x Firebase Admin SDKで環境変数を読み込ませるのにハマった備忘録

npm run dev だと大丈夫だが、
npm run build して npm run start もしくは node .output/server/index.mjs するとRealtime Databaseに書き込めない
具体的に見てみると、Realtime Databaseに書き込もうとすると返ってこない

追ってみると、GOOGLE_APPLICATION_CREDENTIALS環境変数が読み込めていない
WSL上で環境変数を設定しても、nodeに環境変数が渡っていない
どうやらWSL上で動作させる場合はnodeに渡してあげる必要がありそう

この方法でできた。

package.json

  "scripts": {
    "dev": "nuxi dev",
    "build": "nuxi build",
    "start": "GOOGLE_APPLICATION_CREDENTIALS=$GOOGLE_APPLICATION_CREDENTIALS node .output/server/index.mjs"
  },

参考
【メモ】Cloud Functions for Firebase用の関数をWSLでデバッグする際、認証情報を使う - わしのlog