AlexaからAKASHIに打刻してみた

「アレクサ、出勤打刻してー!」

そんな一言から仕事が始められたらいいなという人向けの記事です。


私は、勤怠管理として AKASHI を使っていますが、

普段はテレワークをすることが多く、出勤連絡するまでに以下のように手順が多くて煩わしく感じていました。

  1. PCを起動(パスワード入力)
  2. VPN接続(パスワード入力)
  3. ブラウザ起動
  4. AKASHIを開く
  5. ID/パスワード入力して認証
  6. ようやく出勤打刻

Alexaに「出勤打刻して!」とワンアクションで出勤連絡できないか試したので記します。

AKASHIでアクセストークンの発行

  1. AKASHIにログイン
    • まだの方はトライアル申し込みから始めてください。無料期間もあるようです。
  2. マイページ >APIトークンからアクセストークンを作成し、コピーして控えておきます。
    • サイドメニューに表示がない方は所属会社のシステム管理者の許可が必要です。
    • APIトークンの有効期限は3週間くらい。
      • APIトークンを有効期限前に更新する処理は今後実装予定。

Alexaスキルの作成

  1. Amazon開発者コンソールを開く
  2. スキル >スキルの作成 から作成します。
  3. 呼び出し > スキルの呼び出し名 を確認。
    • 2.の手順だと「タイムカード」になっています。「アレクサ、タイムカードを起動して」というとスキルが起動するようになります。
    • ポイント:音声認識になるので、Alexaが認識できない言葉(造語や同音異義語)を用いると、期待通りに動かないことがあります。AKASHIはまだブランド名として認識されていないようで、ここに「アカシ」と指定してもAlexaは「明石」や「証」と認識してスキルが起動しませんでした。他に「勤怠」も正しく認識される確率が半々くらいだったので避けました。結果「タイムカード」に落ち着きました。
  4. スロット > +スロットタイプ からスロットを作成します。
    • スロットは「出勤」「退勤」などの命令の種類になります。
    • 今回は「出勤」「退勤」「休憩開始」「休憩終了」の4つを作成しました。
      • AKASHI上は他に「直行」「直帰」も打刻できますが、在宅勤務では使わないので不要。
      • 同義語を登録することで、類似の言葉や聞き取りづらい用語を寄せたりすることができます。(任意)
        • 「終業」と言ってしまった場合やAlexaが「大金」と認識してしまった場合でも「退勤」と再認識させることができます。
  5. 対話モデル > インテント から命令の音声パターンを追加します。
    • インテントとは「出勤打刻して」の「出勤打刻」の部分です。「XXXXして」という命令がくるよ。ということをAlexaに設定します。
      • {キーワード}の形式で書きます。今回は「XXXX打刻して」「XXXXして」「XXXX」の3つを作成しました。
        • 「出勤」打刻して、「休憩開始」して、「退勤」のような3つの言い方ができるようにしました。自分のみが利用する分には自分の言い回しが決まっていると思うのでそれに合えば特定の1種類だけ作成するだけでも良いです。
    • インテントスロット からインテントと先に作成したスロットをプルダウンから選択して紐づけます。
    • 最後に保存ボタンとデプロイボタンを押して完了です。Amazon開発者コンソールは一旦ここまでで次にAWS LambdaでAPI呼び出しを実装します。

