【Python】開発経験ゼロの一般クリエイター兼人事が”AIの力だけで”Slackからアイコン画像一覧を取得した話【SlackAPI】

こんにちは!人事広報チームの石井です。

今回は非エンジニアの僕がAIのみ使用し、プログラムを作成したという話についてご紹介します!

僕はエンジニアではなく、ただのクリエイター

改めてですが、僕はエンジニアではなく、普段は人事広報に関する業務や、映像や画像などのクリエイティブな仕事をメインにしています。

エンジニアが多い弊社では、様々な開発に関する会話が展開されていますが、エンジニアリング、プログラミング等々、ガチで1ミリも分かりません
何がどう影響するものなのか、これで何が作れるのか、何も分かっていないという知識レベルです。

僕の詳細は社員インタビューをご覧ください!

【社員インタビュー】クリエイター:石井さん

キッカケは社員からのひとこと

そんな「コード?HDMIの話?」状態の僕がなぜ急にプログラミングを作ることになったかというと、同クリエイターの藤野さんから来た連絡がキッカケとなります。

送られたきた内容は、最近の帰社日はオフライン開催が多く、交流促進のために各社員に名札をつけてもらい、情報としてSlackのアイコンを取り入れるのはどうかという提案でした。
人事部内で相談の結果、すぐ導入できそうなのと、工数もそれほどかからなさそうという点から次回の帰社日以降、取り入れることになりました。

話は少しズレますが、先日エンジニアの三沢さんが業務効率化推進のために、AIチャットツール「Poe(ポー)」というサービスを社内に導入してくれました。

個人が作ったBOTやAIなども含みますが、50万以上のボットが搭載されているツールのようです。

そんなPoeを使って「Slack名一覧取得とアイコン画像取得するプログラムを非エンジニアの僕でもAIの力を使えば作れるのか」という検証を兼ねたのが今回のプロジェクト。

個人的に面白そうだなと感じたので早速取り掛かってみることにしました!

実際にAIにコードを教えてもらおう

まずはGemini1.5ProというGoogleが開発した高性能マルチモーダルAIモデルに今回のプロジェクトの概要をザックリ伝えてみます。

すると、「SlackAPIを使えばできるよ」という回答が出ました。正直この時点でチンプンカンプンで読む気すら失せてましたが、とりあえず言われた通りにやってみます。

上記手順2にあったスコープの設定画面です。Geminiから教えてもらったものをそのまんま指定して進めていきます。

分からないところは詳細に教えてもらうようにキャッチボールをし、より解像度を高めるように指示通り行ったところ….

Slackのワークスぺース内になんとかインストールすることができました。あとはここから実際に名前やアイコンを取得できればゴール・・?!

と思うもつかの間。Geminiから提示されたPythonのコードでつまずきます。

なんだこの呪文は

まずPythonって何か知らないし、いきなり「コードを書きます」と言われてもどこに書けばいいのかすら分からないのです。

とりあえずWindows内のメモ帳でいいだろうということで、記載されているコードをコピーしメモ帳内に貼り付けます。


Geminiからの指示によると「拡張子は.pyにする」という記述があったので.txtから.pyに変え保存。(後にbot.pyからslack_api.pyというファイル名に変更してます)
Pythonファイルが出来上がりました。

これで本当に合っているのか不安になりながら、次の手順をGeminiに質問してみます。

ふむ、Pythonのインストールか。

当然ながら非エンジニアの僕はPythonを起動するソフトを持ち合わせておらず、インストールするところからはじめました。

次の指示にてcmdにて「python slack_api.py」と入力とあり、言われた通り実行しても「指定されたパスが見つかりません。」やら「ディレクトリ名が無効です。」やら言われ、エラーの嵐。どこでつまずいているのかも分からん…….。

悪戦苦闘すること1時間。色々調べた結果、Pythonがちゃんとインストールされていなかったようです。なんやねんそれ(笑)

再インストールをして、再度実行したところ、人の名前とその人のアイコンが記述されたtxtファイルが生成されました。進んだ!!!

しかし、中身を見てみると、正社員以外にBOTやシングルチャンネルゲスト、解約済みのアカウントのデータまで取られていました。
この状態でそれぞれのアイコンを抽出しても、事実上不必要なデータが混ざっている状態になり、完成度・クオリティ共に低い状態で終わってしまいます。
また、表示されていた名前は略称であり、フルネームが出力されているわけではありませんでした。

そこで、Geminiに対して追加注文をしてみます。

すると、以下のコードが帰ってきました。

import requests

# 手順1でコピーしたアクセストークンを貼り付けてください
token = "xoxb-key" 

# users.list API を呼び出す
url = "https://slack.com/api/users.list"
headers = {"Authorization": f"Bearer {token}"}
response = requests.get(url, headers=headers)

# レスポンスを確認する
if response.status_code == 200:
    data = response.json()
    members = data["members"]

    # ファイルに書き込む
    with open("members_info.txt", "w", encoding="utf-8") as f:
        for member in members:
            # シングルチャンネルゲストとボット、無効化されたユーザーを除外
            is_restricted = member.get('is_restricted', False)
            if not member['is_bot'] and not is_restricted and not member.get('deleted', False):
                # ユーザー情報をカンマ区切りで書き込む
                f.write(f"username: {member['name']},email: {member['profile'].get('email', '')},status: {member['profile'].get('status_text', '')},billing-active: {member.get('billing_active', '')},has_2fa: {member.get('has_2fa', '')},has_sso: {member.get('has_sso', '')},userid: {member['id']},fullname: {member['profile']['real_name']},displayname: {member['profile']['display_name']},expiration-timestamp: {member.get('expiration_ts', '')},Image URL: {member['profile']['image_512']}\n")
    print("メンバー情報が members_info.txt に保存されました。")
