Skip to content

Commit d756fc5

Browse files
authored
Merge pull request #11337 from nextcloud/backport/11273/stable28
[stable28] enh(dev/TextProcessing): Add docs for IProviderWithUserId, IProviderWithExpectedRuntime and Imanager#runOrSchedule
2 parents 8cf95f9 + d19c17a commit d756fc5

1 file changed

Lines changed: 155 additions & 3 deletions

File tree

developer_manual/digging_deeper/text_processing.rst

Lines changed: 155 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ To consume the Language Model API, you will need to :ref:`inject<dependency-inj
1919
* ``scheduleTask(Task $task)`` This method provides the actual prompt functionality. The task is defined using the Task class. This method runs the task asynchronously in a background job.
2020
* ``getTask(int $id)`` This method fetches a task specified by its id.
2121

22+
.. versionadded:: 28.0.0
23+
24+
* ``runOrScheduleTask(Task $task)`` This method also runs a task, but fist checks the expected runtime of the provider to be used. If the runtime fits inside the available processing time for the current request the task is run synchronously, otherwise it is scheduled as a background job. The task is defined using the Task class.
25+
2226

2327
If you would like to use the text processing functionality in a client, there are also OCS endpoints available for this: :ref:`OCS Text Processing API<ocs-textprocessing-api>`
2428

@@ -37,9 +41,8 @@ To create a task we use the ``\OCP\TextProcessing\Task`` class. Its constructor
3741

3842
.. code-block:: php
3943
40-
if (in_array(SummaryTaskType::class, $languageModelManager->getAvailableTaskTypes()) {
44+
if (in_array(SummaryTaskType::class, $textprocessingManager->getAvailableTaskTypes()) {
4145
$summaryTask = new Task(SummaryTaskType::class, $emailText, "my_app", $userId, (string) $emailId);
42-
$languageModelManager->scheduleTask($summaryTask);
4346
} else {
4447
// cannot use summarization
4548
}
@@ -55,6 +58,59 @@ The task class objects have the following methods available:
5558
* ``getIdentifier()`` This returns the original scheduler-defined identifier for the task
5659
* ``getUserId()`` This returns the originating user ID of the task.
5760

61+
You could now run the task directly as follows. However, this will block the current PHP process until the task is done, which can sometimes take dozens of minutes, depending on which provider is used.
62+
63+
.. code-block:: php
64+
65+
try {
66+
$textprocessingManager->runTask($summaryTask);
67+
} catch (\OCP\PreConditionNotMetException|\OCP\TextProcessing\Exception\TaskFailureException $e) {
68+
// task failed
69+
// return error
70+
}
71+
// task was successful
72+
73+
The wiser choice, when you are in the context of a HTTP controller, is to schedule the task for execution in a background job, as follows:
74+
75+
.. code-block:: php
76+
77+
try {
78+
$textprocessingManager->scheduleTask($summaryTask);
79+
} catch (\OCP\PreConditionNotMetException|\OCP\DB\Exception $e) {
80+
// scheduling task failed
81+
}
82+
// task was scheduled successfully
83+
84+
Conditional scheduling of tasks
85+
###############################
86+
87+
.. versionadded:: 28.0.0
88+
89+
Of course, you might want to schedule the task in a background job **only** if it takes longer than the request timeout. This is what ``runOrScheduleTask`` does.
90+
91+
.. code-block:: php
92+
93+
try {
94+
$textprocessingManager->runOrScheduleTask($summaryTask);
95+
} catch (\OCP\PreConditionNotMetException|\OCP\DB\Exception $e) {
96+
// scheduling task failed
97+
// return error
98+
} catch (\OCP\TextProcessing\Exception\TaskFailureException $e) {
99+
// task was run but failed
100+
// status will be STATUS_FAILED
101+
// return error
102+
}
103+
104+
switch ($summaryTask->getStatus()) {
105+
case \OCP\TextProcessing\Task::STATUS_SUCCESSFUL:
106+
// task was run directly and was successful
107+
case \OCP\TextProcessing\Task::STATUS_RUNNING:
108+
case \OCP\TextProcessing\Task::STATUS_SCHEDULED:
109+
// task was deferred to background job
110+
default:
111+
// something went wrong
112+
}
113+
58114
Task statuses
59115
^^^^^^^^^^^^^
60116

@@ -164,6 +220,102 @@ The method ``process`` implements the text processing step, e.g. it passes the p
164220

165221
The class would typically be saved into a file in ``lib/TextProcessing`` of your app but you are free to put it elsewhere as long as it's loadable by Nextcloud's :ref:`dependency injection container<dependency-injection>`.
166222

223+
Processing tasks in the context of a user
224+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
225+
226+
.. versionadded:: 28.0.0
227+
228+
Sometimes the processing of a text processing task may depend upon which user requested the task. You can now obtain this information in your provider by additionally implementing the ``OCP\TextProcessing\IProviderWithUserId`` interface:
229+
230+
.. code-block:: php
231+
:emphasize-lines: 10,14,16,31,32,33
232+
233+
<?php
234+
235+
declare(strict_types=1);
236+
237+
namespace OCA\MyApp\TextProcessing;
238+
239+
use OCA\MyApp\AppInfo\Application;
240+
use OCP\Files\File;
241+
use OCP\TextProcessing\IProvider;
242+
use OCP\TextProcessing\IProviderWithUserId;
243+
use OCP\TextProcessing\SummaryTaskType;
244+
use OCP\IL10N;
245+
246+
class Provider implements IProvider, IProviderWithUserId {
247+
248+
private ?string $userId = null;
249+
250+
public function __construct(
251+
private IL10N $l,
252+
) {
253+
}
254+
255+
public function getName(): string {
256+
return $this->l->t('My awesome text processing provider');
257+
}
258+
259+
public function getTaskType(): string {
260+
return SummaryTaskType::class;
261+
}
262+
263+
public function setUserId(?string $userId): void {
264+
$this->userId = $userId;
265+
}
266+
267+
public function process(string $input): string {
268+
// Return the output here, making use of $this->userId
269+
}
270+
}
271+
272+
Streamlining processing for fast providers
273+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
274+
275+
.. versionadded:: 28.0.0
276+
277+
Downstream consumers of the TextProcessing API can optimize execution of tasks if they know how long a task will run with your provider. To allow this kind of optimization you can provide an estimate of how much time your provider typically takes. To do this you simply implement the additional ``OCP\TextProcessing\IProviderWithExpectedRuntime`` interface
278+
279+
.. code-block:: php
280+
:emphasize-lines: 10,14,29,30,31
281+
282+
<?php
283+
284+
declare(strict_types=1);
285+
286+
namespace OCA\MyApp\TextProcessing;
287+
288+
use OCA\MyApp\AppInfo\Application;
289+
use OCP\Files\File;
290+
use OCP\TextProcessing\IProvider;
291+
use OCP\TextProcessing\IProviderWithExpectedRuntime;
292+
use OCP\TextProcessing\SummaryTaskType;
293+
use OCP\IL10N;
294+
295+
class Provider implements IProvider, IProviderWithExpectedRuntime {
296+
297+
public function __construct(
298+
private IL10N $l,
299+
) {
300+
}
301+
302+
public function getName(): string {
303+
return $this->l->t('My awesome text processing provider');
304+
}
305+
306+
public function getTaskType(): string {
307+
return SummaryTaskType::class;
308+
}
309+
310+
public function getExpectedRuntime(): int {
311+
return 10; // expected runtime of a task is 10s
312+
}
313+
314+
public function process(string $input): string {
315+
// Return the output here
316+
}
317+
}
318+
167319
Providing more task types
168320
^^^^^^^^^^^^^^^^^^^^^^^^^
169321

@@ -227,4 +379,4 @@ The provider class is registered via the :ref:`bootstrap mechanism<Bootstrapping
227379
228380
public function boot(IBootContext $context): void {}
229381
230-
}
382+
}

0 commit comments

Comments
 (0)