askui 0.20.6 → 0.20.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. package/dist/cjs/core/inference-response/inference-response.d.ts +5 -0
  2. package/dist/cjs/execution/execution-runtime.d.ts +1 -0
  3. package/dist/cjs/execution/execution-runtime.js +6 -0
  4. package/dist/cjs/execution/inference-client.d.ts +3 -0
  5. package/dist/cjs/execution/inference-client.js +25 -0
  6. package/dist/cjs/execution/ui-control-client.d.ts +89 -0
  7. package/dist/cjs/execution/ui-control-client.js +94 -0
  8. package/dist/cjs/lib/interactive_cli/cli.js +0 -32
  9. package/dist/cjs/lib/interactive_cli/create-example-project.d.ts +0 -1
  10. package/dist/cjs/lib/interactive_cli/create-example-project.js +4 -31
  11. package/dist/cjs/lib/ui-controller.d.ts +4 -0
  12. package/dist/cjs/lib/ui-controller.js +4 -0
  13. package/dist/esm/core/inference-response/inference-response.d.ts +5 -0
  14. package/dist/esm/execution/execution-runtime.d.ts +1 -0
  15. package/dist/esm/execution/execution-runtime.js +6 -0
  16. package/dist/esm/execution/inference-client.d.ts +3 -0
  17. package/dist/esm/execution/inference-client.js +25 -0
  18. package/dist/esm/execution/ui-control-client.d.ts +89 -0
  19. package/dist/esm/execution/ui-control-client.js +94 -0
  20. package/dist/esm/lib/interactive_cli/cli.js +0 -32
  21. package/dist/esm/lib/interactive_cli/create-example-project.d.ts +0 -1
  22. package/dist/esm/lib/interactive_cli/create-example-project.js +4 -31
  23. package/dist/esm/lib/ui-controller.d.ts +4 -0
  24. package/dist/esm/lib/ui-controller.js +4 -0
  25. package/dist/example_projects_templates/templates/askui-helper.nj +2 -17
  26. package/package.json +1 -1
  27. package/dist/example_projects_templates/templates/askui-helper-windows.nj +0 -36
@@ -5,6 +5,11 @@ export interface InferenceResponseBody {
5
5
  type: ModelType;
6
6
  data: ModelType extends 'COMMANDS' ? ControlCommand : Annotation;
7
7
  }
8
+ export interface VQAInferenceResponseBody {
9
+ data: {
10
+ response: string;
11
+ };
12
+ }
8
13
  export declare class InferenceResponse {
9
14
  static fromJson(json: InferenceResponseBody, resizeRatio?: number, image?: string): ControlCommand | Annotation;
10
15
  static createModels(type: ModelType, data: ModelType extends 'COMMANDS' ? ControlCommand : Annotation, resizeRatio: number, image?: string): ControlCommand | Annotation;
@@ -35,4 +35,5 @@ export declare class ExecutionRuntime {
35
35
  takeScreenshotIfImageisNotProvided(imagePath?: string): Promise<string>;
36
36
  getDetectedElements(instruction: string, customElementJson?: CustomElementJson[]): Promise<DetectedElement[]>;
37
37
  annotateImage(imagePath?: string, customElementJson?: CustomElementJson[], elements?: DetectedElement[]): Promise<Annotation>;
38
+ predictVQA(prompt: string, config?: object): Promise<any>;
38
39
  }
@@ -208,5 +208,11 @@ class ExecutionRuntime {
208
208
  return this.inferenceClient.predictImageAnnotation(base64Image, customElements);
209
209
  });
210
210
  }
211
+ predictVQA(prompt, config) {
212
+ return __awaiter(this, void 0, void 0, function* () {
213
+ const base64Image = yield this.takeScreenshotIfImageisNotProvided();
214
+ return this.inferenceClient.predictVQAAnswer(prompt, base64Image, config);
215
+ });
216
+ }
211
217
  }
212
218
  exports.ExecutionRuntime = ExecutionRuntime;
@@ -3,6 +3,7 @@ import { ControlCommand } from '../core/ui-control-commands';
3
3
  import { CustomElement } from '../core/model/custom-element';
4
4
  import { Annotation } from '../core/annotation/annotation';
5
5
  import { DetectedElement } from '../core/model/annotation-result/detected-element';
6
+ import { VQAInferenceResponseBody } from '../core/inference-response/inference-response';
6
7
  import { ModelCompositionBranch } from './model-composition-branch';
