Lightning コンポーネントの作成と Lightning ページへの追加

Einstein Vision を設定し、ライブラリをインストールしました。素晴らしい! 最初のデータセットをアップロードする準備がほぼ整いました。その前に、ファイルをアップロードできるユーザインターフェースが必要です。では、UI を作成しましょう。

Apex クラスを作成する

  1. ギア (設定ギア) をクリックして、[Developer Console (開発者コンソール)] を選択します。
  2. [File (ファイル)] > [Open (開く)] > [Classes (クラス)] をクリックします。
  3. EinsteinVision_Admin というクラスを見つけ、ダブルクリックして開きます。
  4. クラスの内容を次のコードで置き換えます。
    public class EinsteinVision_Admin {
        @AuraEnabled
        public static void createDatasetFromUrl(String zipUrl) {
            EinsteinVision_PredictionService service = new EinsteinVision_PredictionService();
            service.createDatasetFromUrlAsync(zipUrl);
        }
        @AuraEnabled
        public static List<EinsteinVision_Dataset> getDatasets() {
            EinsteinVision_PredictionService service = new EinsteinVision_PredictionService();
            EinsteinVision_Dataset[] datasets = service.getDatasets();
            return datasets;
        }
        @AuraEnabled
        public static String trainDataset(Decimal datasetId) {
            EinsteinVision_PredictionService service = new EinsteinVision_PredictionService();
            EinsteinVision_Model model = service.trainDataset(Long.valueOf(String.valueOf(datasetId)), 'Training', 0, 0, '');
            return model.modelId;
        }
        @AuraEnabled
        public static void deleteDataset(Long datasetId) {
            EinsteinVision_PredictionService service = new EinsteinVision_PredictionService();
            service.deleteDataset(datasetId);
        }
        @AuraEnabled
        public static List<EinsteinVision_Model> getModels(Long datasetId) {
            EinsteinVision_PredictionService service = new EinsteinVision_PredictionService();
            EinsteinVision_Model[] models = service.getModels(datasetId);
            return models;
        }
        @AuraEnabled
        public static void getCatPrediction(Id catId, String fileName, String base64) {
            Blob fileBlob = EncodingUtil.base64Decode(base64);
            EinsteinVision_PredictionService service = new EinsteinVision_PredictionService();
            EinsteinVision_Dataset[] datasets = service.getDatasets();
            for (EinsteinVision_Dataset dataset : datasets) {
                if (dataset.Name.equals('Cats')) {
                    EinsteinVision_Model[] models = service.getModels(dataset);
                    EinsteinVision_Model model = models.get(0);
                    EinsteinVision_PredictionResult result = service.predictBlob(model.modelId, fileBlob, '');
                    EinsteinVision_Probability probability = result.probabilities.get(0);
                    Cat__c cat = [SELECT Id FROM Cat__C WHERE Id=:catId];
                    cat.Cat_Breed__c = probability.label;
                    update cat;
                    Attachment[] attsOld = [SELECT Id FROM Attachment WHERE ParentId=:catId];
                    delete attsOld;
                    Attachment att = new Attachment();
                    att.Body = fileBlob;
                    att.ParentId = cat.Id;
                    att.Name = fileName;
                    insert att;
                }
            }
        }
        @AuraEnabled
        public static List<EinsteinVision_Label> getCatLabels() {
            EinsteinVision_PredictionService service = new EinsteinVision_PredictionService();
            EinsteinVision_Dataset[] datasets = service.getDatasets();
            for (EinsteinVision_Dataset dataset : datasets) {
                if (dataset.Name.equals('Cats')) {
                    return dataset.labelSummary.labels;
                }
            }
            return null;
        }
        @AuraEnabled
        public static String getImageUrlFromAttachment(Id catId) {
            List<Attachment> atts = [SELECT Id FROM Attachment WHERE ParentId=:catId];
            if (atts.size()>0) {
                return atts.get(0).Id;
            }
            return '';
        }
    }
  5. [File (ファイル)] > [Save (保存)] をクリックします。

[My Domain (私のドメイン)] は Trailhead Playground ではあらかじめ有効化されている

Trailhead Playground で [My Domain (私のドメイン)] を有効化したり、設定を変更したりしないでください。デフォルトでは、[My Domain (私のドメイン)] はすべての Trailhead Playground であらかじめ有効化されています。 

Trailhead Playground URL で [My Domain (私のドメイン)] 名が強調表示される

