メモです

メモです

gpt-4o-miniでfinetuningできない

状況

openai.BadRequestError: Error code: 400 - {'error': {'message': 'Model gpt-4o-mini is not available for fine-tuning or does not exist.', 'type': 'invalid_request_error', 'param': None, 'code': 'model_not_available'}}

というエラーコードがで出てgpt-4o-miniでfinetuningできない

解決方法

gpt-4o-miniではなくgpt-4o-mini-2024-07-18を指定する

※現在指定できるモデルは以下リンクの右上の「+Create」を押下し、Base Modelのメニューに表示されるモデルのみ

https://platform.openai.com/finetune

備考

他に気を付ける点として

・クレジットが不足していないか

・管理画面(https://platform.openai.com/settings/profile)でProjectのLimits→Model usage→Allowed modelsで許可しているかどうか

完成したModelもここで許可しないとPlaygroudで使えない

 

AWSがStarfield Root Certificate Authorityを使っている理由

Amazon Certificate Managementをリリースした2016年当時は今では考えられないが誰もAmazonのルートCA証明書を入れていなかったので(2016年以前はそもそもそれがなかったので)、当時からグローバル大企業だったGoDaddy社(いまはStartfiled Technology社という子会社)の証明書をルート証明書にしていた

 

AWS使っているのにStarfield Root Certificate Authorityってなんなすか!と揉めたので記録

チャットアプリで新しいメッセージを受信すると自動的に最下部にスクロールされるやつ

カスタムフック

Vercel謹製のhookがある github.com

参照 (ref)

messagesRef: メッセージリストの一番下の要素を指す
scrollRef: スクロール可能なコンテナ要素を指す
visibilityRef: 特定の要素の可視性を監視するための要素を指す

State

isAtBottom: スクロール位置がリストの一番下にあるかどうかを示す
isVisible: visibilityRefが指す要素が画面上に表示されているかどうかを示す

scrollToBottom関数

messagesRefに紐付けられた要素までスクロールする。 「クリックで最下部までスクロールする」ボタンなどで利用する

自動的に最下部までスクロールされるやつ

isAtBottom, isVisibleに変更があった場合に実行される
scrollIntoView: scrollIntoView() が呼び出された要素がユーザーに見えるところまで要素の親コンテナをスクロールするメソッド

  useEffect(() => {
    if (messagesRef.current) {
      if (isAtBottom && !isVisible) {
        messagesRef.current.scrollIntoView({
          block: 'end'
        })
      }
    }
  }, [isAtBottom, isVisible])

(ほぼ)最下部までスクロールされたかどうかを更新する

  • スクロールが発生するたびに更新する
  • target.scrollTop + target.clientHeight >= target.scrollHeight - offsetの解釈にやや悩むが、要は最下部から数えてoffset分の高さ以内までスクロールされているかどうかを判定している(isAtBottomとあるから最下部までスクロールされているかどうかのBool値のように見えるが、本当にBottomであれば逆にスクロールはできない)
  • offsetは書き込み欄の分を指定する

参考: Element: clientHeight プロパティ - Web API | MDN

 useEffect(() => {
    const { current } = scrollRef

    if (current) {
      const handleScroll = (event: Event) => {
        const target = event.target as HTMLDivElement
        const offset = 25
        const isAtBottom =
          target.scrollTop + target.clientHeight >= target.scrollHeight - offset

        setIsAtBottom(isAtBottom)
      }

      current.addEventListener('scroll', handleScroll, {
        passive: true
      })

      return () => {
        current.removeEventListener('scroll', handleScroll)
      }
    }
  }, [])

IntersectionObserverで画面上に表示されているかどうかを更新する

 useEffect(() => {
    if (visibilityRef.current) {
      let observer = new IntersectionObserver(
        entries => {
          entries.forEach(entry => {
            if (entry.isIntersecting) {
              setIsVisible(true)
            } else {
              setIsVisible(false)
            }
          })
        },
        {
          rootMargin: '0px 0px -150px 0px'
        }
      )

      observer.observe(visibilityRef.current)

      return () => {
        observer.disconnect()
      }
    }
  })

使い方

visibilityRefを指定しているdivは見えているかどうか判定用の空要素

 <div  ref={scrollRef}>
      <div ref={messagesRef}>
          <ChatList messages={messages} />
        <div ref={visibilityRef} className="w-full"/>
     </div>
</div>

ローカル端末のAWS CLIのサインインにアクセスキーを使わないほうがいい

AWS CLIのサインイン方法についてググると、アクセスキーとシークレットキーをCSVでDLして設定する方法が出てくる。

しかし、アクセスキーは永続的に利用できる認証情報であり、AWS上でも発行しようとするたびに「多くの場合、期限のない長期のアクセスキー (IAM ユーザーのアクセスキーなど) は必要ありません」と忠告してくる

 

なので、IAM Identity Centerでユーザーを払い出した後に、

aws configure sso

して

SSO start URLにIAM Identity Center→設定→アイデンティティソース→AWS アクセスポータルの URLからコピーしてきたURLを入れるとアクセスキーなしにサインインできる

 

まぁローカル端末でAWS CLIを使わずにCloudShellを使えばよいのですが…

https://dev.classmethod.jp/articles/cli-is-doko/#toc-9

 

 

AWS SESのMAIL FROMドメインは検証済みIDのサブドメインしか指定できない理由

ドキュメントやブログで明言されていないが、「SESから送信されるメールを他から送付されるメールと区別しやすくするため」な気がする
 
前提
カスタムMAILFROMを設定しようとすると検証済みIDのサブドメインしか指定できないと表示される
 
(推測している)理由
SPFDNSルックアップの回数制限があるので、あんまりサブドメインなしのドメインSPFレコードを追加できない
・仮にSESで大量の不達メールを送ってしまった場合、DMARCで指定したメールにレポートメールが届くが、SESだけ個別のサブドメインにしないと他で送ったメールとドメインが一緒になってしまい区別できない
・SESから送るメールだけDMARCの設定を緩くしたいなど柔軟に対応しやすい
・仮にSESで大量の不達メールを送ってしまった場合にもサブドメインから送ればドメイン丸ごと死ぬことが避けやすい(でもこれは未確認なので怪しい)
 
そもそも、機械的かつ大量にメールを送る場合はドメインサブドメインに切り出すというベストプラクティスがあるっぽい
 
ただ、ベストプラクティスといったが、メールを送る場合はサブドメインを許さない(DMARCのStrictモードを使う)ことで、管理外からサブドメインでメールを送られるのを避けるという厳格な運用もあるっぽい
 
メールアドレスに利用できるドメインを、厳密に管理するのが目的です。
• 例えば、strict を指定すれば、勝手にサブドメインでメールアドレスを作れません。
• 現在 relaxed で運用されている組織も、これ以上に勝手にサブドメインの利用が始まると、管理が困難になります
ので、基本的には strict でのアライメント一致を目指すのがオススメです。
※この資料は実務的な面からのフォローが多くて勉強になった
 
雑記
指定したサブドメインにはバウンスメール用のMXレコード1件だけ登録するとかかれているが、最近はSESで受信もできるので、バウンスメール用(feedback-smtp)をと受信用(inbound-smtp)の2件が登録できるっぽい

Firestoreに改竄されたくない情報を書き込む

概要

-  ReactみたいなSPAからFirestoreに改竄されたくない情報を書き込む

- クライアント側で書き込むと想定外の部分までユーザが改竄できるため、それを防ぐ

ex. userドキュメントのプロフィールだけを更新したはずが、悪意のあるユーザがUIDフィールドを改竄対象のUIDにしたリクエストをFirestoreに送信することで他人のプロフィールを改竄できる

 

1.  Firebase Functionsで書き込む

Firebase FunctionsではFirebase Authenticationのトークンを検証できるので便利

exports.hoge= functions
.region("asia-northeast1") // region指定
.https.onCall(async (data, context) => {
 
if (!context.auth) {
throw new functions.https.HttpsError(
"failed-precondition",
"The function must be called " + "while authenticated."
);
}

// 話が逸れるがdataをこういう感じでバリデーションすることもできる
if (!(typeof text === "string") || text.length === 0) {
// Throwing an HttpsError so that the client gets the error details.
throw new functions.https.HttpsError(
"invalid-argument",
"The function must be called with " +
'one arguments "text" containing the message text to add.'
);
}

return;
});

 

2. セキュリティルールでバリデーションする

ただし、様々なバリデーションチェックを実装する必要があり、事故りやすい.

以下の記事を参考にすると良かった

Cloud Firestoreで「いいね」機能を実装するときの勘所 – su- tech blog

 

注意点

・readとwriteのメソッドは以下の細かなメソッドも含むものなので安易にtrueにしない(writeをtrueにするとユーザはドキュメントを削除できる権限を持つことになる

read: get,list

write: create,update,delete

・updateは要注意。他人のデータを改竄できるようになってないかを確認する

ex. uidフィールドをupdateできてしまう

対策:

- update前後で変更されてはいけないデータをバリデーションする

- hasOnlyでupdateできるフィールドを制限する

・セキュリティルールはVScodeとかで書いた方が楽。formatterのプラグインはあるがぶっ壊れている模様。

 

以下は代表的な関数とか

//create時のチェック
function validateUid() {
return incomingData().Uid == request.auth.uid;
}
 
//update時のチェック
function validateUpdate(giftId){
return request.resource.data.Uid == request.auth.uid;
}
 

3. フィールドそのもの変更をセキュリティルールで禁止する

特定のフィールドへのアクセスを制御する  |  Firebase Documentation

 

Firebase v9のFirestoreセキュリティルールでrequest.authが常にnullになる

【発生していた問題】
Firebaseにおいてv9への移行対応をしていたところ、Firestoreのセキュリティルールで、v8では認証状態に応じて値が格納されていたrequest.authが
v9ではrequest.authが常にnullとなっていた

↓こういうルールを実装していた
allow read: if  request.auth != null;

【解決方法】
セキュリティルールを使う場合はgetFirestoreと同時にgetAuthする

const firebaseApp = initializeApp(firebaseConfig)
const db = getFirestore(firebaseApp)

//これを追加する
const auth = getAuth(firebaseApp)

【解決まで】
・ぼんやりと通信を眺めていたところ、v8の通信時にはAuthenticationヘッダーがあるのにv9のときはないことに気づく
・v9でもAuthenticationヘッダーに手動でtokenを付加するとrequest.authに想定通りの挙動をするようになった
→v8のときはfirestoreを呼んだらauthも自動的に呼んでくれたが、v9では必要なコンポーネントのみを呼ぶようになってるから明示的にauthを呼ぶ必要があった

【雑記】
・firebaseはindexedDBにtokenを突っ込んでる
・setLogLevel('debug')でfirestoreのデバッグ流せることを知った