Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Toggle main menu visibility
Loading...
Searching...
No Matches
ollama.cpp
Go to the documentation of this file.
1
// Copyright (C) 2025 The Qt Company Ltd.
2
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3
4
#
include
"ollama.h"
5
#
include
"translationsettings.h"
6
#
include
"translationutils.h"
7
#
include
"translatormessage.h"
8
9
#
include
<
QtCore
/
qjsonarray
.
h
>
10
#
include
<
QtCore
/
qjsonobject
.
h
>
11
12
using
namespace
Qt::Literals::StringLiterals;
13
14
QT_BEGIN_NAMESPACE
15
16
Ollama::Ollama()
17
: m_payloadBase(std::make_unique<QJsonObject>()),
18
m_useJsonFormat(TranslationSettings::maxJsonFormatTries())
19
{
20
m_payloadBase->insert(
"stream"_L1
,
false
);
21
m_payloadBase->insert(
"think"_L1
,
false
);
22
23
QJsonObject opts;
24
opts.insert(
"temperature"_L1
, TranslationSettings::temperature());
25
m_payloadBase->insert(
"options"_L1
, opts);
26
}
27
28
Ollama
::~
Ollama
() =
default
;
29
30
QList
<
Batch
>
Ollama
::
makeBatches
(
const
Messages
&messages,
const
QString &userContext)
const
31
{
32
QHash<QString, QList<
const
TranslatorMessage *>> nonPluralGroups;
33
QHash<QString, QList<
const
TranslatorMessage *>> pluralGroups;
34
35
for
(
const
auto
&item : messages.items) {
36
const
QString key = item->context() + item->label();
37
if
(item->isPlural())
38
pluralGroups[key].append(item);
39
else
40
nonPluralGroups[key].append(item);
41
}
42
43
const
int
maxBatchSize =
TranslationSettings
::
maxBatchSize
(
)
;
44
QList<Batch> out;
45
out.reserve(nonPluralGroups.size() + pluralGroups.size());
46
47
auto
createBatches = [&](
const
QHash<QString, QList<
const
TranslatorMessage *>> &groups,
48
int
pluralFormsCount) {
49
for
(
auto
it = groups.cbegin(); it != groups.cend(); ++it) {
50
auto
msgIt = it.value().cbegin();
51
while
(msgIt != it.value().cend()) {
52
Batch
b;
53
b.srcLang = messages.srcLang;
54
b.tgtLang = messages.tgtLang;
55
b.context = it.key();
56
b.userContext = userContext;
57
b
.
pluralFormsCount
= pluralFormsCount;
58
b.items.reserve(it.value().size());
59
while
(msgIt != it.value().cend() && b.items.size() < maxBatchSize) {
60
Item
item;
61
item
.
msg
= *msgIt;
62
item.translation = item
.
msg
->translation();
63
b.items.append(std::move(item));
64
msgIt++;
65
}
66
out.append(std::move(b));
67
}
68
}
69
};
70
71
createBatches(nonPluralGroups, 1);
72
createBatches(pluralGroups, messages
.
pluralFormsCount
);
73
74
return
out;
75
}
76
77
QHash
<
QString
,
QStringList
>
Ollama
::
extractTranslations
(
const
QByteArray &response,
bool
plural)
78
{
79
QJsonParseError err;
80
QJsonDocument doc = QJsonDocument::fromJson(response, &err);
81
if
(err.error != QJsonParseError::NoError) {
82
m_useJsonFormat--;
83
return
{};
84
}
85
86
QHash<QString, QStringList> translations;
87
if
(plural) {
88
translations = extractPluralTranslations(doc.object(),
"Plurals"_L1
);
89
}
else
{
90
auto
singleTranslations = extractKeyValuePairs(doc.object(),
"Translations"_L1
);
91
for
(
auto
it = singleTranslations.cbegin(); it != singleTranslations.cend(); ++it)
92
translations[it.key()] << it.value();
93
}
94
95
if
(translations.isEmpty()) {
96
m_useJsonFormat--;
97
return
translations;
98
}
99
100
// If we get a successful response by using json format, the model
101
// is a formatted model. So we want to prevent falling back to
102
// non formatted model (harmony) if there are occasional empty
103
// responses later.
104
if
(m_useJsonFormat > 0)
105
m_useJsonFormat = std::numeric_limits<
int
>::max();
106
107
return
translations;
108
}
109
110
QStringList
Ollama
::
extractModels
(
const
QByteArray &response)
const
111
{
112
QJsonParseError err;
113
QJsonDocument doc = QJsonDocument::fromJson(response, &err);
114
if
(err.error != QJsonParseError::NoError)
115
return
{};
116
const
QJsonObject obj = doc.object();
117
const
QJsonArray arr = obj.value(
"models"_L1
).toArray();
118
QStringList models;
119
for
(
const
QJsonValue &v : arr)
120
models.append(v.toObject().value(
"name"_L1
).toString());
121
return
models;
122
}
123
124
QByteArray
Ollama
::
payload
(
const
Batch
&b)
const
125
{
126
QJsonObject systemMessage;
127
systemMessage.insert(
"role"_L1
,
"system"_L1
);
128
const
bool
plural = b
.
pluralFormsCount
> 1;
129
systemMessage.insert(
"content"_L1
,
130
plural ? pluralTranslationSystemPrompt() : translationSystemPrompt());
131
132
QJsonObject userMessage;
133
userMessage.insert(
"role"_L1
,
"user"_L1
);
134
userMessage.insert(
"content"_L1
, makePrompt(b));
135
136
QJsonArray messages;
137
messages.append(systemMessage);
138
messages.append(userMessage);
139
140
QJsonObject req = *m_payloadBase;
141
req.insert(
"messages"_L1
, messages);
142
143
if
(m_useJsonFormat > 0)
144
req.insert(
"format"_L1
,
"json"_L1
);
145
146
return
QJsonDocument(req).toJson();
147
}
148
149
std
::
optional
<
QByteArray
>
Ollama
::
stageModel
(
const
QString &modelName)
150
{
151
if
(
auto
m = m_payloadBase->constFind(
"model"_L1
);
152
m == m_payloadBase->constEnd() || *m != modelName) {
153
m_useJsonFormat = TranslationSettings::maxJsonFormatTries();
154
m_payloadBase->insert(
"model"_L1
, modelName);
155
}
156
157
std::optional<QByteArray> res;
158
if
(!m_lastWakeupTimer.isValid()
159
|| m_lastWakeupTimer.hasExpired(TranslationSettings::ollamaWakeUpTimeoutMs())) {
160
m_lastWakeupTimer.start();
161
QJsonObject wakeup;
162
wakeup.insert(
"model"_L1
, modelName);
163
res.emplace(QJsonDocument(wakeup).toJson());
164
}
165
166
return
res;
167
}
168
169
void
Ollama
::
setUrl
(
const
QString &url)
170
{
171
m_url = url;
172
}
173
174
QUrl
Ollama
::
translationEndpoint
()
const
175
{
176
return
QUrl(m_url).resolved(QUrl(
"/api/chat"_L1
));
177
}
178
179
QUrl
Ollama
::
discoveryEndpoint
()
const
180
{
181
return
QUrl(m_url).resolved(QUrl(
"/api/tags"_L1
));
182
}
183
184
void
Ollama
::
onRequestRejected
()
185
{
186
m_useJsonFormat--;
187
}
188
189
QString
Ollama
::makePrompt(
const
Batch
&b)
const
190
{
191
QStringList lines;
192
lines.reserve(b.items.size() + 32);
193
194
if
(!b.userContext.isEmpty())
195
lines <<
"Application Context: "_L1
+ b.userContext;
196
197
lines <<
"Context: "_L1
+ b.context;
198
lines <<
"Target: "_L1
+ b.tgtLang;
199
if
(b.pluralFormsCount > 1)
200
lines <<
"Plural forms: "_L1
+ QString::number(b.pluralFormsCount);
201
lines <<
"Items:"_L1
;
202
for
(
const
Item &it : b.items) {
203
QString line =
"- source: '%1'"_L1
.arg(it.msg->sourceText());
204
if
(
const
QString comment = it.msg->comment(); !comment.isEmpty())
205
line +=
", comment: '%1'"_L1
.arg(comment);
206
lines << line;
207
}
208
209
return
lines.join(QLatin1Char(
'\n'
));
210
}
211
212
QT_END_NAMESPACE
Batch
Definition
translationprotocol.h:29
Batch::pluralFormsCount
int pluralFormsCount
Definition
translationprotocol.h:38
Item
[0]
Definition
lalr.h:84
Item::msg
const TranslatorMessage * msg
Definition
translationprotocol.h:25
Ollama
Definition
ollama.h:17
Ollama::makeBatches
QList< Batch > makeBatches(const Messages &messages, const QString &userContext) const override
Definition
ollama.cpp:30
Ollama::translationEndpoint
QUrl translationEndpoint() const override
Definition
ollama.cpp:174
Ollama::onRequestRejected
void onRequestRejected() override
Definition
ollama.cpp:184
Ollama::discoveryEndpoint
QUrl discoveryEndpoint() const override
Definition
ollama.cpp:179
Ollama::extractModels
QStringList extractModels(const QByteArray &data) const override
Definition
ollama.cpp:110
Ollama::payload
QByteArray payload(const Batch &b) const override
Definition
ollama.cpp:124
Ollama::~Ollama
~Ollama() override
Ollama::stageModel
std::optional< QByteArray > stageModel(const QString &modelName) override
Definition
ollama.cpp:149
Ollama::setUrl
void setUrl(const QString &url) override
Definition
ollama.cpp:169
Ollama::extractTranslations
QHash< QString, QStringList > extractTranslations(const QByteArray &response, bool plural) override
Definition
ollama.cpp:77
TranslationSettings
Definition
translationsettings.h:12
TranslationSettings::maxBatchSize
static int maxBatchSize()
Definition
translationsettings.cpp:39
Messages
Definition
translationprotocol.h:15
Messages::pluralFormsCount
int pluralFormsCount
Definition
translationprotocol.h:19
qttools
src
linguist
shared
auto-translation
ollama.cpp
Generated on
for Qt by
1.18.0