Skip to content

Commit

Permalink
Adds a new command spp model list Closes #6103
Browse files Browse the repository at this point in the history
  • Loading branch information
mkm17 committed Sep 26, 2024
1 parent 2d61838 commit 1630898
Show file tree
Hide file tree
Showing 7 changed files with 511 additions and 1 deletion.
140 changes: 140 additions & 0 deletions docs/docs/cmd/spp/model/model-list.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import Global from '/docs/cmd/_global.mdx';
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# spp model list

Retrieves the list of unstructured document processing models

## Usage

```sh
m365 spp model list [options]
```

## Options

```md definition-list
`-u, --siteUrl <siteUrl>`
: The URL of the content center site.
```

<Global />

## Examples

Retrieve a list of SharePoint Premium unstructured document processing models on the content center site.

```sh
m365 spp model list --siteUrl https://contoso.sharepoint.com/sites/ContentCenter
```

## Response

<Tabs>
<TabItem value="JSON">

```json
[
{
"AIBuilderHybridModelType": "Freeform document processing",
"AzureCognitivePrebuiltModelName": null,
"BaseContentTypeName": null,
"ConfidenceScore": "{\r\\\n \"ConfidenceScoresPerLibrary\": {\r\\\n \"64e2de73-dfbe-4085-a49f-8347ddfc7e3a\": 0.86973333358764682\r\\\n }\r\\\n}",
"ContentTypeGroup": "Intelligent Document Content Types",
"ContentTypeId": "0x01010027D65A01A9F279408035C63ED6682D3A",
"ContentTypeName": "UnorderedModel",
"Created": "2024-05-22T20:11:59Z",
"CreatedBy": "i:0#.f|membership|[email protected]",
"DriveId": "b!xlpC8UN4X0WDi7Xz7yRQP_JZHRltjGlEpsj90HfZPCiSNv6idu5tRoCxMjOJSIyo",
"Explanations": "{\r\\\n \"Classifier\": [],\r\\\n \"Extractors\": {}\r\\\n}",
"ID": 1,
"LastTrained": "2024-05-23T17:35:53Z",
"ListID": "a2fe3692-ee76-466d-80b1-323389488ca8",
"ModelSettings": "{\r\\\n \"ModelTypeSpecificSettings\": {\r\\\n \"kind\": \"aiBuilderHybridSettings\",\r\\\n \"AIBHybridModelType\": \"CustomDocument\",\r\\\n \"AIBHybridModelHostName\": \"make.powerapps.com\",\r\\\n \"IsTestEnvironment\": false,\r\\\n \"AIBHybridModelId\": \"16cff4de-bac7-4849-957e-54bdee08e11e\",\r\\\n \"AIBHybridModelEnvironment\": \"Default-4d704217-2c7f-4072-8799-820f988299d7\",\r\\\n \"AIBHybridModelStatus\": \"publisheddraft\",\r\\\n \"DataverseInstanceUrl\": \"https://org.crm4.dynamics.com/\"\r\\\n },\r\\\n \"LastPublishedTime\": \"2024-05-23T10:36:36Z\",\r\\\n \"ClassifiedItemsCount\": \"3\"\r\\\n}",
"ModelType": 8,
"Modified": "2024-05-24T11:57:59Z",
"ModifiedBy": "i:0#.w|sharepoint\\system",
"ObjectId": "01RS33TEFSBQKR7PVA25C2USVWUH2YFFRV",
"PublicationType": 0,
"Schemas": "{\"Version\":2,\"Extractors\":{\"FirstName\":{\"id\":\"labels/FirstName\",\"concepts\":{},\"table\":null,\"detectionOnly\":false},\"LastName\":{\"id\":\"labels/LastName\",\"concepts\":{},\"table\":null,\"detectionOnly\":false},\"Hobbies\":{\"id\":\"labels/Hobbies\",\"concepts\":{},\"table\":null,\"detectionOnly\":false},\"Email\":{\"id\":\"labels/Email\",\"concepts\":{},\"table\":null,\"detectionOnly\":false},\"PhoneNumber\":{\"id\":\"labels/PhoneNumber\",\"concepts\":{},\"table\":null,\"detectionOnly\":false},\"City\":{\"id\":\"labels/City\",\"concepts\":{},\"table\":null,\"detectionOnly\":false},\"JobTitle\":{\"id\":\"labels/JobTitle\",\"concepts\":{},\"table\":null,\"detectionOnly\":false},\"Education_aibtable\":{\"id\":\"tables/Education\",\"concepts\":{},\"table\":{\"name\":\"Education\",\"columns\":[{\"name\":\"SchoolName\",\"id\":null},{\"name\":\"SpecializationName\",\"id\":null},{\"name\":\"StartDate\",\"id\":null},{\"name\":\"EndDate\",\"id\":null}]},\"detectionOnly\":false},\"WorkExperiance_aibtable\":{\"id\":\"tables/WorkExperiance\",\"concepts\":{},\"table\":{\"name\":\"WorkExperiance\",\"columns\":[{\"name\":\"CompanyName\",\"id\":null},{\"name\":\"StartDate\",\"id\":null},{\"name\":\"EndDate\",\"id\":null},{\"name\":\"Position\",\"id\":null},{\"name\":\"TechnologiesKeywords\",\"id\":null}]},\"detectionOnly\":false}},\"Classifiers\":null,\"accuracy\":null,\"relationships\":null,\"TemplatedModel\":null}",
"SourceSiteUrl": "https://contoso.sharepoint.com/sites/ContentCenter",
"SourceUrl": null,
"SourceWebServerRelativeUrl": "/sites/ContentCenter",
"UniqueId": "1f150cb2-a0be-45d7-aa4a-b6a1f5829635"
}
]
```

