【マイナンバー】スマホ用電子証明書がややこしいネーミングで混乱する

データ削除の件も気になっていて、

使ってみようとして少し混乱したので。

👉 スマホのマイナカード機能を止める方法 デジタル庁が案内 端末の初期化ではデータは“消えない” - ITmedia NEWS hatena-bookmark

 

📱 スマホ用電子証明書の有効性確認を行う

以下のサイトを見ながら、まずは確認を行ってみようと。

👉 電子証明書の情報確認 / スマホ用電子証明書の有効性確認を行う | 使い方 hatena-bookmark

練習と思い、上の図を mermaid 記法シーケンス図で書いてみました。


👉 スマホ用電子証明書の有効性確認.md hatena-bookmark

 

📱 「電子証明書」の種類

ちょっと、言葉の意味が分からなくなりました。

以下、上記公式ページから抜粋した「電子証明書」たち。


- スマホ用電子証明書
- あなたの電子証明書
- 利用者証明用電子証明書
- 署名用電子証明書
- 発行元の電子証明書
- スマホ用署名用電子証明書
- スマホ用利用者証明用電子証明書
- あなたのスマホ用電子証明書

....。

直感的に分かりません。

うちのおかんが使えるわけねえだろバカが。

考えられるパターンをある程度書き出してみます。


電子証明書
署名用電子証明書
利用者証明用電子証明書
スマホ用電子証明書
スマホ用署名用電子証明書
スマホ用利用者証明用電子証明書
あなたの電子証明書
あなたの署名用電子証明書
あなたの利用者証明用電子証明書
あなたのスマホ用電子証明書
あなたのスマホ用署名用電子証明書
あなたのスマホ用利用者証明用電子証明書
発行元の電子証明書
発行元の署名用電子証明書
発行元の利用者証明用電子証明書
発行元のスマホ用電子証明書
発行元のスマホ用署名用電子証明書
発行元のスマホ用利用者証明用電子証明書
...

こんなにありました?

 

📱 「あなたの」「発行元の」?

私が混乱したのはこの画面。

「あなたのスマホ用電子証明書」か「発行元のスマホ用電子証明書」どちらのスマホ用電子証明書を

???

「あなたの」

「発行元の」

この2つの言葉が私をさらに混乱させています。

マイナンバーカードデータは、インターネットを利用して、データを照会してから処理を進めますので、「スマホアプリ」でいうところの


「あなたの」→「スマホアプリ内に保存している」

「発行元の」→「クラウド上に登録されている」

と解釈するとなんとなく理解することができました。

 

📱 まとめ

日本語を解読するための表を作っておきます。

そもそも、

「利用者証明」と「署名」と「電子証明書」。

このネーミングが混乱の元。

英語圏やプログラミングでは説明しづらくない?

直感的に使えるネーミングは大事。



【OpenAI】API プロンプトトークン数(利用料金)をカウントする

通常のAPIリクエストではレスポンスボディに利用トークンのカウント数は含まれる。


"usage": {
   "prompt_tokens": 9,
   "completion_tokens": 12,
   "total_tokens": 21
 }

👉 API Reference - OpenAI API hatena-bookmark

しかし「Server-Sent Events(SSE)」では、それをレスポンスで返さない。



👉 【OpenAI】Kotlin OkHttp で Server-Sent Events (SSE) hatena-bookmark

従量制のAPIを利用している限り料金は気になりますよね。

プロンプトのトークンの数をアプリ側で独自にカウントすれば料金(利用トークン数から)は算定できるのでは?

 

🤖 JTokkit

Java のライブラリありますね。OpenAI公式でも紹介されているやつ。


👉 openai-cookbook/How_to_count_tokens_with_tiktoken.ipynb at main · openai/openai-cookbook · GitHub hatena-bookmark

豊富な Java ライブラリを使えるのは Kotlin の便利なところです。

👉 Counting Tokens for ChatML | JTokkit hatena-bookmark

とりあえずテストで動かしてみます。


dependencies {
  testImplementation 'com.knuddels:jtokkit:0.4.0'
}


