feat: translate subtitles with an OpenAI-compatible LLM
This commit is contained in:
1 parent
48cac86d60
commit
4665bf632a
21 files changed
+1877
-5
No files matched your search
@@ -0,0 +1,121 @@
|
||||
#include "apikeystore.h"
|
||||
|
||||
#include <QCoroSignal>
|
||||
|
||||
#include <QPointer>
|
||||
|
||||
#include <qt6keychain/keychain.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
using namespace Qt::Literals::StringLiterals;
|
||||
|
||||
namespace
|
||||
{
|
||||
const QString Service = u"dev.trivk.qtpotato"_s;
|
||||
const QString Key = u"translation-api-key"_s;
|
||||
|
||||
struct JobDeleter {
|
||||
void operator()(QKeychain::Job *job) const
|
||||
{
|
||||
job->deleteLater();
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
std::unique_ptr<T, JobDeleter> makeJob()
|
||||
{
|
||||
auto job = std::unique_ptr<T, JobDeleter>(new T(Service));
|
||||
job->setAutoDelete(false);
|
||||
job->setKey(Key);
|
||||
return job;
|
||||
}
|
||||
}
|
||||
|
||||
ApiKeyStore::ApiKeyStore(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
refresh();
|
||||
}
|
||||
|
||||
bool ApiKeyStore::hasKey() const
|
||||
{
|
||||
return m_hasKey;
|
||||
}
|
||||
|
||||
QString ApiKeyStore::error() const
|
||||
{
|
||||
return m_error;
|
||||
}
|
||||
|
||||
void ApiKeyStore::setKey(const QString &key)
|
||||
{
|
||||
store(key.trimmed());
|
||||
}
|
||||
|
||||
QCoro::Task<ApiKeyStore::ReadResult> ApiKeyStore::readKey()
|
||||
{
|
||||
auto job = makeJob<QKeychain::ReadPasswordJob>();
|
||||
job->start();
|
||||
co_await qCoro(job.get(), &QKeychain::Job::finished);
|
||||
|
||||
if (job->error() == QKeychain::EntryNotFound) {
|
||||
co_return ReadResult{};
|
||||
}
|
||||
if (job->error() != QKeychain::NoError) {
|
||||
co_return ReadResult{{}, job->errorString()};
|
||||
}
|
||||
co_return ReadResult{job->textData(), {}};
|
||||
}
|
||||
|
||||
QCoro::Task<> ApiKeyStore::refresh()
|
||||
{
|
||||
QPointer<ApiKeyStore> self(this);
|
||||
const ReadResult result = co_await readKey();
|
||||
if (!self) {
|
||||
co_return;
|
||||
}
|
||||
setHasKey(!result.key.isEmpty());
|
||||
setError(result.error);
|
||||
}
|
||||
|
||||
QCoro::Task<> ApiKeyStore::store(QString key)
|
||||
{
|
||||
QPointer<ApiKeyStore> self(this);
|
||||
std::unique_ptr<QKeychain::Job, JobDeleter> job;
|
||||
if (key.isEmpty()) {
|
||||
job = makeJob<QKeychain::DeletePasswordJob>();
|
||||
} else {
|
||||
auto write = makeJob<QKeychain::WritePasswordJob>();
|
||||
write->setTextData(key);
|
||||
job.reset(write.release());
|
||||
}
|
||||
job->start();
|
||||
co_await qCoro(job.get(), &QKeychain::Job::finished);
|
||||
if (!self) {
|
||||
co_return;
|
||||
}
|
||||
|
||||
if (job->error() != QKeychain::NoError && job->error() != QKeychain::EntryNotFound) {
|
||||
setError(job->errorString());
|
||||
co_return;
|
||||
}
|
||||
setError({});
|
||||
setHasKey(!key.isEmpty());
|
||||
}
|
||||
|
||||
void ApiKeyStore::setHasKey(bool hasKey)
|
||||
{
|
||||
if (hasKey != m_hasKey) {
|
||||
m_hasKey = hasKey;
|
||||
Q_EMIT hasKeyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void ApiKeyStore::setError(const QString &error)
|
||||
{
|
||||
if (error != m_error) {
|
||||
m_error = error;
|
||||
Q_EMIT errorChanged();
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user