#include "eaiproxy.h"
#include "eaiexecutor.h"
#include "eappaiprompt.h"
#include "eaicallbck.h"
#include "epptwebview.h"
#include "eposterwebview.h"
#include "eparserdocument.h"
#include "localmodelserver.h"
#include "easyncworker.h"
#include "esystemcontext.h"

#include <QScopedPointer>
#include <QDebug>
#include <QApplication>
#include <QClipboard>
#include <QDBusMessage>
#include <QDBusPendingCall>

using namespace uos_ai;

EAiProxy::EAiProxy(QObject *parent)
    : QObject{parent}
{
    connect(EAiExec(), &EAiExecutor::llmAccountLstChanged,
            this, &EAiProxy::llmAccountLstChanged);

    //Init audio singals
    connect(EAiExec(), &EAiExecutor::audioASRInComing,
            this, &EAiProxy::sigAudioASRStream);
    connect(EAiExec(), &EAiExecutor::audioASRError,
            this, &EAiProxy::sigAudioASRError);
    connect(EAiExec(), &EAiExecutor::playTTSError,
            this, &EAiProxy::sigPlayTTSError);
    connect(EAiExec(), &EAiExecutor::playTTSFinished,
            this, &EAiProxy::sigPlayTTSFinished);
    connect(EAiExec(), &EAiExecutor::audioOutputDeviceChanged,
            this, &EAiProxy::sigAudioOutputDevChanged);
    connect(EAiExec(), &EAiExecutor::audioInputDeviceChange,
            this, &EAiProxy::sigAudioInputDevChange);
    connect(EAiExec(), &EAiExecutor::audioSampleLevel,
            this, &EAiProxy::sigAudioSampleLevel);

    //Init TTP signals
    connect(EAiExec(), &EAiExecutor::chatConversationType,
            this, &EAiProxy::sigChatConversationType);

    connect(EAiExec(), &EAiExecutor::textToPictureFinish,
            this, &EAiProxy::sigText2PicFinish);
    connect(EAiExec(), &EAiExecutor::pptCreateSuccess,
            this, &EAiProxy::sigPPTCreateSuccess);
    connect(EAiExec(), &EAiExecutor::pptChangeSuccess,
            this, &EAiProxy::sigPPTChangeSuccess);
    connect(EAiExec(), &EAiExecutor::posterCreateSuccess,
            this, &EAiProxy::sigPosterCreateSuccess);
    //Try to stop all requst from this proxy when it's
    //going to be destructed
    connect(this, &EAiProxy::destroyed, this, [this]() {
        EAiExec()->clearAiRequest(this);
    });

    //Network signal
    connect(EAiExec(), &EAiExecutor::netStateChanged,
            this, &EAiProxy::sigNetStateChanged);

    connect(DGuiApplicationHelper::instance(), &DGuiApplicationHelper::themeTypeChanged,
    this, [this](DGuiApplicationHelper::ColorType themeType) {
        //Check if the theme's changed.
        if (m_themeType != themeType) {
            m_themeType = themeType;
            emit sigThemeChanged(m_themeType);
        }

        //Check if the active color is changed.
        QString activeColor = DGuiApplicationHelper::instance()->applicationPalette()
                              .color(DPalette::Normal, DPalette::Highlight)
                              .name(QColor::HexRgb);
        if (m_activeColor != activeColor) {
            m_activeColor = activeColor;
            emit sigActiveColorChanged(m_activeColor);
        }
    });
    connect(QApplication::instance(), SIGNAL(fontChanged(const QFont &)), this, SLOT(onUpdateSystemFont(const QFont &)));

    m_themeType = DGuiApplicationHelper::instance()->themeType();

    m_activeColor = DGuiApplicationHelper::instance()->applicationPalette()
                    .color(DPalette::Normal, DPalette::Highlight)
                    .name(QColor::HexRgb);

    //Load toast message
    m_aiToastMessage.append("");
    m_aiToastMessage.append(QCoreApplication::translate("AiToastMessage", "Chat history cleared"));
    m_aiToastMessage.append(QCoreApplication::translate("AiToastMessage", "Copied successfully"));

    m_audioRecCounter.reset(new QTimer(this));
    connect(m_audioRecCounter.get(), &QTimer::timeout, this, [this]() {
        m_audioLenLimit--;

        if (m_audioLenLimit <= 10) {
            emit sigAudioCountDown(m_audioLenLimit);

            //Stop count at zero
            if (m_audioLenLimit == 0) {
                m_audioRecCounter->stop();
            }
        }
    });

    connect(EAiExec(), &EAiExecutor::knowledgeBaseExistChanged, this, &EAiProxy::sigKnowledgeBaseStatusChanged);
    connect(EAiExec(), &EAiExecutor::knowledgeBaseFAQGenFinished, this, &EAiProxy::sigKnowledgeBaseFAQGenFinished);

    connect(EAiExec(), &EAiExecutor::localLLMStatusChanged, this, &EAiProxy::sigLocalLLMStatusChanged);
    connect(EAiExec(), &EAiExecutor::embeddingPluginsStatusChanged, this, &EAiProxy::sigEmbeddingPluginsStatusChanged);

    // 拖拽文档解析
    connect(EAiExec(), &EAiExecutor::docSummaryParsingStart, this, &EAiProxy::sigDocSummaryParsingStart);
    connect(EAiExec(), &EAiExecutor::docDragInViewParserResult, this, &EAiProxy::sigDocSummaryParserResult);
    // API: openFile() -> Result
    connect(EAiExec(), &EAiExecutor::openFileFromPathResult, this, &EAiProxy::sigOpenFileFromPathResult);

    connect(EAiExec(), &EAiExecutor::sigAppendWordWizardConv, this, &EAiProxy::sigAppendWordWizardConv);

    connect(EAiExec(), &EAiExecutor::previewReference, this, &EAiProxy::sigPreviewReference);

    connect(EAiExec(), &EAiExecutor::sigOverrideQues, this, &EAiProxy::sigOverrideQues);
    connect(EAiExec(), &EAiExecutor::sigAssistantListChanged, this, &EAiProxy::sigAssistantListChanged);

    connect(EAiExec(), &EAiExecutor::sigMainContentBackgroundColor, this, [this](QString color){
        m_backgroundColor = color;
        emit sigMainContentBackgroundColor(color);
    });

    initAsyncWorkerConn();
}

