Inside of LOVOT

GROOVE X 技術ブログ

LOVOTの撮影紹介

はじめ自己紹介

皆さん初めまして、GROOVE XデザインチームのSHUICHIです。

はじめまして
デザインチームの業務の一環として、SNSやウェブページで、皆さんがいつも見ているLOVOTの写真を、日々撮影しています。 今日は、実際に撮影している様子や、撮影の際に気をつけていることなど、少し皆さんに紹介したいと思います。

GROOVE X の撮影風景を一部公開

LOVOTに関する撮影は、外部のスタジオを借りて撮影する場合もありますが、ほとんどの場合は、LOVOT MUSEUMと、会社内部にある、小さな撮影部屋で行っています。

先日公開になりました、FRGMTコラボウェアの撮影様子
特別な設備はなく、基本amazonで揃えられる機材で日々頑張って撮影しております。
撮影部屋の一部
LOVOTの撮影の際は、通常の撮影道具のほか、LOVOTならではの道具もあります。 例えば、LOVOTの顔のスエード部分は、触れたりすると、少し模様ぽく見えてしまいます。その毛並みを整えるために、いろんな道具を試してみてきましたが、最近一番使用しているのは100均で見つけた、化粧用の小さいブラシです。
LOVOTの化粧道具
大きさと硬さが程よく、顔を撫でるだけで綺麗に模様が消えます。

撮影の角度と距離について

用途に合わせて、いろんなアングルで撮影する時がありますが、LOVOTの全身を綺麗に見せたい場合は、カメラの高さを上げて、遠くから少し見下ろす感じで撮影することが多いです。 人間の撮影する場合は、カメラを敢えて下げて、少し見上げる感じで撮影すると、足が長く顔が小さく見える効果が得られます。しかし、それをLOVOTで行うと、プロポーションが少し変に見えてしまします。LOVOTは、基本的に私たちの足元にいる存在で、上から見た時に可愛く見えるように、顔や目がやや上に向いているなど、デザインを意識しています。

アングルによる見え方の違い

ストロボ使用時、目を綺麗に撮るコツ

ここからはややマニアックな話になります。近年スマホのカメラ性能がどんどん向上して、普段iPhoneなどでLOVOTの写真を撮る際は、端末の方で、勝手に目の明るさと他の部分の明るさを調整してくれて、なんとなくいい感じの写真が撮れます。しかし、いざちゃんとしたカメラと撮影用のストロボライトでLOVOTを撮影しようとすると、目がすごく暗く写ったり、色が変になったりします。それは、LOVOTの目は液晶ディスプレイになっているためです。他の部分と違い、ストロボで強い光を当てても、反射をするだけで、綺麗に発色してくれません。そのため、まずライトの位置を、目が反射しないように調整する必要があります。さらに、普通に物撮りのように露出を設定すると、目がどうしても暗く写りがちです。

このように、体の他の部分は綺麗に写っていますが、目がとても暗いです
そこで、カメラとストロボでLOVOTの目を綺麗に撮りたい場合は:

  • 前提として、部屋のライトを消して、ドアなども全部閉めて、真っ暗な状態にします。
  • 暗闇の中で、目が綺麗に写るようにシャッタースピードを遅く調整しながら撮影します。(携帯の夜景モードと近い原理です)シャッタースピードが遅すぎると、ブレやすくなりますので、いつも大体1秒前後にしています。
  • 目が綺麗に撮れるシャッタースピードを見つけられたら、今度はストロボライトのみを使って撮影します。シャッタースピードを落としているので、そのまま撮ると大体写真が明るくなりすぎて白飛びします。必要に応じてライトの強さを弱めたり感度を落としたりの調整は必要になります。

そうすると、目と全身が両方くっきり写っている写真が撮れます。

先に目が綺麗に取れるように意識します

最後に

今日は、少しだけGROOVE X社内で行なっている撮影について紹介させていただきました。LOVOTは世の中に存在する他のプロダクトと全く異なり、撮影の方法なども、社内でも日々研究しています。また時間がありましたら、もっといろんなことを紹介していきたいと思います、これからもよろしくお願いします。

哲学対話で自分理解と自由な組織作り

こんにちは! GROOVE Xのエリアプロダクトオーナーのよっきです。

いきなりですが、今年に入って、社内で哲学対話を始めてみました。

