会議記録ってActivityStreamsなのでは

先日、社内の会議で議事録を担当する機会がありました。
「議事録」と呼ばれる形では読みやすさのために不必要なものを省くことも必要ですが、最終的な議事録として整形する以前の状態として、会議の記録は詳細に記録しておくにこしたことはありません。

音声記録を取ってそこから書き起こすにしてもSpeechToText技術で自動文字起こしをしたり、書記を指定せず会議中に共同編集ファイルに記録していくなど、ここ数年で普及が進んだ技術をフル活用することもできるでしょうし、その導入コストやセキュリティリスクと従来の方法を天秤にかけて後者を選ぶこともあるでしょう。

さて、さまざまな制限があるとき「何を記録するか」という観点が重要になります。
この取捨で落ちた情報は(推測や関連情報の補完といったことは考えられますが)基本的に復元できません。

会議開始前に用意できる情報としては次のようなものがあるでしょう。

* 会議の題目
* 日時
* 出席者、欠席者
* 事前資料

会議の流れがある程度決まっているのであれば、あらかじめ枠組を用意しておき、内容をある程度カテゴライズできます。

そういった事柄は先でも後でも良いとして、主題は会議の内容自体の記録です。
会議終了後議事録を再構成することを考えると、落としたくない内容は次のように整理できます。

* 発言者
* 発言内容
* 発言の文脈(前後関係)
* 提示資料

文脈についてはもう少し分ければ「何についての発言か」「誰に対しての発言か」「会議のどのタイミングでの発言か」といった情報になります。
また、会議のタイミングに関連して、会議そのものではないものの「途中退室」「一時中断」といった情報も記録できた方がよいかもしれません。

さて、発言者やタイムスタンプ、発言内容といった内容に加えて、さまざまな出来事を記録するための標準仕様は何でしょうか? そう、W3CのActivityStreamsです。

ActivityStreamsは2017年に2.0がW3C Recommendationとなった、ユーザーのメッセージ投稿、フォロー、などのActivityを記録するための形式です。原型としてはユーザーフィードの形式であるAtomを拡張していますが、2.0ではJSON Linked Data(JSON-LD)を基本エンコード形式としています。

ActivityStreamsとして規定されているのはデータ形式としての仕様までで、
このActivityStreamsを採用する分散SNSプロトコルとしてActivityPubがあります。
ActivityPubの実装としてはMastodonなどが有名ですね。

分散SNSの概念説明などをするととても長くなってしまうため割愛しますが、分散SNS用プロトコルについて短くまとめると「プロトコルを共通にすれば他のサービスと共通のインターフェースでやりとりできる」という、標準仕様の利点をSNSにも適用したもの、といえるでしょうか。

ActivityStreams以前にもメッセージングの共通プロトコルはXMPPなどあったわけですが、
これは「JSON-LDを基本エンコード形式とする」点、「メッセージに留まらないActivityを記録する」点など、マイクロブログやチャットに留まらないSNS全般とインターフェースを持てるように設計されています。それこそ議事録なども含めてActivityStreamsに落とし込んだ企業製品もすでにあるようです(記事執筆中に初めて知りました)。

話を戻して、会議の記録とActivityStreamsのマッピングについて考えてみましょう。
疑似的なものなので、typeの指定などが必ずしも適切なものになっていない場合があります。
厳密にはURIであるべき箇所などもあります。

会議中の1つの発言をActivityStreamsで表してみます。

{
  "@context": "https://www.w3.org/ns/activitystreams",
  "summary": "上司1の発言",
  "type": "Create",
  "actor": {
    "type": "Person",
    "name": "上司1"
  },
  "object": {
    "type": "Note",
    "name": "上司発言1",
    "content": "会議を始めます"
  },
  "published":"2020-10-26T15:00:00Z"
}

@contextはJSON-LDでのXML名前空間のようなものとして捉えてください。
typeなどは、コアの部分とは別に規定された語彙を用います。
actorはそのactivityを行う主体、ここでは「上司1」というPersonですね。
「上司1がNoteというタイプのObjectをCreateした」ことで「上司1が発言した」ことが表せるというわけです。

選択式の質問を行った場合をみてみましょう。

{
  "@context": "https://www.w3.org/ns/activitystreams",
  "name": "質疑応答2",
  "id": "shitsugi2",
  "type": "Question",
   "content": "昨日の朝はごはんとパンどちらを食べましたか?",
   "oneOf": [
     {"name": "ごはん"},
     {"name": "パン"}
   ],
   "replies": {
     "type": "Collection",
     "totalItems": 3,
     "items": [
       {
         "attributedTo": "上司1",
         "inReplyTo": "shitsugi2",
         "name": "ごはん"
       },
       {
         "attributedTo": "部下2",
         "inReplyTo": "shitsugi2",
         "name": "パン"
       },
       {
         "attributedTo": "部下1",
         "inReplyTo": "shitsugi2",
         "name": "パン"
       }
     ]
   },
   "result": {
     "type": "Note",
     "content": "昨日の朝、ごはんを食べたのは1人、パンを食べたのは2人ですか。"
   }
 }

大本のオブジェクトがQuestionタイプ、そして択一の選択肢oneOf、その回答をrepliesのCollectiontとしています。attributedToはここでは回答者、inReplyToが何に対しての回答なのかを表します。resultとして回答の結果に言及しています。

「会議3」に途中参加の人「同僚1」がいたことを表してみます。

{
  "@context": "https://www.w3.org/ns/activitystreams",
  "summary": "同僚2が途中参加",
  "type": "Join",
  "actor": {
    "type": "Person",
    "name": "同僚2"
  },
  "object": {
    "type": "Group",
    "name": "会議3"
  },
  "published":"2020-10-26T15:00:00Z"
}

3つほど例を作ってみました。全てとはいいませんが、大部分のことはActivityStreamsで規定された範囲で表せそうな感じがありますね。

オンライン会議が身近になったことで、会議や議事録作成の機会が増えた方もいるかもしれません。
より効率的にできるところは進めていく、その第一歩は「物事をふさわしい枠にはめる」ことではないかと思います。もちろん上のように生のJSONを記述するのは非効率ですが。
そんな視点から、標準仕様を読んでみるのも面白いのではないでしょうか。

さて、「PDF作成でも用途にふさわしい作り方があるのでは」ということで、2020年10月27日(火)16時からウェビナーで「PDFお助け便利帳『無料で作るPDF 3つのポイント+活用ノウハウ3選』」をお送りいたします。

参考資料