GitHub Copilotの威力（日本語からソースコード自動生成）

# 概要
「**GitHub Copilot**」を使用して、日本語からソースコードを半自動生成させてみました。
また、しばらく試行してみて、Copilotの活用シーンを整理しました。

# Copilotとは
 
2020年5月にイーロン・マスク氏らが関わっているAIの非営利団体**OpenAI**によって、自然言語モデル**GPT-3**が発表されました。このモデルは、生成された文章が、人間が書いたのかAIが書いたのか区別できないほど高精度なモデルということで当時、話題になりました。

OpenAIではGPT-3をカスタマイズし、**自然言語からソースコードを生成するCodexモデル**を開発していましたが、**OpenAIとGithubが提携**したことによって、Githubで公開されている数十億行のコードを学習させることができるようになり、より高精度なソースコードを生成させることが出来るようになりました。

そして、2021年6月29日にGithubによって、Codexモデルを利用した開発支援機能「**GitHub Copilot**」が発表されました。
OpenAI Codexは、APIでの利用のため使用方法が限定されていましたが、GitHub Copilotは、下記のような開発環境のアドオンとして機能追加できるため、よりユーザが使いやすいようになっています。

■Copilot対応 開発環境
- Neovim
- JetBrains IDE
- Visual Studio
- Visual Studio Code 

なお、Github Copilotの費用は、最初の60日間は無料で、その後は有料で以下2プランから選択することになります。

■契約プラン
- 10ドル/月
- 100ドル/年

# 試行環境
今回、ソースコードを自動生成させた環境は下図の通りです。
実行環境はWindows11上に構築したWSL2/Ubuntu20.04です。
Windows11上に**Visual Studio Code**をインストールし、拡張機能である「**GitHub Copilot**」と「WSL」を追加します。（下図「1.」と「2.」）

「GitHub Copilot」を追加することで、GitHub認証後に**GiHub Copilot**と連携できるようになります。（下図「3.」）
文章を与えると自動的にソースコードが提示（サジェスト）されます。この提示されたソースコードは、**OpenAI**の**Codexモデル**が利用されています。（下図「3.」～「6.」）

なお、Copilotとは関係ないですが「WSL」をVisual Studio Codeに追加することで、WSL内のファイルを制御できるようになります。


- 実行環境イメージ
```mermaid
flowchart TB
  GCK["拡張機能GitHub Copilot"]
  WSLK["拡張機能WSL"]
  subgraph Windows11/WSL2/Ubuntu20.04
    VS["Visual Studio Code"]

  end
            GCK-->|1.追加|VS
            WSLK-->|2.追加|VS


  subgraph Open AI
    Codex
  end
  subgraph GitHub   
    GC["GitHub Copilot"]
    GC
  end

  direction RL
    GC -->|4.文章| Codex
    VS -->|3.GitHub認証/文章| GC
    Codex -->|5.コード| GC -->|6.コード| VS


```


# 自動生成イメージ
Visual Studio Codeでソースコードを自動生成させるのは、とても簡単です。
**基本は待つだけです。** 1~2文字でも入力すれば、Copilotが何かしらソースコードを提示してくれます。時には、何も入力しなくても提示してくれることもあります。

例えば、下図のように「import」と入力して1秒ほど待つと、「requests」というコードが提示されます。
この**内容を受け入れる場合はTabキー**を押下します。
![suggest0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276223/83650252-96ef-fb44-08cc-f1eb5679ab3c.png)
Tabで受け入れて改行すると、今度は次の行のコードが自動的に提示されます。
提示されたコード「from requests_oauthlib import OAuth1Session」を受け入れる場合は、Tabを押下します。
![suggest0_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276223/cf33f388-79bf-8ab8-381e-92af7e397fd5.png)
改行すると、また次のコードが提示されます。
![suggest0_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276223/8480c82b-7f04-1f7a-1b3f-8a9f7cfbf8a1.png)
さらに改行すると、また次のコードが提示されます。
![suggest0_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276223/4781b9fd-37c8-1212-418b-0501184f9fdb.png)
繰り返し提示されます。
![suggest0_4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276223/d52ba30a-a2a0-6f5c-6c62-98dfae33d2ce.png)
このように、**Tabと改行を繰り返すだけで、Copilotが勝手にソースコードを生成してくれる**のです。




<!-- 時間があれば動画/gif画像を付ける -->