@Test
fun test_jtokkit() {

  val messages = listOf(
    Message("user", "こんにちはと言ってください。"),
    Message("assistant", "こんにちは!")
  )

  val encoding = Encodings.newDefaultEncodingRegistry()
    .getEncodingForModel(ModelType.GPT_3_5_TURBO)

  val count = messages.sumOf { message ->

    // GPT_3_5_TURBO without name
    listOf(
      4, // per message
      encoding.countTokens(message.role),
      encoding.countTokens(message.content)
    ).sum()

  } + 3 // every reply is primed with <|start|>assistant<|message|>

  println(count)

}


@Serializable
data class Message(
  val role: String,
  val content: String
)

メッセージごと、リプライごとのカウント追加が間違ってるのか、なんなのか。

少しカウント数ずれるんだけども。

 

🤖 まとめ

てか、返せよ Usage。

従量制の有料サービスなんだから。

👉 How to get total_tokens from a stream of CompletionCreateRequests - API - OpenAI Developer Forum hatena-bookmark
👉 How do you get token count when streaming - API - OpenAI Developer Forum hatena-bookmark
👉 How to determine the token usage for a session when using stream:true? - API - OpenAI Developer Forum hatena-bookmark

まあ、Webページで確認すればいいけども。

👉 Usage - OpenAI API hatena-bookmark

大して使ってないからどうでもいいか。


【OpenAI】Kotlin OkHttp で Server-Sent Events (SSE)

ChatGPT API で stream 受信したいですよね。

stream boolean Optional Defaults to false

If set, partial message deltas will be sent, like in ChatGPT. Tokens will be sent as data-only server-sent events as they become available, with the stream terminated by a data: [DONE] message.

👉 API Reference - OpenAI API hatena-bookmark

簡単にできそうなのでやってみました。

 

📡 curl

curl で簡単に取得できる。


curl "https://api.openai.com/v1/chat/completions" \
  -H "accept: text/event-stream" \
  -H "authorization: Bearer $OPENAI_API_KEY" \
  -H "content-type: application/json" \
  -d '{
    "model": "gpt-3.5-turbo",
    "messages": [{"role": "user", "content": "Server-Sent Events とは"}],
    "stream": true
  }'


...

data: {"id":"chatcmpl-7OQ1xuBFfam8Ct","object":"chat.completion.chunk","created":1686054286,"model":"gpt-3.5-turbo","choices":[{"delta":{"content":"て"},"index":0,"finish_reason":null}]}

data: {"id":"chatcmpl-7OQ1xuBFfam8Ct","object":"chat.completion.chunk","created":1686054286,"model":"gpt-3.5-turbo","choices":[{"delta":{"content":"います"},"index":0,"finish_reason":null}]}

data: {"id":"chatcmpl-7OQ1xuBFfam8Ct","object":"chat.completion.chunk","created":1686054286,"model":"gpt-3.5-turbo","choices":[{"delta":{"content":"。"},"index":0,"finish_reason":null}]}

data: {"id":"chatcmpl-7OQ1xuBFfam8Ct","object":"chat.completion.chunk","created":1686054286,"model":"gpt-3.5-turbo","choices":[{"delta":{},"index":0,"finish_reason":"stop"}]}

data: [DONE]

パースはだるそうですが、取得はできてるようです!

では、いざ、Kotlin で。

 

📡 okhttp-sse

壊れてるのか何なのか微妙。


testImplementation("com.squareup.okhttp3:okhttp-sse:4.11.0")

👉 okhttp/okhttp-sse at master · square/okhttp · GitHub hatena-bookmark

現在の安定版 4.11.0 ではあやしい。

5.0.0-alpha.11 ではまあまあ動いてるのでそれで。



SSEは、日本語で表現するとサーバ送信イベントと表現されるもので、サーバからクライアントに対してリアルタイムでイベントを送信することができる機能です。 コネクションを張っておいて、サーバからイベントを好きなタイミングで送れるイメージです

 

📡 まとめ

カンファレンスでの公演資料とか、時間が経つと、まあ動かないこと多いですよね!


👉 Server-Sent Events in Android (with Node.js) | by Rahul Ray | Jun, 2023 | ProAndroidDev hatena-bookmark