else:
    print(f"Error: {response.status_code}")

input("Press Enter to exit...")

この内容をslack_api.pyに上書きし、実行すると…。

シングルチャンネルゲストとボット、解約されたユーザーを除外された「members_info.txt」というファイルが生成されました。
中身を見てみると、確かに現役社員のみのデータが抽出されています!やったぜ!

最後にこのtxtを元に、各自がアイコンに設定している画像を指定したフォルダに保存してもらうようにコードを書いてもらいます。

import os
import requests

# members_info.txtを読み込む
with open("members_info.txt", "r", encoding="utf-8") as f:
    lines = f.readlines()

# 保存先フォルダを指定する
save_folder = "member_images"

# フォルダが存在しない場合は作成する
if not os.path.exists(save_folder):
    os.makedirs(save_folder)

# 名前と画像URLを抽出し、画像をダウンロードする
for line in lines:
    # カンマ区切りで情報を取得
    elements = line.strip().split(",")
    data = {}
    for element in elements:
        key, value = element.split(": ", 1)
        data[key] = value
    
    name = data.get("fullname", "")  # フルネームを取得
    image_url = data.get("Image URL", "")

    if name and image_url:
        # ファイル名を生成する
        image_name = f"{name}.png"
        save_path = os.path.join(save_folder, image_name)

        # 画像をダウンロードする
        try:
            response = requests.get(image_url)
            response.raise_for_status()  # HTTPエラーが発生した場合、例外を発生させる

            with open(save_path, "wb") as image_file:
                image_file.write(response.content)

            print(f"{name} の画像を保存しました: {save_path}")

        except requests.exceptions.RequestException as e:
            print(f"{name} の画像のダウンロード中にエラーが発生しました: {e}")

フォルダ名を指定したり、どの階層に保存するかなど、必要な情報を追加で与えたりして最終的に上記のコードが生成されました。これを「download_images.py」と命名し、実行します。

すると・・・。

ドババババと「~~の画像を保存しました」とログが出ました!

指定した保存先を見てみると

ちゃんと全社員分の画像が保存されていました!!!やった~!

 

まとめ

ご覧のように全くエンジニアの経験がなく、知識もない状態でも、AIだけを用いてプログラミングを書いてもらい、自分の思い通りに操作することができました!

ただ、様々な死闘を繰り広げた結果、たくさんのファイルが出来上がってしまいましたw

いつもの僕であれば画像を右クリックして保存などかなりアナログな方法で画像を保存していますが(Slackにおいては)、非エンジニアの僕でも似非プログラマーとしてエンジニア気分を味わうことができました。
AIを使ったとはいえ、今どのコードを改変してもらっているのか、次にやらなければならないことは何か….途中訳わからなくなって途方に暮れた瞬間がありました。
でもそこで投げ出さなくてよかったなと感じましたし、最終的に画像が出力された時、素直に嬉しく達成感がありました!

そして、今回の処理にかかった時間は約6時間w。現役のエンジニアであればこんなの数分で出来ちゃうんだろうなと思うとプロはすごいなと改めて実感します。

…最後にこの様子をチラチラ見ていた同事業部でエンジニアの三沢さんとWEBデザイナーの荒井さんに感想を聞いてみました。

エンジニア:三沢
午前中にPoe使ってやってみたら?といってすぐに会議だったので、やり始めたことも知らないまま、気づいたらPythonファイルが出来上がっていたので驚きました。 横目に見つつ唯一口を出したのが、.pyファイルをダブルクリックしてもメモ帳で開けないからか、いちいち.txtに直して編集してから.pyに戻しているのを見たときです。
.pyのままでもメモ帳で開けることを教えてあげました。このエピソードで本当にプログラミング経験がゼロということが伝わると思います。
日頃から社内に向けて生成AIを使いこなせるエンジニアになれ」と発信しているのですが、エンジニアではない彼が1日でSlackAPIを使えるようになったわけですから、エンジニア職でまだ生成AIにあまり触れてない社員のいい刺激になったんではないでしょうか笑
WEBデザイナー:荒井
よりにもよってPythonをメモ帳で書いてるのが面白かったです。インデントがずれるとエラーになってしまうので、本来ならプログラミング向きのエディタを使うべきなのですが…。自分も昔メモ帳でホームページ作ってたなぁと懐かしい気持ちになりました。
今回のようにやりたい事が明確に見えていれば、全く経験の無い方でもAIを使ってプログラムを書くのは難しい事ではないと思います。
今後も日々の業務の中で「これは〇〇したら自動化できるんじゃないか?」と気づく事があればどんどん挑戦してみてほしいです!

これからはAIの時代と言われていますし、自身の業務領域はどんどんAIを駆使して効率化図っていければ良いですね!

今からエンジニア目指そうかな~w(無理みが深い)

それでは!!