また、提示された際に「**Ctrl+Enter**」を押下すると、ある程度まとまった範囲で提示してくれます。
例えば、「requests」が提示された際に「Ctrl＋Enter」を押下すると、下図のように纏まったソースコードが10パターン提示されます。
選択したいパターンの「**Accept Solution**」をクリックすると、そのコードを全て書き込んでくれます。
![suggest2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276223/66faca74-099a-d99a-75a2-5a8d9f5d160d.png)



# 試行
では、より実践的に開発してみます。
今回は、以下の**3行のコメントをVisual Studio Codeに入力して、コードを自動生成**してみます。
あらかじめ、ファイル名には.pyとPythonと分かるようにしておきます。（Copilotは、Python以外も対応していますが、サジェストの採用率はPythonが40％と高いようです。）

```comment:開発したい内容をコメント文で入力
# ニュースサイトをクローリングして、時系列順にAIのキーワードを抽出する。
# 抽出したキーワードからWordCloudを作成する。
# 作成したWordCloudをTwitterに投稿する。
```

結果は、ほぼ、**Tabと改行だけでソースコードの土台ができました**。
下記に、提示されたソースコードの一部を紹介します。


Twitterに投稿するための各種キーの設定です。OSの環境変数から取得するようになっています。
なお、**コメント行も自動で生成されます。**
```suggest:サジェスト例１
# Twitter APIのキーを設定
CK = os.environ['CK']
CS = os.environ['CS']
AT = os.environ['AT']
AS = os.environ['AS']
```

クローリングするサイトのURLを指定しています。
```suggest:サジェスト例２
# ニュースサイトのURLを設定
URL = 'https://www3.nhk.or.jp/news/easy/k10011852901000/k10011852901000.html'
```

まるで「**クローリングなんて簡単、簡単！**」と言わんばかりに、あっという間にBeautifulSoupを用いた処理を生成します。
```suggest:サジェスト例３
# ニュースサイトをクローリングして、本文を取得する
def get_news_text(url):
    r = requests.get(url)
    soup = BeautifulSoup(r.text, 'html.parser')
    news_text = soup.find('div', class_='text').text
    return news_text
```

次は、Mecabを使用してキーワードのみを抽出します。
「**私は自然言語にも強いのよ。**」と言っているようです。
```suggest:サジェスト例４
# 本文からAIのキーワードを抽出する
def get_ai_keywords(text):
    # 形態素解析
    tagger = MeCab.Tagger('-Ochasen')
    tagger.parse('')
    node = tagger.parseToNode(text)
    keywords = []
    while node:
        # 品詞が名詞、動詞、形容詞の場合にキーワードとして抽出
        if node.feature.split(',')[0] in ['名詞', '動詞', '形容詞']:
            keywords.append(node.surface)
        node = node.next
    # キーワードをカウント
    keywords_count = {}
    for keyword in keywords:
        if keyword in keywords_count:
            keywords_count[keyword] += 1
        else:
            keywords_count[keyword] = 1
    # キーワードを降順に並び替え
    keywords_count = sorted(keywords_count.items(), key=lambda x:x[1], reverse=True)
    return keywords_count
```

さらに、「**WordCloudなんて、もう古い技術だけど仕方ないわね**」と言われたりして、、、
```
# 抽出したキーワードからWordCloudを作成する
def create_wordcloud(keywords_count):
    # フォントを設定
    font_path = '/usr/share/fonts/truetype/fonts-japanese-gothic.ttf'
    # マスク画像を設定
    mask = np.array(Image.open('mask.png'))
    # WordCloudを作成
    wordcloud = WordCloud(background_color='white', font_path=font_path, mask=mask)
    wordcloud.generate_from_frequencies(dict(keywords_count))
    # WordCloudを保存
    wordcloud.to_file('wordcloud.png')
```

最後は、Twitterに投稿して、「**はい。いっちょうあがり！**」という感じです。
```
# WordCloudをTwitterに投稿する
def post_wordcloud():
    # 画像を読み込む
    files = {'media[]': open('wordcloud.png', 'rb')}
    # ツイート本文を設定
    text = 'AIのキーワードを抽出したWordCloudです。'
    # Twitterに投稿
    twitter = OAuth1Session(CK, CS, AT, AS)
    url = 'https://upload.twitter.com/1.1/media/upload.json'
    req_media = twitter.post(url, files=files)
    if req_media.status_code != 200:
        print('画像のアップロードに失敗しました。')
        sys.exit()
    media_id = json.loads(req_media.text)['media_id']
    url = 'https://api.twitter.com/1.1/statuses/update.json'
    params = {'status': text, 'media_ids': media_id}
    req_media = twitter.post(url, params=params)
    if req_media.status_code != 200:
        print('ツイートに失敗しました。')
        sys.exit()
    print('ツイートしました。')
```