void EAiProxy::onUpdateSystemFont(const QFont &font)
{
    QFontInfo fontInfo(font);
    setFontInfo(fontInfo.family(), fontInfo.pixelSize());
    emit sigFontChanged(fontInfo.family(), fontInfo.pixelSize());
}

bool EAiProxy::isKnowledgeBaseExist()
{
    return EAiExec()->isKnowledgeBaseExist();
}

bool EAiProxy::isEmbeddingPluginsExist()
{
    return EAiExec()->isEmbeddingPluginsExist();
}

void EAiProxy::configureKnowledgeBase()
{
    return EAiExec()->launchLLMConfigWindow(false);
}

void EAiProxy::installEmbeddingPlugins()
{
    return EAiExec()->openInstallWidget(PLUGINSNAME);
}

void EAiProxy::onDocSummarySelect()
{
    EAiExec()->documentSummarySelect();
}

void EAiProxy::onDocSummaryParsing(const QString &docPath)
{
    EAiExec()->documentSummaryParsing(docPath);
}

void EAiProxy::openFile(const QString &filePath)
{
    EAiExec()->openFile(filePath);
}

void EAiProxy::openUrl(const QString &url)
{
    EAiExec()->openUrl(url);
}

void EAiProxy::appendWordWizardConv()
{
    EAiExec()->appendWordWizardConv();
}