</TabItem>
<TabItem value="Text">

```text
AIBuilderHybridModelType ContentTypeName LastTrained UniqueId PublicationType
------------------------------ ---------------------------------- -------------------- ------------------------------------ ---------------
Freeform document processing UnorderedModel 2024-05-23T17:35:53Z 1f150cb2-a0be-45d7-aa4a-b6a1f5829635 0
```

</TabItem>
<TabItem value="CSV">

```csv
AIBuilderHybridModelType,AzureCognitivePrebuiltModelName,BaseContentTypeName,ConfidenceScore,ContentTypeGroup,ContentTypeId,ContentTypeName,Created,CreatedBy,DriveId,Explanations,ID,LastTrained,ListID,ModelSettings,ModelType,Modified,ModifiedBy,ObjectId,PublicationType,Schemas,SourceSiteUrl,SourceUrl,SourceWebServerRelativeUrl,UniqueId
Freeform document processing,,,"{
""ConfidenceScoresPerLibrary"": {
""64e2de73-dfbe-4085-a49f-8347ddfc7e3a"": 0.86973333358764682
}
}",Intelligent Document Content Types,0x01010027D65A01A9F279408035C63ED6682D3A,UnorderedModel,2024-05-22T20:11:59Z,i:0#.f|membership|[email protected],b!xlpC8UN4X0WDi7Xz7yRQP_JZHRltjGlEpsj90HfZPCiSNv6idu5tRoCxMjOJSIyo,"{
""Classifier"": [],
""Extractors"": {}
}",1,2024-05-23T17:35:53Z,a2fe3692-ee76-466d-80b1-323389488ca8,"{
""ModelTypeSpecificSettings"": {
""kind"": ""aiBuilderHybridSettings"",
""AIBHybridModelType"": ""CustomDocument"",
""AIBHybridModelHostName"": ""make.powerapps.com"",
""IsTestEnvironment"": false,
""AIBHybridModelId"": ""16cff4de-bac7-4849-957e-54bdee08e11e"",
""AIBHybridModelEnvironment"": ""Default-4d704217-2c7f-4072-8799-820f988299d7"",
""AIBHybridModelStatus"": ""publisheddraft"",
""DataverseInstanceUrl"": ""https://org.crm4.dynamics.com/""
},
""LastPublishedTime"": ""2024-05-23T10:36:36Z"",
""ClassifiedItemsCount"": ""3""
}",8,2024-05-24T11:57:59Z,i:0#.w|sharepoint\system,01RS33TEFSBQKR7PVA25C2USVWUH2YFFRV,0,"Model Schema",https://contoso.sharepoint.com/sites/ContentCenter,,/sites/ContentCenter,1f150cb2-a0be-45d7-aa4a-b6a1f5829635
```

</TabItem>
<TabItem value="Markdown">

