-
Notifications
You must be signed in to change notification settings - Fork 145
Expand file tree
/
Copy pathDocumentGenerationService.php
More file actions
122 lines (104 loc) · 4.18 KB
/
Copy pathDocumentGenerationService.php
File metadata and controls
122 lines (104 loc) · 4.18 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
<?php
/**
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace OCA\Richdocuments\Service;
use League\CommonMark\GithubFlavoredMarkdownConverter;
use OCA\Richdocuments\AppInfo\Application;
use OCA\Richdocuments\TaskProcessing\TextToDocumentProvider;
use OCA\Richdocuments\TaskProcessing\TextToSpreadsheetProvider;
use OCP\TaskProcessing\Exception\Exception;
use OCP\TaskProcessing\Exception\NotFoundException;
use OCP\TaskProcessing\Exception\PreConditionNotMetException;
use OCP\TaskProcessing\Exception\UnauthorizedException;
use OCP\TaskProcessing\Exception\ValidationException;
use OCP\TaskProcessing\IManager;
use OCP\TaskProcessing\Task;
use OCP\TaskProcessing\TaskTypes\TextToText;
use RuntimeException;
class DocumentGenerationService {
public const TEXT_PROMPT = <<<EOF
Generate a markdown document with titles, paragraphs, bullet points and tables if needed.
Write the document in the same language as the description.
Here is the document description:
EOF;
public const SPREADSHEET_PROMPT = <<<EOF
Generate a CSV spreadsheet. Use the semicolon as a column separator.
Write the CSV content in the same language as the description.
Here is the CSV spreadsheet description:
EOF;
public function __construct(
private IManager $taskProcessingManager,
private RemoteService $remoteService,
) {
}
public function generateTextDocument(?string $userId, string $description, string $targetFormat = TextToDocumentProvider::DEFAULT_TARGET_FORMAT) {
$prompt = self::TEXT_PROMPT;
$taskInput = $prompt . "\n\n" . $description;
$markdownContent = $this->runTextToTextTask($taskInput, $userId);
$converter = new GithubFlavoredMarkdownConverter();
$htmlContent = $converter->convert($markdownContent)->getContent();
$htmlStream = $this->stringToStream($htmlContent);
$docxContent = $this->remoteService->convertTo('document.html', $htmlStream, $targetFormat);
return $docxContent;
}
public function generateSpreadSheetDocument(?string $userId, string $description, string $targetFormat = TextToSpreadsheetProvider::DEFAULT_TARGET_FORMAT) {
$prompt = self::SPREADSHEET_PROMPT;
$taskInput = $prompt . "\n\n" . $description;
$csvContent = $this->runTextToTextTask($taskInput, $userId);
$csvStream = $this->stringToStream($csvContent);
// Passing these will ensure the CSV is correctly
// parsed into a spreadsheet
$conversionOptions = [
// Sets the input filter to use the following:
// 44 - , (comma) as the field separator
// 34 - " (double quote) as the text delimiter
// 76 - UTF-8 as the character set
// 1 - Start at line one of the input
'infilterOptions' => '44,34,76,1',
];
$xlsxContent = $this->remoteService->convertTo('document.csv', $csvStream, $targetFormat, $conversionOptions);
return $xlsxContent;
}
private function runTextToTextTask(string $input, ?string $userId): string {
$task = new Task(
TextToText::ID,
['input' => $input],
Application::APPNAME,
$userId,
);
try {
$this->taskProcessingManager->scheduleTask($task);
} catch (PreConditionNotMetException|UnauthorizedException|ValidationException|Exception $e) {
throw new RuntimeException($e->getMessage(), $e->getCode(), $e);
}
while (true) {
try {
$task = $this->taskProcessingManager->getTask($task->getId());
sleep(2);
} catch (NotFoundException|Exception $e) {
throw new RuntimeException($e->getMessage(), $e->getCode(), $e);
}
if (in_array($task->getStatus(), [Task::STATUS_SUCCESSFUL, Task::STATUS_FAILED, Task::STATUS_CANCELLED])) {
break;
}
}
if ($task->getStatus() !== Task::STATUS_SUCCESSFUL) {
throw new RuntimeException('LLM backend Task with id ' . $task->getId() . ' failed or was cancelled');
}
$output = $task->getOutput();
if (!isset($output['output'])) {
throw new RuntimeException('LLM backend Task with id ' . $task->getId() . ' does not have output key');
}
/** @var string $taskOutputString */
$taskOutputString = $output['output'];
return $taskOutputString;
}
private function stringToStream(string $text) {
$stream = fopen('php://memory', 'r+');
fwrite($stream, $text);
rewind($stream);
return $stream;
}
}