void EAiProxy::webViewLoadFinished()
{
    EAiExec()->webViewLoadFinished();
}

void EAiProxy::previewRefDoc(const QString &docPath, const QStringList &docContents)
{
    EAiExec()->previewRefDoc(docPath, docContents);
}

QString EAiProxy::getInstList()
{
    return EAiExec()->getInstList();
}

void EAiProxy::sendPPTOutline(const QString &content)
{
    EPPTWebView *pptweb = ESystemContext::createWebWindow<EPPTWebView>(content, "2", "0");
    connect(pptweb, &EPPTWebView::sigPPTCreated,
            EAiExec(), &EAiExecutor::onPPTCreated);
    connect(pptweb, &EPPTWebView::sigPPTChanged,
            EAiExec(), &EAiExecutor::onPPTChanged);
}

void EAiProxy::editPPT(const QString &content)
{
    EPPTWebView *pptweb = ESystemContext::createWebWindow<EPPTWebView>(content, "1", "0");
    connect(pptweb, &EPPTWebView::sigPPTCreated,
            EAiExec(), &EAiExecutor::onPPTCreated);
    connect(pptweb, &EPPTWebView::sigPPTChanged,
            EAiExec(), &EAiExecutor::onPPTChanged);
}

void EAiProxy::downloadPPT(const QString &id)
{
    EPPTWebView *pptweb = ESystemContext::createWebWindow<EPPTWebView>("", "1", id);
    connect(pptweb, &EPPTWebView::sigPPTCreated,
            EAiExec(), &EAiExecutor::onPPTCreated);
    connect(pptweb, &EPPTWebView::sigPPTChanged,
            EAiExec(), &EAiExecutor::onPPTChanged);
}

void EAiProxy::editPoster(const QString &content)
{
    QRegularExpression regex("ID：(\\d+)");
    QRegularExpressionMatch match = regex.match(content);

    if (match.hasMatch()) {
        // 提取ID
        QString id = match.captured(1);
        EPosterWebView *posterweb = ESystemContext::createWebWindow<EPosterWebView>(EPosterWebView::WebSitePage::ModifyParameters, id);
        connect(posterweb, &EPosterWebView::sigPosterCreated, EAiExec(), &EAiExecutor::onPosterCreated);
    } else {
        qDebug() << "没有找到ID";
    }
}

void EAiProxy::genePoster(const QString &content)
{
    QRegularExpression regex("ID：(\\d+)");
    QRegularExpressionMatch match = regex.match(content);

    if (match.hasMatch()) {
        // 提取ID
        QString id = match.captured(1);
        EPosterWebView *posterweb = ESystemContext::createWebWindow<EPosterWebView>(EPosterWebView::WebSitePage::GenerateWorks, id);
        connect(posterweb, &EPosterWebView::sigPosterCreated, EAiExec(), &EAiExecutor::onPosterCreated);
    } else {
        qDebug() << "没有找到ID";
    }
}

void EAiProxy::downloadPoster(const QString &id)
{
    EPosterWebView *posterweb = ESystemContext::createWebWindow<EPosterWebView>(EPosterWebView::WebSitePage::ModifyWork, id);
    connect(posterweb, &EPosterWebView::sigPosterCreated, EAiExec(), &EAiExecutor::onPosterCreated);
}

bool EAiProxy::isAgentSupported()
{
#ifdef ENABLE_AGENT_PLUGIN
    return true;
#else
    return false;
#endif
}

void EAiProxy::openAppstore(const QString &id)
{
    if (id == "agent") {
        auto con = QDBusConnection::sessionBus();
        QDBusMessage msg = QDBusMessage::createMethodCall("com.home.appstore.client", "/com/home/appstore/client",
                                       "com.home.appstore.client", "openBusinessUri");

        QVariantList args;
        args << QVariant::fromValue(QString("tab/topAiAgentApp"));
        msg.setArguments(args);

        con.asyncCall(msg);
    }
}

