OpenAIでUiPathのXamlファイルを解析してみよう

## はじめに
ほかの開発者が書いたコードや過去に自分が作ったものを解析するのが大変だと思いませんか。本記事では、OpenAIを活用して簡単にコードが解析できるワークフローを作成しようと思います。

本文の構成：
・事前準備：UiPath Automation CloudでOpenAIのコネクタを作成する
・ワークフローの実装：コード解析用のワークフローを作成する
・実行結果を確認する：質問を複数回投げて結果を確認する

 ## 事前準備
Integration ServiceにてOpenAIを利用するため、UiPath Automation Cloudでコネクタを作成するのが前提です。以下の手順に従ってください。

①UiPath Automation Cloudにログインし、Integration Serviceのアイコンをクリックする。
![IS1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3334103/8a177b50-fac0-ce04-25aa-6a84a33b8717.jpeg)

②Connectorsタブの検索欄でOpenAIを検索して選択する。
![IS2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3334103/07721c43-43f0-427a-62ad-fc765f9c53fd.jpeg)

③右上のConnect to OpenAIをクリックする。
![IS3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3334103/1e6c298a-5c93-69ae-fd19-fdaaee4b89fe.jpeg)

④OpenAIのAPI keyを入力する。
![IS4.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3334103/04f85311-d0df-cff0-23a1-c877c95ffada.jpeg)

※APIキーの取得方法は以下のリンクをご参考ください。

https://qiita.com/kurata04/items/a10bdc44cc0d1e62dad3


⑤成功したら、Connectionsタブで以下の画面が表示される。
![IS5.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3334103/3074664f-ede8-b8b2-a134-f5c3eb86a5bd.jpeg)

## ワークフローの実装
今回作成したいワークフローの完成図のイメージです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3334103/84c8035e-61c0-e317-b896-c945f5f35628.png)

これから、ステップバイステップで作成しましょう。

①UiPath Studioを立ち上げて、新規プロセスを作成します。今回プロセスの名前はXAML_Analyzerにしましょう。WindowsレガシはOpenAIのアクティビティパッケージに対応できないため、対応OSは必ずWindowsを選んでください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3334103/8bcdadc2-ecc6-4824-d5c9-b17c01b4fe5b.png)

②続いて、OpenAIのアクティビティが利用できるように、UiPath StudioでOpenAIのアクティビティパッケージをインストールする必要があります。操作手順は下図に従ってください。
![St1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3334103/f6b1aad3-c807-ebb0-8a65-84e0f38c2a77.jpeg)

インストールできたら、アクティビティパネルでOpenAIに関するアクティビティが現れます。

<img width="400" src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3334103/c9315d08-ef99-8b29-032f-6495cfd8f667.png>

③メインパネルに「テキストファイルを読み込み」をドラッグアンドドロップし、解析したいXAMLファイルを選んでください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3334103/284aa617-656c-8c12-5a82-b61e5e9aebe3.png)

ここでなぜXAMLファイルがテキストファイルとして開けるかについて簡単に説明します。UiPathのXAMLファイルの本質は、XML形式で記述されたファイルです。通常はユーザーインターフェースやワークフローを記述するために使用されますが、プレーンテキストファイルでもあり、XML形式でエンコードされています。これにより、どのテキストエディターでも開いて表示することができます。例えば、Notepad++でCalculateSumAndAvg.xamlを開いて中身を見てみましょう。（CalculateSumAndAvg.xamlは1~5の合計値と平均値を算出する明快なワークフローです。）

まずは、Studioで開いたCalculateSumAndAvg.xamlの様子です。
![WF.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3334103/9ea84101-90e8-6c34-33a2-257952eeb44f.jpeg)

