Slack Emojiを支える技術

この記事はAkerun Advent Calendar の2日目の記事です。 今回は弊社のSlack Emojiを量産する技術についてです。

Emojiは全従業員共通の概念

f:id:photosynth-inc:20171202214637g:plain

最初にEmoji(当時はEmoticonと呼んでいた)がSlackに追加されたときには、弊社のエンジニアやデザイナーがちょっと盛り上がった程度で終わっていました。

ですが、社員も増えて来てタイミングで大量にEmojiを追加してみたら、なんと皆さんいい感じに食いついてきて、今では一部の社員だけでなく、アルバイト含めた全従業員がカジュアルにEmojiを使っています。

またコミュニケーションが円滑に進んだり、業務の完了やステータスを伝えるために使われていたりと、多種多様案使い方のために、各自でカスタムEmojiを追加したりもするようになってきたので、その辺のEmoji追加を支える技術について書きたいと思います。

代表的な二つのChrome Extensionを導入する

これがあるとないとでは、今後のEmoji生活が変わってきます。 絶対に入れましょう。

複数のEmoji画像を一度にアップロードする

chrome.google.com

まず、ネットにある沢山のEmoji画像を大量にぶち込みたいので、このChromeExtensionを導入します。 これを導入することで、SlackのEmojiの管理画面に、以下の用にEmojiをドラッグアンドドロップできる、Viewが追加されます。

f:id:photosynth-inc:20171202220948p:plain

アップロードするEmojiは世界中の有志の方が親切にgithubに固めて上げてくれているので、それを使いましょう。ぐぐるとたくさんあります。 弊社ではポケモンが人気ですね。

GitHub - Templarian/slack-emoji-pokemon: Slack Pokemon Emojis

Web上の画像を右クリックからアップロードする

chrome.google.com

こちらもめちゃくちゃ便利です。

f:id:photosynth-inc:20171202221626p:plain

何か突発的にEmojiを追加しないといけないタイミングが皆さんあると思うのですが、これでググってすぐに話題に対応できるタイミングでEmojiを追加することができます。慣れれば最速5秒程度で追加できます。

また、なぜかこのサイトと親和性があり、クリックすると本来画像がダウンロードされるサイトなのですが、すぐにアップロードしてくれます(名前も勝手に付けてくれます)。

なので、まずは、このサイトでいいやつを追加してもいいかもですね。

Slackmojis - The Best Custom Slack Emojis

コマンドラインからSlackEmojiをアップロード

ネット上にある様々なEmojiをこのツールを使ってCLIから自動アップロードできます。

github.com

見ずにアップロードが不安なので、確認はした方がいいと思いますが。

便利。

絵文字系のEmojiを量産する

emoji.pine.moe

よく使います。先程のExtensionを入れていれば作成後に右クリックして上げるだけでいいので便利です。

f:id:photosynth-inc:20171202224611p:plain

社員の顔写真を自動でEmojiにする

これは自作です。MSのVison APIを使ってカジュアルにつくって見ました。 弊社では、全員の顔が見えるように、Slackのプロフィール画像を顔社員にしているので、今回はそれを自動でダウンロードして、加工しています。

Gem

# frozen_string_literal: true
source "https://rubygems.org"

gem "microsoft_computer_vision"
gem "mini_magick"
gem 'rest-client'

MSのVison APIのgemあるの便利。また、画像加工は今回はmini_magickを使って見ました。

SourceCode

手順としては以下です。

  • SlackAPIを叩いて、プロフ画像のURL一覧を取得する
  • そのURLをそのままVision APIに渡して顔座標を得る
  • 画像URLと顔座標からMiniMagick自体のメソットで画像ダウンロード+画像加工を行う
#!/usr/bin/env ruby
# coding : utf-8

require 'microsoft_computer_vision'
require 'mini_magick'
require 'json'
require 'rest-client'

class SlackProfileImage2Emoji
  class << self
    def run
      members = slack_members
      members.each do |member|
        sleep 5
        puts member
        rect, err = detect_face member[:profile_image]
        unless err
          image = crop_face rect: rect, url: member[:profile_image]
          image.write "orgs/ps_#{member[:name]}.#{member[:profile_image].split('.').last}"

          # Slackにアップロードできるサイズに縮小する
          image.resize "128x128"
          image.write "icons/ps_#{member[:name]}.#{member[:profile_image].split('.').last}"
        end
      end
    end

    # 画像URLに対応する顔座標を返却する
    def detect_face image_url
      client = MicrosoftComputerVision::Client.new('<VISION_API_TOKEN>')
      options = {
        visual_features: 'Faces',
        details: 'Celebrities'
      }
      res = client.analyze(image_url, options)
      json = JSON.parse res.body
      puts json

      return {
        width:  json["faces"].first["faceRectangle"]["width"],
        height: json["faces"].first["faceRectangle"]["height"],
        left:   json["faces"].first["faceRectangle"]["left"],
        top:    json["faces"].first["faceRectangle"]["top"],
      }, nil
    rescue
      puts "------- Error: Can not get face info"
      return nil, true
    end

    # Slackの従業員のプロフィール画像のURL一覧を取得する
    def slack_members
      res = RestClient.get 'https://slack.com/api/users.list', {
        params: {
          token: "<YOUR_SLACK_TOKEN>",
        }
      }

      (JSON.parse res.body)["members"].select{|member|
        # 適当にフィルタ
        member["deleted"] == false &&
          member["is_restricted"] == true &&
          member["is_bot"] == false &&
          member["name"] != "slackbot"
      }.map{|member|
        # 名前と画像URLのハッシュにして返却
        {name: member["real_name"].downcase.gsub(/ /, '_'), profile_image: member["profile"]["image_original"]}
      }
    end

    # 顔座標とURLを受け取って加工する
    def crop_face rect:, url:
      image = MiniMagick::Image.open(url)
      image.crop "#{rect[:width]}x#{rect[:height]}+#{rect[:left]}+#{rect[:top]}"
      image
    end

  end
end

if __FILE__ == $0
  # 引数ありなら、単一のURLの画像についてだけ顔認識APIを叩く
  if ARGV[0]
    puts (SlackProfileImage2Emoji.detect_face ARGV[0])
  else
    SlackProfileImage2Emoji.run
  end
end

完成品

f:id:photosynth-inc:20171202224209p:plain

※わざと小さくしてます。

定期的に実行するだけでいいので、便利。

まとめ

皆様も素敵なEmojiライフを❗


株式会社フォトシンスでは、急成長するIoT製品「Akerun」を進化させるエンジニアを募集しております!

www.wantedly.com