先日、ノーツコンソーシアムの研究会 Domino Lounge で一緒に活動しているユーザ企業の方から LotusScript に関する問い合わせがありました。ちょうど良いタイミングでオフ会があったので、前乗りしてオンサイトサポート活動を行いました。LotusScript におけるハマりポイントがいくつかあったので、許可をもらって記事にさせていただくことにしました。
なお、材料となるのは Domino IQ のサンプルアプリですが、Domino IQ の機能に特化した話ではありません。予めご了承ください。
お問い合わせ内容
ディスカッションテンプレートをもとに Domino IQ のサンプルアプリを作っており、次の2つの処理をまとめて実行させたいとのことでした。
- 文書内の本文を IQ に要約させて Summary フィールドにセット
- その要約からさらにカテゴリを生成させ、Categories フィールドにセット
お問い合わせがあった時点でのコードは次の通りでした(記事化に当たり一部調整済み)。
|
Sub Initialize Dim ns As New NotesSession Dim ndb As NotesDatabase Dim nuiw As New NotesUIWorkspace Dim nuid As NotesUIDocument Dim llmreq As NotesLLMRequest Dim llmres As NotesLLMResponse Dim sText As String Set ndb = ns.CurrentDatabase Set nuid = nuiw.CurrentDocument '要約の問い合わせ sText = nuid.FieldGetText("Body") Set llmreq = ns.CreateLLMRequest() Set llmres = llmreq.Completion(ndb.Server, "DiscussSummerry", sText) If (llmres.FinishReason = LLM_FINISH_REASON_STOP) Then Call nuid.FieldAppendText("Summery",llmres.Content) Call nuid.Save() Call nuid.Reload() End If 'カテゴリの問い合わせ Dim sText1 As String sText1 = nuid.FieldGetText("Summery") Set llmreq = ns.CreateLLMRequest() Set llmres = llmreq.Completion(ndb.Server, "DiscussCategory", sText) If (llmres.FinishReason = LLM_FINISH_REASON_STOP) Then Call nuid.FieldAppendText("Categories",llmres.Content) Call nuid.Save() End If End Sub |
このスクリプトを実行すると『文書は保存されていません。』とエラーが出るので、何が悪いのか教えてほしいというお問い合わせでした。
コードを見る限り、処理 1 と 2 をそれぞれ作成し、スクリプトをつなげたように見えます。そして、つなげる前のスクリプトは単体では正常に動作したとのご報告がありました。
エージェントの対象と NotesUIDocument
調査にあたり、まず、現象を確認します。
新規で文書を作成し、エージェントを実行すると確かに『文書は保存されていません。』エラーが発生します。
どこでエラーが発生しているのか確認するために、デバッグモードにして実行してみます。すると、デバッガが起動することなくエラーが発生します。この結果より LotusScript のエラーではないと判定できます。
Use したスクリプトライブラリ内の Initialize 内でエラーが発生した場合、LotusScript が原因でもデバッガは起動しません。今回はそのようなパターンではないので LotusScript のエラーではないと判定しています。
このような場合、エージェントのプロパティの確認が必要です。今回のエージェントでは次のようになっていました。さて、問題点がわかりますか?
エラーの原因は[実行時]-[対象]の設定が『すべての選択文書』となっているからです。
LotusScript のエージェントの場合、この対象の設定は NotesDatabase クラスの UnprocessedDocuments プロパティの利用を前提にした機能だと理解しておくとよいでしょう。ビューで選択した文書や新着メールなどを効率よく取得することができます。
そうした仕様からなのか UI の文書が新規文書でまだ保存されていない状態だと『文書は保存されていません。』エラーが発生することになります。UI の文書がバックエンドの nsf 内に存在しないからだと思います。
今回のスクリプトでは、処理対象の文書は NotesUIDocument 経由で取得しているので、対象による文書の特定は不要です。このような場合では、対象を『なし』としておく必要があります。
その結果、問題のエラーが回避でき、デバッガが起動するようになります。これでやっと LotusScript の土俵に乗った状態といえます。
今回は LotusScript のエージェントのエラーではあったのですが、原因はスクリプト外にあったという点がポイントですね。
保存は何度も行わない
お問い合わせのコードを見ていて気が付いた点です。nuid.Save() を 2 カ所で実行している点です。先の『文書は保存されていません。』エラーに対応するため試行錯誤で入れたコードだと思われますが、よい対応とは言えません。
本件に限らずエンドユーザ作成のコードを見ていると、一連の処理で何度も保存しているコードを見ることがあります。正常に動けばそれでいいじゃないか、細かいこと言うなと思うかもしれませんが、私は気になりました。
例えば、将来の改造で作成者や読者の操作する機能を追加したことを考えてください。一度目の保存で文書に対する権限がなくなったとすると、二度目の保存ではエラーが発生することになります。複数回の保存が、将来の改造において足かせになりかねません。後任者(将来の自分を含む)に対するトラップになりうるので、保存は一回にとどめるようにしましょう。
また、保存するなら目立つ場所で行うのも重要です。コードの最後や関数のできるだけ外側がよいと思います。文書の取得や作成と同レベル(同じ関数内)にしておくと気づきやすいですね。
サポート終了後のスクリプト
今回のお問い合わせに対しては、最終的に以下のコードを回答としました。
|
'これは編集モード前提のエージェントです。 Option Declare Sub Initialize Dim ns As New NotesSession Dim ndb As NotesDatabase Dim nuiw As New NotesUIWorkspace Dim nuid As NotesUIDocument Dim llmreq As NotesLLMRequest Dim llmres As NotesLLMResponse Dim sBody As String Dim sSum As String '変数初期化 Set ndb = ns.CurrentDatabase Set nuid = nuiw.CurrentDocument '本文をテキストで取得 sBody = nuid.FieldGetText("Body") '要約問い合わせ Set llmreq = ns.CreateLLMRequest() Set llmres = llmreq.Completion(ndb.Server, "DiscussSummerry", sBody) If (llmres.FinishReason = LLM_FINISH_REASON_STOP) Then '要約取得 sSum = llmres.Content '要約セット Call nuid.FieldAppendText("Summery", sSum) End If 'カテゴリ問い合わせ If sSum <> "" Then 'カテゴリ問い合わせ Set llmres = llmreq.Completion(ndb.Server, "DiscussCategory", sSum) If (llmres.FinishReason = LLM_FINISH_REASON_STOP) Then 'カテゴリ取得とセット Call nuid.FieldAppendText("Categories",llmres.Content) End If End If End Sub |
修正にあたり意識した点は次の通りです。私が担当した LotusScript 講座の受講経験をお持ちだったので、(復習を兼ねて)少々細かな点についても補足させていただきました。
- 編集モード(入力中の実行)を前提に、保存をなくし、IQ の結果をフィールドにセットするだけにした(保存は UI の操作に任せ、スクリプトに頼りすぎない)
- IQ が作成した要約を文字列変数に保管し、カテゴリ作成に利用(UI と スクリプト間の往復を減らす)
- NotesLLMRequest の初期化は 1 回でよい
- Option Declare を宣言し、暗黙の変数宣言を禁止












