void EAiProxy::onAsyncWorkerFinished(int type)
{
    emit EAsync()->sigWorkerFinished(type);
}

void EAiProxy::rateAnwser(const int questionIdx, const int answerIdx, int rate, const QString &extJson)
{
    EAiExec()->rateAnwser(questionIdx, answerIdx, rate, extJson);
}

QString EAiProxy::getNotifierName(AiAction act, int mode)
{
    Q_UNUSED(act);

    QString actionName("");

    actionName = (Mode::CacheMode == mode)
                 ? GET_NOTIFIER_NAME(AiReply)
                 : GET_SNOTIFIER_NAME(AiReply);

    return actionName;
}

void EAiProxy::initAsyncWorkerConn()
{
    connect(EAsync(), &EAsyncWorker::sigAsyncWorker, this, &EAiProxy::sigAsyncWorker);
}

QString EAiProxy::sendAiRequest(const QString &llmId, int llmType, int act, const QString &param, int mode)
{
    QString reqId("");

    if ((act > None && act < MaxAiAction)
            && (mode > Mode::None && mode < Mode::MaxMode)
            && (!param.isEmpty())
            /*&& (!llmId.isEmpty())*/ //Allow no account request
       ) {
        QSharedPointer<EAiPrompt> aiPrompt;
        QSharedPointer<EAiCallback> aiCallback;

        aiCallback.reset(new EAiCacheCallback(this));
        aiCallback->setDataMode(Mode(mode));

        //act param isn't used
        aiCallback->setNotifier(getNotifierName(None, mode));

        switch (act) {
        case Conversation:
            aiPrompt.reset(new EConversationPrompt(param));
            aiCallback->setOp(Conversation);
            break;
        case DocumentSummary:
            aiPrompt.reset(new EAiDocSummaryPrompt(param, QString("")));
            aiCallback->setOp(DocumentSummary);
            break;
        default:
            qWarning() << " Don't implement operation:" << act;
            break;
        }

        //Set ai model type
        if (!aiPrompt.isNull()) {
            aiPrompt->setLLM(llmType);
        }
        //Send request to Executor queue.
        reqId = EAiExec()->sendAiRequst(llmId, aiPrompt, aiCallback);
    } else {
        qWarning() << "Invalid parameter:"
                   << " llmId =" << llmId
                   << " act=" << act
                   << " param=" << param
                   << " mode=" << mode;
    }

    return reqId;
}

QString EAiProxy::sendRequest(const QString &llmId, const QString &chatChunkData)
{
    uos_ai::ChatChunk chatChunk;
    uos_ai::ChatChunk::json2ChatChunk(chatChunkData.toUtf8(), chatChunk);
    EAiExec()->sendRequest(llmId, chatChunk, this, getNotifierName(None, Mode::StreamMode));

    QJsonObject chatChunkObj;
    uos_ai::ChatChunk::chatChunk2Json(chatChunkObj, chatChunk);
    return QJsonDocument(chatChunkObj).toJson(QJsonDocument::Compact);
}

void EAiProxy::cancelAiRequest(const QString &id)
{
    EAiExec()->cancelAiRequst(id);
}

QString EAiProxy::currentLLMAccountId()
{
    return EAiExec()->currentLLMAccountId();
}

QString EAiProxy::queryLLMAccountList()
{
    return EAiExec()->queryLLMAccountList();
}

bool EAiProxy::setCurrentLLMAccountId(const QString &id)
{
    return EAiExec()->setCurrentLLMAccountId(id);
}

QString EAiProxy::currentAssistantId()
{
    return EAiExec()->currentAssistantId();
}

QString EAiProxy::queryAssistantList()
{
    return EAiExec()->queryAssistantList();
}

bool EAiProxy::setCurrentAssistantId(const QString &id)
{
    return EAiExec()->setCurrentAssistantId(id);
}