Lambda関数の作成

  1. AWSコンソールにログインします。持っていない方はサインアップから登録が必要です。
    • AWSの利用には料金が発生することがあります。
  2. 次を参考にLambdaの関数を作成します。
  3. AKASHIのAPIを実行するメソッドを追加します。2.で記載したコードから差分だけ記載します。
    • スロット名は自身で設定したものに変更して下さい。
    • ACCESS_TOKENは控えておいたAKASHIのアクセストークン、COMPANY_IDはAKASHIにログインする際の企業IDをLambdaの環境変数に設定します。
    • import os  
      import json    
      import urllib.request  
      from urllib.parse import urlencode 
      from datetime import datetime
      ・・・
      class AkashiStampIntentHandler(AbstractRequestHandler):
          def can_handle(self, handler_input):
              return ask_utils.is_intent_name("KintaiIntent")(handler_input) # カスタムインテント(KintaiIntent=XX打刻、XXして)と言われたら発火する
      
          def handle(self, handler_input):
              slots = handler_input.request_envelope.request.intent.slots
              kintai_original_value = slots['KintaiType'].value # カスタムスロット(出勤、退勤、休憩開始、休憩終了)の言葉の変数を抽出
              kintai_values = slots['KintaiType'].resolutions.resolutions_per_authority[0].values
      
              action_codes = {
                  11: '出勤',
                  12: '退勤',
                  21: '直行',
                  22: '直帰',
                  31: '休憩開始',
                  32: '休憩終了'
              }
      
      
              if kintai_values is not None:
                  type_value = int(kintai_values[0].value.id) # 同義語含めて該当するスロットのid
              else: 
                  type_value = None
      
              print(f"スロット: {kintai_original_value}")
              print(f"スロットname: {kintai_values[0].value.name}")
              print(f"type_value: {type_value}")
      
              token = os.environ['ACCESS_TOKEN']
              company_id = os.environ['COMPANY_ID']
              stamped_at = datetime.now().strftime("%Y/%m/%d %H:%M:%S")
      
              if any(word in kintai_original_value for word in ["テレワーク", "リモートワーク", "在宅勤務"]):
                  telework = True
                  telework_msg = "テレワーク"
              else:
                  telework = False
                  telework_msg = ""
      
              # POSTリクエストのパラメータを構築
              request_params = {
                  'token': token,
                  'type': type_value,
                  'stamped_at': stamped_at,
                  'telework': telework,
                  # 'timezone': timezone
              }
      
              # POSTリクエストを送信するURL
              url = f"https://atnd.ak4.jp/api/cooperation/{company_id}/stamps"
      
              # POSTリクエストを構築
              data = json.dumps(request_params).encode('utf-8')
              headers = {'Content-Type': 'application/json'}
              request = urllib.request.Request(url, data=data, headers=headers, method='POST')
      
              # リクエストを送信し、レスポンスを取得
              with urllib.request.urlopen(request) as response:
                  response_data = response.read().decode('utf-8')
                  response_code = response.getcode()
      
              # レスポンスを出力
              print(f"Response Code: {response_code}")
              print(f"Response Body: {response_data}")
      
              # JSON文字列をPythonのデータ構造に変換
              response_data = json.loads(response_data)
      
              # successとtypeの値を取り出す
              if response_data['success']:
                  type_value = action_codes[response_data['response']['type']]
                  time_value = response_data['response']['stampedAt'].split(' ')[1][:5]
                  alert_count = response_data['response']['alertCount'] or 0
                  alert_count = response_data['response']['alertCount'] or 0
                  speak_output = f"{time_value} に{telework_msg}{type_value} 打刻をしました。アラート件数は{alert_count}件です。"
              else:
                  speak_output = "打刻に失敗しました。"
      
      
              return (
                  handler_input.response_builder
                  .speak(speak_output)
                  .response
              )
      
      
      sb = SkillBuilder() # 元からあるコード
      
      sb.add_request_handler(LaunchRequestHandler()) # 元からあるコード
      sb.add_request_handler(AkashiStampIntentHandler()) # ★追加
      
    • 画面のデプロイボタンを押します。しばらく待ちます。

シミュレータでのテスト

  1. Amazon開発者コンソールからテストできるので開きます。
  2. 「テスト」をクリックし、「開発中」プルダウンを選択します。
  3. Alexaシミュレータから文字入力またはマイクで指示を出します。
    • 「タイムカード起動して」と言うと「ハロー」と返事が返ってくれば成功です。
    • その後に、「出勤打刻して」と言うと、「何時何分に出勤打刻をしました。アラート件数は~」と言うはずです。
      • AKASHIの打刻画面または出勤簿を確認し、出勤打刻ができていれば成功です。
    • 「テレワーク開始」「テレワーク終了」というと、テレワーク記録がAKASHIに登録されます。

実機での検証

  1. スマホのAlexaアプリを起動します。
    • その他 > マイスキル > 開発 から「タイムカード」を選択します。
    • スキルを有効にします。既に有効になっていた場合も一度無効してから有効する方が動作が安定します。
      • この操作をしないとスキルのデプロイがすぐに反映しない場合があります。Alexaアプリから命令したらうまくいくのにAmazon Echoからはうまく動作しない場合はこの手順を実施してください。
  2. Amazon Echoに、シミュレータの時と同じように音声で命令してみてください。
    • 「アレクサ、タイムカードで退勤打刻して」と1文で命令することもできます。
    • 途中でも触れましたが、スキルの呼び出し名を「タイムカード」以外にした方は言葉によってはAlexaが誤認識した可能性があります。

今後のAKASHIに期待すること

  1. Alexaのアカウントリンク機能が使えるようにOAuth連携できればこのスキルを公開することができるので対応してほしいです。
  2. 他のAKASHIのAPIもAlexaから使えるようにしたい。
    • AKASHI 公開API 仕様
    • 工数管理も使っているが工数の記録がめんどうだったり忘れたりします。音声でタスクの開始終了が自動計算されるとか、そこまでいかなくとも、音声の履歴がAKASHIの工数画面から見れれば工数入力する際のメモにできるかなと思いました。

参考