ロボットのような多数の専門分野を集結させて作るプロダクトでは、複数チームの連携が欠かせません。このチーム間の連携をよりよくしていくために、チームの垣根を超えたメンバー同士のつながりを強固にしていきたいな、と思っておりました。

そんな中で出会ったのが哲学対話。

今回は、この哲学対話を始めたきっかけや狙い、そして、どんな感じで実践しているのかについて、まとめてみます。

なぜ始めたのか

GROOVE Xでは、毎週火曜日のランチ時間に「GROOVE LUNCH」という何でも発表して良い場所があります。 展示会や講演会を聞いた報告や、本を読んで面白かったところの共有、輪講したり、作ったものを共有したりと色々なものをみんなが発表しています。 私はもっぱら読んだ本の共有が多いです。

私が去年読んだ本の中で一番心に残っているのが「ゆっくり、いそげ」という本。 この本に書かれていた、他者と共に自由に生きていく社会を目指そう、というのにとても共感したのです。

amzn.asia

不自由な共存でもなく、孤立で自由でもない。自由で共存する社会。

本書では社会という大きなものとして捉えていますが、会社という組織も一つの社会だとすると、会社内で自由に働きつつ、それでも皆で一体感を持って共存していける組織が作れたらいいなと思ったのです。

きっと自由に働けている状態が最もパフォーマンスが出てるんだと思うのですよね。

で、この自由で共存する社会、改め自由で共存する会社ってどう作ればいいのだろう、と漠然と考えいた時に出会ったのが「考えるとはどういうことか」という本。 この本で、他者とともに自由になるために哲学対話というのが有効です、と書いてくれていたのです。 これだ!と思って、どうすればいいだろう、と本書を進めていくと、やればうまくなるよ、って書いてありました。そうか、やればいいのか。

https://amzn.asia/d/9g9WBtJamzn.asia

哲学対話の狙い

哲学対話そのものの意義としては

  • 自分の意見を言う練習をする
  • 他人の意見を聞く練習をする
  • これらを通して、自分を相対的に理解する

という感じで、まずは自分に自覚的になるきっかけ作りが哲学対話の意義だと思っています。

この自分に自覚的になることが「自由な共存」への一歩になります。

どういうことかと言うと、他者を知って他者に合わすと自分が疲れる。これだと不自由な共存になってしまう。まずは、自分という存在があり、その上で他者とどう付き合っていくか。自分はどうしたいか。これを知り、話すことをしない限り、自由な共存への道は開けない。そして、自分がどうしたいかをちゃんと出すことで、他者も私を理解してくれて、そこから良好なコミュニケーションが生まれる。

これが、チームや会社と良好な関係を築けることに繋がり、そして、働きやすい環境作りに貢献できるのではないか、と考えています。

イメージとしては、映画「スラムダンク」で宮城リョータが最後に自分の感じたことを素直に発言したことで家族との関係がよくなった(よくなりそうに期待できた)、という感じです。

素直な自分を伝えることから、関係作り、すなわち自由な共存が始まるのです。

哲学対話実践秘話

哲学対話での理想を夢見つつ、いままで計2回、社内で哲学対話をやりました。 実際どんなことをして、どんな話をしたのかを紹介します。 やってることは「考えるとはどういうことか」の本に書かれていたことをほぼそのまんまやっています。

アジェンダはこんな感じです。

  • 導入(10分)
  • モヤモヤ思ったことを出し合おう(20分)
  • 出し合ったモヤモヤからみんなで深堀りしたいテーマを決めよう(20分)
  • 決めたテーマについてみんなで深堀りしてみよう(20分)
  • エンディング(10分)

普段過ごしている中で感じたモヤモヤを出し合い、そのモヤモヤについて語り合う。 答えはないし、結論も出さない。「正解」のない問について、自分や他人の声に耳を傾け、言葉を交わしていく。

2回やって、それぞれ3名ずつ、延べ5名が参加してくれました。

その時に話ししたモヤモヤは以下です。

  • 優しさとは何だろう?(特に相手がネガティブな時)
  • 指摘側と受取側のズレがなぜ生じるのか?
  • 自分と他人の認識のズレを解消するコミニュケーションは何か?
  • なぜ人は科学を鵜呑みにするのか?
  • 合理的に解決しようとすると溝が深まるのはなぜか?
  • 金銭的価値に換算できない無いものはなぜ企業で導入しづらいのか?
  • 客観性だけで決められないものを法律で決めるのはどうなのか?