QString EAiProxy::getAiFAQ()
{
    return EAiExec()->getRandomAiFAQ();
}

void EAiProxy::launchLLMConfigWindow(bool showAddllmPage)
{
    QString locateTitle = "";
    if (!showAddllmPage)
        locateTitle = tr("Model Configuration");

    return EAiExec()->launchLLMConfigWindow(showAddllmPage, false, false, locateTitle);
}

void EAiProxy::launchKnowledgeBaseConfigWindow()
{
    return EAiExec()->launchKnowledgeBaseConfigWindow();
}

void EAiProxy::launchAboutWindow()
{
    return EAiExec()->launchAboutWindow();
}

void EAiProxy::setFontInfo(const QString &fontFamily, int pixelSize)
{
    m_fontFamily = fontFamily;
    m_fontPixelSize = pixelSize;
}

QString EAiProxy::fontInfo()
{
    return m_fontFamily + "#" + QString::number(m_fontPixelSize);
}

void EAiProxy::setWindowMode(bool isWindowMode)
{
    m_isWindowMode = isWindowMode;
}

bool EAiProxy::isWindowMode()
{
    return m_isWindowMode;
}


void EAiProxy::showToast(int type)
{
    auto index = AiToast(type);

    if (index > 0 && type < m_aiToastMessage.size()) {
        EAiExec()->showToast(m_aiToastMessage[index]);
    }
}

void EAiProxy::closeChatWindow()
{
    EAiExec()->closeChatWindow();
}

bool EAiProxy::isAudioInputAvailable()
{
    return EAiExec()->isAudioInputAvailable();
}

bool EAiProxy::isAudioOutputAvailable()
{
    return EAiExec()->isAudioOutputAvailable();
}

bool EAiProxy::startRecorder(int mode)
{
    //Reset audio limit at start.
    m_audioLenLimit = AUDIO_LENGTH;

    //Stop time anyway.
    m_audioRecCounter->stop();
    m_audioRecCounter->start(1000);

    return EAiExec()->startRecorder(mode);
}

bool EAiProxy::stopRecorder()
{
    //Stop countdown timer
    m_audioRecCounter->stop();

    return EAiExec()->stopRecorder();
}

bool EAiProxy::playTextAudio(const QString &id, const QString &text, bool isEnd)
{
    return EAiExec()->playTextAudio(id, text, isEnd);
}

bool EAiProxy::stopPlayTextAudio()
{
    return EAiExec()->stopPlayTextAudio();
}

void EAiProxy::playSystemSound(int effId)
{
    return EAiExec()->playSystemSound(effId);
}

void EAiProxy::copyReplyText(const QString &reply)
{
#ifdef COMPILE_ON_V25
    if (ESystemContext::isTreeland()) {
        QTimer::singleShot(10, this, [reply]{
            QClipboard *clip = QApplication::clipboard();
            clip->setText(reply);
        });
    }
#else
    QClipboard *clip = QApplication::clipboard();
    clip->setText(reply);
#endif
}

void EAiProxy::logAiChatRecord(const QString &reqId,
                               const QString &question,
                               const QString &anwser,
                               bool isRetry,
                               int err,
                               const QString &errorInfo,
                               int actionType,
                               const QString &llmIcon,
                               const QString &llmName,
                               const QString &docSummaryParam)
{
    return EAiExec()->logChatRecord(
               reqId, question, QStringList(anwser),
               isRetry, err, errorInfo,
               actionType,
               llmIcon, llmName, docSummaryParam);
}

void EAiProxy::logAiChatRecord(const QString &reqId,
                               const QString &question,
                               const QStringList &anwser,
                               bool isRetry,
                               int err,
                               const QString &errorInfo,
                               int actionType,
                               const QString &llmIcon,
                               const QString &llmName,
                               const QString &docSummaryParam)
{
    return EAiExec()->logChatRecord(
               reqId, question, anwser,
               isRetry, err, errorInfo,
               actionType,
               llmIcon, llmName, docSummaryParam);
}

