Skip to content

Commit 51aa851

Browse files
committed
separate the rephrasing model from the chat model
Rephrasing can be done with faster, simpler models as there is not much reasoning needed.
1 parent ecb0a42 commit 51aa851

File tree

7 files changed

+72
-14
lines changed

7 files changed

+72
-14
lines changed

Model/AbstractModel.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@ protected function sendAPIRequest($method, $url, $data, $retry = 0)
221221
if ($this->debug) {
222222
echo 'Sending ' . $method . ' request to ' . $url . ' with payload:' . "\n";
223223
print_r($json);
224+
echo "\n";
224225
}
225226

226227
// send request and handle retries
@@ -237,6 +238,7 @@ protected function sendAPIRequest($method, $url, $data, $retry = 0)
237238
if ($this->debug) {
238239
echo 'Received response:' . "\n";
239240
print_r($response);
241+
echo "\n";
240242
}
241243

242244
// decode the response

cli.php

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -221,11 +221,15 @@ protected function chat()
221221
{
222222
if ($this->loglevel['debug']['enabled']) {
223223
$this->helper->getChatModel()->setDebug(true);
224+
$this->helper->getRephraseModel()->setDebug(true);
225+
$this->helper->getEmbedModel()->setDebug(true);
224226
}
225227

226228
$history = [];
227229
while ($q = $this->readLine('Your Question')) {
228230
$this->helper->getChatModel()->resetUsageStats();
231+
$this->helper->getRephraseModel()->resetUsageStats();
232+
$this->helper->getEmbedModel()->resetUsageStats();
229233
$result = $this->helper->askChatQuestion($q, $history);
230234
$this->colors->ptln("Interpretation: {$result['question']}", Colors::C_LIGHTPURPLE);
231235
$history[] = [$result['question'], $result['answer']];
@@ -277,7 +281,7 @@ protected function models()
277281
$name,
278282
sprintf(" In: %7d\nOut: %7d", $info['inputTokens'], $info['outputTokens']),
279283
sprintf(" In: %.2f\nOut: %.2f", $info['inputTokenPrice'], $info['outputTokenPrice']),
280-
$info['description']."\n"
284+
$info['description'] . "\n"
281285
],
282286
[
283287
$info['confok'] ? Colors::C_LIGHTGREEN : Colors::C_LIGHTRED,
@@ -300,7 +304,7 @@ protected function models()
300304
sprintf("%7d", $info['inputTokens']),
301305
sprintf("%.2f", $info['inputTokenPrice']),
302306
$info['dimensions'],
303-
$info['description']."\n"
307+
$info['description'] . "\n"
304308
],
305309
[
306310
$info['confok'] ? Colors::C_LIGHTGREEN : Colors::C_LIGHTRED,
@@ -322,6 +326,8 @@ protected function ask($query)
322326
{
323327
if ($this->loglevel['debug']['enabled']) {
324328
$this->helper->getChatModel()->setDebug(true);
329+
$this->helper->getRephraseModel()->setDebug(true);
330+
$this->helper->getEmbedModel()->setDebug(true);
325331
}
326332

327333
$result = $this->helper->askQuestion($query);
@@ -433,9 +439,18 @@ protected function printSources($sources)
433439
*/
434440
protected function printUsage()
435441
{
442+
$chat = $this->helper->getChatModel()->getUsageStats();
443+
$rephrase = $this->helper->getRephraseModel()->getUsageStats();
444+
$embed = $this->helper->getEmbedModel()->getUsageStats();
445+
436446
$this->info(
437-
'Made {requests} requests in {time}s to Model. Used {tokens} tokens for about ${cost}.',
438-
$this->helper->getChatModel()->getUsageStats()
447+
'Made {requests} requests in {time}s to models. Used {tokens} tokens for about ${cost}.',
448+
[
449+
'requests' => $chat['requests'] + $rephrase['requests'] + $embed['requests'],
450+
'time' => $chat['time'] + $rephrase['time'] + $embed['time'],
451+
'tokens' => $chat['tokens'] + $chat['tokens'] + $embed['tokens'],
452+
'cost' => $chat['cost'] + $chat['cost'] + $embed['cost'],
453+
]
439454
);
440455
}
441456

conf/default.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99

1010
$conf['chatmodel'] = 'OpenAI gpt-3.5-turbo';
11+
$conf['rephrasemodel'] = 'OpenAI gpt-3.5-turbo';
1112
$conf['embedmodel'] = 'OpenAI text-embedding-ada-002';
1213
$conf['storage'] = 'SQLite';
1314

@@ -35,6 +36,8 @@
3536

3637
$conf['chunkSize'] = 1500;
3738
$conf['contextChunks'] = 5;
39+
$conf['chatHistory'] = 1;
40+
$conf['rephraseHistory'] = 1;
3841

3942
$conf['logging'] = 0;
4043
$conf['restrict'] = '';

conf/metadata.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
*/
88

99
$meta['chatmodel'] = array(\dokuwiki\plugin\aichat\ModelSetting::class, 'type' => 'chat');
10+
$meta['rephrasemodel'] = array(\dokuwiki\plugin\aichat\ModelSetting::class, 'type' => 'chat');
1011
$meta['embedmodel'] = array(\dokuwiki\plugin\aichat\ModelSetting::class, 'type' => 'embedding');
1112
$meta['storage'] = array('multichoice',
1213
'_choices' => array(

helper.php

Lines changed: 42 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
use dokuwiki\plugin\aichat\Embeddings;
88
use dokuwiki\plugin\aichat\Model\ChatInterface;
99
use dokuwiki\plugin\aichat\Model\EmbeddingInterface;
10-
use dokuwiki\plugin\aichat\Model\OpenAI\Embedding3Small;
1110
use dokuwiki\plugin\aichat\Storage\AbstractStorage;
1211

1312
/**
@@ -22,6 +21,8 @@ class helper_plugin_aichat extends Plugin
2221
protected $logger;
2322
/** @var ChatInterface */
2423
protected $chatModel;
24+
/** @var ChatInterface */
25+
protected $rephraseModel;
2526
/** @var EmbeddingInterface */
2627
protected $embedModel;
2728
/** @var Embeddings */
@@ -32,6 +33,7 @@ class helper_plugin_aichat extends Plugin
3233
/** @var array where to store meta data on the last run */
3334
protected $runDataFile;
3435

36+
3537
/**
3638
* Constructor. Initializes vendor autoloader
3739
*/
@@ -94,6 +96,26 @@ public function getChatModel()
9496
return $this->chatModel;
9597
}
9698

99+
/**
100+
* @return ChatInterface
101+
*/
102+
public function getRephraseModel()
103+
{
104+
if ($this->rephraseModel instanceof ChatInterface) {
105+
return $this->rephraseModel;
106+
}
107+
108+
[$namespace, $name] = sexplode(' ', $this->getConf('rephrasemodel'), 2);
109+
$class = '\\dokuwiki\\plugin\\aichat\\Model\\' . $namespace . '\\ChatModel';
110+
111+
if (!class_exists($class)) {
112+
throw new \RuntimeException('No ChatModel found for ' . $namespace);
113+
}
114+
115+
$this->rephraseModel = new $class($name, $this->conf);
116+
return $this->rephraseModel;
117+
}
118+
97119
/**
98120
* Access the Embedding Model
99121
*
@@ -172,7 +194,7 @@ public function getStorage()
172194
*/
173195
public function askChatQuestion($question, $history = [])
174196
{
175-
if ($history) {
197+
if ($history && $this->getConf('rephraseHistory') > 0) {
176198
$standaloneQuestion = $this->rephraseChatQuestion($question, $history);
177199
} else {
178200
$standaloneQuestion = $question;
@@ -204,7 +226,9 @@ public function askQuestion($question, $history = [])
204226
$history = [];
205227
}
206228

207-
$messages = $this->prepareMessages($prompt, $question, $history);
229+
$messages = $this->prepareMessages(
230+
$this->getChatModel(), $prompt, $question, $history, $this->getConf('chatHistory')
231+
);
208232
$answer = $this->getChatModel()->getAnswer($messages);
209233

210234
return [
@@ -225,29 +249,35 @@ public function askQuestion($question, $history = [])
225249
public function rephraseChatQuestion($question, $history)
226250
{
227251
$prompt = $this->getPrompt('rephrase');
228-
$messages = $this->prepareMessages($prompt, $question, $history);
229-
return $this->getChatModel()->getAnswer($messages);
252+
$messages = $this->prepareMessages(
253+
$this->getRephraseModel(), $prompt, $question, $history, $this->getConf('rephraseHistory')
254+
);
255+
return $this->getRephraseModel()->getAnswer($messages);
230256
}
231257

232258
/**
233259
* Prepare the messages for the AI
234260
*
261+
* @param ChatInterface $model The used model
235262
* @param string $prompt The fully prepared system prompt
236263
* @param string $question The user question
237264
* @param array[] $history The chat history [[user, ai], [user, ai], ...]
265+
* @param int $historySize The maximum number of messages to use from the history
238266
* @return array An OpenAI compatible array of messages
239267
*/
240-
protected function prepareMessages($prompt, $question, $history)
268+
protected function prepareMessages(
269+
ChatInterface $model, string $prompt, string $question, array $history, int $historySize
270+
): array
241271
{
242272
// calculate the space for context
243-
$remainingContext = $this->getChatModel()->getMaxInputTokenLength();
273+
$remainingContext = $model->getMaxInputTokenLength();
244274
$remainingContext -= $this->countTokens($prompt);
245275
$remainingContext -= $this->countTokens($question);
246276
$safetyMargin = $remainingContext * 0.05; // 5% safety margin
247277
$remainingContext -= $safetyMargin;
248278
// FIXME we may want to also have an upper limit for the history and not always use the full context
249279

250-
$messages = $this->historyMessages($history, $remainingContext);
280+
$messages = $this->historyMessages($history, $remainingContext, $historySize);
251281
$messages[] = [
252282
'role' => 'system',
253283
'content' => $prompt
@@ -265,15 +295,17 @@ protected function prepareMessages($prompt, $question, $history)
265295
* Only as many messages are used as fit into the token limit
266296
*
267297
* @param array[] $history The chat history [[user, ai], [user, ai], ...]
268-
* @param int $tokenLimit
298+
* @param int $tokenLimit The maximum number of tokens to use
299+
* @param int $sizeLimit The maximum number of messages to use
269300
* @return array
270301
*/
271-
protected function historyMessages($history, $tokenLimit)
302+
protected function historyMessages(array $history, int $tokenLimit, int $sizeLimit): array
272303
{
273304
$remainingContext = $tokenLimit;
274305

275306
$messages = [];
276307
$history = array_reverse($history);
308+
$history = array_slice($history, 0, $sizeLimit);
277309
foreach ($history as $row) {
278310
$length = $this->countTokens($row[0] . $row[1]);
279311
if ($length > $remainingContext) {

lang/en/prompt_rephrase.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
11
Given the previous conversation, rephrase the user's follow-up question to be a standalone question. {{LANGUAGE}}
2+
3+
Only reply with the rephrased question, do not answer it.

lang/en/settings.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88

99
$lang['chatmodel'] = 'The 🧠 model to use for chat completion. Configure required credentials below.';
10+
$lang['rephrasemodel'] = 'The 🧠 model to use for rephrasing questions. Configure required credentials below.';
1011
$lang['embedmodel'] = 'The 🧠 model to use for text embedding. Configure required credentials below.<br>🔄 You need to rebuild the vector storage when changing this setting.';
1112
$lang['storage'] = 'Which 📥 vector storage to use. Configure required credentials below.<br>🔄 You need to rebuild the vector storage when changing this setting.';
1213

@@ -32,6 +33,8 @@
3233

3334
$lang['chunkSize'] = 'Maximum number of tokens per chunk.<br>🔄 You need to rebuild the vector storage when changing this setting.';
3435
$lang['contextChunks'] = 'Number of chunks to send to the AI model for context.';
36+
$lang['chatHistory'] = 'Number of previous chat messages to consider for context in the conversation.';
37+
$lang['rephraseHistory'] = 'Number of previous chat messages to consider for context when rephrasing a question. Set to 0 to disable rephrasing.';
3538

3639
$lang['logging'] = 'Log all questions and answers. Use the <a href="?do=admin&page=logviewer&facility=aichat">Log Viewer</a> to access.';
3740
$lang['restrict'] = 'Restrict access to these users and groups (comma separated). Leave empty to allow all users.';

0 commit comments

Comments
 (0)