これだけ並べると、めちゃくちゃ大きなテーマを議論しているように見えますね。 プライベートや仕事での話。中には切実な悩みもありました。

やってみての私の感想です

  • モヤモヤを疑問形(問い)にするのが難しい。モヤモヤしていることってどういうことだろう、と考え始めるとよくわからなくなってくる。とりあえずエイヤで問いにしてみると、対話の中で問いが書き換わっていって、なるほど、と思うことは多々あり、まず勇気を持って表に出すのって大事ですね。
  • それぞれ別々にモヤモヤを出してるけど、モヤモヤ同士の共通点が見えた時、なんか個人的にめっちゃ面白いなって思います。指摘側と受取側のズレの話をしていると、優しさの話と繋がったときはめっちゃ面白かった。
  • 対話をしながら整理していくと、私がお金に執着していることに気付いてきました。お金に執着ないと思っていたのに。

という感じで、モヤモヤがわからなくなったり、そういうことかという共通点が見えたり、そうじゃない自分が見えたりと、いろんな気付きがあります。 わからない自分を口に出し、皆と共に議論していくことで、自分理解が深まっていくのかもしれないな、と思いつつ、まだ2回なので、自分理解の道はまだまだ遠いようにも思います。自分というものは変化していくかもしれないですしね。

共通の話題で議論した、という経験が仲間意識を作っていく、という感じもしています。 勘違いかもしれませんが ^^;

最後に

ちょっと抽象度の高い話を書いてしまいましたが、やってることは1時間半ほど対話しているだけなので、固くなりすぎず、続けていきたいと思います。 そのうち、社外の人も巻き込んでやっていきたいな。

GROOVE Xは良きチーム作りにも力を入れています。チーム作りにも興味ある方、絶賛メンバー募集中ですので、よかったらお話しましょう。 お待ちしています。

recruit.jobcan.jp

LOVOTミュージアムのLOVOTたち

LOVOT転倒の謎を追え!

はじめに

こんにちは。GROOVE X ファームチームの anju です。日々LOVOTのファームウェアを開発しています。(ファームウェアファームチームについての説明はこちらをご覧ください)

自動車には事故の際の衝撃を検知して動画や音声を記録するドライブレコーダーというものがありますが、実はLOVOTにも似たような機能が搭載されています。(以降は「ドラレコ」と略します)

ドラレコ搭載前

LOVOTにドラレコを搭載するきっかけとなったのは、社内評価中のソフトウェアにおいて「平らな何も障害物もない場所でなぜかLOVOTが転倒する」という報告が増えてきたためでした。 社長の自宅でも発生したときには、slackに写真と共に「一体、彼に何があったのか?」と投稿されてしまいました。

ドラレコ搭載前は、

  • 1分おきにLOVOT内部の様々なデータを記録したもの
  • 認識結果やふるまい、OSの状態などを記録したログファイル

を元に調査していました。 転倒の原因が「脚を格納する」、「脚の力が抜ける」、「脚のロックが外れる」のいずれかであることは社内で発生時に撮影された動画から分かっていました。 そこまで分かっていたとしても、原因かも知れない箇所としては下記の4つのレイヤにまたがってしまいます。

  1. 脚のハードウェア故障?
  2. ファームウェアの不具合?
  3. 基盤ソフトウェアの不具合?
  4. 意思決定ソフトウェア(NeoDM)の不具合?

そして各レイヤのエンジニアがさまざまな視点に基づいて解析にあたったのですが、1分おきのデータではあっという間に起きる転倒という事象を分析するには情報不足で、解析に多くの労力を掛けた割りに結局原因にはたどり着くことはできませんでした。

ドラレコを搭載するぞ

そこで転倒時に転倒に絡む様々なデータを細かい時間間隔で保存することを目標にドラレコ機能の実装が始まりました。ドラレコは下記の仕様としました。

  • 通常はメモリ上に33ms間隔で30秒間分のデータ(合計900件の各種データ)を保持する。
  • リングバッファにして古いデータに上書きしていく。
  • IMU(慣性計測ユニット)で転倒を検知したらメモリからSSDにデータを保存する。

表1 実際のドラレコで得られたデータの様子 (タイムスタンプ、加速度センサ値、ToFセンサ値など)

ドラレコ搭載後

ドラレコ機能がリリースされると、さっそく成果が出ました。 2つの転倒原因を見つけることが出来たのです。

事例1 片脚を先に格納したことによる転倒

