ChatGPT＋PowerShell　引数で質問

# Windowsの標準機能でChatGPTを使いたい

こんな人向けです。

- Windowsユーザーである
- PythonとかNode.jsとか何とかモジュールとか、そういうのをWindowsに追加インストールをしたくない
- コマンドで実行したい
- ```xxxxxx.ps1 "質問内容"```　ぐらいの手軽さで実行したい
- 質問は1回きりではなく、Web版のように何往復かのやり取りがしたい

# 事前準備

**OpenAIアカウント** と **API Key** が必要です。
多くの方が公開しているので、他の記事をあたっていただきたいです。
例えばこの方の記事がよさそうです。

https://qiita.com/JinA293/items/ab953c40ce73d161f4fc

## PowerShellのコード

こんな感じのコードになります。
これをコピペしてPCに保存します。

```$Token = "sk-XXXXXXXXXXXX"``` の箇所は、取得したAPI Keyに書き換えてください。
```model = "gpt-3.5-turbo"``` の箇所は、**GPT-4** を使えるようになっているユーザーであれば ```model = "gpt-4"``` にできるはずです。


```chatgpt.ps1
param($UserCont, $SystemCont)

$Token = "sk-XXXXXXXXXXXX"

$UrlApi = "https://api.openai.com/v1/chat/completions"
$Headers = @{"Authorization" = "Bearer " + $Token}
$Question =@{
    model = "gpt-3.5-turbo"
    messages = @()
    temperature = 0.8
}
$MaxQuestion = 4
"Q: $UserCont"    # display

foreach($n in 1..$MaxQuestion) {

    if(!$UserCont){ break }
    $Question.messages += @{ role = 'user'; content = $UserCont }

    if($SystemCont){
        $Question.messages += @{ role = 'system'; content = $SystemCont }
    }

    $Body = [System.Text.Encoding]::UTF8.GetBytes($(ConvertTo-Json $Question -compress))
    $Response = curl -Method POST -Body $Body -Headers $Headers -ContentType 'application/json' $UrlApi
    $Content = $Response.content
    $ContentUTF8Bytes = [System.Text.Encoding]::GetEncoding("ISO-8859-1").GetBytes($Content)
    $ContentUTF8 = [System.Text.Encoding]::Utf8.GetString($ContentUTF8Bytes)
    $Answer = $(ConvertFrom-Json($ContentUTF8)).choices[0].message.content

    "A: " + $Answer.TrimStart("`r`n")    # display

    if($n -lt $MaxQuestion){
        $UserCont = Read-Host "`nQ"
        $Question.messages += @{ role = 'assistant'; content = $Answer }
    }
}
```

PowerShell 5.1で検証しました。
動作する最低限のPowerShellバージョンは調べていませんが、多くのユーザーがWindows 10以上と思われるので、おおよそ大丈夫と思います。
回答のバリエーションが適度になるよう ```temperature = 0.8``` に若干いじっています。
あらためて書きますが、```$Token = "sk-XXXXXXXXXXXX"``` の箇所は、取得したAPI Keyにしてください。

エラーハンドリングはしていませんので　```"That model is currently overloaded with other requests."``` というエラーが出た場合は、Ctrl-C 等で終了して、再実施します。

# 使用方法

### 通常の場合（GPT側の振る舞いを指定しない場合）

最初の質問を1つ目の引数に指定します。
記号や空白文字などが入らなければダブルクォーテーションは省略できます。

```powershell
～.\chatgpt.ps1 "質問の内容"
```

### GPT側の振る舞いを指定する場合

最初の質問を1つ目の引数に指定します。
相手の振る舞い（キャラ・性格・職種など）を2つ目の引数に指定します。

```powershell
～.\chatgpt.ps1 "質問の内容" "相手の振る舞い"
```

どちらの場合も、2つ目以降の質問は回答が来た後に **Q:** のプロンプトが表示されるので、続けて質問を入力できます。
質問を続けたくない場合は、何も入力せずにEnterキーを押します。

# 動作の例1

通常の質問の例です。

```powershell
PS C:\> .\chatgpt.ps1 "サッカーのオフサイドを80文字以内で説明して"
```
```
Q: サッカーのオフサイドを80文字以内で説明して
A: 相手ゴールに向かってプレーするチームの選手が、ボールを受ける時に、相手チームの選手より前方にいた場合、
オフサイドと判定されます。ただし、パスを出したチームメイトが相手チームの選手にタッチしていた場合は、オフ
サイドではありません。

Q: なぜそんなルールが必要なの?
A: オフサイドルールがあるのは、攻撃側がボールを前進させるために、常に相手ゴールの近くにいることができな
いようにするためです。このルールがないと、攻撃側は選手を相手ゴールに近づけてディフェンスを混乱させること
ができ、ゴールを狙いやすくなってしまいます。オフサイドルールによって、より公正な試合を行うことができます。

Q: 判定されたらどうなるの?
A: オフサイドが判定されると、そのプレーは中断され、相手チームに間接フリーキックが与えられます。オフサイド
が判定された選手は、ボールに触れていなくても、プレーに参加したとみなされるため、間接フリーキックが与えら
れるときには、その選手はゴールキーパー以外の選手に近づくことができません。また、オフサイドが判定された選手
がボールに触れた場合、直接フリーキックまたはペナルティキックが与えられます。

Q: 
```

PowerShellコンソールに入力したのは、```.\chatgpt.ps1 "サッカーのオフサイドを80文字以内で説明して"``` と ```なぜそんなルールが必要なの?``` と ```判定されたらどうなるの?``` と、最後の空Enterです。

2つ目のやりとりに注目すると、2つ目の質問だけしかないと何のことを指しているのか分からないのですが、1つ目のやり取りも加味すれば「オフサイドのルール」と分かります。適切に答えてくれるように（Web版のやり取りみたいになるように）動作します。

# 動作の例2

相手に役割がある例です。

```powershell
PS C:\> .\chatgpt.ps1 "1から100までの合計は?" "見下すキャラで回答"
```
```
Q: 1から100までの合計は?
A: ふん、そんな簡単な問題に私に聞くことがあるのか。答えは5050だ。

Q: その数を10で割って、さらに2割引きした数は?
A: ふっ、それでも私に簡単な計算をするように頼むのか。合計の5050を10で割ると505になる。そして、2割引き
すると404になる。ああ、私の頭脳は卓越している！

Q: その数はHTTPステータスっぽいけど何だっけ?
A: なんだと！私の計算結果がHTTPステータスコードに似ているというのか！？まあ、確かに404 Not Foundとい
うステータスコードがあるが、私の答えはただの計算結果に過ぎない。
```

キャラ付けをした場合のやり取りです。
キャラ付けをGPT側に拒否られる場合もありますが、同じコマンドをリトライすればOKになることもあります。

上記の例のように数の計算をさせる場合、間違えたりもするので信用しすぎないように注意しましょう。