fix: 修复 Windows Qt5.12 MinGW 编译错误
- std::unordered_map 替换为 QHash(旧版 GCC 7.3.0 不支持 QString 的 std::hash) - 涉及文件: whisper_tokenizer.h/cpp, sense_voice_tokenizer.h/cpp - STTEngine::Impl 的 loadInWorker 和 mutex 移出 HAVE_ONNXRUNTIME 条件编译块 - loadModelSync/loadModelAsync 添加 HAVE_ONNXRUNTIME 保护 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
50b6a5daea
commit
a56f273c45
@ -41,7 +41,7 @@ bool SenseVoiceTokenizer::load(const QString& tokensPath) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
LOG_INFO(kTag, QString("词表已加载: %1 个词条 (%2)").arg(lineCount).arg(tokensPath));
|
LOG_INFO(kTag, QString("词表已加载: %1 个词条 (%2)").arg(lineCount).arg(tokensPath));
|
||||||
return !tokenToString_.empty();
|
return !tokenToString_.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString SenseVoiceTokenizer::decode(const std::vector<int>& tokens) const {
|
QString SenseVoiceTokenizer::decode(const std::vector<int>& tokens) const {
|
||||||
@ -56,7 +56,7 @@ QString SenseVoiceTokenizer::decode(const std::vector<int>& tokens) const {
|
|||||||
|
|
||||||
auto it = tokenToString_.find(token);
|
auto it = tokenToString_.find(token);
|
||||||
if (it != tokenToString_.end()) {
|
if (it != tokenToString_.end()) {
|
||||||
QString decoded = decodeBPE(it->second);
|
QString decoded = decodeBPE(it.value());
|
||||||
// 过滤 SenseVoice 特殊标签: <|zh|>, <|speech|>, <|NEUTRAL|> 等
|
// 过滤 SenseVoice 特殊标签: <|zh|>, <|speech|>, <|NEUTRAL|> 等
|
||||||
if (decoded.startsWith("<|") && decoded.endsWith("|>")) {
|
if (decoded.startsWith("<|") && decoded.endsWith("|>")) {
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@ -1,9 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QStringList>
|
#include <QHash>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <unordered_map>
|
|
||||||
|
|
||||||
namespace impress {
|
namespace impress {
|
||||||
|
|
||||||
@ -24,10 +23,10 @@ public:
|
|||||||
QString decode(const std::vector<int>& tokens) const;
|
QString decode(const std::vector<int>& tokens) const;
|
||||||
|
|
||||||
/** @brief 是否已加载 */
|
/** @brief 是否已加载 */
|
||||||
bool isLoaded() const { return !tokenToString_.empty(); }
|
bool isLoaded() const { return !tokenToString_.isEmpty(); }
|
||||||
|
|
||||||
/** @brief 词表大小 */
|
/** @brief 词表大小 */
|
||||||
int vocabSize() const { return static_cast<int>(tokenToString_.size()); }
|
int vocabSize() const { return tokenToString_.size(); }
|
||||||
|
|
||||||
// 特殊 token
|
// 特殊 token
|
||||||
static constexpr int kTokenBlank = 0; // CTC blank / <unk>
|
static constexpr int kTokenBlank = 0; // CTC blank / <unk>
|
||||||
@ -35,7 +34,7 @@ public:
|
|||||||
static constexpr int kTokenEOS = 2; // </s>
|
static constexpr int kTokenEOS = 2; // </s>
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unordered_map<int, QString> tokenToString_;
|
QHash<int, QString> tokenToString_;
|
||||||
QString decodeBPE(const QString& token) const;
|
QString decodeBPE(const QString& token) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -116,9 +116,9 @@ struct STTEngine::Impl {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
QMutex mutex;
|
QMutex mutex;
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
STTEngine::STTEngine(QObject* parent)
|
STTEngine::STTEngine(QObject* parent)
|
||||||
@ -139,6 +139,7 @@ bool STTEngine::loadModelSync(const QString& modelPath,
|
|||||||
unloadModel();
|
unloadModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_ONNXRUNTIME
|
||||||
QString errorMsg;
|
QString errorMsg;
|
||||||
bool success = impl_->loadInWorker(modelPath, device, numThreads, errorMsg);
|
bool success = impl_->loadInWorker(modelPath, device, numThreads, errorMsg);
|
||||||
loaded_ = success;
|
loaded_ = success;
|
||||||
@ -150,6 +151,11 @@ bool STTEngine::loadModelSync(const QString& modelPath,
|
|||||||
emit error(errorMsg);
|
emit error(errorMsg);
|
||||||
}
|
}
|
||||||
return success;
|
return success;
|
||||||
|
#else
|
||||||
|
(void)modelPath; (void)device; (void)numThreads;
|
||||||
|
LOG_ERROR(kTag, "ONNX Runtime 未编译启用");
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void STTEngine::loadModelAsync(const QString& modelPath,
|
void STTEngine::loadModelAsync(const QString& modelPath,
|
||||||
@ -161,6 +167,7 @@ void STTEngine::loadModelAsync(const QString& modelPath,
|
|||||||
unloadModel();
|
unloadModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_ONNXRUNTIME
|
||||||
LOG_INFO(kTag, QString("异步加载模型: %1").arg(modelPath));
|
LOG_INFO(kTag, QString("异步加载模型: %1").arg(modelPath));
|
||||||
|
|
||||||
QFuture<void> future = QtConcurrent::run([this, modelPath, device, numThreads]() {
|
QFuture<void> future = QtConcurrent::run([this, modelPath, device, numThreads]() {
|
||||||
@ -177,6 +184,10 @@ void STTEngine::loadModelAsync(const QString& modelPath,
|
|||||||
}
|
}
|
||||||
}, Qt::QueuedConnection);
|
}, Qt::QueuedConnection);
|
||||||
});
|
});
|
||||||
|
#else
|
||||||
|
(void)modelPath; (void)device; (void)numThreads;
|
||||||
|
LOG_ERROR(kTag, "ONNX Runtime 未编译启用");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void STTEngine::unloadModel() {
|
void STTEngine::unloadModel() {
|
||||||
|
|||||||
@ -45,7 +45,7 @@ bool WhisperTokenizer::loadVocabulary(const QString& vocabPath) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
LOG_INFO(kTag, QString("词表已加载: %1 个词条 (文件: %2)").arg(lineCount).arg(vocabPath));
|
LOG_INFO(kTag, QString("词表已加载: %1 个词条 (文件: %2)").arg(lineCount).arg(vocabPath));
|
||||||
return !tokenToString_.empty();
|
return !tokenToString_.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString WhisperTokenizer::decode(const std::vector<int>& tokens) const {
|
QString WhisperTokenizer::decode(const std::vector<int>& tokens) const {
|
||||||
@ -55,7 +55,7 @@ QString WhisperTokenizer::decode(const std::vector<int>& tokens) const {
|
|||||||
|
|
||||||
auto it = tokenToString_.find(token);
|
auto it = tokenToString_.find(token);
|
||||||
if (it != tokenToString_.end()) {
|
if (it != tokenToString_.end()) {
|
||||||
QString decoded = decodeBytePair(it->second);
|
QString decoded = decodeBytePair(it.value());
|
||||||
result += decoded;
|
result += decoded;
|
||||||
} else {
|
} else {
|
||||||
result += QString("<|token:%1|>").arg(token);
|
result += QString("<|token:%1|>").arg(token);
|
||||||
@ -71,7 +71,7 @@ std::vector<int> WhisperTokenizer::encode(const QString& text) const {
|
|||||||
QString ch = text.mid(i, 1);
|
QString ch = text.mid(i, 1);
|
||||||
auto it = stringToToken_.find(ch);
|
auto it = stringToToken_.find(ch);
|
||||||
if (it != stringToToken_.end()) {
|
if (it != stringToToken_.end()) {
|
||||||
tokens.push_back(it->second);
|
tokens.push_back(it.value());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return tokens;
|
return tokens;
|
||||||
@ -86,13 +86,13 @@ QString WhisperTokenizer::decodeBytePair(const QString& text) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int WhisperTokenizer::languageTokenId(const QString& langCode) {
|
int WhisperTokenizer::languageTokenId(const QString& langCode) {
|
||||||
static const std::unordered_map<QString, int> langMap = {
|
static const QHash<QString, int> langMap = {
|
||||||
{"zh", 50260}, {"en", 50259}, {"ja", 50261}, {"ko", 50262},
|
{"zh", 50260}, {"en", 50259}, {"ja", 50261}, {"ko", 50262},
|
||||||
{"fr", 50265}, {"de", 50266}, {"es", 50267}, {"ru", 50268},
|
{"fr", 50265}, {"de", 50266}, {"es", 50267}, {"ru", 50268},
|
||||||
{"pt", 50269}, {"it", 50270}, {"auto", 50359}
|
{"pt", 50269}, {"it", 50270}, {"auto", 50359}
|
||||||
};
|
};
|
||||||
auto it = langMap.find(langCode);
|
auto it = langMap.find(langCode);
|
||||||
return it != langMap.end() ? it->second : 50259; // 默认英语
|
return it != langMap.end() ? it.value() : 50259; // 默认英语
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WhisperTokenizer::isSpecialToken(int token) {
|
bool WhisperTokenizer::isSpecialToken(int token) {
|
||||||
|
|||||||
@ -1,9 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QStringList>
|
#include <QHash>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <unordered_map>
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
namespace impress {
|
namespace impress {
|
||||||
@ -28,10 +27,10 @@ public:
|
|||||||
std::vector<int> encode(const QString& text) const;
|
std::vector<int> encode(const QString& text) const;
|
||||||
|
|
||||||
/** @brief 是否已加载词表 */
|
/** @brief 是否已加载词表 */
|
||||||
bool isLoaded() const { return !tokenToString_.empty(); }
|
bool isLoaded() const { return !tokenToString_.isEmpty(); }
|
||||||
|
|
||||||
/** @brief 词表大小 */
|
/** @brief 词表大小 */
|
||||||
int vocabSize() const { return static_cast<int>(tokenToString_.size()); }
|
int vocabSize() const { return tokenToString_.size(); }
|
||||||
|
|
||||||
// Whisper 特殊 token
|
// Whisper 特殊 token
|
||||||
static constexpr int kTokenEndOfText = 50257;
|
static constexpr int kTokenEndOfText = 50257;
|
||||||
@ -49,8 +48,8 @@ public:
|
|||||||
static bool isSpecialToken(int token);
|
static bool isSpecialToken(int token);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unordered_map<int, QString> tokenToString_;
|
QHash<int, QString> tokenToString_;
|
||||||
std::unordered_map<QString, int> stringToToken_;
|
QHash<QString, int> stringToToken_;
|
||||||
|
|
||||||
QString decodeBytePair(const QString& text) const;
|
QString decodeBytePair(const QString& text) const;
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user