Skip to content

Commit

Permalink
Merge pull request #34 from nextcloud/add/copywriter
Browse files Browse the repository at this point in the history
Add rudimentary copywriter functionality, implement assistant metatask wrapper
  • Loading branch information
julien-nc committed Feb 1, 2024
2 parents c8487a7 + 2591760 commit 0e58541
Show file tree
Hide file tree
Showing 42 changed files with 2,036 additions and 979 deletions.
5 changes: 3 additions & 2 deletions appinfo/info.xml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ include text processing providers to:
* Get an answer from a free prompt
* Reformulate (OpenAi/LocalAi only)
]]> </description>
<version>1.0.3</version>
<version>1.0.5</version>
<licence>agpl</licence>
<author>Julien Veyssier</author>
<namespace>TpAssistant</namespace>
Expand All @@ -49,10 +49,11 @@ include text processing providers to:
<screenshot>https://github.com/nextcloud/assistant/raw/main/img/screenshot3.jpg</screenshot>
<background-jobs>
<job>OCA\TpAssistant\Cron\CleanupImageGenerations</job>
<job>OCA\TpAssistant\Cron\CleanupTranscriptions</job>
<job>OCA\TpAssistant\Cron\CleanupAssistantTasks</job>
</background-jobs>
<commands>
<command>OCA\TpAssistant\Command\CleanupImageGenerations</command>
<command>OCA\TpAssistant\Command\CleanupAssistantTasks</command>
</commands>
<dependencies>
<nextcloud min-version="28" max-version="29"/>
Expand Down
10 changes: 6 additions & 4 deletions appinfo/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@
['name' => 'config#setConfig', 'url' => '/config', 'verb' => 'PUT'],
['name' => 'config#setAdminConfig', 'url' => '/admin-config', 'verb' => 'PUT'],

['name' => 'assistant#getTextProcessingTaskResultPage', 'url' => '/t/{taskId}', 'verb' => 'GET'],
['name' => 'assistant#runTextProcessingTask', 'url' => '/run', 'verb' => 'POST'],
['name' => 'assistant#runOrScheduleTextProcessingTask', 'url' => '/run-or-schedule', 'verb' => 'POST'],
['name' => 'assistant#getTextProcessingTaskResultPage', 'url' => '/task/view/{taskId}', 'verb' => 'GET'],
['name' => 'assistant#runTextProcessingTask', 'url' => '/task/run', 'verb' => 'POST'],
['name' => 'assistant#scheduleTextProcessingTask', 'url' => '/task/schedule', 'verb' => 'POST'],
['name' => 'assistant#runOrScheduleTextProcessingTask', 'url' => '/task/run-or-schedule', 'verb' => 'POST'],
['name' => 'assistant#getTextProcessingResult', 'url' => '/task/{taskId}', 'verb' => 'GET'],
['name' => 'assistant#parseTextFromFile', 'url' => '/parse-file', 'verb' => 'POST'],

['name' => 'Text2Image#processPrompt', 'url' => '/i/process_prompt', 'verb' => 'POST'],
['name' => 'Text2Image#getPromptHistory', 'url' => '/i/prompt_history', 'verb' => 'GET'],
Expand All @@ -25,7 +28,6 @@
['name' => 'FreePrompt#cancelGeneration', 'url' => '/f/cancel_generation', 'verb' => 'POST'],