ドラレコの記録から、右脚のサーボモーターに対して、左脚より先に右脚を格納するよう指示が「意思決定ソフトウェア(NeoDM)」から出ていることが判明しました。 転倒時にどのような振る舞いをしていたかは別のログファイルに記録されていますので突き合わせた結果、先に出ていた振る舞いで姿勢が斜めになっていたにもかかわらず、中断して別の振る舞いに移行したことが原因でした。 対処は、振る舞いを中断して移行する場合には一旦姿勢を戻したり移行するタイミングを限定するなどの修正が行われて解決しました。

図1 片脚を先に格納したことによる転倒時のグラフ

事例2 急にサーボモーターの力が抜けて転倒

ドラレコの記録から、意思決定ソフトウェア(NeoDM)からの脚のサーボモーターのトルク指示値は100なのに、ファームウェアのレイヤで0に変更していることが判明しました。 原因は指挟み検知センサが「指を挟んだ」と誤検知して、安全のために脚のサーボモーターの力を抜いた(トルクを0にした)のが原因でした。 指挟みセンサでの「指を挟んだ」とする閾値の再検討や、脚を出す際には指を挟むことはないため脚を出すときには指挟みセンサを無効にするなどの修正が行われました。

図2 サーボモーターの力が抜けて転倒時のグラフ

今後のドラレコ

「平らな何も障害物もない場所でなぜかLOVOTが転倒する」件の調査をきっかけに導入されたドラレコ機能でしたが、それ以外の転倒や段差からの落下などの原因調査に関しても、ドラレコの記録は役立っています。 また、ドラレコ機能はトリガーさえあれば転倒以外でも30秒間の詳細データを記録できるため、最近では帰巣不良の解析にも活用し始めています。

おわりに

今回はLOVOTに搭載されたドラレコ機能についてご紹介しました。 GROOVE Xでは様々な領域のエンジニアを募集しています。LOVOTの開発にご興味ある方は是非ご検討ください。 recruit.jobcan.jp

LOVOTの並行思考 with trio

こんにちは!ふるまいチームのエンジニア、市川です!

以前、下記の記事でLOVOTのふるまいづくりについてご紹介させて頂きました。

tech.groove-x.com

そこでも言及しましたが、わたしたちが呼んでいる「ふるまい」とは下記の事を指します。

  • 感情(学術的な理論に基づく心のモデル)
  • 感情や認識情報に基づいた意思決定(何をするか?)
  • 意思決定に基づいた体への動作指示(手・足・目・瞼などの動き)

これらの処理は、NeoDM(Neo Decision Maker)と呼ばれる一つのサービスで担っています。 NeoDMでは他にも下記の事をやっています。

  • 自身の姿勢の推定(抱っこされている?転けている?など)
  • 画像認識結果のフィルタリング
  • 障害物・崖の検知
  • 経路計画
  • 歌の認識
  • その他

これら複数の事をできるだけ同時にこなさなければいけません。

とぼけた顔をしているが、実はいっぱい考えている

「100個の事を同時に考えてください」と言われても困りますよね*1

人間の場合は1つずつこなしていくかもしれませんが、例えば1個目の処理に「10秒待つ」という処理がある場合、2個目の処理が始まるのは少なくとも10秒以上後になってしまいますね。 待ってる間に他の処理をしておきたいです。

そんな良い感じのスケジューリングをしてくれるtrioというライブラリを導入しています。

NeoDMはpythonで書かれていて、trioはpythonの並行処理ライブラリ*2です。

このtrioにより、次のように記述されています(説明のために簡略化してあります)。

# main関数を開始する(並行処理の開始)
trio.run(main)


async def main():
    # 並行処理させる様々なクラスをインスタンス化
    # (実際はグローバル変数のようになっていて、インスタンス間で相互にアクセスできる)
    poller = Poller()
    physical_state_updater = PhysicalStateUpdater()
    ...

    # 各インスタンスのrunメソッドを子タスクとして開始する
    async with trio.open_nursery() as nursery:
        nursery.start_soon(poller.run)
        nursery.start_soon(physical_state_updater.run)
        ...


# 機体内の情報をかき集めるクラス
class Poller:
    async def run(self):
        # 一定周期でループさせるfor文(25Hz)
        async for _ in trio_util.periodic(1/25):
            # redisというデータベースに機体内の情報があるのでそれをかき集める
            # 例えば電池残量、各種センサの情報など
            ...