本番組織では [My Domain (私のドメイン)] で組織に固有のサブドメインを作成することができます。[My Domain (私のドメイン)] で、Salesforce によって割り当てられたインスタンス URL (https://na17.lightning.force.com など) を自分で選んだサブドメイン (https://mydomainname.lightning.force.com など) に置き換えます。 

組織でカスタム Lightning コンポーネントを作成したり、シングルサインオン (SSO) を設定したりするには [My Domain (私のドメイン)] が必要です。[My Domain (私のドメイン)] についての詳細は、こちらのナレッジ記事を参照してください。本番組織で [My Domain (私のドメイン)] を有効化する方法については、「ユーザ認証」モジュールを参照してください。

Lightning コンポーネントを作成する

  1. [File (ファイル)] > [New (新規)] > [Lightning Component (Lightning コンポーネント)] をクリックします。
  2. コンポーネントに「EinsteinVision_Admin_UI」と名前を付けます。
  3. [Submit (実行)] をクリックします。
  4. コンポーネントの内容を次のコードで置き換えます。
    <aura:component implements="flexipage:availableForAllPageTypes" access="global" controller="EinsteinVision_Admin">
        <aura:attribute name="datasets" type="EinsteinVision_Dataset[]"></aura:attribute>
        <aura:attribute name="models" type="EinsteinVision_Model[]"></aura:attribute>
        <aura:attribute name="spinnerWaiting" type="Boolean" default="false"/>
        <aura:handler name="init" value="{!this}" action="{!c.onLoadDatasets}" />
        <div class="slds-card">
            <div class="slds-p-left_medium slds-p-right_medium">
                <lightning:layout verticalAlign="end" class="slds-m-around--small">
                    <lightning:layoutitem flexibility="grow">
                        <lightning:input type="URL" label="ZIP file url:" aura:id="zipUrl" value="" />
                    </lightning:layoutitem>
                    <lightning:layoutitem >
                        <lightning:button onclick="{!c.onCreateDataset}">Create Dataset</lightning:button>
                        <lightning:button onclick="{!c.onLoadDatasets}">Refresh Datasets</lightning:button>
                    </lightning:layoutitem>
                </lightning:layout>
                <table class="slds-table slds-table--bordered slds-table--cell-buffer">
                    <thead>
                        <tr class="slds-text-title--caps">
                            <th scope="col">
                                <div class="slds-truncate" title="Dataset Name">Dataset Name</div>
                            </th>
                            <th scope="col">
                                <div class="slds-truncate" title="Dataset Labels">Dataset Labels</div>
                            </th>
                            <th scope="col">
                                <div class="slds-truncate" title="Dataset Models">Dataset Models</div>
                            </th>
                            <th scoe="col">
                                <div class="slds-truncate" title="Actions">Actions</div>
                            </th>
                        </tr>
                    </thead>
                    <tbody>
                        <aura:iteration items="{!v.datasets}" var="dataset">
                            <tr>
                                <td scope="row" data-label="Dataset Name">
                                    <div class="slds-truncate" title="{!dataset.name}">{!dataset.name}</div>
                                </td>
                                <td scope="row" data-label="Dataset Labels">
                                    <aura:iteration items="{!dataset.labelSummary.labels}" var="label">
                                        {!label.name} ({!label.numExamples})<br></br>
                                    </aura:iteration>
                                </td>
                                <td scope="row" data-label="Dataset Models">
                                    <aura:iteration items="{!v.models}" var="model">
                                        {!model.modelId} ({!model.status} - {!model.progress*100}%)<br></br>
                                    </aura:iteration>
                                </td>
                                <td scope="row" data-label="Actions">
                                    <div class="slds-truncate">
                                        <lightning:button onclick="{!c.onTrainDataset}" value="{!dataset.id}" variant="brand">Train</lightning:button>
                                        <lightning:button onclick="{!c.onDeleteDataset}" value="{!dataset.id}" variant="destructive">Delete</lightning:button>
                                    </div>
                                </td>
                            </tr>
                        </aura:iteration>
                    </tbody>
                </table>
                <aura:if isTrue="{!v.spinnerWaiting}">
                    <lightning:spinner size="medium" alternativeText="Loading data..." />
                </aura:if>
            </div>
        </div>
    </aura:component>
  5. 右のコンポーネントパレットで [CONTROLLER (コントローラ)] ボタンをクリックして、内容を次のコードで置き換えます。
    ({
        onCreateDataset : function(component, event, helper) {
    		helper.onCreateDataset(component);
        },
        onLoadDatasets : function(component, event, helper) {
    		helper.onLoadDatasets(component);
        },
        onTrainDataset : function(component, event, helper) {
    		helper.onTrainDataset(component, event);
        },
        onDeleteDataset : function(component, event, helper) {
    		helper.onDeleteDataset(component, event);
        }
    })
  6. 次に、パレットで [HELPER (ヘルパー)] ボタンをクリックして、内容を次のコードで置き換えます。
    ({
        onCreateDataset: function(component) {
            var action = component.get("c.createDatasetFromUrl");
            var zipUrl = component.find("zipUrl").get("v.value");
            var self = this;
            action.setParams({
                zipUrl: zipUrl
            });
            action.setCallback(this, function(response) {
                component.set("v.waiting", false);
                var state = response.getState();
                if (state === 'ERROR') {
                    var errors = response.getError();
                    if (errors) {
                        if (errors[0] && errors[0].message) {
                            return alert(errors[0].message);
                        }
                    } else {
                        return console.log("Unknown error");
                    }
                }
                var result = response.getReturnValue();
                self.onLoadDatasets(component);
            });
            component.set("v.waiting", true);
            $A.enqueueAction(action);
        },
        onLoadDatasets : function(component) {
            var self = this;
            var action = component.get("c.getDatasets");
            action.setCallback(this, function(response) {
                var state = response.getState();
                if (state === 'ERROR') {
                    var errors = response.getError();
                    if (errors) {
                        if (errors[0] && errors[0].message) {
                            return alert(errors[0].message);
                        }
                    } else {
                        return console.log("Unknown error");
                    }
                }
                component.set("v.datasets", response.getReturnValue());
                var dataset = response.getReturnValue();
                if (dataset && dataset.length>0) {
    	            self.onModelStatus(component, dataset);
                } else {
    		        component.set("v.spinnerWaiting", false);
                }
            });
            component.set("v.spinnerWaiting", true);
            $A.enqueueAction(action);
        },
        onModelStatus : function(component, datasets) {
            var action = component.get("c.getModels");
            action.setParams({
                datasetId: datasets[0].id
            });
            action.setCallback(this, function(response) {
                component.set("v.spinnerWaiting", false);
                var state = response.getState();
                if (state === 'ERROR') {
                    var errors = response.getError();
                    if (errors) {
                        if (errors[0] && errors[0].message) {
                            return alert(errors[0].message);
                        }
                    } else {
                        return console.log("Unknown error");
                    }
                } else {
                    component.set("v.models", response.getReturnValue());
                }
            });
            component.set("v.spinnerWaiting", true);
            $A.enqueueAction(action);
        },
        onDeleteDataset : function(component, event) {
            var action = component.get("c.deleteDataset");
            var datasetId = event.getSource().get("v.value");
            var self = this;
            action.setParams({
                datasetId: datasetId
            });
            action.setCallback(this, function(response) {
                component.set("v.spinnerWaiting", false);
                var state = response.getState();
                if (state === 'ERROR') {
                    var errors = response.getError();
                    if (errors) {
                        if (errors[0] && errors[0].message) {
                            return alert(errors[0].message);
                        }
                    } else {
                        return console.log("Unknown error");
                    }
                }
                self.onLoadDatasets(component);
            });
            component.set("v.spinnerWaiting", true);
            $A.enqueueAction(action);
        },
        onTrainDataset : function(component, event) {
            var action = component.get("c.trainDataset");
            var datasetId = event.getSource().get("v.value");
            var self = this;
            action.setParams({
                datasetId: datasetId
            });
            action.setCallback(this, function(response) {
                component.set("v.spinnerWaiting", false);
                var state = response.getState();
                if (state === 'ERROR') {
                    var errors = response.getError();
                    if (errors) {
                        if (errors[0] && errors[0].message) {
                            return alert(errors[0].message);
                        }
                    } else {
                        return console.log("Unknown error");
                    }
                } else {
                    var toastEvent = $A.get("e.force:showToast");
                    toastEvent.setParams({
                        "title": "Success!",
                        "type": "success",
                        "message": "The model id for the training is " + response.getReturnValue() + ". Refresh the dataset for seeing the training progress."
                    });
                    toastEvent.fire();
                }
            });
            component.set("v.spinnerWaiting", true);
            $A.enqueueAction(action);
        }
    })
  7. [File (ファイル)] > [Save All (すべて保存)] をクリックします。
  8. 開発者コンソールを閉じます。

Lightning アプリケーションを作成する

  1. [Setup (設定)] の [Home (ホーム)] タブで、[Quick Find (クイック検索)] ボックスに「Lightning App」と入力し、[Lightning App Builder (Lightning アプリケーションビルダー)] を選択します。
  2. [New (新規)] をクリックします。
  3. [App Page (アプリケーションページ)] を選択したままで、[Next (次へ)] をクリックします。
  4. [Label (表示ラベル)] に「Einstein Vision」と入力し、[Next (次へ)] をクリックします。
  5. [One Region (1 つの範囲)] を選択し、[Finish (完了)] をクリックします。
  6. EinsteinVision_Admin_UI Lightning コンポーネントを Lightning ページにドラッグします
  7. [Save (保存)] をクリックします。
  8. [Activate (有効化)] をクリックします。
  9. [Page Settings (ページの設定)] で、[Activate for System Administrators only (システム管理者のみを対象に有効化)] を選択します。
  10. [Lightning Experience] タブを選択します。
  11. [Cat Rescue] を選択して、[Add page to app (アプリケーションにページを追加)] をクリックします。
  12. [Save (保存)] をクリックします。
  13. [Back (戻る)] 戻るボタン をクリックして、[Setup (設定)] に戻ります。
無料で学習を続けましょう!
続けるにはアカウントにサインアップしてください。
サインアップすると次のような機能が利用できるようになります。
  • 各自のキャリア目標に合わせてパーソナライズされたおすすめが表示される
  • ハンズオン Challenge やテストでスキルを練習できる
  • 進捗状況を追跡して上司と共有できる
  • メンターやキャリアチャンスと繋がることができる