このワークショップでは、GitHub Copilot を使ってPythonコードの解説や改善を行う方法を学びます。 GitHub Copilot Chat は Chat 体験を通じて AI との対話を行うことができます。 ぜひ、このワークショップを通じて GitHub Copilot の使い方を学んでみましょう。
リソース: https://github.com/yuhattor/copilot-handson-sample
Visual Studio Code の設定を開きます。
設定画面に github.copilot.chat.localeOverride
を打ち込み、ロケールを ja
に設定してください。
下記のファイルを delivery_manager.py
として保存してください。
import random
from typing import List, Callable, Optional, Dict, Any
class KitchenObjectSO:
def __init__(self, name: str):
self.name = name
class RecipeSO:
def __init__(self, kitchen_object_so_list: List[KitchenObjectSO]):
self.kitchen_object_so_list = kitchen_object_so_list
class RecipeListSO:
def __init__(self, recipe_so_list: List[RecipeSO]):
self.recipe_so_list = recipe_so_list
class PlateKitchenObject:
def __init__(self):
self._kitchen_object_so_list = []
def get_kitchen_object_so_list(self) -> List[KitchenObjectSO]:
return self._kitchen_object_so_list
class KitchenGameManager:
_instance = None
@classmethod
def get_instance(cls):
if cls._instance is None:
cls._instance = KitchenGameManager()
return cls._instance
def is_game_playing(self) -> bool:
return True
class DeliveryManager:
_instance = None
@classmethod
def get_instance(cls):
if cls._instance is None:
cls._instance = DeliveryManager()
return cls._instance
def __init__(self):
self.on_recipe_spawned_callbacks = []
self.on_recipe_completed_callbacks = []
self.on_recipe_success_callbacks = []
self.on_recipe_failed_callbacks = []
self.recipe_list_so = None
self.waiting_recipe_so_list = []
self.spawn_recipe_timer = 0.0
self.spawn_recipe_timer_max = 4.0
self.waiting_recipes_max = 4
self.successful_recipes_amount = 0
def add_on_recipe_spawned_callback(self, callback: Callable[[], None]):
self.on_recipe_spawned_callbacks.append(callback)
def add_on_recipe_completed_callback(self, callback: Callable[[], None]):
self.on_recipe_completed_callbacks.append(callback)
def add_on_recipe_success_callback(self, callback: Callable[[], None]):
self.on_recipe_success_callbacks.append(callback)
def add_on_recipe_failed_callback(self, callback: Callable[[], None]):
self.on_recipe_failed_callbacks.append(callback)
def set_recipe_list_so(self, recipe_list_so: RecipeListSO):
self.recipe_list_so = recipe_list_so
def update(self, delta_time: float):
self.spawn_recipe_timer -= delta_time
if self.spawn_recipe_timer <= 0.0:
self.spawn_recipe_timer = self.spawn_recipe_timer_max
if KitchenGameManager.get_instance().is_game_playing() and len(self.waiting_recipe_so_list) < self.waiting_recipes_max:
waiting_recipe_so = self.recipe_list_so.recipe_so_list[random.randint(0, len(self.recipe_list_so.recipe_so_list) - 1)]
self.waiting_recipe_so_list.append(waiting_recipe_so)
for callback in self.on_recipe_spawned_callbacks:
callback()
# レシピの材料と皿の材料が一致しているかどうかを確認する
def deliver_recipe(self, plate_kitchen_object: PlateKitchenObject):
for i in range(len(self.waiting_recipe_so_list)):
waiting_recipe_so = self.waiting_recipe_so_list[i]
if len(waiting_recipe_so.kitchen_object_so_list) == len(plate_kitchen_object.get_kitchen_object_so_list()):
plate_contents_matches_recipe = True
for recipe_kitchen_object_so in waiting_recipe_so.kitchen_object_so_list:
ingredient_found = False
for plate_kitchen_object_so in plate_kitchen_object.get_kitchen_object_so_list():
if plate_kitchen_object_so == recipe_kitchen_object_so:
ingredient_found = True
break
if not ingredient_found:
plate_contents_matches_recipe = False
if plate_contents_matches_recipe:
self.successful_recipes_amount += 1
self.waiting_recipe_so_list.pop(i)
for callback in self.on_recipe_completed_callbacks:
callback()
for callback in self.on_recipe_success_callbacks:
callback()
return
for callback in self.on_recipe_failed_callbacks:
callback()
def get_waiting_recipe_so_list(self) -> List[RecipeSO]:
return self.waiting_recipe_so_list
def get_successful_recipes_amount(self) -> int:
return self.successful_recipes_amount
GitHub Copilot Chat を効率的に使いこなすためには、キーボードショートカットを覚えることが有用です。ここでは、主要なショートカットをいくつか紹介します。これらは、エディタやコードビュー内で素早く Copilot Chat を起動したり、会話を開始したりするのに役立ちます。 macOS:
ショートカットキー | アクション |
Ctrl + Command + I | Chat ビューを開いて Copilot との会話を開始 |
Shift + Command + I | Copilot Edits ビューを開き、複数ファイルの編集セッションを開始 |
Shift + Option + Command + L | Quick Chat を開いて素早く Copilot に質問 |
Command + I | インラインチャットを開始し、エディタ内から直接 Copilot とチャット |
Windows:
ショートカットキー | アクション |
Ctrl + Alt + I | Chat ビューを開いて Copilot との会話を開始 |
Ctrl + Shift + I | Copilot Edits ビューを開き、複数ファイルの編集セッションを開始 |
Ctrl + Alt + Shift + L | Quick Chat を開いて素早く Copilot に質問 |
Ctrl + I | インラインチャットを開始し、エディタ内から直接 Copilot とチャット |
これらのショートカットを使うことで、GitHub Copilot Chat を効率的に活用できます。自然言語での問い合わせや、/
コマンドを使用した特定の指示も可能です。
チャット中に @
を入力すると、ドメインエキスパート(特定の分野の専門家)などのチャット参加者のリストが表示されます。
たとえば、以下のように入力できます。
@workspace どうやって認証を実装するの?
Copilot Chat は自動的に質問を適切な参加者へルーティングすることも可能です。
/
を入力すると、特定のアクション(コードブロックの解説やテスト生成、ドキュメンテーション生成など)を簡潔に指示できます。
コマンド | 説明 |
/explain | 選択したコードブロックやプログラミング概念を Copilot に解説してもらう |
/tests | 選択した関数やメソッドに対してテストコードを自動生成 |
これらのショートカットやコマンドを活用することで、GitHub Copilot Chat からより素早く、より豊かなアシスタンスを得ることができます。
Copilot Chat にこのコードを解説させてみましょう。
delivery_manager.py
の解説を自分のプロンプトで Copilot Chat に尋ねてみましょう。 (必要に応じて説明してもらいたい箇所をカーソルで選択しましょう)例:
このコードは何をしているのか教えてください
2.
/explain
を使ったとき、 Copilot Chat がどのような解説を返してくるか確認してみましょう。
例:
このコードの悪い部分は何かありますか?
このコードはどのような問題を抱えていますか?コードの効率性を向上するために何ができますか
deliver_recipe()
メソッドの中身を改善するためにはどのような方法があるか聞いてみましょう #selection
のコンテキスト変数を使って、特定の部分について聞くことができます。#sym
を使って、シンボルを選択して、そのシンボルについて聞いてみましょう。deliver_recipe()
においてループ処理で効率化できる可能性がわかりました。
改善してみましょう。
例えば、以下のように聞いてみましょう。
効率の良いループ処理を提案してください
以下のコードを logic_errors.py
として保存してください。
def calculate_average(nums):
sum = 0
for i in range(len(nums) + 1):
sum += nums[i]
avg = sum / len(nums)
return avg
numbers = [1, 2, 3, 4, 5]
avg = calculate_average(numbers)
print(f"The average is {avg}.")
このコードを解説させてみましょう。
python logic_errors.py
を実行してみましょう。 インデックスエラーが発生するはずです。
/fix
で修正してもらいましょう。#terminalLastCommand
を使って文脈を指定し、直前のコマンドの実行結果の解説をしてもらいましょう。もし、Python の環境準備ができない場合でも、python logic_errors.py
というコマンドを実行してみましょう。
bash: python: command not found
のようにでた場合は、#terminalLastCommand
を使って、エラーの内容を解説してもらいましょう。 なぜ実行できなかったかは自明ですが、Copilot Chat もターミナルをちゃんと見てくれるか確認してみましょう。
#terminalSelection
を使って、選択した部分について質問してみましょう。任意のコマンドを選択して、そのコマンドや、そのコマンドの実行結果について質問することができます。
pip -h
, python -h
, git -h
などを実行後、出力の一部を選択して、それについて質問してみましょう。#terminalSelection
を使って質問してみましょう。多様なコンテキスト変数を使って、コードの読解を助けるような質問をしてみましょう。
Link: こちらのドキュメントをご覧ください 以下のようにMarkdownテーブルに変換しました。#selection
のようなコンテキスト変数はバッククォートで囲んでいます。
コンテキスト変数 | 説明 |
クイックピックでコンテキストを選択 ( | ワークスペースのファイル、シンボル、現在のエディタ選択範囲や表示内容、ターミナルの選択範囲や最後に実行したコマンド、VS Code APIなどから、チャットのプロンプトに関連するコンテキストを選択できます。 |
コードベースのコンテキスト ( | ワークスペースの関連コンテンツをプロンプトのコンテキストとして追加します。 |
エディタのコンテキスト ( | アクティブなエディタの表示内容をプロンプトのコンテキストとして追加します。 |
選択範囲のコンテキスト ( | 現在のエディタの選択範囲をプロンプトのコンテキストとして追加します。 |
ターミナル選択のコンテキスト ( | 現在のターミナルの選択範囲をチャットプロンプトのコンテキストとして追加します。 |
最後のターミナルコマンド ( | 最後に実行したターミナルコマンドをプロンプトのコンテキストとして追加します。 |
VS Code API ( | VS Code拡張機能開発に関する質問をする際に、VS Code APIをプロンプトのコンテキストとして追加します。 |
ファイル選択 ( | ワークスペースからファイルを選択し、プロンプトのコンテキストとして追加します。 |
ファイル名指定 ( |
|
シンボル選択 ( | ワークスペースからシンボルを選択し、プロンプトのコンテキストとして追加します。 |
シンボル名指定 ( |
|
ドラッグ&ドロップ | ファイルやエディタをチャットにドラッグ&ドロップすると、そのファイルがコンテキストとして追加されます。 |
Copilot Chat は、実行の遅いコードを高速化する方法を提案できます。
ここからのハンズオンでは3のハンズオンのように「コードの改善を確認」するだけではなく、実際に実行してみましょう。また、工夫して早くする方法をAIからどの様に引き出すのか、コードをどの様にモジュールとして書かせるのかなどをトライしてみましょう。
既存のコードが正しく機能するものの非効率的で、パフォーマンスのボトルネックになっていることがあります。パフォーマンスに悪影響を与える可能性があるコーディングの例としては、効率の悪いループ、不要な計算、過剰なメモリ割り当てなどがあります。
Copilot Chatは、パフォーマンスのホットスポットを特定して、データ構造の最適化(配列の代わりにハッシュマップを使うなど)、冗長な計算の削減、アルゴリズムの効率の向上などのリファクタリング戦略を提案できます。
次のPythonコードでは、10,000番目の素数まで、1,000番目ごとの素数が出力されます。これにはタイマーが含まれており、コードの実行にかかった時間が出力の最後の行として表示されます。プログラムの完了には数秒かかります。
import time
def is_prime(n):
if n <= 1:
return False
for i in range(2, n):
if n % i == 0:
return False
return True
def every_1000th_prime():
primes = []
num = 2
while len(primes) < 10000:
if is_prime(num):
primes.append(num)
num += 1
return [primes[i] for i in range(999, 10000, 1000)]
if __name__ == "__main__":
start_time = time.time()
primes = every_1000th_prime()
for prime in primes:
print(prime)
end_time = time.time()
elapsed_time = end_time - start_time
print(f"Time taken: {elapsed_time:.10f} seconds")
このコードのパフォーマンスを最適化してください
Copilot は、エラトステネスの篩の関数を使って素数をより効率的に生成することを提案します。このプログラムを実行すると、ほんの一瞬で完了します。
import time
def sieve_of_eratosthenes(limit):
sieve = [True] * (limit + 1)
sieve[0] = sieve[1] = False
for start in range(2, int(limit**0.5) + 1):
if sieve[start]:
for multiple in range(start*start, limit + 1, start):
sieve[multiple] = False
return [num for num, is_prime in enumerate(sieve) if is_prime]
def every_1000th_prime():
limit = 105000 # Higher than needed to ensure 10,000 primes
primes = sieve_of_eratosthenes(limit)
return [primes[i] for i in range(999, 10000, 1000)]
if __name__ == "__main__":
start_time = time.time()
primes = every_1000th_prime()
for prime in primes:
print(prime)
end_time = time.time()
elapsed_time = end_time - start_time
print(f"Time taken: {elapsed_time:.10f} seconds")
Copilot Chat は、ビジネス ロジックからデータ アクセス コードを切り離し、アプリケーションの保守とスケーリングを容易にする方法を提案できます。
SQL クエリがハードコーディングされ、データ アクセス コードが密結合されていると、データベースのスケーリングや切り替えが困難になり、ロジックの繰り返しにつながることがよくあります。
この Python コードは SQLite データベースに接続し、ユーザー レコードを取得して、ユーザー データを返します。ただし、データベース接続ロジックを抽象化できず、SQL インジェクションに対して脆弱なハードコーディングされたクエリが使用されます。
import sqlite3
def get_user_by_id(user_id):
conn = sqlite3.connect('database.db')
cursor = conn.cursor()
cursor.execute(f"SELECT display_name FROM users WHERE id = {user_id}")
user = cursor.fetchone()
conn.close()
return user
安全で更新・拡張しやすいようにこのコードを改善する方法は何ですか?可能な改善点を挙げてください(修正コードは示さなくて結構です)。
Copilot は、コードの改善に関する提案をいくつか行います。
データベース接続の詳細を抽象化します。 パラメーター化されたクエリを使って、SQL インジェクションを防ぎます。 エラーが発生する場合は、コンテキスト マネージャーを使って、データベース接続が適切に終了されていることを確認します。 エラー処理を追加します。
このコードをより拡張性が高く保守しやすいようにリファクタリングしてください。コンテキストマネージャを使用し、ハードコードされたSQLクエリや密結合されたデータアクセスコードを避けてください。代わりに、リポジトリパターンを使用してデータベース操作を抽象化し、コードをよりモジュール化し再利用可能にしてください。可能な場合はパフォーマンス向上のためにコードを最適化してください。エラートラップを含め、SQLインジェクションに対して脆弱でないことを確認してください。
Copilot は、それぞれが特定の目的を持つ個別のファイルにコードを分割することを提案します。また、ユーザーの詳細を返すコード例も示します。
提案された変更では、リポジトリ パターンが実装され、パラメーター化されたクエリを使って SQL インジェクションが防止されています。
ファイルが実行できない場合、実行処理もコードに追加する様に Copilot に尋ねてみましょう。
修正内容によってはエラーが出る可能性があります。 もしエラーが出た場合は、Copilot Chat にエラーの解決を依頼してみましょう。
# database.py
import sqlite3
class Database:
def __init__(self, db_path):
self.db_path = db_path
def __enter__(self):
self.conn = sqlite3.connect(self.db_path)
self.cursor = self.conn.cursor()
return self
def __exit__(self, exc_type, exc_val, exc_tb):
if exc_type or exc_val or exc_tb:
self.conn.rollback()
else:
self.conn.commit()
self.conn.close()
# user_repository.py
class UserRepository:
def __init__(self, db):
self.db = db
def get_user_by_id(self, user_id):
try:
self.db.cursor.execute("SELECT display_name FROM users WHERE id = ?", (user_id,))
user = self.db.cursor.fetchone()
return user
except sqlite3.Error as e:
print(f"An error occurred: {e}")
return None
# main.py
from database import Database
from user_repository import UserRepository
def get_user_by_id(user_id):
with Database('database.db') as db:
user_repo = UserRepository(db)
return user_repo.get_user_by_id(user_id)
# Example usage
if __name__ == "__main__":
user = get_user_by_id(1)
if user:
print(user)
else:
print("User not found or an error occurred.")
ここでは、GitHub Copilot の slash コマンドを使ってテストを自動生成したり、テストフレームワークを設定したりする方法を学びます。slash コマンドは Copilot Chat 内で利用でき、コマンドを入力することで特定のアクションを実行してくれます。
このハンズオンを通じて、/tests
、/setupTests
、/fixTestFailure
といった slash コマンドの使い方を覚え、テストコードを書くプロセスを支援してもらいましょう。
Copilot は、あなたのコードベースの関数やメソッドに対してテストを自動生成できます。以下の slash コマンドを使うことで、テストに関するさまざまな支援を受けることができます。
Action | Description | |
| エディタ内で選択されたメソッドや関数、または全てに対するテストを自動生成します。生成されたテストは、既存のテストファイルに追記されるか、新しいテストファイルが作成されます。 | |
| あなたのコードに合ったテストフレームワークの設定方法を支援してくれます。どのフレームワークが適切か、設定手順、VS Code 用のテスティング拡張機能の提案を受けることができます。 | |
| 失敗しているテストを修正するためのヒントや提案を行ってくれます。 | |
これらの slash コマンドは Copilot Chat 内で利用することができ、より効率的かつ体系的なテスト作成フローをサポートしてくれます。 |
いくつかの方法で、テストを書いてみましょう GitHub Copilot Chat で /tests
を使った場合と、GitHub Copilot の自動補完機能を使ってテストを書いた場合の違いを見てみましょう。 また、setupTests
や /fixTestFailure
を試してみましょう。
# テストのためのモジュールをインポート
import unittest
# 文字列が渡された場合は、エラーを起こす
# それ以外の場合は、掛け算を行う
def multiply(a, b):
# 数値のみを受け付ける
if not (isinstance(a, (int, float)) and isinstance(b, (int, float))):
raise ValueError("引数には数値を指定してください")
return a * b
# テストを書く
class
自動補完機能で、class
と入力すると、以下のように補ってもらえます。
# テストのためのモジュールをインポート
import unittest
# 文字列が渡された場合は、エラーを起こす
# それ以外の場合は、掛け算を行う
def multiply(a, b):
# 数値のみを受け付ける
if not (isinstance(a, (int, float)) and isinstance(b, (int, float))):
raise ValueError("引数には数値を指定してください")
return a * b
# テストを書く
class TestMultiply(unittest.TestCase):
def test_multiply(self):
self.assertEqual(multiply(2, 3), 6)
エクササイズ:
次に、テストのバリエーションを増やします。
エクササイズ:
# テストのためのモジュールをインポート
import unittest
def multiply(a, b):
# 数値のみを受け付ける
if not (isinstance(a, (int, float)) and isinstance(b, (int, float))):
raise ValueError("引数には数値を指定してください")
return a * b
# テストを書く
class TestMultiply(unittest.TestCase):
# 10 通りのテストパターン
def test_multiply(self):
次にコードを読んでみましょう。 GitHub Copilot Chat に以下のコードをマークダウンにしてもらうように聞いてみましょう。
CREATE TABLE documents (
document_id VARCHAR(63) PRIMARY KEY, -- Primary key, unique ID
store_facility VARCHAR(63) NOT NULL, -- Storage facility (name of the SST where actual data exists)
sst_document_id VARCHAR(63) NOT NULL, -- Communication document ID
title VARCHAR(255) NOT NULL, -- Title
from_adr TEXT NOT NULL, -- Sender's address
to_adr TEXT NOT NULL, -- Recipient's address
data_type VARCHAR(63) NOT NULL, -- Content data type
extra_data TEXT, -- Additional data type
pt_guid VARCHAR(255), -- Patient guide in case of a patient
password_text VARCHAR(63), -- Security password
create_date TIMESTAMP WITHOUT TIME ZONE NOT NULL, -- Creation date
last_status VARCHAR(63), -- Last status
last_caption VARCHAR(255), -- Last description
last_update TIMESTAMP WITHOUT TIME ZONE, -- Last update date
limit_date TIMESTAMP WITHOUT TIME ZONE, -- Expiry date
fix_flg VARCHAR(1), -- Fixed flag (0: normal, 1: fixed)
del_flg VARCHAR(1) -- Delete flag (1: deleted, 0: valid)
);
エクササイズ:
選択した範囲をマークダウンテーブルに変換して
選択した範囲をマークダウンテーブルに変換してください。以下の列を持つテーブルを書いてください No., カラム名, 型, 長さ(length), Decimal, 必須(Yes/No), 主キー, 詳細(日本語)
以下に Python の FastAPI で書かれたコードがあります main.py
のファイルを作成して、/explain
機能を使って解説を出力する際に、より詳細な仕様が返ってくるようにフォーマットを整えてみましょう。 どのように詳細仕様書に変換することができますか?
@router.get('/', response_model=schema.Showarticle)
def all_articles(db: Session = Depends(get_db)):
return article.get_all(db)
@router.get('/{article_id}', status_code=status.HTTP_200_OK, response_model=schema.Showarticle)
def show_article(article_id: int, db: Session = Depends(get_db)):
return article.show_article(article_id, db)
@router.post('/', status_code=status.HTTP_201_CREATED)
def create(articles: schema.ArticleBase, db: Session = Depends(get_db)):
return article.create(articles, db)
@router.put('/{article_id}', status_code=status.HTTP_202_ACCEPTED)
def update_article(article_id: int, articles: schema.ArticleBase, db: Session = Depends(get_db)):
return article.update(article_id, articles, db)
@router.delete('/{article_id}', status_code=status.HTTP_204_NO_CONTENT)
def delete_article(article_id: int, db: Session = Depends(get_db)):
return article.delete(article_id, db)
次に以下のようなフォーマットを与えて書いてもらいましょう。
以下のリストを網羅できるように、API について仕様を書き出してくだくさい
- 処理概要
- アクセスURL
- プロトコル
- メソッド
- GET
- POST
- PUT
- DELETE
- リクエスト
- フォーマット
- JSON
- その他
- パラメータ
- 数
- 名前(例:`article_id`)
- タイプ(数値、文字列など)
- 長さ
- 必須(必須/任意)
- 説明
- 備考
- レスポンス
- フォーマット
- JSON
- その他
- パラメータ
- 数
- 名前(例:`title`)
- タイプ(数値、文字列など)
- 長さ
- 繰り返し(はい/いいえ/回数)
- 説明
- 備考
- サンプル
GitHub Copilot を使うと、Markdown で使える Mermaid表記を使って以下のように図を描いてくれます。
変換をしてみましょう。
https://gist.github.com/yuhattor/cab9ae84bd41608e5d61cb96b76458b6
erDiagram
USERS {
string id PK
string first_name
string last_name
string first_name_kana
string last_name_kana
date birthday
string gender
string uid
string email
boolean email_verified
string phone_number
string picture
string zipcode
string prefecture
string city
string town
string address1
string address2
string building_name
string organization
string industry
string occupation
string employment_type
integer service_years
integer annual_income
float estimated_interest_rate
integer down_payment
integer budget
integer household_income
integer anual_income
integer own_capital
integer liabilities
integer loan_repayment_period
integer family_structure
integer dependents
boolean marriage
boolean has_spouse
datetime discarded_at
datetime created_at
datetime updated_at
}
INQUIRIES {
string id PK
string user_id FK
string listing_id
text message
datetime discarded_at
datetime created_at
datetime updated_at
}
RESERVATIONS {
string id PK
string user_id FK
string listing_id
datetime appointment
datetime discarded_at
datetime created_at
datetime updated_at
}
FILTERS {
string id PK
string user_id FK
string name
string description
string text
string code
string sort
string sort_by
string handover
string parking_lot_availability
string share
integer min_price
integer max_price
integer min_age
integer max_age
integer min_area
integer max_area
string land_rights
json floorplans
json directions
json facilities
datetime discarded_at
datetime created_at
datetime updated_at
}
FAVORITES {
string id PK
string user_id FK
string share
string title
string description
json listings
datetime discarded_at
datetime created_at
datetime updated_at
}
INVITATIONS {
string id PK
string user_id FK
string email
datetime invited_at
datetime canceled_at
datetime activated_at
string activated_by FK
datetime discarded_at
datetime created_at
datetime updated_at
}
USERS ||--o{ INQUIRIES : "has"
USERS ||--o{ RESERVATIONS : "has"
USERS ||--o{ FILTERS : "has"
USERS ||--o{ FAVORITES : "has"
USERS ||--o{ INVITATIONS : "sends"
USERS ||--o{ INVITATIONS : "activates"
Copilot Chat は、同じ操作を別のプログラミング言語で実行するようにコードを書き直すのに役立ちます。
あるプログラミング言語から別のプログラミング言語にコードを移行する理由はさまざまです。各プログラミング言語にはそれぞれの長所と短所があるため、別の言語で使用できる機能を使いたい場合があります。
次のPerlスクリプトは、ユーザーにテキスト ファイルのパスの入力を求めるものです。ユーザーが入力した内容をチェックし、そのパスでテキスト ファイルが見つかった場合は、ファイルの内容の単語数と文字数を出力します。
#!/usr/bin/perl
use strict;
use warnings;
use File::Spec;
use File::Basename;
print "Please enter the path to a local text file: ";
chomp(my $file_path = <STDIN>);
if ($file_path =~ /[`|;&<>(){}\[\]]/ || !File::Spec->file_name_is_absolute($file_path) && dirname($file_path) ne '.') {
die "Invalid file path. Please provide a valid path.\n";
}
if (!-e $file_path) {
die "File not found. Please provide an existing file path.\n";
}
open(my $fh, '<', $file_path) or die "Could not open file '$file_path': $!\n";
my $is_binary = 0;
while (read($fh, my $buffer, 1024)) {
if ($buffer =~ /[^\x09\x0A\x0D\x20-\x7E]/) {
$is_binary = 1;
last;
}
}
close($fh);
if ($is_binary) {
die "The file '$file_path' is a binary file. Please provide a text file.\n";
}
open($fh, '<', $file_path) or die "Could not open file '$file_path': $!\n";
my $content = do { local $/; <$fh> };
close($fh);
my $word_count = scalar(split /\s+/, $content);
my $char_count = length($content);
print "The file '$file_path' contains $word_count words and $char_count characters.\n";
このPerlスクリプトをPythonに変換する方法を教えてください。新しいスクリプトの機能と出力は既存のものと全く同じでなければなりません。また、新しいファイルを実行する方法も教えてください。
Copilot により、次の Python コードが生成されます。
import os
import re
def is_binary(file_path):
try:
with open(file_path, 'rt', encoding='utf-8') as file:
file.read(1024)
return False
except UnicodeDecodeError:
return True
file_path = input("Please enter the path to a local text file: ")
if re.search(r'[`|;&<>(){}\[\]]', file_path) or (not os.path.isabs(file_path) and os.path.dirname(file_path) != '.'):
raise ValueError("Invalid file path. Please provide a valid path.")
if not os.path.exists(file_path):
raise FileNotFoundError("File not found. Please provide an existing file path.")
if is_binary(file_path):
raise ValueError(f"The file '{file_path}' is a binary file. Please provide a text file.")
with open(file_path, 'r', encoding='utf-8') as file:
content = file.read()
word_count = len(content.split())
char_count = len(content)
print(f"The file '{file_path}' contains {word_count} words and {char_count} characters.")
このファイルを wordcount.py
として保存します。
次に、新しいファイルを実行する方法が Copilot から説明されます。
python wordcount.py
これで、元の Perl スクリプトと同じ機能を持つ Python スクリプトが完成し、実行方法も説明されました。
GitHub Copilotでは、リポジトリ固有のカスタムインストラクションを設定することで、特定のプロジェクトに関連する質問に対してより適切な回答を得ることができます。このセクションでは、リポジトリカスタムインストラクションの設定方法と活用方法を学びましょう。
リポジトリカスタムインストラクションは、特定のリポジトリに関連するCopilot Chatの質問に自動的にコンテキスト情報を追加する機能です。チームの開発スタイル、プロジェクト固有の規約、使用するフレームワークなどの情報を設定しておくことで、毎回同じ情報を質問に含める必要がなくなります。
これらの指示はチャット上には表示されませんが、Copilotが回答を生成する際に参照され、より質の高い回答を提供するために使用されます。
.github
ディレクトリを作成します(存在しない場合).github
ディレクトリ内に copilot-instructions.md
ファイルを作成します例えば、次のような内容を追加できます:
このプロジェクトではTypeScriptを使用し、コードスタイルにはESLintとPrettierを使用しています。
すべてのコンポーネントはReact関数コンポーネントとして実装し、Hooksを積極的に活用してください。
APIリクエストにはAxiosを使用し、状態管理にはReduxを使用しています。
効果的なリポジトリカスタムインストラクションを作成するためのポイントは以下の通りです:
.github
フォルダを作成しますcopilot-instructions.md
ファイルを作成しますこのプロジェクトでは以下の規約を守ってください:
1. JavaScriptコードは、ダブルクォートとタブインデントを使用します
2. 関数にはJSDocコメントを必ず付けてください
3. コンポーネント名はPascalCase、変数・関数名はcamelCaseで命名します
4. テストは必ずJestを使用して記述してください
Copilot Chatでカスタムインストラクションを使用するかどうかを選択できます:
この設定は変更するまで保持されます。
終了した方は、 Agent Hands-onにすすみましょう。