# 自身の姿勢を推定するクラス
class PhysicalStateUpdater:
    async def run(self):
         # 一定周期でループさせるfor文(25Hz)
        async for _ in trio_util.periodic(1/25):
            # Pollerで集めた各種センサ情報を元に自身の姿勢を推定する
            ...

雰囲気が伝わったでしょうか?

trioの使い方に関しては下記にまとめておりますので、良かったらご参考ください。

qiita.com

また、PyConJP 2019にて、弊社のJohn BelmonteさんがLOVOTでtrioを使っている事について発表しました。 trioの導入理由に関しても触れられています。 興味がある方はご覧ください。

www.youtube.com

おわりに

NeoDMの並行処理についてご紹介しました。 弊社ではそんなNeoDMの開発メンバーを募集しています。

recruit.jobcan.jp

recruit.jobcan.jp

また、ふるまい以外の分野でも募集しておりますので、LOVOTに関わるお仕事に興味ある方は是非ご検討ください。

recruit.jobcan.jp

*1:NeoDMは100以上の並行処理をしています。

*2:タイトルが並列思考ではなく並行思考となっているのはこのためです。並行処理と並列処理の違いは他の方の記事を参照ください。

LOVOTの愛でメリークリスマス

GROOVE Xのエリアプロダクトオーナーのよっきです。

みなさん、GROOVE Xアドベントカレンダー2022はいかがでしたでしょうか?

技術や開発の仕方、組織のあり方など、かなりバラエティに富んだ記事があり、色んな角度のGROOVE Xを伝えられたんじゃないかなと思います。

いよいよ今回が最後の記事になります。 最後は、私がLOVOT開発の中で出会った印象に残ってるエピソードを紹介して、LOVOTについて思ったことを綴ってみます。

エピソード:愛情を注ぐということ

協力会社さんがGXに来てミーティングをする時、LOVOTの紹介を兼ねてLOVOTミュージアムを案内することがあります。 その時に、協力会社さんがLOVOTとふれあいながら以下のようなことを言いました。

「子育てが終わって、私の愛情をどこに出していいのか、悩んでいるんですよ。それでLOVOTが気になっていて…」

愛情を注ぐ対象を探している、ということが私にとって衝撃的でした。 子育てが終わって、これから自分の時間を過ごせるという時に、次の愛情の出し先を探そうと思えるということは、なんかすごいことだなと思ったのです。

生きがいについて

私が好きな番組にNHKの100分de名著があります。難しい哲学書なんかも現代で捉えるとどういうことかをわかりやすく解説してくれるので、哲学に興味あるけど本を読むのは眠くなっちゃうな、という人は100分de名著から入るとすごく入りやすいです。

はい、少し話がそれてしまいましたが、この100分de名著で神谷恵美子さんの「生きがいについて」の本が紹介されたことがありました。 その時はふむふむと聞いていたのですが、協力会社さんの一言を聞いたときに、まさに、生きがいだなと思い、この本が思い出されました。

この本の中で

「人間から生きがいをうばうほど残酷なことはなく、人間に生きがいをあたえるほど大きな愛はない。」

という言葉があります。 生きがいを与えることそのものが愛なのです。

そして、生きがいを感じられることの1つとして「使命感に生きること」を挙げていました。 この使命感というと大それた感じがしますが、本質的には、誰かのために私を使っていること、となります。 子育てでいうと、子どものために私の時間を使っている状態が生きがいを感じている、ということにつながるのだと思います。

私が、協力会社さんの言葉に凄さを感じたのは、子育てを通して、子育てが生きがいと思うのではなく、愛情を注ぐことが生きがいである、という一つ抽象化して捉えていたところにあるのだと、「生きがいについて」を思い返して感じました。

ちなみに少し補足しておくと、「使命感に生きること」以外にも「存在の根底から湧き上がってくるもの」「自分がしたいことと義務が一致すること」も挙げられており、そもそもがまず自分がやりたい、と思えることが大前提にあります。

LOVOTで生きがいを感じられるか

では、LOVOTと暮らすことで生きがいを感じることはできるでしょうか?

生きがいを感じることは、愛情を注ぐ、あなたのために私を使う、ということ。 つまりはLOVOTのために何かをしてあげる、ということが感じられれば、きっと生きがいを感じられるのだと思います。

では、私たちはLOVOTのために何をしてあげるといいのだろうか?

