-
-
Notifications
You must be signed in to change notification settings - Fork 4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Introduce LanguageModel/TextProcessing OCP API #38854
Merged
Merged
Changes from 75 commits
Commits
Show all changes
77 commits
Select commit
Hold shift + click to select a range
70d5bf7
Initial work on lm OCP API
marcelklehr 01dd1a8
LLM OCP API: Rework to use Task objects
marcelklehr 3413873
LLM OCP API: Implement private backend code + add ILanguageModelTask
marcelklehr 6fc4cb6
LLM OCP API: Add db migration
marcelklehr 82d3b00
LLM OCP API: Add to RegistrationContext
marcelklehr 9e9fc1d
Fix Copyright
marcelklehr 9d5717d
LLM OCP API: ADd topics and headline tasks
marcelklehr 795b097
LLM OCP API: Implement ocs API
marcelklehr b6941aa
LLM OCP API: cs:fix
marcelklehr b8a9f08
LLM OCP API: Make linters happy
marcelklehr b6a95e3
LLM OCP API: Fix type errors
marcelklehr 9935034
LLM OCP API: Add @since
marcelklehr fac83ce
LLM OCP API: Fix static analysis
marcelklehr 75d7af8
LLM OCP API: cs:fix
marcelklehr 72ea761
LLM OCP API: Fix coding style and psalm
marcelklehr 249dd5c
Update lib/public/LanguageModel/ITopicsProvider.php
marcelklehr fb4de16
LLM OCP API: Add task definitions
marcelklehr 5bc6180
LLM OCP API: Commit autoloaders
marcelklehr fb55afc
Update lib/public/AppFramework/Bootstrap/IRegistrationContext.php
marcelklehr 8e4aa92
Apply suggestions from code review
marcelklehr 906e9b7
LLM OCP API: Type shenanigans for Visitor pattern
marcelklehr 83db23e
LLM OCP API: strict types and copyright
marcelklehr a7cd6bf
OCP: Introduce OCP\Common\Exception\NotFoundException
marcelklehr b00a9a6
LLM OCP API: Use OCP\Common\Exception\NotFoundException
marcelklehr 94fcf88
LLM OCP API: Fix copyright
marcelklehr 1d3661d
cs:fix
marcelklehr cb0f918
Add tasks::last_updated column and vacate tasks after a week
marcelklehr 1623ad9
TaskMapper#update: Use time factory
marcelklehr 0a94525
ILanguageModelManager: Add docblock description
marcelklehr 27e1c86
ILanguageModelTask: Use php type checking along with psalm parameteri…
marcelklehr ebc7631
Add preliminary tests
marcelklehr 20cb993
Fix tests
marcelklehr 66c0e6b
Make tests pass
marcelklehr c568c4a
Add test for task cleanup
marcelklehr 1747068
Fix LanguageModelManager#runTask: Insert task into db if it doesn't e…
marcelklehr fb657bf
cs:fix
marcelklehr 5b77246
Apply suggestions from code review
marcelklehr f6f8cb4
LLM OCP API: Add identifier param
marcelklehr 62b19e0
LLM OCP API: Fix psalm error
marcelklehr f7e1e79
LLM OCP API: Fix security issue
marcelklehr d6d4e0f
LLM OCP API: Fix psam errors
marcelklehr 0a0e812
LLM OCP API: Fix psam error
marcelklehr d33b7a8
LLM OCS API: s/tasks/tasktypes/
marcelklehr 61b9b4f
LLM OCS API: Add OpenAPI docs
marcelklehr 95d2bd5
Apply suggestions from code review
marcelklehr ba950f7
Update lib/public/LanguageModel/ILanguageModelProvider.php
marcelklehr bad124c
Update lib/public/LanguageModel/Events/TaskFailedEvent.php
marcelklehr 0909657
LLM Migration: Return null if nothing changed
marcelklehr a28d8fa
LLM OCP API: Add missing copyright and strict types
marcelklehr d56286b
LLM OCP API: s/getAvailableTasks/getAvailableTaskClasses/
marcelklehr 9455227
LLM OCP API: Simplify LanguageModelManager#canHandleTask
marcelklehr 05fcf31
LLM OCP API: Don't lose trace of wrapped exceptions
marcelklehr e810a8b
LLM OCP API: Explain TaskBackgroundJob#setAllowParallelRuns
marcelklehr 9ccc65d
LLM OCP API: Simplify TaskBackgroundJob#run catch block
marcelklehr 3974953
OCP\Common\NotFoundException: Add param type
marcelklehr 8f1a4f4
LLM OCP API: Avoid using OC in OCP
marcelklehr de1cfaa
LLM OCP API: Fix psalm issues
marcelklehr ea4dc4c
LLM OCP API: Fix OpenApi docs
marcelklehr 9f405a1
LLM OCP API: Improve scheduleTask docblock
marcelklehr bf2dcd6
LLM OCP API: Change Tests to use EventDispatcher mock
marcelklehr a4578cd
cs:fix
marcelklehr 49ea56b
LanguageModelApiController: Use jsonSerialize method to help psalm
marcelklehr 069962d
Since 27.1.0
marcelklehr b7c3b50
Update core/Controller/LanguageModelApiController.php
marcelklehr 48c8206
Fix openapi docs
marcelklehr d430cbb
Update core/Controller/LanguageModelApiController.php
marcelklehr bd45c43
Update core/Controller/LanguageModelApiController.php
marcelklehr ffe27ce
Massive refactoring: Turn LanguageModel OCP API into TextProcessing API
marcelklehr 95d2d3a
Fix psalm errors
marcelklehr df1cf18
Fix psalm errors
marcelklehr 590eefe
Apply suggestions from code review
marcelklehr add5962
Update autoloaders
marcelklehr 2811932
cs:fix
marcelklehr d63c122
Fix psalm errors
marcelklehr 7389567
Remove Task::factory method
marcelklehr fd0fd97
Fix tests: Adjust constructor signature
marcelklehr 6d568b0
Fix tests: Adjust constructor signature
marcelklehr File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
/** | ||
* @copyright Copyright (c) 2023 Marcel Klehr <[email protected]> | ||
* | ||
* @author Marcel Klehr <[email protected]> | ||
* | ||
* @license GNU AGPL version 3 or any later version | ||
* | ||
* This program is free software: you can redistribute it and/or modify | ||
* it under the terms of the GNU Affero General Public License as | ||
* published by the Free Software Foundation, either version 3 of the | ||
* License, or (at your option) any later version. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU Affero General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU Affero General Public License | ||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
*/ | ||
|
||
|
||
namespace OC\Core\Controller; | ||
|
||
use InvalidArgumentException; | ||
use OCP\AppFramework\Http; | ||
use OCP\AppFramework\Http\DataResponse; | ||
use OCP\Common\Exception\NotFoundException; | ||
use OCP\IL10N; | ||
use OCP\IRequest; | ||
use OCP\TextProcessing\ITaskType; | ||
use OCP\TextProcessing\Task; | ||
use OCP\TextProcessing\IManager; | ||
use OCP\PreConditionNotMetException; | ||
use Psr\Container\ContainerExceptionInterface; | ||
use Psr\Container\ContainerInterface; | ||
use Psr\Container\NotFoundExceptionInterface; | ||
use Psr\Log\LoggerInterface; | ||
|
||
class TextProcessingApiController extends \OCP\AppFramework\OCSController { | ||
public function __construct( | ||
string $appName, | ||
IRequest $request, | ||
private IManager $languageModelManager, | ||
private IL10N $l, | ||
private ?string $userId, | ||
private ContainerInterface $container, | ||
private LoggerInterface $logger, | ||
) { | ||
parent::__construct($appName, $request); | ||
} | ||
|
||
/** | ||
* This endpoint returns all available LanguageModel task types | ||
* | ||
* @PublicPage | ||
*/ | ||
public function taskTypes(): DataResponse { | ||
$typeClasses = $this->languageModelManager->getAvailableTaskTypes(); | ||
$types = []; | ||
foreach ($typeClasses as $typeClass) { | ||
try { | ||
/** @var ITaskType $object */ | ||
$object = $this->container->get($typeClass); | ||
} catch (NotFoundExceptionInterface|ContainerExceptionInterface $e) { | ||
$this->logger->warning('Could not find ' . $typeClass, ['exception' => $e]); | ||
continue; | ||
} | ||
$types[] = [ | ||
'id' => $typeClass, | ||
'name' => $object->getName(), | ||
'description' => $object->getDescription(), | ||
]; | ||
} | ||
|
||
return new DataResponse([ | ||
'types' => $types, | ||
]); | ||
|
||
} | ||
|
||
/** | ||
* This endpoint allows scheduling a language model task | ||
* | ||
* @PublicPage | ||
* @UserRateThrottle(limit=20, period=120) | ||
* @AnonRateThrottle(limit=5, period=120) | ||
*/ | ||
public function schedule(string $input, string $type, string $appId, string $identifier = ''): DataResponse { | ||
try { | ||
$task = new Task($type, $input, $this->userId, $appId, $identifier); | ||
} catch (InvalidArgumentException) { | ||
return new DataResponse(['message' => $this->l->t('Requested task type does not exist')], Http::STATUS_BAD_REQUEST); | ||
} | ||
try { | ||
$this->languageModelManager->scheduleTask($task); | ||
|
||
$json = $task->jsonSerialize(); | ||
|
||
return new DataResponse([ | ||
'task' => $json, | ||
]); | ||
|
||
} catch (PreConditionNotMetException) { | ||
return new DataResponse(['message' => $this->l->t('Necessary language model provider is not available')], Http::STATUS_PRECONDITION_FAILED); | ||
} | ||
} | ||
|
||
/** | ||
* This endpoint allows checking the status and results of a task. | ||
* Tasks are removed 1 week after receiving their last update. | ||
* | ||
* @PublicPage | ||
* @param int $id The id of the task | ||
*/ | ||
public function getTask(int $id): DataResponse { | ||
try { | ||
$task = $this->languageModelManager->getTask($id); | ||
|
||
if ($this->userId !== $task->getUserId()) { | ||
return new DataResponse(['message' => $this->l->t('Task not found')], Http::STATUS_NOT_FOUND); | ||
} | ||
|
||
$json = $task->jsonSerialize(); | ||
|
||
return new DataResponse([ | ||
'task' => $json, | ||
]); | ||
|
||
} catch (NotFoundException $e) { | ||
return new DataResponse(['message' => $this->l->t('Task not found')], Http::STATUS_NOT_FOUND); | ||
} catch (\RuntimeException $e) { | ||
return new DataResponse(['message' => $this->l->t('Internal error')], Http::STATUS_INTERNAL_SERVER_ERROR); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
/** | ||
* @copyright Copyright (c) 2023 Marcel Klehr <[email protected]> | ||
* | ||
* @author Marcel Klehr <[email protected]> | ||
* | ||
* @license GNU AGPL version 3 or any later version | ||
* | ||
* This program is free software: you can redistribute it and/or modify | ||
* it under the terms of the GNU Affero General Public License as | ||
* published by the Free Software Foundation, either version 3 of the | ||
* License, or (at your option) any later version. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU Affero General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU Affero General Public License | ||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
* | ||
*/ | ||
|
||
namespace OC\Core\Migrations; | ||
|
||
use Closure; | ||
use OCP\DB\ISchemaWrapper; | ||
use OCP\DB\Types; | ||
use OCP\Migration\IOutput; | ||
use OCP\Migration\SimpleMigrationStep; | ||
|
||
/** | ||
* Introduce llm_tasks table | ||
*/ | ||
class Version28000Date20230616104802 extends SimpleMigrationStep { | ||
/** | ||
* @param IOutput $output | ||
* @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` | ||
* @param array $options | ||
* @return null|ISchemaWrapper | ||
*/ | ||
public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper { | ||
/** @var ISchemaWrapper $schema */ | ||
$schema = $schemaClosure(); | ||
|
||
if (!$schema->hasTable('llm_tasks')) { | ||
$table = $schema->createTable('llm_tasks'); | ||
|
||
$table->addColumn('id', Types::BIGINT, [ | ||
'notnull' => true, | ||
'length' => 64, | ||
'autoincrement' => true, | ||
]); | ||
$table->addColumn('type', Types::STRING, [ | ||
'notnull' => true, | ||
'length' => 255, | ||
]); | ||
$table->addColumn('input', Types::TEXT, [ | ||
'notnull' => true, | ||
]); | ||
$table->addColumn('output', Types::TEXT, [ | ||
'notnull' => false, | ||
]); | ||
$table->addColumn('status', Types::INTEGER, [ | ||
'notnull' => false, | ||
'length' => 6, | ||
'default' => 0, | ||
]); | ||
$table->addColumn('user_id', Types::STRING, [ | ||
'notnull' => true, | ||
'length' => 64, | ||
]); | ||
$table->addColumn('app_id', Types::STRING, [ | ||
'notnull' => true, | ||
'length' => 32, | ||
'default' => '', | ||
]); | ||
$table->addColumn('identifier', Types::STRING, [ | ||
'notnull' => true, | ||
'length' => 255, | ||
'default' => '', | ||
]); | ||
$table->addColumn('last_updated', 'integer', [ | ||
'notnull' => false, | ||
'length' => 4, | ||
'default' => 0, | ||
'unsigned' => true, | ||
]); | ||
|
||
$table->setPrimaryKey(['id'], 'llm_tasks_id_index'); | ||
$table->addUniqueIndex(['status', 'type'], 'llm_tasks_status_type'); | ||
$table->addIndex(['last_updated'], 'llm_tasks_updated'); | ||
|
||
return $schema; | ||
} | ||
|
||
return null; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As discussed, maybe it makes sense to have another endpoint to list the providers (maybe grouped by task type).
Also, maybe we could include the "selected provider" for each task type in the result of this
taskTypes
method.WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we really need the providers on the frontend though? I think we would usually want to hide them, no?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah they wouldn't be displayed in the text processing UI component but maybe it's useful for the settings part where admins can choose the "default" provider for each task type.
What do you think about that other aspect? It might make sense to let advanced users know which provider is used when choosing a task type. This information would not necessarily be very visible in the UI. But just in case we find a nice way to give more details if users want to know.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tend to think this should be hidden from the user. Only the admin should see this.
I'll deal with that in the follow up PR :)