```md
# spp model list --siteUrl "https://contoso.sharepoint.com/sites/ContentCenter"

Date: 7/22/2024

## 1

Property | Value
---------|-------
AIBuilderHybridModelType | Freeform document processing
ContentTypeGroup | Intelligent Document Content Types
ContentTypeId | 0x01010027D65A01A9F279408035C63ED6682D3A
ContentTypeName | UnorderedModel
Created | 2024-05-22T20:11:59Z
CreatedBy | i:0#.f\|membership\|[email protected]
DriveId | b!xlpC8UN4X0WDi7Xz7yRQP\_JZHRltjGlEpsj90HfZPCiSNv6idu5tRoCxMjOJSIyo
ID | 1
LastTrained | 2024-05-23T17:35:53Z
ListID | a2fe3692-ee76-466d-80b1-323389488ca8
ModelType | 8
Modified | 2024-05-24T11:57:59Z
ModifiedBy | i:0#.w\|sharepoint\system
ObjectId | 01RS33TEFSBQKR7PVA25C2USVWUH2YFFRV
PublicationType | 0
Schemas | {"Version":2,"Extractors":{"FirstName":{"id":"labels/FirstName","concepts":{},"table":null,"detectionOnly":false},"LastName":{"id":"labels/LastName","concepts":{},"table":null,"detectionOnly":false},"Hobbies":{"id":"labels/Hobbies","concepts":{},"table":null,"detectionOnly":false},"Email":{"id":"labels/Email","concepts":{},"table":null,"detectionOnly":false},"PhoneNumber":{"id":"labels/PhoneNumber","concepts":{},"table":null,"detectionOnly":false},"City":{"id":"labels/City","concepts":{},"table":null,"detectionOnly":false},"JobTitle":{"id":"labels/JobTitle","concepts":{},"table":null,"detectionOnly":false},"Education\_aibtable":{"id":"tables/Education","concepts":{},"table":{"name":"Education","columns":[{"name":"SchoolName","id":null},{"name":"SpecializationName","id":null},{"name":"StartDate","id":null},{"name":"EndDate","id":null}]},"detectionOnly":false},"WorkExperiance\_aibtable":{"id":"tables/WorkExperiance","concepts":{},"table":{"name":"WorkExperiance","columns":[{"name":"CompanyName","id":null},{"name":"StartDate","id":null},{"name":"EndDate","id":null},{"name":"Position","id":null},{"name":"TechnologiesKeywords","id":null}]},"detectionOnly":false}},"Classifiers":null,"accuracy":null,"relationships":null,"TemplatedModel":null}
SourceSiteUrl | https://contoso.sharepoint.com/sites/ContentCenter
SourceWebServerRelativeUrl | /sites/ContentCenter
UniqueId | 1f150cb2-a0be-45d7-aa4a-b6a1f5829635
```

</TabItem>
</Tabs>
9 changes: 9 additions & 0 deletions docs/src/config/sidebars.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3956,6 +3956,15 @@ const sidebars: SidebarsConfig = {
id: 'cmd/spp/contentcenter/contentcenter-list'
}
]
},
{
model: [
{
type: 'doc',
label: 'model list',
id: 'cmd/spp/model/model-list'
}
]
}
]
},
Expand Down
3 changes: 2 additions & 1 deletion src/m365/spp/commands.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const prefix: string = 'spp';

export default {
CONTENTCENTER_LIST: `${prefix} contentcenter list`
CONTENTCENTER_LIST: `${prefix} contentcenter list`,
MODEL_LIST: `${prefix} model list`
};
185 changes: 185 additions & 0 deletions src/m365/spp/commands/model/model-list.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
import assert from 'assert';
import sinon from 'sinon';
import auth from '../../../../Auth.js';
import { cli } from '../../../../cli/cli.js';
import { CommandInfo } from '../../../../cli/CommandInfo.js';
import { Logger } from '../../../../cli/Logger.js';
import { CommandError } from '../../../../Command.js';
import request from '../../../../request.js';
import { telemetry } from '../../../../telemetry.js';
import { pid } from '../../../../utils/pid.js';
import { session } from '../../../../utils/session.js';
import { sinonUtil } from '../../../../utils/sinonUtil.js';
import commands from '../../commands.js';
import command from './model-list.js';