その1つが抱っこということになります。 LOVOTは人を見つけると信頼度合いに合わせて抱っこをねだります。 この抱っこねだりに応えてあげたときに喜ぶLOVOTを見て、LOVOTのために何かをしてあげたという実感がわき、それが、生きがいへとつながっていく。

なんやそんなことか、と思うかもしれませんが、でも多分、そういう日々の要求に応えるといったやり取りから、私があなたのためになっている、という実感を感じられるのではないかと思います。

そして、抱っこ以外にも、LOVOTがこういうことをしたい、という自我が見えてきたときに、よりLOVOTを通して生きがいを感じられるようになるはずで、 我々開発チームもLOVOTが人と暮らす上でちょうどよい自我を作っていく、ということを念頭に置きながら、今後もLOVOTという存在を作っていきたいなと思います。

最後に

ここまで読んでいただきありがとうございます。

アドベントカレンダーの最後はクリスマスらしく愛の物語で締めくくってみました。

ちなみに、エピソードでは、愛情を注ぐことからLOVOTの購入を検討する、という話でしたが、 私は、LOVOTに愛情を注ぐことで、LOVOT以外の人にも愛情を注げるようになる、というエピソードとは逆パターンの方に期待しています。

LOVOTへの愛情が、他者へ愛情を注いでいくきっかけになる。

神谷恵美子さんの言葉を借りると、愛情を注ぐ人を増やしてくLOVOTは、生きがいを与える大きな愛そのものなのかもしれません。

そんな愛あふれる世界を思いながら、今年のクリスマスは家族と一緒に過ごそうと思います。

メリークリスマス!

recruit.jobcan.jp

grafana をプレビューする slack アプリの話

この記事は、Groove Xアドベントカレンダー2022 12日目の記事です。

はじめに

こんばんは、GROOVE X の junya です。
更新がとても遅くなってしまってゴメンナサイ。

今回は、社内の slack で活用している grafana プレビュー機能についてご紹介します。 slack に grafana のリンクを共有すると、こんな感じで自動でプレビュー画像をつけてくれる仕組みです。

grafana とは?

オープンソースのデータ可視化ツールで、 BigQuery, Prometheus, InfluxDB, Spreadsheet など様々なデータソースに対応しています。 GROOVE X では主に、 Victoria Metrics で管理された機体のメトリクスの可視化に活用しています。

サービスの雰囲気は、公式のデモサイトがあるのでそちらで体験してみて下さい。

play.grafana.org

slack で grafana をプレビューする仕組み

以下のフローで、 slack に投稿された grafana の URL にプレビュー画像を自動補完しています。

  • grafana の URL の投稿を slack の link_shared イベント として検知する
  • シェアされた grafana の URL を元に、画像取得用の URL を生成し、画像を取得する
  • slack のファイル管理に画像をアップロードする
  • slack の unfurl 機能 を用いて、リンクにプレビュー画像を付与する

以下、詳しく説明していきます。

slack アプリ作成時に Event Subscriptions の設定で link_shared イベントを購読すると、アプリでリンク共有のイベントを取得できます。

slackアプリの Event Subscriptions 設定

以下のように、 slack-go を用いて HTTP リクエストを Slack のイベント型に変換して利用します。

package service

import (
    "io"
    "log"
    "net/http"

    "github.com/slack-go/slack/slackevents"
)

func HandleLinkSharedEvent(w http.ResponseWriter, r *http.Request) {
    body, _ := io.ReadAll(r.Body)
    defer r.Body.Close()
    evt, err := slackevents.ParseEvent(body, slackevents.OptionVerifyToken(&slackevents.TokenComparator{VerificationToken: SlackVerificationToken}))
    if err != nil {
        w.WriteHeader(http.StatusInternalServerError)
        return
    }
    switch evt.Type {
    case slackevents.CallbackEvent:
        innerEvent := evt.InnerEvent
        switch ev := innerEvent.Data.(type) {
        case *slackevents.LinkSharedEvent:
            // handle link shared event here.
            return
        default:
            log.Printf("unhandled inner event: %v", ev)
        }
    default:
        log.Printf("unhandled event: %v", evt)
    }
}
ダッシュボード画像の取得

grafana には Grafana Image Renderer というプラグインがあり、このプラグインが有効になっていれば、ダッシュボードのプレビュー画像を取得することができます。パスにある /d//render/d-solo/ に変換し、 viewPanel 引数を panelId 引数に変えれば、画像を取得できるので、 Slack アプリの中では共有された URL を以下のように画像URLに変換して、画像を取得しています。