7
8
  export declare class InferenceClient {
8
9
  private readonly baseUrl;
@@ -16,8 +17,10 @@ export declare class InferenceClient {
16
17
  isImageRequired(instruction: string): Promise<boolean>;
17
18
  private resizeIfNeeded;
18
19
  inference(customElements?: CustomElement[], image?: string, instruction?: string): Promise<ControlCommand | Annotation>;
20
+ vqaInference(image: string, prompt: string, config?: object): Promise<VQAInferenceResponseBody>;
19
21
  private static logMetaInformation;
20
22
  predictControlCommand(instruction: string, customElements?: CustomElement[], image?: string): Promise<ControlCommand>;
21
23
  getDetectedElements(instruction: string, image: string, customElements?: CustomElement[]): Promise<DetectedElement[]>;
22
24
  predictImageAnnotation(image: string, customElements?: CustomElement[]): Promise<Annotation>;
25
+ predictVQAAnswer(prompt: string, image: string, config?: object): Promise<any>;
23
26
  }
@@ -35,6 +35,7 @@ class InferenceClient {
35
35
  this.urls = {
36
36
  inference: (0, url_join_1.default)(url, 'inference'),
37
37
  isImageRequired: (0, url_join_1.default)(url, 'instruction', 'is-image-required'),
38
+ vqaInference: (0, url_join_1.default)(url, 'vqa', 'inference'),
38
39
  };
39
40
  this.httpClient.urlsToRetry = Object.values(this.urls);
40
41
  if (this.resize !== undefined && this.resize <= 0) {
@@ -77,6 +78,17 @@ class InferenceClient {
77
78
  return ui_control_commands_1.InferenceResponse.fromJson(response.body, resizedImage.resizeRatio, image);
78
79
  });
79
80
  }
81
+ vqaInference(image, prompt, config) {
82
+ return __awaiter(this, void 0, void 0, function* () {
83
+ const response = yield this.httpClient.post(this.urls.vqaInference, {
84
+ config,
85
+ image,
86
+ prompt,
87
+ });
88
+ InferenceClient.logMetaInformation(response);
89
+ return response.body;
90
+ });
91
+ }
80
92
  static logMetaInformation(response) {
81
93
  if (response.headers['askui-usage-warnings'] !== undefined) {
82
94
  logger_1.logger.warn(response.headers['askui-usage-warnings']);
@@ -109,5 +121,18 @@ class InferenceClient {
109
121
  return inferenceResponse;
110
122
  });
111
123
  }
124
+ predictVQAAnswer(prompt, image, config) {
125
+ return __awaiter(this, void 0, void 0, function* () {
126
+ const inferenceResponse = yield this.vqaInference(image, prompt, config);
127
+ const { response } = inferenceResponse.data;
128
+ try {
129
+ return JSON.parse(response);
130
+ }
131
+ catch (error) {
132
+ logger_1.logger.warn(`Response is no valid JSON: ${response}`);
133
+ }
134
+ return response;
135
+ });
136
+ }
112
137
  }
113
138
  exports.InferenceClient = InferenceClient;