describe(commands.MODEL_LIST, () => {
let log: string[];
let logger: Logger;
let loggerLogSpy: sinon.SinonSpy;
let commandInfo: CommandInfo;
const models = [
{
"AIBuilderHybridModelType": null,
"AzureCognitivePrebuiltModelName": null,
"BaseContentTypeName": null,
"ConfidenceScore": "{\"trainingStatus\":{\"kind\":\"original\",\"ClassifierStatus\":{\"TrainingStatus\":\"success\",\"TimeStamp\":1716547860981},\"ExtractorsStatus\":[{\"TimeStamp\":1716547860173,\"ExtractorName\":\"Name\",\"TrainingStatus\":\"success\"}]},\"modelAccuracy\":{\"Classifier\":1,\"Extractors\":{\"Name\":0.333333343}},\"perSampleAccuracy\":{\"1\":{\"Classifier\":1,\"Extractors\":{\"Name\":1}},\"2\":{\"Classifier\":1,\"Extractors\":{\"Name\":0}},\"3\":{\"Classifier\":1,\"Extractors\":{\"Name\":0}},\"4\":{\"Classifier\":1,\"Extractors\":{\"Name\":0}},\"5\":{\"Classifier\":1,\"Extractors\":{\"Name\":0}},\"6\":{\"Classifier\":1,\"Extractors\":{\"Name\":1}}},\"perSamplePrediction\":{\"1\":{\"Extractors\":{\"Name\":[\"Michał\"]}},\"2\":{\"Extractors\":{\"Name\":[]}},\"3\":{\"Extractors\":{\"Name\":[]}},\"4\":{\"Extractors\":{\"Name\":[]}},\"5\":{\"Extractors\":{\"Name\":[]}},\"6\":{\"Extractors\":{\"Name\":[]}}},\"trainingFailures\":{}}",
"ContentTypeGroup": "Intelligent Document Content Types",
"ContentTypeId": "0x010100A5C3671D1FB1A64D9F280C628D041692",
"ContentTypeName": "TeachingModel",
"Created": "2024-05-23T16:51:29Z",
"CreatedBy": "i:0#.f|membership|[email protected]",
"DriveId": "b!qTVLltt1P02LUgejOy6O_1amoFeu1EJBlawH83UtYbQs_H3KVKAcQpuQOpNLl646",
"Explanations": "{\"Classifier\":[{\"id\":\"950f39cd-5e72-4442-ae8a-ea4bae32962c\",\"kind\":\"regexFeature\",\"name\":\"Email address\",\"active\":true,\"pattern\":\"[A-Za-z0-9._%-]+@[A-Za-z0-9.-]+.[A-Za-z]{2,6}\"},{\"id\":\"d3f2940d-1df1-4ba8-975a-db3a4d626d5c\",\"kind\":\"dictionaryFeature\",\"name\":\"FirstName\",\"active\":true,\"nGrams\":[\"Michał\"],\"caseSensitive\":false,\"ignoreDigitIdentity\":false,\"ignoreLetterIdentity\":false},{\"id\":\"077966e1-73be-44c9-855f-a4eade6a280b\",\"kind\":\"modelFeature\",\"name\":\"Name\",\"active\":true,\"modelReference\":\"Name\",\"conceptId\":\"309b64e5-acd5-4538-a5b6-c6bfcdc1ffbf\"}],\"Extractors\":{\"Name\":[{\"id\":\"69e412bc-e5bc-4657-b378-34a01966bb92\",\"kind\":\"dictionaryFeature\",\"name\":\"Before label\",\"active\":true,\"nGrams\":[\"Test\",\"'Surname\",\"Test (\"],\"caseSensitive\":false,\"ignoreDigitIdentity\":false,\"ignoreLetterIdentity\":false}]}}",
"ID": 1,
"LastTrained": "2024-05-24T17:51:16Z",
"ListID": "ca7dfc2c-a054-421c-9b90-3a934b97ae3a",
"ModelSettings": "{\"ModelOrigin\":{\"LibraryId\":\"8a6027ab-c584-4394-ba9c-3dc4dd152b65\",\"Published\":false,\"SelecteFileUniqueIds\":[]}}",
"ModelType": 2,
"Modified": "2024-05-24T17:51:02Z",
"ModifiedBy": "i:0#.f|membership|[email protected]",
"ObjectId": "01HQDCWVGIEBDRN3RVK5A3UJW3M4TCMT45",
"PublicationType": 0,
"Schemas": "{\"Version\":2,\"Extractors\":{\"Name\":{\"concepts\":{\"309b64e5-acd5-4538-a5b6-c6bfcdc1ffbf\":{\"name\":\"Name\"}},\"relationships\":[],\"id\":\"Name\"}}}",
"SourceSiteUrl": "https://contoso.sharepoint.com/sites/SyntexTest",
"SourceUrl": null,
"SourceWebServerRelativeUrl": "/sites/SyntexTest",
"UniqueId": "164720c8-35ee-4157-ba26-db6726264f9d"
}
];

before(() => {
sinon.stub(auth, 'restoreAuth').resolves();
sinon.stub(telemetry, 'trackEvent').returns();
sinon.stub(pid, 'getProcessName').returns('');
sinon.stub(session, 'getId').returns('');
auth.connection.active = true;
commandInfo = cli.getCommandInfo(command);
});

beforeEach(() => {
log = [];
logger = {
log: async (msg: string) => {
log.push(msg);
},
logRaw: async (msg: string) => {
log.push(msg);
},
logToStderr: async (msg: string) => {
log.push(msg);
}
};
loggerLogSpy = sinon.spy(logger, 'log');
});

afterEach(() => {
sinonUtil.restore([
request.get
]);
});

after(() => {
sinon.restore();
auth.connection.active = false;
});

it('has correct name', () => {
assert.strictEqual(command.name, commands.MODEL_LIST);
});

it('has a description', () => {
assert.notStrictEqual(command.description, null);
});

it('defines correct properties for the default output', () => {
assert.deepStrictEqual(command.defaultProperties(), ['AIBuilderHybridModelType', 'ContentTypeName', 'LastTrained', 'UniqueId', 'PublicationType']);
});

it('passes validation when required parameters are valid', async () => {
const actual = await command.validate({ options: { siteUrl: 'https://contoso.sharepoint.com/sites/sales' } }, commandInfo);
assert.strictEqual(actual, true);
});

it('fails validation when siteUrl is not valid', async () => {
const actual = await command.validate({ options: { siteUrl: 'invalidUrl' } }, commandInfo);
assert.notStrictEqual(actual, true);
});

it('correctly handles site is not Content Site', async () => {
sinon.stub(request, 'get').callsFake(async (opts) => {
if (opts.url === `https://contoso.sharepoint.com/sites/portal/_api/web?$select=WebTemplateConfiguration`) {
return {
WebTemplateConfiguration: 'SITEPAGEPUBLISHING#0'
};
}

throw 'Invalid request';
});

await assert.rejects(command.action(logger, { options: { verbose: true, siteUrl: 'https://contoso.sharepoint.com/sites/portal' } }),
new CommandError('https://contoso.sharepoint.com/sites/portal is not a content site.'));
});


it('correctly handles an access denied error', async () => {
sinon.stub(request, 'get').callsFake(async (opts) => {
if (opts.url === `https://contoso.sharepoint.com/sites/portal/_api/web?$select=WebTemplateConfiguration`) {
throw {
error: {
"odata.error": {
message: {
lang: "en-US",
value: "Attempted to perform an unauthorized operation."
}
}
}
};
}

throw 'Invalid request';
});

await assert.rejects(command.action(logger, { options: { verbose: true, siteUrl: 'https://contoso.sharepoint.com/sites/portal' } }),
new CommandError('Attempted to perform an unauthorized operation.'));
});


it('retrieves all site models', async () => {
sinon.stub(request, 'get').callsFake(async (opts) => {
if (opts.url === `https://contoso.sharepoint.com/sites/portal/_api/web?$select=WebTemplateConfiguration`) {
return {
WebTemplateConfiguration: 'CONTENTCTR#0'
};
}

if (opts.url === 'https://contoso.sharepoint.com/sites/portal/_api/machinelearning/models') {
return { value: models };
}

throw 'Invalid request';
});

await command.action(logger, { options: { siteUrl: 'https://contoso.sharepoint.com/sites/portal' } });
assert(loggerLogSpy.calledOnceWithExactly(models));
});

it('gets correct model list when the the site URL has trailing slash', async () => {
sinon.stub(request, 'get').callsFake(async (opts) => {
if (opts.url === `https://contoso.sharepoint.com/sites/portal/_api/web?$select=WebTemplateConfiguration`) {
return {
WebTemplateConfiguration: 'CONTENTCTR#0'
};
}

if (opts.url === 'https://contoso.sharepoint.com/sites/portal/_api/machinelearning/models') {
return { value: models };
}

throw 'Invalid request';
});

await command.action(logger, { options: { siteUrl: 'https://contoso.sharepoint.com/sites/portal/' } });
assert(loggerLogSpy.calledOnceWithExactly(models));
});
});
Loading

0 comments on commit 1630898

Please sign in to comment.