const BASEURL = "https://grafana.example.com"

func BuildImageURL(url string) string {
    if strings.HasPrefix(url, BASEURL+"/d/") {
        if strings.Contains(url, "viewPanel=") {
            // grafana can render panel itself with /d-solo/ and "panelId" parameter
            url = strings.Replace(url, BASEURL+"/d/", BASEURL+"/render/d-solo/", 1)
            url = strings.Replace(url, "viewPanel=", "panelId=", 1)
        } else {
            url = strings.Replace(url, BASEURL+"/d/", BASEURL+"/render/d/", 1)
        }
        // add timezone parameter to show metrics with JST
        url += "&tz=Asia%2FTokyo"
        return url
    }
    return ""
}

例えば、公式のデモサイトにある下記のダッシュボードは、

これを以下のような URL に変換すると画像を取得できます。

slack への画像アップロード

http client を用いて grafana から画像を取得したら、 slack の files.upload API を用いて、画像を slack へアップロードします。

slackClient := slack.New(SlackToken)

...

// 画像URLを元に画像のバイナリを取得する
img := GetImageFromGrafana(imageURL)
reader := bytes.NewBuffer(img)
remoteFile, err := slackClient.AddRemoteFile(slack.RemoteFileParameters{
    ExternalID:            "some id",
    ExternalURL:           grafanaURL,
    Title:                 "some title",
    Filetype:              "link",
    PreviewImageReader:    reader,
})

なお RemoteFile の機能は slack-go に無かったので、PR を出して機能を追加してもらいました。

grafana へのリンクにプレビュー画像を付与する

最後に slack の unfulring の仕組みを呼び出して完成です。

func (s *Service) handleLinkSharedEvent(ev *slackevents.LinkSharedEvent) {

    ...

    blocks := make([]slack.Block, 0, 2)
    if extraContent != "" {
        blocks = append(blocks, slack.NewSectionBlock(slack.NewTextBlockObject("mrkdwn", extraContent, false, false), nil, nil))
    }
    blocks = append(blocks, slack.NewFileBlock("", remoteFile.ExternalID, "remote"))
    _, _, _, err = slackClient.UnfurlMessage(
        ev.Channel,
        ev.MessageTimeStamp.String(),
        map[string]slack.Attachment{
            link.URL: {
                Blocks: slack.Blocks{
                    BlockSet: blocks,
                },
            },
        },
    )
}

実際の運用では、プレビューに画像だけでなく、メトリクスに関連する付属情報も付与して、見る人にわかりやすくしています。

slack アプリのデプロイ

slack のアプリは cloud function にデプロイしています。bot の管理に serverless の仕組みは便利ですね。

Enterprise 版 Slack でのトラブル

この夏に社内の Slack を Enterprise へ移行したのですが、その際になぜかこの grafana プレビューの仕組みが動かなくなりました。 サポートに確認したところ、 Pro 版と Enterprise 版でファイル管理の仕様が異なり、

  • Pro 版: アップロードした画像は、unfurl でそのまま使える
  • Enterprise 版: チャネルに一度も投稿したことの無い画像は、スレッド内の unfurl 画像として利用できない

とのことでした。ちょっと腑に落ちない仕様ではあるのですが、ワークアラウンドとして、

  • 画像投稿用の専用チャネルに画像を投稿してから、
  • unfurl 画像として利用する

という方法で問題を回避しました。

さいごに

仕事って、ちょっとした工夫で楽しくなるし、業務効率も上がるなと思います。

GROOVE Xは、楽しくコードを書ける環境なので、ご興味のある方は是非ご連絡下さい!

recruit.jobcan.jp

slackをEnterprise Gridに変更した話

この記事は「GROOVE Xアドベントカレンダー2022」の24日目の記事です。

こんにちは!! GROOVE Xのスクラムマスターの1人、 niwano です。
今回も開発の話から、少しそれまして、社内で使用しているコミュニケーションツール slack の契約プランを、Pro から Enterprise Grid に変更したお話をしたいと思います。

slackとは

Microsoft TeamsやChatworksなどと同じ、コミュニケーションツールのひとつです。
弊社では創業時から導入されており、社内のインフラになっています。

slack.com