このファイルをNotepad++で開くと、以下のようなコードになります。
```CalculateSumAndAvg.xaml
<Activity mc:Ignorable="sap sap2010" x:Class="Main" mva:VisualBasic.Settings="{x:Null}" sap:VirtualizedContainerService.HintSize="1233,1447" sap2010:WorkflowViewState.IdRef="ActivityBuilder_1" xmlns="http://schemas.microsoft.com/netfx/2009/xaml/activities" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mva="clr-namespace:Microsoft.VisualBasic.Activities;assembly=System.Activities" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:sap="http://schemas.microsoft.com/netfx/2009/xaml/activities/presentation" xmlns:sap2010="http://schemas.microsoft.com/netfx/2010/xaml/activities/presentation" xmlns:scg="clr-namespace:System.Collections.Generic;assembly=mscorlib" xmlns:sco="clr-namespace:System.Collections.ObjectModel;assembly=mscorlib" xmlns:ui="http://schemas.uipath.com/workflow/activities" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  <TextExpression.NamespacesForImplementation>
    <sco:Collection x:TypeArguments="x:String">
      <x:String>Microsoft.VisualBasic</x:String>
      <x:String>Microsoft.VisualBasic.Activities</x:String>
      <x:String>System</x:String>
      <x:String>System.Activities</x:String>
      <x:String>System.Activities.Expressions</x:String>
      <x:String>System.Activities.Statements</x:String>
      <x:String>System.Activities.Validation</x:String>
      <x:String>System.Activities.XamlIntegration</x:String>
      <x:String>System.Collections</x:String>
      <x:String>System.Collections.Generic</x:String>
      <x:String>System.Collections.ObjectModel</x:String>
      <x:String>System.Data</x:String>
      <x:String>System.Diagnostics</x:String>
      <x:String>System.Drawing</x:String>
      <x:String>System.IO</x:String>
      <x:String>System.Linq</x:String>
      <x:String>System.Net.Mail</x:String>
      <x:String>System.Windows.Markup</x:String>
      <x:String>System.Xml</x:String>
      <x:String>System.Xml.Linq</x:String>
      <x:String>UiPath.Core</x:String>
      <x:String>UiPath.Core.Activities</x:String>
      <x:String>System.Collections.ObjectModel</x:String>
      <x:String>System.Activities.DynamicUpdate</x:String>
      <x:String>UiPath.Platform.ResourceHandling</x:String>
      <x:String>System.Reflection</x:String>
      <x:String>System.Runtime.InteropServices</x:String>
    </sco:Collection>
  </TextExpression.NamespacesForImplementation>
  <TextExpression.ReferencesForImplementation>
    <sco:Collection x:TypeArguments="AssemblyReference">
      <AssemblyReference>Microsoft.VisualBasic</AssemblyReference>
      <AssemblyReference>mscorlib</AssemblyReference>
      <AssemblyReference>PresentationCore</AssemblyReference>
      <AssemblyReference>PresentationFramework</AssemblyReference>
      <AssemblyReference>System</AssemblyReference>
      <AssemblyReference>System.Activities</AssemblyReference>
      <AssemblyReference>System.ComponentModel.TypeConverter</AssemblyReference>
      <AssemblyReference>System.Core</AssemblyReference>
      <AssemblyReference>System.Data</AssemblyReference>
      <AssemblyReference>System.Data.DataSetExtensions</AssemblyReference>
      <AssemblyReference>System.Drawing</AssemblyReference>
      <AssemblyReference>System.Linq</AssemblyReference>
      <AssemblyReference>System.ObjectModel</AssemblyReference>
      <AssemblyReference>System.Xaml</AssemblyReference>
      <AssemblyReference>System.Xml</AssemblyReference>
      <AssemblyReference>System.Xml.Linq</AssemblyReference>
      <AssemblyReference>UiPath.System.Activities</AssemblyReference>
      <AssemblyReference>UiPath.UiAutomation.Activities</AssemblyReference>
      <AssemblyReference>WindowsBase</AssemblyReference>
      <AssemblyReference>UiPath.Studio.Constants</AssemblyReference>
      <AssemblyReference>UiPath.UIAutomationNext</AssemblyReference>
      <AssemblyReference>UiPath.System.Activities.Design</AssemblyReference>
      <AssemblyReference>UiPath.Platform</AssemblyReference>
      <AssemblyReference>System.ComponentModel.Composition</AssemblyReference>
      <AssemblyReference>System.Memory</AssemblyReference>
      <AssemblyReference>System.ValueTuple</AssemblyReference>
      <AssemblyReference>NPOI</AssemblyReference>
      <AssemblyReference>UiPath.Excel.Activities.Design</AssemblyReference>
      <AssemblyReference>System.ServiceModel</AssemblyReference>
      <AssemblyReference>Microsoft.Bcl.AsyncInterfaces</AssemblyReference>
      <AssemblyReference>System.Runtime.WindowsRuntime</AssemblyReference>
      <AssemblyReference>System.Reflection.Metadata</AssemblyReference>
    </sco:Collection>
  </TextExpression.ReferencesForImplementation>
  <Sequence DisplayName="Main Sequence" sap:VirtualizedContainerService.HintSize="656,1382" sap2010:WorkflowViewState.IdRef="Sequence_1">
    <sap:WorkflowViewStateService.ViewState>
      <scg:Dictionary x:TypeArguments="x:String, x:Object">
        <x:Boolean x:Key="IsExpanded">True</x:Boolean>
      </scg:Dictionary>
    </sap:WorkflowViewStateService.ViewState>
    <Sequence DisplayName="Main Sequence" sap:VirtualizedContainerService.HintSize="594,1271" sap2010:WorkflowViewState.IdRef="Sequence_2">
      <Sequence.Variables>
        <Variable x:TypeArguments="s:Int32[]" Name="arrNums" />
        <Variable x:TypeArguments="x:Int32" Name="intCounter" />
        <Variable x:TypeArguments="x:Int32" Name="intSum" />
        <Variable x:TypeArguments="x:Double" Name="douAvg" />
      </Sequence.Variables>
      <sap:WorkflowViewStateService.ViewState>
        <scg:Dictionary x:TypeArguments="x:String, x:Object">
          <x:Boolean x:Key="IsExpanded">True</x:Boolean>
          <x:Boolean x:Key="IsPinned">False</x:Boolean>
        </scg:Dictionary>
      </sap:WorkflowViewStateService.ViewState>
      <Assign sap:VirtualizedContainerService.HintSize="532,82" sap2010:WorkflowViewState.IdRef="Assign_1">
        <Assign.To>
          <OutArgument x:TypeArguments="s:Int32[]">[arrNums]</OutArgument>
        </Assign.To>
        <Assign.Value>
          <InArgument x:TypeArguments="s:Int32[]">[{1,2,3,4,5}]</InArgument>
        </Assign.Value>
      </Assign>
      <Assign sap:VirtualizedContainerService.HintSize="532,82" sap2010:WorkflowViewState.IdRef="Assign_2">
        <Assign.To>
          <OutArgument x:TypeArguments="x:Int32">[intCounter]</OutArgument>
        </Assign.To>
        <Assign.Value>
          <InArgument x:TypeArguments="x:Int32">0</InArgument>
        </Assign.Value>
      </Assign>
      <Assign sap:VirtualizedContainerService.HintSize="532,82" sap2010:WorkflowViewState.IdRef="Assign_3">
        <Assign.To>
          <OutArgument x:TypeArguments="x:Int32">[intSum]</OutArgument>
        </Assign.To>
        <Assign.Value>
          <InArgument x:TypeArguments="x:Int32">0</InArgument>
        </Assign.Value>
      </Assign>
      <ui:InterruptibleWhile CurrentIndex="{x:Null}" Condition="[intCounter &lt; arrNums.Length]" DisplayName="While" sap:VirtualizedContainerService.HintSize="532,470" sap2010:WorkflowViewState.IdRef="InterruptibleWhile_1">
        <ui:InterruptibleWhile.Body>
          <Sequence DisplayName="Body" sap:VirtualizedContainerService.HintSize="496,304" sap2010:WorkflowViewState.IdRef="Sequence_3">
            <sap:WorkflowViewStateService.ViewState>
              <scg:Dictionary x:TypeArguments="x:String, x:Object">
                <x:Boolean x:Key="IsExpanded">True</x:Boolean>
              </scg:Dictionary>
            </sap:WorkflowViewStateService.ViewState>
            <Assign sap:VirtualizedContainerService.HintSize="434,82" sap2010:WorkflowViewState.IdRef="Assign_4">
              <Assign.To>
                <OutArgument x:TypeArguments="x:Int32">[intSum]</OutArgument>
              </Assign.To>
              <Assign.Value>
                <InArgument x:TypeArguments="x:Int32">[intSum + arrNums(intCounter)]</InArgument>
              </Assign.Value>
            </Assign>
            <Assign DisplayName="代入" sap:VirtualizedContainerService.HintSize="434,82" sap2010:WorkflowViewState.IdRef="Assign_6">
              <Assign.To>
                <OutArgument x:TypeArguments="x:Int32">[intCounter]</OutArgument>
              </Assign.To>
              <Assign.Value>
                <InArgument x:TypeArguments="x:Int32">[intCounter+1]</InArgument>
              </Assign.Value>
            </Assign>
          </Sequence>
        </ui:InterruptibleWhile.Body>
      </ui:InterruptibleWhile>
      <Assign sap:VirtualizedContainerService.HintSize="532,82" sap2010:WorkflowViewState.IdRef="Assign_5">
        <Assign.To>
          <OutArgument x:TypeArguments="x:Double">[douAvg]</OutArgument>
        </Assign.To>
        <Assign.Value>
          <InArgument x:TypeArguments="x:Double">[intSum / arrNums.Length]</InArgument>
        </Assign.Value>
      </Assign>
      <ui:MessageBox Caption="{x:Null}" ChosenButton="{x:Null}" AutoCloseAfter="00:00:00" DisplayName="Message Box" sap:VirtualizedContainerService.HintSize="532,85" sap2010:WorkflowViewState.IdRef="MessageBox_1" Text="[intSum]" />
      <ui:MessageBox Caption="{x:Null}" ChosenButton="{x:Null}" AutoCloseAfter="00:00:00" DisplayName="Message Box" sap:VirtualizedContainerService.HintSize="532,85" sap2010:WorkflowViewState.IdRef="MessageBox_2" Text="[douAvg]" />
    </Sequence>
  </Sequence>
</Activity>
```