@@ -59,6 +59,95 @@ export declare class UiControlClient extends ApiCommands {
59
59
  private getAIElementsByNames;
60
60
  fluentCommandExecutor(instructionString: string, context?: CommandExecutorContext): Promise<void>;
61
61
  getterExecutor(instruction: string, context?: CommandExecutorContext): Promise<DetectedElement[]>;
62
+ /**
63
+ * Takes a prompt that contains a question you want to be answered
64
+ * or the data you want to have extracted from your screen.
65
+ *
66
+ * The optional 'config' can be used to specifiy the JSON schema the
67
+ * returned object shall have (https://json-schema.org).
68
+ *
69
+ * See the following examples on how to use it:
70
+ *
71
+ * let isWidgetsNew =
72
+ * await aui.ask(
73
+ * "Does the sidebar element 'Widgets' have a 'NEW' tag?",
74
+ * {
75
+ * json_schema: {
76
+ * "type": "boolean"
77
+ * }
78
+ * });
79
+ *
80
+ * Output of console.log(isWidgetsNew): true
81
+ *
82
+ * let newClients =
83
+ * await aui.ask(
84
+ * "How many new clients?",
85
+ * {
86
+ * json_schema: {
87
+ * "type": "number"
88
+ * }
89
+ * });
90
+ *
91
+ * Output of console.log(newClients): 9123
92
+ *
93
+ * let userNames =
94
+ * await aui.ask(
95
+ * "Return a list with the users names.",
96
+ * {
97
+ * json_schema: {
98
+ * "type": "array",
99
+ * "items": {
100
+ * "type": "string"
101
+ * }
102
+ * }
103
+ * });
104
+ *
105
+ * Output of console.log(userNames):
106
+ * [
107
+ * 'Yiorgos Avraamu',
108
+ * 'Avram Tsarios',
109
+ * 'Quintin Ed',
110
+ * 'Enéas Kwadwo',
111
+ * 'Agapetus Tadeáš'
112
+ * ]
113
+ *
114
+ * let users =
115
+ * await aui.ask(
116
+ * "Extract the users from the table.",
117
+ * {
118
+ * json_schema: {
119
+ * "type": "array",
120
+ * "items": {
121
+ * "type": "object",
122
+ * "properties": {
123
+ * "name": {
124
+ * "type": "string"
125
+ * },
126
+ * "usage": {
127
+ * "type": "number"
128
+ * }
129
+ * },
130
+ * "additionalProperties": false,
131
+ * "required": ["name", "usage"]
132
+ * },
133
+ * },
134
+ * });
135
+ *
136
+ * Output of console.log(users):
137
+ * [
138
+ * { name: 'Yiorgos Avraamu', usage: 50 },
139
+ * { name: 'Avram Tarasios', usage: 10 },
140
+ * { name: 'Quintin Ed', usage: 74 },
141
+ * { name: 'Eneás Kwadwo', usage: 98 },
142
+ * { name: 'Agapetus Tadeáš', usage: 22 }
143
+ * ]
144
+ *
145
+ * @param {string} prompt - The question you want to be answered or
146
+ * the data you want to have extracted.
147
+ * @param {Object} config - object that specifies the return json: {json_schema: {...}}.
148
+ * @returns {any} - The answer as JSON specified in the config object.
149
+ */
150
+ ask(prompt: string, config?: object): Promise<any>;
62
151
  private secretText;
63
152
  private getAndResetSecretText;
64
153
  /**
@@ -166,6 +166,100 @@ class UiControlClient extends dsl_1.ApiCommands {
166
166
  ]);
167
167
  });
168
168
  }
169
+ /**
170
+ * Takes a prompt that contains a question you want to be answered
171
+ * or the data you want to have extracted from your screen.
172
+ *
173
+ * The optional 'config' can be used to specifiy the JSON schema the
174
+ * returned object shall have (https://json-schema.org).
175
+ *
176
+ * See the following examples on how to use it:
177
+ *
178
+ * let isWidgetsNew =
179
+ * await aui.ask(
180
+ * "Does the sidebar element 'Widgets' have a 'NEW' tag?",
181
+ * {
182
+ * json_schema: {
183
+ * "type": "boolean"
184
+ * }
185
+ * });
186
+ *
187
+ * Output of console.log(isWidgetsNew): true
188
+ *
189
+ * let newClients =
190
+ * await aui.ask(
191
+ * "How many new clients?",
192
+ * {
193
+ * json_schema: {
194
+ * "type": "number"
195
+ * }
196
+ * });
197
+ *
198
+ * Output of console.log(newClients): 9123
199
+ *
200
+ * let userNames =
201
+ * await aui.ask(
202
+ * "Return a list with the users names.",
203
+ * {
204
+ * json_schema: {
205
+ * "type": "array",
206
+ * "items": {
207
+ * "type": "string"
208
+ * }
209
+ * }
210
+ * });
211
+ *
212
+ * Output of console.log(userNames):
213
+ * [
214
+ * 'Yiorgos Avraamu',
215
+ * 'Avram Tsarios',
216
+ * 'Quintin Ed',
217
+ * 'Enéas Kwadwo',
218
+ * 'Agapetus Tadeáš'
219
+ * ]
220
+ *
221
+ * let users =
222
+ * await aui.ask(
223
+ * "Extract the users from the table.",
224
+ * {
225
+ * json_schema: {
226
+ * "type": "array",
227
+ * "items": {
228
+ * "type": "object",
229
+ * "properties": {
230
+ * "name": {
231
+ * "type": "string"
232
+ * },
233
+ * "usage": {
234
+ * "type": "number"
235
+ * }
236
+ * },
237
+ * "additionalProperties": false,
238
+ * "required": ["name", "usage"]
239
+ * },
240
+ * },
241
+ * });
242
+ *
243
+ * Output of console.log(users):
244
+ * [
245
+ * { name: 'Yiorgos Avraamu', usage: 50 },
246
+ * { name: 'Avram Tarasios', usage: 10 },
247
+ * { name: 'Quintin Ed', usage: 74 },
248
+ * { name: 'Eneás Kwadwo', usage: 98 },
249
+ * { name: 'Agapetus Tadeáš', usage: 22 }
250
+ * ]
251
+ *
252
+ * @param {string} prompt - The question you want to be answered or
253
+ * the data you want to have extracted.
254
+ * @param {Object} config - object that specifies the return json: {json_schema: {...}}.
255
+ * @returns {any} - The answer as JSON specified in the config object.
256
+ */
257
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
258
+ ask(prompt, config) {
259
+ return __awaiter(this, void 0, void 0, function* () {
260
+ return this.executionRuntime.predictVQA(prompt, config);
261
+ });
262
+ }
169
263
  getAndResetSecretText() {
170
264
  const { secretText } = this;
171
265
  this.secretText = undefined;
@@ -17,7 +17,6 @@ const inquirer_1 = __importDefault(require("inquirer"));
17
17
  const commander_1 = require("commander");
18
18
  const fs_extra_1 = __importDefault(require("fs-extra"));
19
19
  const create_example_project_1 = require("./create-example-project");
20
- const nonEmpty = (subject) => (input) => input.trim().length > 0 || `${subject} is required.`;
21
20
  /* eslint-disable sort-keys */
22
21
  const questions = [
23
22
  {
@@ -26,21 +25,6 @@ const questions = [
26
25
  message: 'Which framework do you prefer?:',
27
26
  choices: ['jest'],
28
27
  },
29
- {
30
- type: 'input',
31
- name: 'workspaceId',
32
- message: 'Your workspace id:',
33
- validate: nonEmpty('workspace id'),
34
- when: (answers) => !answers.skipCredentials,
35
- },
36
- {
37
- type: 'password',
38
- name: 'accessToken',
39
- message: 'Your access token:',
40
- mask: '*',
41
- validate: nonEmpty('access token'),
42
- when: (answers) => !answers.skipCredentials,
43
- },
44
28
  {
45
29
  type: 'confirm',
46
30
  name: 'typescriptConfig',
@@ -57,22 +41,6 @@ const options = [
57
41
  description: 'the test framework to use.',
58
42
  option: '-f, --test-framework <value>',
59
43
  },
60
- {
61
- choices: [],
62
- default: false,
63
- description: 'skip the credentials setup.',
64
- option: '-sc, --skip-credentials',
65
- },
66
- {
67
- choices: [],
68
- description: 'a workspace id.',
69
- option: '-w, --workspace-id <value>',
70
- },
71
- {
72
- choices: [],
73
- description: 'an access token for the workspace with the id.',
74
- option: '-a, --access-token <value>',
75
- },
76
44
  {
77
45
  choices: [],
78
46
  default: 'askui_example',
@@ -18,7 +18,6 @@ export declare class CreateExampleProject {
18
18
  private createAskUIHelperFromTemplate;
19
19
  private setupTestFrameWork;
20
20
  private static installTestFrameworkPackages;
21
- private addUserCredentials;
22
21
  private copyESLintConfigFiles;
23
22
  private copyGitignore;
24
23
  private copyTsConfigFile;
@@ -30,7 +30,7 @@ class CreateExampleProject {
30
30
  this.projectRootDirectoryPath = process.cwd();
31
31
  this.automationsDirectoryName = this.getAutomationsDirectoryName();
32
32
  this.automationsDirectoryPath = path_1.default.join(this.projectRootDirectoryPath, this.automationsDirectoryName);
33
- this.askUIControllerUrl = 'https://docs.askui.com/docs/general/Components/AskUI-Controller';
33
+ this.askUIControllerUrl = 'https://docs.askui.com/docs/suite/Components/AskUI-Development-Environment#askui-startcontroller-command';
34
34
  this.helperTemplateConfig = {};
35
35
  }
36
36
  getAutomationsDirectoryName() {
@@ -131,10 +131,7 @@ class CreateExampleProject {
131
131
  title: 'Create askui-helper.ts ',
132
132
  task: () => __awaiter(this, void 0, void 0, function* () {
133
133
  const askuiHelperTemplateFilePath = path_1.default.join((0, path_2.getPathToNodeModulesRoot)(), 'example_projects_templates', 'templates');
134
- let templateFileName = 'askui-helper.nj';
135
- if (this.cliOptions.operatingSystem === 'windows') {
136
- templateFileName = 'askui-helper-windows.nj';
137
- }
134
+ const templateFileName = 'askui-helper.nj';
138
135
  nunjucks_1.default.configure(askuiHelperTemplateFilePath, { autoescape: false });
139
136
  const result = nunjucks_1.default.render(templateFileName, this.helperTemplateConfig);
140
137
  const filePath = path_1.default.join(this.automationsDirectoryPath, 'helpers', 'askui-helper.ts');
@@ -193,24 +190,6 @@ class CreateExampleProject {
193
190
  yield runCommand(frameworkDependencies.jest);
194
191
  });
195
192
  }
196
- addUserCredentials() {
197
- return __awaiter(this, void 0, void 0, function* () {
198
- return [
199
- {
200
- /* eslint-disable sort-keys */
201
- title: 'Add user credentials',
202
- enabled: () => !this.cliOptions.skipCredentials,
203
- task: () => __awaiter(this, void 0, void 0, function* () {
204
- this.helperTemplateConfig['credentials'] = ` credentials: {
205
- workspaceId: '${this.cliOptions.workspaceId}',
206
- token: '${this.cliOptions.accessToken}',
207
- },`;
208
- }),
209
- },
210
- /* eslint-enable */
211
- ];
212
- });
213
- }
214
193
  copyESLintConfigFiles() {
215
194
  return __awaiter(this, void 0, void 0, function* () {
216
195
  const esLintRcFilePath = path_1.default.join('example_projects_templates', 'typescript', '.eslintrc.json-template');
@@ -282,20 +261,14 @@ class CreateExampleProject {
282
261
  ...(yield this.copyESLintConfigFiles()),
283
262
  ...(yield this.copyGitignore()),
284
263
  ...(yield this.copyTsConfigFile()),
285
- ...(yield this.addUserCredentials()),
286
264
  ...(yield this.createAskUIHelperFromTemplate()),
287
265
  ]);
288
266
  yield tasks.run();
289
267
  /* eslint-disable no-console */
290
268
  console.log(chalk_1.default.greenBright('\nCongratulations!'));
291
269
  console.log(`askui example was created under ${chalk_1.default.gray(this.automationsDirectoryPath)}`);
292
- if (this.cliOptions.operatingSystem === 'windows') {
293
- console.log(chalk_1.default.redBright(`\nPlease make sure the AskUI Controller is running: ${this.askUIControllerUrl}\n`));
294
- console.log(`You can start your automation with this command ${chalk_1.default.green('AskUI-RunProject')}`);
295
- }
296
- else {
297
- console.log(`You can start your automation with this command ${chalk_1.default.green('npm run askui')}`);
298
- }
270
+ console.log(chalk_1.default.redBright(`\nPlease make sure the AskUI Controller is running: ${this.askUIControllerUrl}\n`));
271
+ console.log(`You can start your automation with this command ${chalk_1.default.green('AskUI-RunProject')}`);
299
272
  /* eslint-enable no-console */
300
273
  });
301
274
  }
@@ -1,4 +1,8 @@
1
1
  import { UiControllerArgs } from './ui-controller-args';
2
+ /**
3
+ * @deprecated Will be removed soon because the AskUI Controller
4
+ * gets started as an operating system service.
5
+ */
2
6
  export declare class UiController {
3
7
  private args?;
4
8
  private server;
@@ -14,6 +14,10 @@ const ui_controller_darwin_1 = require("./ui-controller-darwin");
14
14
  const ui_controller_linux_1 = require("./ui-controller-linux");
15
15
  const ui_controller_win32_1 = require("./ui-controller-win32");
16
16
  const download_binaries_1 = require("./download-binaries");
17
+ /**
18
+ * @deprecated Will be removed soon because the AskUI Controller
19
+ * gets started as an operating system service.
20
+ */
17
21
  class UiController {
18
22
  constructor(args) {
19
23
  this.args = args;
@@ -5,6 +5,11 @@ export interface InferenceResponseBody {
5
5
  type: ModelType;
6
6
  data: ModelType extends 'COMMANDS' ? ControlCommand : Annotation;
7
7
  }
8
+ export interface VQAInferenceResponseBody {
9
+ data: {
10
+ response: string;
11
+ };
12
+ }
8
13
  export declare class InferenceResponse {
9
14
  static fromJson(json: InferenceResponseBody, resizeRatio?: number, image?: string): ControlCommand | Annotation;
10
15
  static createModels(type: ModelType, data: ModelType extends 'COMMANDS' ? ControlCommand : Annotation, resizeRatio: number, image?: string): ControlCommand | Annotation;
@@ -35,4 +35,5 @@ export declare class ExecutionRuntime {
35
35
  takeScreenshotIfImageisNotProvided(imagePath?: string): Promise<string>;
36
36
  getDetectedElements(instruction: string, customElementJson?: CustomElementJson[]): Promise<DetectedElement[]>;
37
37
  annotateImage(imagePath?: string, customElementJson?: CustomElementJson[], elements?: DetectedElement[]): Promise<Annotation>;
38
+ predictVQA(prompt: string, config?: object): Promise<any>;
38
39
  }
@@ -205,4 +205,10 @@ export class ExecutionRuntime {
205
205
  return this.inferenceClient.predictImageAnnotation(base64Image, customElements);
206
206
  });
207
207
  }
208
+ predictVQA(prompt, config) {
209
+ return __awaiter(this, void 0, void 0, function* () {
210
+ const base64Image = yield this.takeScreenshotIfImageisNotProvided();
211
+ return this.inferenceClient.predictVQAAnswer(prompt, base64Image, config);
212
+ });
213
+ }
208
214
  }
@@ -3,6 +3,7 @@ import { ControlCommand } from '../core/ui-control-commands';
3
3
  import { CustomElement } from '../core/model/custom-element';
4
4
  import { Annotation } from '../core/annotation/annotation';
5
5
  import { DetectedElement } from '../core/model/annotation-result/detected-element';
6
+ import { VQAInferenceResponseBody } from '../core/inference-response/inference-response';
6
7
  import { ModelCompositionBranch } from './model-composition-branch';
7
8
  export declare class InferenceClient {
8
9
  private readonly baseUrl;
@@ -16,8 +17,10 @@ export declare class InferenceClient {
16
17
  isImageRequired(instruction: string): Promise<boolean>;
17
18
  private resizeIfNeeded;
18
19
  inference(customElements?: CustomElement[], image?: string, instruction?: string): Promise<ControlCommand | Annotation>;
20
+ vqaInference(image: string, prompt: string, config?: object): Promise<VQAInferenceResponseBody>;
19
21
  private static logMetaInformation;
20
22
  predictControlCommand(instruction: string, customElements?: CustomElement[], image?: string): Promise<ControlCommand>;
21
23
  getDetectedElements(instruction: string, image: string, customElements?: CustomElement[]): Promise<DetectedElement[]>;
22
24
  predictImageAnnotation(image: string, customElements?: CustomElement[]): Promise<Annotation>;
25
+ predictVQAAnswer(prompt: string, image: string, config?: object): Promise<any>;
23
26
  }
@@ -29,6 +29,7 @@ export class InferenceClient {
29
29
  this.urls = {
30
30
  inference: urljoin(url, 'inference'),
31
31
  isImageRequired: urljoin(url, 'instruction', 'is-image-required'),
32
+ vqaInference: urljoin(url, 'vqa', 'inference'),
32
33
  };
33
34
  this.httpClient.urlsToRetry = Object.values(this.urls);
34
35
  if (this.resize !== undefined && this.resize <= 0) {
@@ -71,6 +72,17 @@ export class InferenceClient {
71
72
  return InferenceResponse.fromJson(response.body, resizedImage.resizeRatio, image);
72
73
  });
73
74
  }
75
+ vqaInference(image, prompt, config) {
76
+ return __awaiter(this, void 0, void 0, function* () {
77
+ const response = yield this.httpClient.post(this.urls.vqaInference, {
78
+ config,
79
+ image,
80
+ prompt,
81
+ });
82
+ InferenceClient.logMetaInformation(response);
83
+ return response.body;
84
+ });
85
+ }
74
86
  static logMetaInformation(response) {
75
87
  if (response.headers['askui-usage-warnings'] !== undefined) {
76
88
  logger.warn(response.headers['askui-usage-warnings']);
@@ -103,4 +115,17 @@ export class InferenceClient {
103
115
  return inferenceResponse;
104
116
  });
105
117
  }
118
+ predictVQAAnswer(prompt, image, config) {
119
+ return __awaiter(this, void 0, void 0, function* () {
120
+ const inferenceResponse = yield this.vqaInference(image, prompt, config);
121
+ const { response } = inferenceResponse.data;
122
+ try {
123
+ return JSON.parse(response);
124
+ }
125
+ catch (error) {
126
+ logger.warn(`Response is no valid JSON: ${response}`);
127
+ }
128
+ return response;
129
+ });
130
+ }
106
131
  }
@@ -59,6 +59,95 @@ export declare class UiControlClient extends ApiCommands {
59
59
  private getAIElementsByNames;
60
60
  fluentCommandExecutor(instructionString: string, context?: CommandExecutorContext): Promise<void>;
61
61
  getterExecutor(instruction: string, context?: CommandExecutorContext): Promise<DetectedElement[]>;
62
+ /**
63
+ * Takes a prompt that contains a question you want to be answered
64
+ * or the data you want to have extracted from your screen.
65
+ *
66
+ * The optional 'config' can be used to specifiy the JSON schema the
67
+ * returned object shall have (https://json-schema.org).
68
+ *
69
+ * See the following examples on how to use it:
70
+ *
71
+ * let isWidgetsNew =
72
+ * await aui.ask(
73
+ * "Does the sidebar element 'Widgets' have a 'NEW' tag?",
74
+ * {
75
+ * json_schema: {
76
+ * "type": "boolean"
77
+ * }
78
+ * });
79
+ *
80
+ * Output of console.log(isWidgetsNew): true
81
+ *
82
+ * let newClients =
83
+ * await aui.ask(
84
+ * "How many new clients?",
85
+ * {
86
+ * json_schema: {
87
+ * "type": "number"
88
+ * }
89
+ * });
90
+ *
91
+ * Output of console.log(newClients): 9123
92
+ *
93
+ * let userNames =
94
+ * await aui.ask(
95
+ * "Return a list with the users names.",
96
+ * {
97
+ * json_schema: {
98
+ * "type": "array",
99
+ * "items": {
100
+ * "type": "string"
101
+ * }
102
+ * }
103
+ * });
104
+ *
105
+ * Output of console.log(userNames):
106
+ * [
107
+ * 'Yiorgos Avraamu',
108
+ * 'Avram Tsarios',
109
+ * 'Quintin Ed',
110
+ * 'Enéas Kwadwo',
111
+ * 'Agapetus Tadeáš'
112
+ * ]
113
+ *
114
+ * let users =
115
+ * await aui.ask(
116
+ * "Extract the users from the table.",
117
+ * {
118
+ * json_schema: {
119
+ * "type": "array",
120
+ * "items": {
121
+ * "type": "object",
122
+ * "properties": {
123
+ * "name": {
124
+ * "type": "string"
125
+ * },
126
+ * "usage": {
127
+ * "type": "number"
128
+ * }
129
+ * },
130
+ * "additionalProperties": false,
131
+ * "required": ["name", "usage"]
132
+ * },
133
+ * },
134
+ * });
135
+ *
136
+ * Output of console.log(users):
137
+ * [
138
+ * { name: 'Yiorgos Avraamu', usage: 50 },
139
+ * { name: 'Avram Tarasios', usage: 10 },
140
+ * { name: 'Quintin Ed', usage: 74 },
141
+ * { name: 'Eneás Kwadwo', usage: 98 },
142
+ * { name: 'Agapetus Tadeáš', usage: 22 }
143
+ * ]
144
+ *
145
+ * @param {string} prompt - The question you want to be answered or
146
+ * the data you want to have extracted.
147
+ * @param {Object} config - object that specifies the return json: {json_schema: {...}}.
148
+ * @returns {any} - The answer as JSON specified in the config object.
149
+ */
150
+ ask(prompt: string, config?: object): Promise<any>;
62
151
  private secretText;
63
152
  private getAndResetSecretText;
64
153
  /**
@@ -163,6 +163,100 @@ export class UiControlClient extends ApiCommands {
163
163
  ]);
164
164
  });
165
165
  }
166
+ /**
167
+ * Takes a prompt that contains a question you want to be answered
168
+ * or the data you want to have extracted from your screen.
169
+ *
170
+ * The optional 'config' can be used to specifiy the JSON schema the
171
+ * returned object shall have (https://json-schema.org).
172
+ *
173
+ * See the following examples on how to use it:
174
+ *
175
+ * let isWidgetsNew =
176
+ * await aui.ask(
177
+ * "Does the sidebar element 'Widgets' have a 'NEW' tag?",
178
+ * {
179
+ * json_schema: {
180
+ * "type": "boolean"
181
+ * }
182
+ * });
183
+ *
184
+ * Output of console.log(isWidgetsNew): true
185
+ *
186
+ * let newClients =
187
+ * await aui.ask(
188
+ * "How many new clients?",
189
+ * {
190
+ * json_schema: {
191
+ * "type": "number"
192
+ * }
193
+ * });
194
+ *
195
+ * Output of console.log(newClients): 9123
196
+ *
197
+ * let userNames =
198
+ * await aui.ask(
199
+ * "Return a list with the users names.",
200
+ * {
201
+ * json_schema: {
202
+ * "type": "array",
203
+ * "items": {
204
+ * "type": "string"
205
+ * }
206
+ * }
207
+ * });
208
+ *
209
+ * Output of console.log(userNames):
210
+ * [
211
+ * 'Yiorgos Avraamu',
212
+ * 'Avram Tsarios',
213
+ * 'Quintin Ed',
214
+ * 'Enéas Kwadwo',
215
+ * 'Agapetus Tadeáš'
216
+ * ]
217
+ *
218
+ * let users =
219
+ * await aui.ask(
220
+ * "Extract the users from the table.",
221
+ * {
222
+ * json_schema: {
223
+ * "type": "array",
224
+ * "items": {
225
+ * "type": "object",
226
+ * "properties": {
227
+ * "name": {
228
+ * "type": "string"
229
+ * },
230
+ * "usage": {
231
+ * "type": "number"
232
+ * }
233
+ * },
234
+ * "additionalProperties": false,
235
+ * "required": ["name", "usage"]
236
+ * },
237
+ * },
238
+ * });
239
+ *
240
+ * Output of console.log(users):
241
+ * [
242
+ * { name: 'Yiorgos Avraamu', usage: 50 },
243
+ * { name: 'Avram Tarasios', usage: 10 },
244
+ * { name: 'Quintin Ed', usage: 74 },
245
+ * { name: 'Eneás Kwadwo', usage: 98 },
246
+ * { name: 'Agapetus Tadeáš', usage: 22 }
247
+ * ]
248
+ *
249
+ * @param {string} prompt - The question you want to be answered or
250
+ * the data you want to have extracted.
251
+ * @param {Object} config - object that specifies the return json: {json_schema: {...}}.
252
+ * @returns {any} - The answer as JSON specified in the config object.
253
+ */
254
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
255
+ ask(prompt, config) {
256
+ return __awaiter(this, void 0, void 0, function* () {
257
+ return this.executionRuntime.predictVQA(prompt, config);
258
+ });
259
+ }
166
260
  getAndResetSecretText() {
167
261
  const { secretText } = this;
168
262
  this.secretText = undefined;
@@ -11,7 +11,6 @@ import inquirer from 'inquirer';
11
11
  import { Command, Option } from 'commander';
12
12
  import fs from 'fs-extra';
13
13
  import { CreateExampleProject } from './create-example-project';
14
- const nonEmpty = (subject) => (input) => input.trim().length > 0 || `${subject} is required.`;
15
14
  /* eslint-disable sort-keys */
16
15
  const questions = [
17
16
  {
@@ -20,21 +19,6 @@ const questions = [
20
19
  message: 'Which framework do you prefer?:',
21
20
  choices: ['jest'],
22
21
  },
23
- {
24
- type: 'input',
25
- name: 'workspaceId',
26
- message: 'Your workspace id:',
27
- validate: nonEmpty('workspace id'),
28
- when: (answers) => !answers.skipCredentials,
29
- },
30
- {
31
- type: 'password',
32
- name: 'accessToken',
33
- message: 'Your access token:',
34
- mask: '*',
35
- validate: nonEmpty('access token'),
36
- when: (answers) => !answers.skipCredentials,
37
- },
38
22
  {
39
23
  type: 'confirm',
40
24
  name: 'typescriptConfig',
@@ -51,22 +35,6 @@ const options = [
51
35
  description: 'the test framework to use.',
52
36
  option: '-f, --test-framework <value>',
53
37
  },
54
- {
55
- choices: [],
56
- default: false,
57
- description: 'skip the credentials setup.',
58
- option: '-sc, --skip-credentials',
59
- },
60
- {
61
- choices: [],
62
- description: 'a workspace id.',
63
- option: '-w, --workspace-id <value>',
64
- },
65
- {
66
- choices: [],
67
- description: 'an access token for the workspace with the id.',
68
- option: '-a, --access-token <value>',
69
- },
70
38
  {
71
39
  choices: [],
72
40
  default: 'askui_example',
@@ -18,7 +18,6 @@ export declare class CreateExampleProject {
18
18
  private createAskUIHelperFromTemplate;
19
19
  private setupTestFrameWork;
20
20
  private static installTestFrameworkPackages;
21
- private addUserCredentials;
22
21
  private copyESLintConfigFiles;
23
22
  private copyGitignore;
24
23
  private copyTsConfigFile;
@@ -24,7 +24,7 @@ export class CreateExampleProject {
24
24
  this.projectRootDirectoryPath = process.cwd();
25
25
  this.automationsDirectoryName = this.getAutomationsDirectoryName();
26
26
  this.automationsDirectoryPath = path.join(this.projectRootDirectoryPath, this.automationsDirectoryName);
27
- this.askUIControllerUrl = 'https://docs.askui.com/docs/general/Components/AskUI-Controller';
27
+ this.askUIControllerUrl = 'https://docs.askui.com/docs/suite/Components/AskUI-Development-Environment#askui-startcontroller-command';
28
28
  this.helperTemplateConfig = {};
29
29
  }
30
30
  getAutomationsDirectoryName() {
@@ -125,10 +125,7 @@ export class CreateExampleProject {
125
125
  title: 'Create askui-helper.ts ',
126
126
  task: () => __awaiter(this, void 0, void 0, function* () {
127
127
  const askuiHelperTemplateFilePath = path.join(getPathToNodeModulesRoot(), 'example_projects_templates', 'templates');
128
- let templateFileName = 'askui-helper.nj';
129
- if (this.cliOptions.operatingSystem === 'windows') {
130
- templateFileName = 'askui-helper-windows.nj';
131
- }
128
+ const templateFileName = 'askui-helper.nj';
132
129
  nunjucks.configure(askuiHelperTemplateFilePath, { autoescape: false });
133
130
  const result = nunjucks.render(templateFileName, this.helperTemplateConfig);
134
131
  const filePath = path.join(this.automationsDirectoryPath, 'helpers', 'askui-helper.ts');
@@ -187,24 +184,6 @@ export class CreateExampleProject {
187
184
  yield runCommand(frameworkDependencies.jest);
188
185
  });
189
186
  }
190
- addUserCredentials() {
191
- return __awaiter(this, void 0, void 0, function* () {
192
- return [
193
- {
194
- /* eslint-disable sort-keys */
195
- title: 'Add user credentials',
196
- enabled: () => !this.cliOptions.skipCredentials,
197
- task: () => __awaiter(this, void 0, void 0, function* () {
198
- this.helperTemplateConfig['credentials'] = ` credentials: {
199
- workspaceId: '${this.cliOptions.workspaceId}',
200
- token: '${this.cliOptions.accessToken}',
201
- },`;
202
- }),
203
- },
204
- /* eslint-enable */
205
- ];
206
- });
207
- }
208
187
  copyESLintConfigFiles() {
209
188
  return __awaiter(this, void 0, void 0, function* () {
210
189
  const esLintRcFilePath = path.join('example_projects_templates', 'typescript', '.eslintrc.json-template');
@@ -276,20 +255,14 @@ export class CreateExampleProject {
276
255
  ...(yield this.copyESLintConfigFiles()),
277
256
  ...(yield this.copyGitignore()),
278
257
  ...(yield this.copyTsConfigFile()),
279
- ...(yield this.addUserCredentials()),
280
258
  ...(yield this.createAskUIHelperFromTemplate()),
281
259
  ]);
282
260
  yield tasks.run();
283
261
  /* eslint-disable no-console */
284
262
  console.log(chalk.greenBright('\nCongratulations!'));
285
263
  console.log(`askui example was created under ${chalk.gray(this.automationsDirectoryPath)}`);
286
- if (this.cliOptions.operatingSystem === 'windows') {
287
- console.log(chalk.redBright(`\nPlease make sure the AskUI Controller is running: ${this.askUIControllerUrl}\n`));
288
- console.log(`You can start your automation with this command ${chalk.green('AskUI-RunProject')}`);
289
- }
290
- else {
291
- console.log(`You can start your automation with this command ${chalk.green('npm run askui')}`);
292
- }
264
+ console.log(chalk.redBright(`\nPlease make sure the AskUI Controller is running: ${this.askUIControllerUrl}\n`));
265
+ console.log(`You can start your automation with this command ${chalk.green('AskUI-RunProject')}`);
293
266
  /* eslint-enable no-console */
294
267
  });
295
268
  }
@@ -1,4 +1,8 @@
1
1
  import { UiControllerArgs } from './ui-controller-args';
2
+ /**
3
+ * @deprecated Will be removed soon because the AskUI Controller
4
+ * gets started as an operating system service.
5
+ */
2
6
  export declare class UiController {
3
7
  private args?;
4
8
  private server;
@@ -11,6 +11,10 @@ import { UiControllerDarwin } from './ui-controller-darwin';
11
11
  import { UiControllerLinux } from './ui-controller-linux';
12
12
  import { UiControllerWin32 } from './ui-controller-win32';
13
13
  import { platform } from './download-binaries';
14
+ /**
15
+ * @deprecated Will be removed soon because the AskUI Controller
16
+ * gets started as an operating system service.
17
+ */
14
18
  export class UiController {
15
19
  constructor(args) {
16
20
  this.args = args;
@@ -1,27 +1,14 @@
1
- import { UiControlClient, UiController } from 'askui';
1
+ import { UiControlClient } from 'askui';
2
2
  {{ allure_stepreporter_import }}
3
3
 
4
- // Server for controlling the operating system
5
- let uiController: UiController;
6
-
7
4
  // Client is necessary to use the askui API
5
+ // eslint-disable-next-line import/no-mutable-exports
8
6
  let aui: UiControlClient;
9
7
 
10
8
  {{ timeout_placeholder }}
11
9
 
12
10
  beforeAll(async () => {
13
- uiController = new UiController({
14
- /**
15
- * Select the display you want to run your tests on, display 0 is your main display;
16
- * ignore if you have only one display
17
- */
18
- display: 0,
19
- });
20
-
21
- await uiController.start();
22
-
23
11
  aui = await UiControlClient.build({
24
- {{ credentials }}
25
12
  {{ reporter_placeholder }}
26
13
  });
27
14
 
@@ -43,8 +30,6 @@ afterEach(async () => {
43
30
 
44
31
  afterAll(async () => {
45
32
  aui.disconnect();
46
-
47
- await uiController.stop();
48
33
  });
49
34
 
50
35
  export { aui };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "askui",
3
- "version": "0.20.6",
3
+ "version": "0.20.8",
4
4
  "license": "MIT",
5
5
  "author": "askui GmbH <info@askui.com> (http://www.askui.com/)",
6
6
  "description": "Reliable, automated end-to-end-testing that depends on what is shown on your screen instead of the technology you are running on",
@@ -1,36 +0,0 @@
1
- import { UiControlClient } from 'askui';
2
- {{ allure_stepreporter_import }}
3
-
4
- // Client is necessary to use the askui API
5
- // eslint-disable-next-line import/no-mutable-exports
6
- let aui: UiControlClient;
7
-
8
- {{ timeout_placeholder }}
9
-
10
- beforeAll(async () => {
11
- aui = await UiControlClient.build({
12
- {{ credentials }}
13
- {{ reporter_placeholder }}
14
- });
15
-
16
- await aui.connect();
17
- });
18
-
19
- beforeEach(async () => {
20
- /* Uncomment to enable video recording
21
- await aui.startVideoRecording();
22
- */
23
- });
24
-
25
- afterEach(async () => {
26
- /* Uncomment to enable video recording
27
- await aui.stopVideoRecording();
28
- {{ allure_stepreporter_attach_video }}
29
- */
30
- });
31
-
32
- afterAll(async () => {
33
- aui.disconnect();
34
- });
35
-
36
- export { aui };