ここまで作った関数を呼び出すmain処理も全て自動で作成されます。
```
def main():
    # ニュースサイトをクローリングして、本文を取得する
    text = get_news_text(URL)
    # 本文からAIのキーワードを抽出する
    keywords_count = get_ai_keywords(text)
    # 抽出したキーワードからWordCloudを作成する
    create_wordcloud(keywords_count)
    # WordCloudをTwitterに投稿する
    post_wordcloud()

if __name__ == '__main__':
    main()
```

ただ、永遠と提示されるので**辞め時は人間が判断しなければなりません**。
最終的には、私が多少デバッグを行い、下図のようなWordCloudを作成させることが出来ました。

- 結果例１
AIニュースサイト「[ledge.ai](https://ledge.ai/theme/news/)」から生成したAIキーワード
![wordcloud_ledge.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276223/845a6014-95e8-7c1d-d5d2-af3112e13a27.png)
- 結果例２
AIニュースサイト「[ainow.ai](https://ainow.ai/)」から生成したAIキーワード
![wordcloud_aiknow.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276223/bd3be175-972f-b6a1-cffc-092c2938660c.png)



# Copilotの活用シーン
しばらく試行した結果、私なりにCopilotの活用シーンを整理しました。

## Copilotを使う良いタイミング
| 区分   |     項目      | 評価 |
| ---: | ----------- | :-------: |
| 1    | 設計 |     - |
| 2    | コーディング |   ◎ |
| 3    | テスト |   - |
| 4    | デバッグ |   ◎ |

開発工程においてCopilotを活用できるのは、**コーディング時**と**デバッグ時**だと思います。
**コーディング時はほとんど何もしなくて良かった**ため、考えるまでもなく評価「◎」としています。
人間の出番はデバッグ時からですが、**デバッグ時のCopilotの威力が尋常ではない**と感じました。
例を３つ挙げます。

#### デバッグ例１
下図のようにプログラム中の変数の中身を表示しようと「#デバッグ用」と打ち込むだけで、**デバッグ用の構文を自動生成**してくれました。（赤枠の箇所）
Copilotが**前段のキーワードに関する処理を考慮して**デバッグ文を提示してくれるのです。何を表示したいのか当てられてしまい、正直、**自分の心が見透かされている**と感じました。
![suggest_A2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276223/d7409f4b-4921-13b9-e462-183c1788bb6f.png)

#### デバッグ例２
また、BeautifulSoupでfind関数だと欲しいデータが取得できなかったため、私がfind_all関数に書き換えたのですが、戻り値news_textの型を知らず、print文でどう指定すれば良いか分かりませんでした。そのような時、「print」と打ち込むだけで、残りの変数名「new_text[0].text」など**配列の要素を含んだ変数を自動補完**してくれました。いちいち、**Webで調べたりドキュメントを参照したりする手間が省けて、非常に楽**でした。
![suggest_A3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276223/3a55d208-6f02-8967-8e7e-0c9152cbc975.png)

#### デバッグ例３
さらに、変数が配列型では使いにくかったので、テキストに変換したいなと思い、コメントで「# 配列から」と打ち込むと「抽出したテキストを結合」と補完され、対応する処理を自動提示してくれました。
**プログラミング言語によって微妙に仕様が異なる紛らわしい配列操作をいとも簡単に提示**してくれるのです。
![suggest_A4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276223/e7aba5e8-6075-9b8b-4bcc-ab37d8312f37.png)

## Copilotを活用できる人、活用できない人
| 区分   |     項目      | 評価 |
| ---: | ----------- | :-------: |
| 1    | プログラミング言語未経験者|      ○ |
| 2    | **初心者～上級者**|      ◎ |
| 3    | こだわり派 |      △ |

**多くの人がCopilotの恩恵を受けられる**と考えています。
仮にプログラミング言語の理解が2割程度であっても、大半はCopilotが自動生成してくれますので、最後のデバッグのみを人間が対応すれば、一応、完成までたどり着けるのではないかと思います。まさに、AIとの**ペアプログラミング**です。（**初心者◎**）

仮に、言語を全く知らずデバッグが出来なかったとしても、言語に詳しい方にデバッグだけお願いすれば良い訳ですから、一からお願いするよりもはるかに**短期間、低予算**で委託することが出来るはずです。（**未経験者○**）

もちろん、言語を10割理解している上級者であっても、**生産性は圧倒的にCopilotが高い**はずですから、**ベースはCopilotに任せて、気になる箇所だけ人間が修正**すれば良いとも思います。（**上級者◎**）

逆に、自分の**ソースコードにこだわりを持っている方**は、AIが提示したソースコードには気に入らないコードと感じる場合もあるかもしれません。AIが提示したと言っても結局は、GitHub上にあるソースコード群をもとに提示されているため、思想の異なるコーディングが次々に提示される可能性もあります。

例えば、**「a + b」を計算**するサジェストにおいて、ある時は**変数「x」に代入**し、また、ある時は **「+=」を使って「a」を上書き**するというような、細かなサジェストの違いが発生する可能性があります。
```rei:Copilot提示例１
 x = a + b
```
```rei:Copilot提示例２
 a += b
```
どちらのサジェストが良いということはないですが、**ソースコード全体としての統一感が失われる**ことがあります。
このような動作を嫌い、自分でコーディングしたいと思われる方は、あまり向いていないかもしれません。（**こだわり派△**）

## Copilotが向いている開発、向いていない開発
| 区分   |     項目      | 評価 |
| ---: | ----------- | :-------: |
| 1    | 研究関連 |     ◎ |
| 2    | アジャイル開発 |     ◎ |
| 3    | ミッションクリティカル |   × |
| 4    | 最先端技術開発 |   △ |

Copilotでは、GitHub上のソースコードからサジェストされていると考えると、**研究要素が強いソースコードが多い**のではないかと推測します。このため、**ソースコードに一部誤りがある**可能性は否定できません。
そのようなソースコードでも許容できる開発を考えると、同じように**研究関連の開発**や**アジャイル的に試行錯誤しながら開発できるような案件**が向いていると思います。（**研究開発◎、アジャイル開発◎**）

一方、**ミッションクリティカルなシステム開発**には向いていないと思います。
止まってはいけない社会的にも重要なシステム（交通機関や金融機関など）は、高品質なプログラムを要求されますので、フールプルーフやフェイルセーフを意識してエラー処理を作りこむことがあると思いますが、Copilotが提示するソースコードに**細部を考慮したエラー処理がない**可能性が高いと考えています。あるいは、高速処理を要求されるようなシステムでは、性能を意識したコーディングが必要ですが、こちらも**Copilotの提示が最良と判断するのは尚早**だと思います。このような**高品質なプログラムを要求される場合はCopilotを使用するのはリスク**と考えておいても良いでしょう。（**ミッションクリティカル×**）

他には、最新技術を使用したい場合には、なかなか所望のソースコードを提示してくれない可能性が高いです。
もちろん、コメントで最新技術を提示するよう指定することは可能ですが、GitHubに登録されているソースコードが少ないと限界があります。（**最先端技術開発△**）

### その他特徴
Copilotの仕様上の特徴ですが、何も提示するものがなさそうな時は、**過去に提示した履歴から提示することがある**ようです。
おそらく、人間が与える文章が少なすぎて何を提示して良いのか分からない時に、このような動作になる仕様だと思われます。





# 感想
Copilotを60日間の試行期間中に使ってみようと思っていましたが、全く時間が取れず、結局、月額利用で試してみました。
実際、私の場合、大体、**コーディング時間は十分の一**くらいにはなっていると思います。
すぐに辞めるつもりではありましたが、**かなりの時間短縮**になり、一度、この感動を味わってしまうと、辞めるのは惜しいと考えています。
**何かを作りたいときだけ一時的に利用するのであれば、費用対効果の面で十分あり**だと思いました。


# 補足
Copilotが作成したファイルと私がデバッグしたファイルを下記に登録しました。

https://github.com/artisanbaggio/Copilot_test.git
「test_only_copilot.py」←Copilotのみが生成したソースコード。このままでは動作しません。
「test_only_copilot_human.py」←Copilotのソースコードに私が手を加えたものです。動作しますが、Twitter投稿まではしません。

# 参考サイト
[GitHub Copilot](https://github.com/features/copilot)
[OpenAI Codex](https://openai.com/blog/openai-codex/)

以上、最後までお読みいただき、ありがとうございました。