だいぶ読みづらくなりますが、XAMLファイルが実はXML言語で記述されているとわかりましたね。そのため、テキストファイルと同様に「テキストファイルを読み込み」のインプットになれるわけです。XAMLファイルを読み込んだ結果がOpenAIに投げる質問の一部となるので、アウトプットをstXamlText（String型）に設定しておきます。

④質問を補完します。「代入」アクティビティを配置し、左辺をstQuestion（String型）に設定し、右辺は質問内容を編集しておきます。今回は日本語でコード解析の結果を返してほしいため、```"日本語でこのコードを解析してください" & stXamltext```と入力します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3334103/ae7de776-c386-924f-ab69-82db129ec470.png)

⑤いよいよ今回の中核に入りました。アクティビティパネルでOpenAIを検索し、「Generate Chat Completion」アクティビティをメインパネルに配置します。すると、アクティビティが自動的に設定されたConnectionsに繋がってくれます。プロンプトは今回の質問内容なので、stQuestionを入れます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3334103/feab982a-f578-c595-dde7-ffa7f2f2c82c.png)

このアクティビティのプロパティがいろいろあるのですが、今回は最も最低限で実行可能の設定条件を紹介し、詳しい説明は割愛しようと思います。詳細を知りたい方は以下のリンクを参照してください。