['name' => 'SpeechToText#getResultPage', 'url' => '/stt/resultPage', 'verb' => 'GET'],
['name' => 'SpeechToText#getTranscript', 'url' => '/stt/transcript', 'verb' => 'GET'],
['name' => 'SpeechToText#transcribeAudio', 'url' => '/stt/transcribeAudio', 'verb' => 'POST'],
['name' => 'SpeechToText#transcribeFile', 'url' => '/stt/transcribeFile', 'verb' => 'POST'],
],
Expand Down
12 changes: 11 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@
}
],
"require": {
"php": "^8.0"
"php": "^8.0",
"erusev/parsedown": "^1.7",
"phpoffice/phpword": "^1.2"
},
"scripts": {
"lint": "find . -name \\*.php -not -path './vendor/*' -print0 | xargs -0 -n1 php -l",
Expand All @@ -25,5 +27,13 @@
"psalm/phar": "^5.16",
"nextcloud/ocp": "dev-master",
"phpunit/phpunit": "^9.5"
},
"config": {
"sort-packages": true,
"optimize-autoloader": true,
"platform": {
"php": "8.0"
},
"autoloader-suffix": "TpAssistant"
}
}
11 changes: 8 additions & 3 deletions lib/AppInfo/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
class Application extends App implements IBootstrap {

public const APP_ID = 'assistant';
public const DEFAULT_ASSISTANT_TASK_IDLE_TIME = 60 * 60 * 24 * 14; // 14 days

public const MAX_STORED_IMAGE_PROMPTS_PER_USER = 5;
public const MAX_STORED_TEXT_PROMPTS_PER_USER = 5;
Expand All @@ -40,9 +41,13 @@ class Application extends App implements IBootstrap {
public const IMAGE_FOLDER = 'generated_images';
public const SPEECH_TO_TEXT_REC_FOLDER = 'stt_recordings';

public const TASK_TYPE_TEXT_GEN = 0;
public const TASK_TYPE_TEXT_TO_IMAGE = 1;
public const TASK_TYPE_SPEECH_TO_TEXT = 2;
public const STT_TASK_SCHEDULED = 0;
public const STT_TASK_SUCCESSFUL = 1;
public const STT_TASK_FAILED = -1;

public const TASK_CATEGORY_TEXT_GEN = 0;
public const TASK_CATEGORY_TEXT_TO_IMAGE = 1;
public const TASK_CATEGORY_SPEECH_TO_TEXT = 2;

public function __construct(array $urlParams = []) {
parent::__construct(self::APP_ID, $urlParams);
Expand Down
54 changes: 54 additions & 0 deletions lib/Command/CleanupAssistantTasks.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php

// SPDX-FileCopyrightText: Sami Finnilä <[email protected]>
// SPDX-License-Identifier: AGPL-3.0-or-later

namespace OCA\TpAssistant\Command;

use Exception;
use OC\Core\Command\Base;
use OCA\TpAssistant\AppInfo\Application;
use OCA\TpAssistant\Db\MetaTaskMapper;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

class CleanupAssistantTasks extends Base {
public function __construct(
private MetaTaskMapper $metaTaskMapper,
) {
parent::__construct();
}

protected function configure() {
$maxIdleTimeSetting = Application::DEFAULT_ASSISTANT_TASK_IDLE_TIME;
$this->setName('assistant:task_cleanup')
->setDescription('Cleanup assistant tasks')
->addArgument(
'max_age',
InputArgument::OPTIONAL,
'The max idle time (in seconds)',
$maxIdleTimeSetting
);
}

protected function execute(InputInterface $input, OutputInterface $output) {
$maxAge = intval($input->getArgument('max_age'));

if ($maxAge < 1) {
$output->writeln('Invalid value for max_age: ' . $maxAge);
return 1;
}

$output->writeln('Cleanning up assistant tasks older than ' . $maxAge . ' seconds.');
try {
$cleanedUp = $this->metaTaskMapper->cleanupOldMetaTasks($maxAge);
} catch (Exception $e) {
$output->writeln('Error: ' . $e->getMessage());
return 1;
}

$output->writeln('Deleted ' . $cleanedUp . ' idle tasks.');
return 0;
}
}
119 changes: 91 additions & 28 deletions lib/Controller/AssistantController.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,21 @@
use OCA\TpAssistant\Service\AssistantService;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\Attribute\BruteForceProtection;
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
use OCP\AppFramework\Http\Attribute\NoCSRFRequired;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\Http\TemplateResponse;
use OCP\AppFramework\Services\IInitialState;

use OCP\IRequest;

class AssistantController extends Controller {

public function __construct(
string $appName,
IRequest $request,
string $appName,
IRequest $request,
private AssistantService $assistantService,
private IInitialState $initialStateService,
private ?string $userId
private IInitialState $initialStateService,
private ?string $userId,
) {
parent::__construct($appName, $request);
}
Expand All @@ -33,59 +31,124 @@ public function __construct(
*/
#[NoAdminRequired]
#[NoCSRFRequired]
#[BruteForceProtection(action: 'taskResultPage')]
public function getTextProcessingTaskResultPage(int $taskId): TemplateResponse {
$task = $this->assistantService->getTextProcessingTask($this->userId, $taskId);
if ($task === null) {
$response = new TemplateResponse(
'',
'403',
[],
TemplateResponse::RENDER_AS_ERROR
);
$response->setStatus(Http::STATUS_NOT_FOUND);
$response->throttle(['userId' => $this->userId, 'taskId' => $taskId]);
return $response;

if ($this->userId !== null) {
$task = $this->assistantService->getTextProcessingTask($this->userId, $taskId);
if ($task !== null) {
$this->initialStateService->provideInitialState('task', $task->jsonSerializeCc());
return new TemplateResponse(Application::APP_ID, 'taskResultPage');
}
}
return new TemplateResponse('', '403', [], TemplateResponse::RENDER_AS_ERROR, Http::STATUS_FORBIDDEN);
}

/**
* @param int $taskId
* @return DataResponse
*/
#[NoAdminRequired]
public function getTextProcessingResult(int $taskId): DataResponse {

if ($this->userId !== null) {
$task = $this->assistantService->getTextProcessingTask($this->userId, $taskId);
if ($task !== null) {
return new DataResponse([
'task' => $task->jsonSerializeCc(),
]);
}
}
return new DataResponse('', Http::STATUS_NOT_FOUND);
}

/**
* @param array $inputs
* @param string $type
* @param string $appId
* @param string $identifier
* @return DataResponse
*/
#[NoAdminRequired]
public function runTextProcessingTask(string $type, array $inputs, string $appId, string $identifier): DataResponse {
if ($this->userId === null) {
return new DataResponse('Unknow user', Http::STATUS_BAD_REQUEST);
}

try {
$task = $this->assistantService->runTextProcessingTask($type, $inputs, $appId, $this->userId, $identifier);
} catch (\Exception | \Throwable $e) {
return new DataResponse($e->getMessage(), Http::STATUS_BAD_REQUEST);
}
$this->initialStateService->provideInitialState('task', $task->jsonSerialize());
return new TemplateResponse(Application::APP_ID, 'taskResultPage');
return new DataResponse([
'task' => $task->jsonSerializeCc(),
]);
}

/**
* @param string $input
* @param array $inputs
* @param string $type
* @param string $appId
* @param string $identifier
* @return DataResponse
*/
#[NoAdminRequired]
public function runTextProcessingTask(string $type, string $input, string $appId, string $identifier): DataResponse {
public function scheduleTextProcessingTask(string $type, array $inputs, string $appId, string $identifier): DataResponse {
if ($this->userId === null) {
return new DataResponse('Unknow user', Http::STATUS_BAD_REQUEST);
}

try {
$task = $this->assistantService->runTextProcessingTask($type, $input, $appId, $this->userId, $identifier);
$task = $this->assistantService->scheduleTextProcessingTask($type, $inputs, $appId, $this->userId, $identifier);
} catch (\Exception | \Throwable $e) {
return new DataResponse($e->getMessage(), Http::STATUS_BAD_REQUEST);
}
return new DataResponse([
'task' => $task->jsonSerialize(),
'task' => $task->jsonSerializeCc(),
]);
}

/**
* @param string $input
* @param array $inputs
* @param string $type
* @param string $appId
* @param string $identifier
* @return DataResponse
*/
#[NoAdminRequired]
public function runOrScheduleTextProcessingTask(string $type, string $input, string $appId, string $identifier): DataResponse {
public function runOrScheduleTextProcessingTask(string $type, array $inputs, string $appId, string $identifier): DataResponse {
if ($this->userId === null) {
return new DataResponse('Unknow user', Http::STATUS_BAD_REQUEST);
}

try {
$task = $this->assistantService->runOrScheduleTextProcessingTask($type, $inputs, $appId, $this->userId, $identifier);
} catch (\Exception | \Throwable $e) {
return new DataResponse($e->getMessage(), Http::STATUS_BAD_REQUEST);
}
return new DataResponse([
'task' => $task->jsonSerializeCc(),
]);
}

/**
* Parse text from file (if parsing the file type is supported)
*
* @param string $filePath
* @return DataResponse
*/
#[NoAdminRequired]
public function parseTextFromFile(string $filePath): DataResponse {
if ($this->userId === null) {
return new DataResponse('Unknow user', Http::STATUS_BAD_REQUEST);
}

try {
$task = $this->assistantService->runOrScheduleTextProcessingTask($type, $input, $appId, $this->userId, $identifier);
$text = $this->assistantService->parseTextFromFile($filePath, $this->userId);
} catch (\Exception | \Throwable $e) {
return new DataResponse($e->getMessage(), Http::STATUS_BAD_REQUEST);
}
return new DataResponse([
'task' => $task->jsonSerialize(),
'parsedText' => $text,
]);
}
}
Loading

0 comments on commit 0e58541

Please sign in to comment.