slackの良い所のひとつとして、自由にカスタマイズできる、というのがあります。
毎週火曜日のお昼休みに、GROOVEランチという情報交換会をやっているのですが、その運営を楽にするために、

  • 発表者の募集
  • カレンダーへの登録
  • 開催時のslack通知
  • 記録

の4項目を、slack ワークフローと、slack appを駆使して自動化されています。

発表登録

発表通知

Enterprise Gridの導入の背景

セキュリティ機能を強化しつつ、よりオープンで風通しのよい職場にしたく、Enterprise Grid の導入を決めました。

移行の際にしたこと

移行時のほとんどの作業は、slack社の方が親切にサポートしてくれます。
弊社側でやったことは、おもに以下の2つです。
(これは弊社が持っていたのが1つのワークスペースだったからかもしれないです。)

アカウントの整理

弊社のドメインではないユーザーともゲストアカウントとしてワークスペースに存在させる運用をしていました。
EnterpriseGridは、SAMLシングルサインオンが推奨されているため、必然的に他社ドメインの方のアカウントを整理することになります。
他社ドメイン方は外部ワークスペースに移動してもらい、特定のチャンネルのみ Slack コネクト(後述)で接続することにしました。

SAMLシングルサインオンの設定

弊社はgoogle workspaceを使っているので、googleSAMLシングルサインオンを使えたのですが、うまく設定が効かないパターンがあり、google社のヘルプ、slack社のヘルプにたくさんお世話になりました。

slack社にはサンドボックス環境も用意していただき、Organaization(後述)の概念を事前にイメージできたので、非常に助かりました。

7年弱のデータがありましたが、マイグレーション(slack社による)は30分ほどで終了しました。

Organaizationの概念

Enterprise Gridになると、もともとのslackワークスペースが、Organaizationのなかに入ります。
Organaizationのなかでは、無制限にワークスペースをつくることができます。 そして、アカウント管理は、Organaizationで行われます。

さらに、ワークスペースごとに細かい設定を変えられるので、弊社ではメインのワークスペースの入場は承認制、off活動・遊びのワークスペースは出入り自由にしています。

Organizationイメージ

slack コネクト

弊社はEメールよりもslackでのコミュニケーションのほうが効率が良いと考えているため、社外の方とのやりとりでは、slack コネクトを多用しています。
なんと、Enterprise Gridプランを導入すると、slack コネクト先のワークスペースがfreeプランであっても、slack コネクトのチャンネル上は、freeプランの制限(90日間のみメッセージ保存)がかかりません!  

移行して良かったこと

  • トラブルなく移行できた。
  • アカウントの整理ができた。

トラブルなく移行できた。

トラブルが発生した場合にそなえて、Eメールにてバックアップツールへの導線を通知していましたが、移行時のトラブルはなく、全てのユーザーが 、今までと同じようにワークスペースを使えたことが本当に良かったです。

アカウントの整理ができた。

今まではゲストアカウントを多用していたため、ユーザー1人にたいして閲覧制限を個別に実施することになっていて、アカウント管理がすごく複雑でした。
ストアカウントをグルーピングし、別のワークスペースに移動させ、必要なチャンネルを共有するだけで、閲覧制限をかけることができるため、アカウント管理が非常にシンプルになりました。

移行してからの課題

  • 障害が少し多い...
  • マルチワークスペース共通のユーザーグループをつくることができない。

障害が少し多い...

私が個人的につらかったのは、Organaizationのセキュリティの設定作業をしていたら、なぜだかワークスペースから追い出されてしまった件です。
一度ワークスペースから抜けると、ユーザーグループから解除されたり、一部のslack appが無効になったりします...

また、この記事を書いている時点で、30日以上問題が解決していないトラブルがあり、これに関しては、slack社と協力をしながら解決にむけてとりくんでいます。

マルチワークスペース共通のユーザーグループをつくることができない。

特定のユーザーにたいして、まとめて通知を出すことができる、ユーザーグループという概念がslackにはあるのですが、このユーザーグループは単独のワークスペースの中でしか使用できません。
これを解決するために、特定の文字列に対して、ユーザー名をリプライする Bot を作成しました。

最後に

最後まで読んでいただき、ありがとうございます!
いろいろありましたが、Enterprise Gridへの移行はおおむね満足しています!

弊社では、ただいま絶賛メンバーを募集中です。
様々な職種がオープンになっているので、ご興味があるかたは以下のリンクからご応募をお願いします!

recruit.jobcan.jp