https://docs.uipath.com/activities/other/latest/integration-service/uipath-openai-openai-generate-chat-completion


プロパティで「モデル名」をgpt-3.5-turboやgpt-4に指定して「上位の生成テキスト」のところでアウトプット変数のstAnswerを作成します。そのほかのプロパティは規定値のままにすることにしましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3334103/22764dd5-e675-6cb8-721f-72d6e75fa4a6.png)

⑥「メッセージ ボックス」を配置し、返ってきた回答を表示させます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3334103/e770045e-cb18-3861-ae57-a54f6409f258.png)

最後に、もう一回ワークフローの完成図を確認しますね。間違いなければ、実行を押します。
![68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f333333343130332f38346338303335652d363163302d653331372d623839362d6339343566356633353.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3334103/2294d01e-7d6f-bb6b-7a9a-fa28a90d1565.png)

## 実行結果を確認する

さあ、実行結果を見ましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3334103/c7f9dd88-240b-8448-93bf-baed04747fcc.png)

CalculateSumAndAvg.xamlの中で定義された変数とワークフローの目的をきちんと返してくれましたね。以上の回答に満足しなければ、「より詳しい説明してください」と投げると、以下の回答が返してきました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3334103/f11fefaa-c731-9292-db27-890c72c19682.png)

さらに、算出の結果がほしい場合は、「結果を返してください」と投げたら、以下の結果が返ってきました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3334103/c1b0f9af-99ac-2290-f3c3-2a86f2ce8398.png)

## 終わりに
今回はOpenAIを活用してXAMLファイルで記述されたコードを解析する方法を紹介しました。XAMLファイルはStudioで開くとユーザーインターフェースとして表示されますが、裏ではXML言語で記述されているため、テキストとして読み書きができるのです。それと質問者の意図と組み合わせると様々な質問ができ、さらにOpenAIに投げるときちんと回答がもらえます。

## 関連URL
※[OpenAIのAPIキー取得方法|2024年7月最新版|料金体系や注意事項](http://qiita.com)
※[OpenAI API](https://openai.com/index/openai-api/)
※[Generate Chat Completionアクティビティについて](https://docs.uipath.com/activities/other/latest/integration-service/uipath-openai-openai-generate-chat-completion)