QString EAiProxy::getAiChatRecords(bool lastRec)
{
    return EAiExec()->getChatRecords(lastRec);
}

void EAiProxy::logConversations(const QString &conversationsData)
{
    QVector<uos_ai::Conversations> convs;
    uos_ai::Conversations::json2Convs(convs, conversationsData.toUtf8());

    EAiExec()->logConversations(convs);
}

QString EAiProxy::getConversations()
{
    return EAiExec()->getConversations();
}

void EAiProxy::clearConversations()
{
    return EAiExec()->clearConversations();
}

void EAiProxy::clearAiChatRecords()
{
    return EAiExec()->clearChatRecords();
}

bool EAiProxy::saveImageAs(const QString &filePath)
{
    return EAiExec()->saveImageAs(filePath);
}

bool EAiProxy::previewImage(const QString &filePath)
{
    return EAiExec()->previewImage(filePath);
}

void EAiProxy::copyImage2Clipboard(const QString &filePath)
{
    return EAiExec()->copyImg2Clipboard(filePath);
}

bool EAiProxy::isNetworkAvailable()
{
    return EAiExec()->isNetworkAvailable();
}

QJsonObject EAiProxy::loadTranslations()
{
    static QJsonObject translations;
    if (!translations.isEmpty())
        return translations;

    translations["Go to configuration"] = tr("Go to configuration");
    translations["No account"] = tr("No account");
    translations["Input question"] = tr("Input question");
    translations["The content generated by AI is for reference only, please pay attention to the accuracy of the information."] = tr("The content generated by AI is for reference only, please pay attention to the accuracy of the information.");
    translations["Welcome to UOS AI"] = tr("Welcome to UOS AI");
    translations["Here are some of the things UOS AI can help you do"] = tr("Here are some of the things UOS AI can help you do");
    translations["Stop"] = tr("Stop");
    translations["Regenerate"] = tr("Regenerate");
    translations["Clear conversation history"] = tr("Clear conversation history");
    translations["Please connect the microphone and try again"] = tr("Please connect the microphone and try again");
    translations["Chat history cleared"] = tr("Chat history cleared");
    translations["No account"] = tr("No account");
    translations["Click to start/stop recording"] = tr("Click to start/stop recording");
    translations["Listening"] = tr("Listening");
    translations["Sleeping"] = tr("Sleeping");
    translations["Microphone not detected"] = tr("Microphone not detected");
    translations["Connection failed, click to try again"] = tr("Connection failed, click to try again");
    translations["Click on the animation or Ctrl+Super+A to activate"] = tr("Click on the animation or Ctrl+Super+A to activate");
    translations["Voice input is temporarily unavailable, please check the network!"] = tr("Voice input is temporarily unavailable, please check the network!");
    translations["Unable to connect to the server, please check your network or try again later."] = tr("Unable to connect to the server, please check your network or try again later.");
    translations["Voice conversation"] = tr("Voice conversation");
    translations["Click the animation or press Enter to send"] = tr("Click the animation or press Enter to send");
    translations["Stop recording after %1 seconds"] = tr("Stop recording after %1 seconds");
    translations["Thinking"] = tr("Thinking");
    translations["Click animation to interrupt"] = tr("Click animation to interrupt");
    translations["Answering"] = tr("Answering");
    translations["Your free account quota has been exhausted, please configure your model account to continue using it."] = tr("Your free account quota has been exhausted, please configure your model account to continue using it.");
    translations["Your free account has expired, please configure your model account to continue using it."] = tr("Your free account has expired, please configure your model account to continue using it.");
    translations["UOS AI requires an AI model account to be configured before it can be used. Please configure a model account first."] = tr("UOS AI requires an AI model account to be configured before it can be used. Please configure a model account first.");
    translations["Activate"] = tr("Activate");
    translations["Voice input"] = tr("Voice input");
    translations["Voice broadcast is temporarily unavailable, please check the network!"] = tr("Voice broadcast is temporarily unavailable, please check the network!");
    translations["Turn off voice conversation"] = tr("Turn off voice conversation");
    translations["The picture has been generated, please switch to the chat interface to view it."] = tr("The picture has been generated, please switch to the chat interface to view it.");
    translations["No account, please configure an account"] = tr("No account, please configure an account");
    translations["Answer each question up to 5 times"] = tr("Answer each question up to 5 times");
    translations["Copied successfully"] = tr("Copied successfully");
    translations["Sound output device not detected"] = tr("Sound output device not detected");
    translations["The sound output device is not detected, please check and try again!"] = tr("The sound output device is not detected, please check and try again!");
    translations["Settings"] = tr("Settings");
    translations["About"] = tr("About");
    translations["Mode"] = tr("Mode");
    translations["Window Mode"] = tr("Window Mode");
    translations["Sidebar Mode"] = tr("Sidebar Mode");
    translations["Assistant List"] = tr("Assistant List");
    translations["Agent List"] = tr("Agent List");
    translations["Agent Store"] = tr("Agent Store");
    translations["UOS System Assistant"] = tr("UOS System Assistant");
    translations["Deepin System Assistant"] = tr("Deepin System Assistant");
    translations["Personal Knowledge Assistant"] = tr("Personal Knowledge Assistant");
    translations["Please configure the knowledge base"] = tr("Please configure the knowledge base");
    translations["knowledge base configure content"] = tr("Before using the [Personal Knowledge Assistant], it is necessary to configure the knowledge base. After configuring the knowledge base, AI will answer questions or generate content based on the content you have configured in the knowledge base.");
    translations["Please configure the large model"] = tr("Please configure the large model");
    translations["The personal knowledge assistant can only be used after configuring a large model."] = tr("The personal knowledge assistant can only be used after configuring a large model.");
    translations["To configure"] = tr("To configure");
    translations["To install"] = tr("To install");
    translations["Please install EmbeddingPlugins"] = tr("Please install [EmbeddingPlugins]");
    translations["EmbeddingPlugins install content"] = tr("This assistant requires the installation of the EmbeddingPlugins to run");

    // document summary
    translations["Drag files here to add them."] = tr("Drag files here to add them.");
    translations["You can only add one file, supported file types include: txt, doc, docx, xls, xlsx, ppt, pptx, pdf."] = tr("You can only add one file, supported file types include: txt, doc, docx, xls, xlsx, ppt, pptx, pdf.");
    translations["You can only add a maximum of one file."] = tr("You can only add a maximum of one file.");
    translations["The file format is not supported."] = tr("The file format is not supported.");
    translations["Summarize the key content of the file."] = tr("Summarize the key content of the file.");
    translations["Parsing..."] = tr("Parsing...");
    translations["File Error"] = tr("File Error");
    translations["File has been deleted."] = tr("File has been deleted.");
    translations["The file size exceeds the 100MB limit."] = tr("The file size exceeds the 100MB limit.");
    translations["Upload a document"] = tr("Upload a document");
    translations["File deleted"] = tr("File deleted");
    translations["No text was parsed"] = tr("No text was parsed");
    translations["Reference"] = tr("Reference");

    // Instruction
    translations["Instruction"] = tr("Instruction");
    translations["Type \"/\" in the input box to activate."] = tr("Type \"/\" in the input box to activate.");
    translations["Please enter; “Ctrl+Enter” to change the line."] = tr("Please enter; “Ctrl+Enter” to change the line.");

    //联网搜索
    translations["Search complete."] = tr("Search complete.");
    translations["Click to view results"] = tr("Click to view results");

    // textToPicture
    translations["edit"] = tr("edit");
    translations["save"] = tr("save");
    translations["copy"] = tr("copy");

    return translations;
}
