#include "session_p.h"
#include "session.h"
#include "timereventloop.h"
#include "appsocketserver.h"
//#include "llmutils.h"
#include "dbwrapper.h"
#include "threadtaskmana.h"
#include "uossimplelog.h"
#include "uosfreeaccounts.h"
#include "functionhandler.h"
#include "chatfixedresponse.h"
#include "servercodetranslation.h"
#include "conversation.h"
#include "text2imagehandler.h"
#include "networkmonitor.h"
#include "generateprompt.h"
#include "utils/globalfilewatcher.h"

#include <QtConcurrent>
#include <QImage>

using namespace uos_ai;

SessionPrivate::SessionPrivate(Session *session, const QString &appId)
    : m_appId(appId)
    , m_q(session)
{

    m_llmVendor.initExternal();

    {
        QString assistantId = DbWrapper::localDbWrapper().queryCurAssistantIdByAppId(appId);
        checkUpdateAssistantAccount(assistantId);
    }

    {
        QString llmId = DbWrapper::localDbWrapper().queryLlmIdByAssistantId(m_assistantProxy.id);
        auto supLLM = m_llmVendor.queryServerAccountByRole(m_assistantProxy);

        if (llmId.isEmpty() && m_assistantProxy.type == UOS_AI) {
            llmId = DbWrapper::localDbWrapper().queryCurLlmIdByAppId(appId);
            if (!supLLM.isEmpty()) {
                const auto it = std::find_if(supLLM.begin(), supLLM.end(), [llmId](const LLMServerProxy &account){
                    return account.id == llmId;
                });

                if (it == supLLM.end())
                    llmId.clear();
            } else {
                llmId.clear();
            }
        }

        m_appServerProxy = m_llmVendor.queryValidServerAccount(llmId);
        if (!m_appServerProxy.isValid()) {
            if (!supLLM.isEmpty())
                m_appServerProxy = supLLM.first();
            else
                qWarning() << "no llm for" << m_assistantProxy.id << m_assistantProxy.displayName;
        }
    }

    FileWatcher *watcher = new FileWatcher(this);
    watcher->addPath(FunctionHandler::functionPluginPath());

    connect(watcher, &FileWatcher::directoryChanged, this, [ = ](const QString & path) {
        m_needQueryFunctions = true;
    });

    connect(watcher, &FileWatcher::fileChanged, this, [ = ](const QString & path) {
        m_needQueryFunctions = true;
    });

    connect(&m_llmVendor, &LLMServiceVendor::agentChanged, m_q, &Session::assistantListChanged);
}

SessionPrivate::~SessionPrivate()
{
    for (const QString &id : m_runTaskIds) {
        LLMThreadTaskMana::instance()->requestTaskFinished(id);
    }
}

void SessionPrivate::cancelRequestTask(const QString &id)
{
    m_runTaskIds.removeAll(id);
    LLMThreadTaskMana::instance()->cancelRequestTask(id);
}

bool SessionPrivate::handleRequestError(QSharedPointer<LLM> copilot, const QString &uuid)
{
    int errorCode;
    QString errorString;

    if (!NetworkMonitor::getInstance().isOnline()) {
        errorCode = AIServer::NetworkError;
        errorString = ServerCodeTranslation::serverCodeTranslation(errorCode, "");
    } else {
        errorCode = copilot->lastError();
        errorString = copilot->lastErrorString();
    }

    QMetaObject::invokeMethod(m_q, "error", Qt::QueuedConnection, Q_ARG(QString, uuid), Q_ARG(int, errorCode), Q_ARG(QString, errorString));
    return true;
}

bool SessionPrivate::supportFunctionCall(const LLMServerProxy &account)
{
    if (qApp->applicationName() != m_appId)
        return false;

    if (LLMServerProxy::llmManufacturer(account.model) == ModelManufacturer::BAIDU_WXQF)
        return true;

//    if (account.model == LOCAL_YOURONG_1_5B || account.model== LOCAL_YOURONG_7B)
//        return true;

//    if (account.model == DeepSeek_Uos_Free)
//        return true;

    return false;
}

bool SessionPrivate::handleAiServerRequest(QSharedPointer<LLM> copilot, const QString &uuid
                                           , QJsonObject &response, const QString &conversation
                                           , const QJsonArray &functions, const LLMServerProxy &llmAccount)
{
#ifdef DEBUG_LOG
    qWarning() << "User Name = " << llmAccount.name << "Chat Model = " << LLMServerProxy::llmName(llmAccount.model) << "ChatSeesion Request = " << conversation;
#endif

    QString maybeResponse = ChatFixedResponse::checkRequestText(conversation);
    if (!maybeResponse.isEmpty()) {
        response["content"] = maybeResponse;

        // 给点延时，直接返回，接收端可能还没来得及连接
        TimerEventLoop loop;
        loop.setTimeout(20);
        loop.exec();

        emit copilot->readyReadChatDeltaContent(maybeResponse);
        return true;
    }

    for (int i = 0; i < 3; i++) {
        response = copilot->predict(conversation, functions);

        // 速率被限制了，尝试请求下
        if (copilot->lastError() != AIServer::ServerRateLimitError && copilot->lastError() != AIServer::TimeoutError) {
            break;
        }

        int timeout = 500;

        TimerEventLoop loop;
        connect(copilot.data(), &LLM::aborted, &loop, &TimerEventLoop::quit);
        loop.setTimeout(timeout);
        loop.exec();
        disconnect(copilot.data(), &LLM::aborted, &loop, &TimerEventLoop::quit);
    }

#ifdef DEBUG_LOG
    qWarning() << "ChatSeesion Response = " << response;
#endif

    // 如果结束了，只有一种可能，此对象被销毁了，销毁了就不要继续下面的流程了
    if (LLMThreadTaskMana::instance()->isFinished(uuid)) {
        return false;
    }

    if (copilot->lastError() != AIServer::NoError) {
        qWarning() << "ChatSeesion Error = " << copilot->lastError() << copilot->lastErrorString();
        handleRequestError(copilot, uuid);
        return false;
    }

    return true;
}

LLMServerProxy SessionPrivate::queryValidServerAccount(const QString &llmId)
{
    LLMServerProxy tmpLLMAccount = m_llmVendor.queryValidServerAccount(llmId);
    if (!tmpLLMAccount.isValid())
        tmpLLMAccount = m_appServerProxy;

    return tmpLLMAccount;
}

bool SessionPrivate::checkLLMAccountStatus(const QString &uuid, LLMServerProxy &llmAccount, int &errorType)
{
    // 免费账号判断有效期和次数
    if (llmAccount.type == ModelType::FREE_NORMAL || llmAccount.type == ModelType::FREE_KOL) {
        int available = 0;
        QString modelUrl;
        int errorCode = UosFreeAccounts::instance().getDeterAccountLegal(llmAccount.account.apiKey, available, modelUrl);
        if (!modelUrl.isEmpty() && llmAccount.model != WXQF_ERNIE_Bot_4)
            // 兼容旧版本添加的KOL bot_4账号
            llmAccount.url = modelUrl;
        auto serverCodeTranslation = [=](int errorType) {
            QMetaObject::invokeMethod(m_q, "error", Qt::QueuedConnection,
                Q_ARG(QString, uuid),
                Q_ARG(int, errorType),
                Q_ARG(QString, ServerCodeTranslation::serverCodeTranslation(errorType, "").toUtf8())
                );
        };

        if (errorCode != QNetworkReply::NoError) {
            errorType = AIServer::NetworkError;
            serverCodeTranslation(errorType);
            return false;
        }

        switch (available) {
        case 1:
            errorType = AIServer::FREEACCOUNTEXPIRED;
            serverCodeTranslation(errorType);
            return false;
        case 2:
            errorType = AIServer::FREEACCOUNTUSAGELIMIT;
            serverCodeTranslation(errorType);
            return false;
        case 5:
            errorType = AIServer::FREEACCOUNTCHATUSAGELIMIT;
            break;
        case 6:
            errorType = AIServer::FREEACCOUNTTEXT2IMAGEUSAGELIMIT;
            break;
        default:
            break;
        }
    }
    return true;
}

QString SessionPrivate::handleLocalModel(QSharedPointer<LLM> copilot, const QString &uuid, const QString &conversation, const LLMServerProxy &llmAccount)
{
    QString prompt = Conversation::conversationLastUserData(conversation);

    QList<QByteArray> imgData = copilot->text2Image(prompt, 4);
    QMetaObject::invokeMethod(m_q, "chatAction", Qt::QueuedConnection, Q_ARG(QString, uuid), Q_ARG(int, ChatText2Image));

    if (copilot->lastError() != AIServer::NoError) {
        handleRequestError(copilot, uuid);
        return uuid;
    }

    QMetaObject::invokeMethod(m_q, "text2ImageReceived", Qt::QueuedConnection, Q_ARG(QString, uuid), Q_ARG(QList<QByteArray>, imgData));
    return uuid;
}

QPair<AIServer::ErrorType, QStringList> SessionPrivate::requestChatFunctionText(LLMServerProxy tmpLLMAccount, const QString &conversation, const QVariantHash &params)
{
    QString uuid = QUuid::createUuid().toString(QUuid::Id128);
    if (!tmpLLMAccount.isValid()) {
        QStringList reply;
        reply << uuid;
        reply << QCoreApplication::translate("SessionPrivate", "UOS AI requires an AI model account to be configured before it can be used. Please configure a model account first.");
        return qMakePair(AIServer::AccountInvalid, reply);
    }

    bool stream = params.value(PREDICT_PARAM_STREAM, false).toBool();

    // 这里如果开启了管道，需要等管道完全开启才能返回
    QEventLoop eventloop;
    bool isLoopQuit = false;

    QFuture<QString> future = QtConcurrent::run(LLMThreadTaskMana::instance()->threadPool(tmpLLMAccount.id), [ =, &eventloop, &isLoopQuit]() {
        LLMServerProxy tmpLLMAccountLocal = tmpLLMAccount;

        // 免费账号需要解密
        LLMServerProxy tmpLLMAccountDecrypt = tmpLLMAccountLocal.decryptAccount();

        QSharedPointer<LLM> copilot = m_llmVendor.getCopilot(tmpLLMAccountDecrypt);
        if (copilot.isNull()) {
            eventloop.quit();
            isLoopQuit = true;
            QMetaObject::invokeMethod(m_q, "error", Qt::QueuedConnection, Q_ARG(QString, uuid), Q_ARG(int, AIServer::ContentAccessDenied), Q_ARG(QString, "Invalid LLM Account."));
            return uuid;
        }

        copilot->loadParams(params);
        copilot->setCreatedId(uuid);
        copilot->switchStream(stream);

        connect(m_q, &Session::executionAborted, copilot.data(), &LLM::aborted);

        m_runTaskIds << uuid;
        LLMThreadTaskMana::instance()->addRequestTask(uuid, copilot.toWeakRef());

        if (tmpLLMAccountDecrypt.model == LLMChatModel::LOCAL_TEXT2IMAGE) {
            eventloop.quit();
            isLoopQuit = true;
            return handleLocalModel(copilot, uuid, conversation, tmpLLMAccountDecrypt);
        }

        AppSocketServer socketServer(uuid);

        // 开启流格式了，才会开启管道
        if (stream) {
            socketServer.startServer();
            connect(copilot.data(), &LLM::readyReadChatDeltaContent, &socketServer, &AppSocketServer::sendDataToClient);
            eventloop.quit();
            isLoopQuit = true;
        }

        // 免费账号判断有效期和次数
        int errorType = -1;
        if (!checkLLMAccountStatus(uuid, tmpLLMAccountLocal, errorType)) {
            qWarning() << "Failed to check the validity period and usage times of the free account.";
            return uuid;
        }
        // 获取模型接口URL
        tmpLLMAccountDecrypt.url = tmpLLMAccountLocal.url;

        // 更新llm的账号
        copilot->updateAccount(tmpLLMAccountDecrypt);

        QJsonObject appFunctions;
        // functions 目前只开放给助手自己使用
        if (supportFunctionCall(tmpLLMAccountDecrypt))
            appFunctions = FunctionHandler::queryAppFunctions(m_needQueryFunctions);

        QJsonObject response;
        QJsonArray functions = FunctionHandler::functions(appFunctions);

        if (errorType == AIServer::FREEACCOUNTCHATUSAGELIMIT)
            disconnect(copilot.data(), &LLM::readyReadChatDeltaContent, &socketServer, &AppSocketServer::sendDataToClient);

        if (!handleAiServerRequest(copilot, uuid, response, conversation, functions, tmpLLMAccountDecrypt))
            return uuid;

        int chatAction = FunctionHandler::chatAction(response);
        QMetaObject::invokeMethod(m_q, "chatAction", Qt::QueuedConnection, Q_ARG(QString, uuid), Q_ARG(int, chatAction));

        if (chatAction & ChatText2Image) {
            if (errorType == AIServer::FREEACCOUNTTEXT2IMAGEUSAGELIMIT) {
                QMetaObject::invokeMethod(m_q, "error", Qt::QueuedConnection,
                    Q_ARG(QString, uuid),
                    Q_ARG(int, errorType),
                    Q_ARG(QString, ServerCodeTranslation::serverCodeTranslation(errorType, "").toUtf8())
                    );
                return uuid;
            }

            QJsonObject tmpResponse;
            disconnect(copilot.data(), &LLM::readyReadChatDeltaContent, &socketServer, &AppSocketServer::sendDataToClient);

            QString prompt = Text2ImageHandler::imagePrompt(response, conversation);
            if (!handleAiServerRequest(copilot, uuid, tmpResponse, prompt, QJsonArray(), tmpLLMAccountDecrypt))
                return uuid;

            QList<QByteArray> imgData = copilot->text2Image(tmpResponse.value("content").toString(), 1);//文生图 1张

            if (copilot->lastError() != AIServer::NoError) {
                handleRequestError(copilot, uuid);
                return uuid;
            }

            QMetaObject::invokeMethod(m_q, "text2ImageReceived", Qt::QueuedConnection, Q_ARG(QString, uuid), Q_ARG(QList<QByteArray>, imgData));

            if (tmpLLMAccountDecrypt.type == ModelType::FREE_NORMAL || tmpLLMAccountDecrypt.type == ModelType::FREE_KOL) {
                UosFreeAccounts::instance().increaseUse(tmpLLMAccountDecrypt.id.split("_")[0], chatAction);
            }
            return uuid;
        }

        if (errorType == AIServer::FREEACCOUNTCHATUSAGELIMIT) {
            QMetaObject::invokeMethod(m_q, "error", Qt::QueuedConnection,
                Q_ARG(QString, uuid),
                Q_ARG(int, errorType),
                Q_ARG(QString, ServerCodeTranslation::serverCodeTranslation(errorType, "").toUtf8())
                );
            return uuid;
        }

        if (tmpLLMAccountDecrypt.type == ModelType::FREE_NORMAL || tmpLLMAccountDecrypt.type == ModelType::FREE_KOL) {
            UosFreeAccounts::instance().increaseUse(tmpLLMAccountDecrypt.id.split("_")[0], chatAction);
        }

        if (chatAction & ChatAction::ChatFunctionCall) {
            QString directReply;
            const QJsonArray &functionCalls = FunctionHandler::functionCall(response, conversation, &directReply);
            if (directReply.isEmpty()) {
                QJsonDocument document(functionCalls);
                if (!handleAiServerRequest(copilot, uuid, response, document.toJson(QJsonDocument::Compact), functions, tmpLLMAccountDecrypt))
                    return uuid;
            } else {
                response["content"] = directReply;
                emit copilot->readyReadChatDeltaContent(directReply);
            }
        }

        // 正常大部分场景不会进这里, 如果socket写入的字节比总字节还少，有可能还没写完，稍微延迟
        TimerEventLoop oneloop;
        oneloop.setTimeout(100);
        oneloop.exec();

        QMetaObject::invokeMethod(m_q, "chatTextReceived", Qt::QueuedConnection, Q_ARG(QString, uuid), Q_ARG(QString, response.value("content").toString()));

        return uuid;
    });

    QFutureWatcher<QString> *futureWatcher = new QFutureWatcher<QString>(this);
    QObject::connect(futureWatcher, &QFutureWatcher<QString>::finished, this, &SessionPrivate::onRequestTaskFinished);
    futureWatcher->setFuture(future);

    QStringList reply;
    reply << uuid;
    reply << "chatTextReceived";

    // 开启了stream才需要等待管道完全开启
    // 这里是多线程，可能已经quit了，还没来及exec
    if (stream && !isLoopQuit) {
        eventloop.exec();
    }

    return qMakePair(AIServer::NoError, reply);
}

QPair<AIServer::ErrorType, QStringList> SessionPrivate::requestInstFunction(LLMServerProxy tmpLLMAccount, const QString &conversation, const QJsonArray &funcs, const QVariantHash &params)
{
    QString uuid = QUuid::createUuid().toString(QUuid::Id128);
    if (!tmpLLMAccount.isValid()) {
        QStringList reply;
        reply << uuid;
        reply << QCoreApplication::translate("SessionPrivate", "UOS AI requires an AI model account to be configured before it can be used. Please configure a model account first.");
        return qMakePair(AIServer::AccountInvalid, reply);
    }

    bool stream = params.value(PREDICT_PARAM_STREAM, false).toBool();

    // 这里如果开启了管道，需要等管道完全开启才能返回
    QEventLoop eventloop;
    bool isLoopQuit = false;

    QFuture<QString> future = QtConcurrent::run(LLMThreadTaskMana::instance()->threadPool(tmpLLMAccount.id), [ =, &eventloop, &isLoopQuit]() {
        LLMServerProxy tmpLLMAccountLocal = tmpLLMAccount;

        // 免费账号需要解密
        LLMServerProxy tmpLLMAccountDecrypt = tmpLLMAccountLocal.decryptAccount();

        QSharedPointer<LLM> copilot = m_llmVendor.getCopilot(tmpLLMAccountDecrypt);
        if (copilot.isNull()) {
            eventloop.quit();
            isLoopQuit = true;
            QMetaObject::invokeMethod(m_q, "error", Qt::QueuedConnection, Q_ARG(QString, uuid), Q_ARG(int, AIServer::ContentAccessDenied), Q_ARG(QString, "Invalid LLM Account."));
            return uuid;
        }

        copilot->loadParams(params);
        copilot->setCreatedId(uuid);
        copilot->switchStream(stream);

        connect(m_q, &Session::executionAborted, copilot.data(), &LLM::aborted);

        m_runTaskIds << uuid;
        LLMThreadTaskMana::instance()->addRequestTask(uuid, copilot.toWeakRef());

        if (tmpLLMAccountDecrypt.model == LLMChatModel::LOCAL_TEXT2IMAGE) {
            eventloop.quit();
            isLoopQuit = true;
            return handleLocalModel(copilot, uuid, conversation, tmpLLMAccountDecrypt);
        }

        AppSocketServer socketServer(uuid);

        // 开启流格式了，才会开启管道
        if (stream) {
            socketServer.startServer();
            connect(copilot.data(), &LLM::readyReadChatDeltaContent, &socketServer, &AppSocketServer::sendDataToClient);
            eventloop.quit();
            isLoopQuit = true;
        }

        // 免费账号判断有效期和次数
        int errorType = -1;
        if (!checkLLMAccountStatus(uuid, tmpLLMAccountLocal, errorType)) {
            qWarning() << "Failed to check the validity period and usage times of the free account.";
            return uuid;
        }
        // 获取模型接口URL
        tmpLLMAccountDecrypt.url = tmpLLMAccountLocal.url;

        // 更新llm的账号
        copilot->updateAccount(tmpLLMAccountDecrypt);

        QJsonObject response;

        if (errorType == AIServer::FREEACCOUNTCHATUSAGELIMIT)
            disconnect(copilot.data(), &LLM::readyReadChatDeltaContent, &socketServer, &AppSocketServer::sendDataToClient);

        if (!handleAiServerRequest(copilot, uuid, response, conversation, funcs, tmpLLMAccountDecrypt))
            return uuid;

        int chatAction = FunctionHandler::chatAction(response);
        QMetaObject::invokeMethod(m_q, "chatAction", Qt::QueuedConnection, Q_ARG(QString, uuid), Q_ARG(int, chatAction));

        if (chatAction != ChatFunctionCall) {
            int fcInvalidErr = AIServer::InstFunctionCallingInvalid;
            QMetaObject::invokeMethod(m_q, "error", Qt::QueuedConnection,
                Q_ARG(QString, uuid),
                Q_ARG(int, fcInvalidErr),
                Q_ARG(QString, ServerCodeTranslation::serverCodeTranslation(fcInvalidErr, "").toUtf8())
                );
            return uuid;
        }

        if (errorType == AIServer::FREEACCOUNTCHATUSAGELIMIT) {
            QMetaObject::invokeMethod(m_q, "error", Qt::QueuedConnection,
                Q_ARG(QString, uuid),
                Q_ARG(int, errorType),
                Q_ARG(QString, ServerCodeTranslation::serverCodeTranslation(errorType, "").toUtf8())
                );
            return uuid;
        }

        if (tmpLLMAccountDecrypt.type == ModelType::FREE_NORMAL || tmpLLMAccountDecrypt.type == ModelType::FREE_KOL) {
            UosFreeAccounts::instance().increaseUse(tmpLLMAccountDecrypt.id.split("_")[0], chatAction);
        }

        QString directReply;
        const QJsonArray &functionCalls = FunctionHandler::instFuncCall(response, conversation, &directReply);
        if (directReply.isEmpty()) {
            QJsonDocument document(functionCalls);
            if (!handleAiServerRequest(copilot, uuid, response, document.toJson(QJsonDocument::Compact), funcs, tmpLLMAccountDecrypt))
                return uuid;
        } else {
            response["content"] = directReply;
            emit copilot->readyReadChatDeltaContent(directReply);
        }

        // 正常大部分场景不会进这里, 如果socket写入的字节比总字节还少，有可能还没写完，稍微延迟
        TimerEventLoop oneloop;
        oneloop.setTimeout(100);
        oneloop.exec();

        QMetaObject::invokeMethod(m_q, "chatTextReceived", Qt::QueuedConnection, Q_ARG(QString, uuid), Q_ARG(QString, response.value("content").toString()));

        return uuid;
    });

    QFutureWatcher<QString> *futureWatcher = new QFutureWatcher<QString>(this);
    QObject::connect(futureWatcher, &QFutureWatcher<QString>::finished, this, &SessionPrivate::onRequestTaskFinished);
    futureWatcher->setFuture(future);

    QStringList reply;
    reply << uuid;
    reply << "chatTextReceived";

    // 开启了stream才需要等待管道完全开启
    // 这里是多线程，可能已经quit了，还没来及exec
    if (stream && !isLoopQuit) {
        eventloop.exec();
    }

    return qMakePair(AIServer::NoError, reply);
}

QPair<AIServer::ErrorType, QStringList> SessionPrivate::requestPlugin(LLMServerProxy tmpLLMAccount, const QString &conversation, const QVariantHash &params)
{
    QString uuid = QUuid::createUuid().toString(QUuid::Id128);
    bool stream = params.value(PREDICT_PARAM_STREAM, false).toBool();

    // 这里如果开启了管道，需要等管道完全开启才能返回
    QEventLoop eventloop;
    bool isLoopQuit = false;

    QFuture<QString> future = QtConcurrent::run(LLMThreadTaskMana::instance()->threadPool(tmpLLMAccount.id), [=, &eventloop, &isLoopQuit]() {
        QSharedPointer<LLM> copilot = m_llmVendor.getCopilot(tmpLLMAccount);
        if (copilot.isNull()) {
            eventloop.quit();
            isLoopQuit = true;

            TimerEventLoop oneloop;
            oneloop.setTimeout(100);
            oneloop.exec();

            QMetaObject::invokeMethod(m_q, "error", Qt::QueuedConnection, Q_ARG(QString, uuid), Q_ARG(int, AIServer::ContentAccessDenied), Q_ARG(QString, "Invalid LLM Account."));
            return uuid;
        }

        connect(m_q, &Session::executionAborted, copilot.data(), &LLM::aborted);
        copilot->loadParams(params);
        copilot->setCreatedId(uuid);
        copilot->switchStream(stream);

        // AppSocketServer 在本线程中需要一个eventloop处理事件。
        AppSocketServer socketServer(uuid);

        // 开启流格式了，才会开启管道
        if (stream) {
            socketServer.startServer();
            connect(copilot.data(), &LLM::readyReadChatDeltaContent, &socketServer, &AppSocketServer::sendDataToClient);
            eventloop.quit();
            isLoopQuit = true;
        }

        m_runTaskIds << uuid;
        LLMThreadTaskMana::instance()->addRequestTask(uuid, copilot.toWeakRef());

        QJsonArray functions;
        QString role = m_assistantProxy.id;

        QDateTime requestTime = QDateTime::currentDateTime();
        QJsonObject response = copilot->predict(conversation, functions);

        // 如果结束了，只有一种可能，此对象被销毁了，销毁了就不要继续下面的流程了
        if (LLMThreadTaskMana::instance()->isFinished(uuid))
            return uuid;

        if (copilot->lastError() != AIServer::NoError) {
            qWarning() << "plugin chat error" << copilot->lastError() << copilot->lastErrorString();
            handleRequestError(copilot, uuid);
            return uuid;
        }

        //ztb、xxzsk、yzsbs的引用数据
        if (response.contains("references") && (m_assistantProxy.id == "ztbbd" || m_assistantProxy.id == "xxzsk" || m_assistantProxy.id == "yzsbs") ) {
            QJsonObject root = response.value("references").toObject();
            QJsonDocument doc(root);
            QString datas = QString::fromUtf8(doc.toJson(QJsonDocument::Compact));
            QMetaObject::invokeMethod(m_q, "previewReference", Qt::QueuedConnection,
                                      Q_ARG(QString, datas));
        }

        // AppSocketServer 正常大部分场景不会进这里, 如果socket写入的字节比总字节还少，有可能还没写完，稍微延迟
        TimerEventLoop oneloop;
        oneloop.setTimeout(100);
        oneloop.exec();

        QMetaObject::invokeMethod(m_q, "chatTextReceived", Qt::QueuedConnection, Q_ARG(QString, uuid), Q_ARG(QString, response.value("content").toString()));

        return uuid;
    });

    QFutureWatcher<QString> *futureWatcher = new QFutureWatcher<QString>(this);
    QObject::connect(futureWatcher, &QFutureWatcher<QString>::finished, this, &SessionPrivate::onRequestTaskFinished);
    futureWatcher->setFuture(future);

    QStringList reply;
    reply << uuid;
    reply << "chatTextReceived";

    // 开启了stream才需要等待管道完全开启
    // 这里是多线程，可能已经quit了，还没来及exec
    if (stream && !isLoopQuit)
        eventloop.exec();

    return qMakePair(AIServer::NoError, reply);
}

QString SessionPrivate::chatRequest(LLMServerProxy llmAccount, const QString &ctx, const QVariantHash &params)
{
    QString uuid = QUuid::createUuid().toString(QUuid::Id128);

    bool stream = params.value(PREDICT_PARAM_STREAM, false).toBool();
    bool increaseUse = params.value(PREDICT_PARAM_INCREASEUSE, false).toBool();

    // 这里如果开启了管道，需要等管道完全开启才能返回
    QEventLoop eventloop;
    bool isLoopQuit = false;

    QFuture<QString> future = QtConcurrent::run(LLMThreadTaskMana::instance()->threadPool(llmAccount.id), [=, &eventloop, &isLoopQuit]() {
        if (!llmAccount.isValid()) {
            eventloop.quit();
            isLoopQuit = true;

            QString errInfo = QCoreApplication::translate("SessionPrivate", "UOS AI requires an AI model account to be configured before it can be used. Please configure a model account first.");
            onError(uuid, AIServer::AccountInvalid, errInfo);
            return uuid;
        }

        LLMServerProxy tmpLLMAccount = llmAccount;
        LLMServerProxy llmAccountDecrypt = tmpLLMAccount.decryptAccount();

        QSharedPointer<LLM> copilot = m_llmVendor.getCopilot(llmAccountDecrypt);
        if (copilot.isNull()) {
            eventloop.quit();
            isLoopQuit = true;
            onError(uuid, AIServer::ContentAccessDenied, "Invalid LLM Account.");
            return uuid;
        }
        copilot->loadParams(params);
        copilot->setCreatedId(uuid);
        copilot->switchStream(stream);
        connect(m_q, &Session::executionAborted, copilot.data(), &LLM::aborted);

        m_runTaskIds << uuid;
        LLMThreadTaskMana::instance()->addRequestTask(uuid, copilot.toWeakRef());

        // AppSocketServer 在本线程中需要一个eventloop处理事件。
        AppSocketServer socketServer(uuid);
        // 开启流格式了，才会开启管道
        if (stream) {
            socketServer.startServer();
            connect(copilot.data(), &LLM::readyReadChatDeltaContent, &socketServer, &AppSocketServer::sendDataToClient);
            eventloop.quit();
            isLoopQuit = true;
        }

        // 免费账号判断有效期和次数
        int errorType = -1;
        if (!checkLLMAccountStatus(uuid, tmpLLMAccount, errorType)) {
            qWarning() << "Failed to check the validity period and usage times of the free account.";
            return uuid;
        }
        // 获取模型接口URL
        llmAccountDecrypt.url = tmpLLMAccount.url;

        // 更新llm的账号
        copilot->updateAccount(llmAccountDecrypt);

        if (errorType == AIServer::FREEACCOUNTCHATUSAGELIMIT) {
            QMetaObject::invokeMethod(m_q, "error", Qt::QueuedConnection,
                Q_ARG(QString, uuid),
                Q_ARG(int, errorType),
                Q_ARG(QString, ServerCodeTranslation::serverCodeTranslation(errorType, "").toUtf8())
                );
            return uuid;
        }

        QJsonObject response = copilot->predict(ctx, QJsonArray());
        // 如果结束了，只有一种可能，此对象被销毁了，销毁了就不要继续下面的流程了
        if (LLMThreadTaskMana::instance()->isFinished(uuid))
            return uuid;

        if (copilot->lastError() != AIServer::NoError) {
            qWarning() << "chat error" << copilot->lastError() << copilot->lastErrorString();
            handleRequestError(copilot, uuid);
            return uuid;
        }

        if ((llmAccountDecrypt.type == ModelType::FREE_NORMAL || llmAccountDecrypt.type == ModelType::FREE_KOL) && increaseUse) {
            UosFreeAccounts::instance().increaseUse(llmAccountDecrypt.id.split("_")[0], ChatAction::ChatTextPlain);
        }

        // AppSocketServer 正常大部分场景不会进这里, 如果socket写入的字节比总字节还少，有可能还没写完，稍微延迟
        TimerEventLoop oneloop;
        oneloop.setTimeout(100);
        oneloop.exec();

        QMetaObject::invokeMethod(m_q, "chatTextReceived", Qt::QueuedConnection, Q_ARG(QString, uuid), Q_ARG(QString, response.value("content").toString()));
        return uuid;
    });

    QFutureWatcher<QString> *futureWatcher = new QFutureWatcher<QString>(this);
    QObject::connect(futureWatcher, &QFutureWatcher<QString>::finished, this, &SessionPrivate::onRequestTaskFinished);
    futureWatcher->setFuture(future);

    // 开启了stream才需要等待管道完全开启
    // 这里是多线程，可能已经quit了，还没来及exec
    if (stream && !isLoopQuit)
        eventloop.exec();

    return uuid;
}

QString SessionPrivate::genImageRequest(LLMServerProxy tmpLLMAccount, const QString &imageDesc)
{
    QString uuid = QUuid::createUuid().toString(QUuid::Id128);

    if (!tmpLLMAccount.isValid()) {
        QString errInfo = QCoreApplication::translate("SessionPrivate", "UOS AI requires an AI model account to be configured before it can be used. Please configure a model account first.");
        onError(uuid, AIServer::AccountInvalid, errInfo);
        return uuid;
    }

    QFuture<QString> future = QtConcurrent::run(LLMThreadTaskMana::instance()->threadPool(tmpLLMAccount.id), [=]() {
        LLMServerProxy tmpLLMAccountLocal = tmpLLMAccount;

        // 免费账号需要解密
        LLMServerProxy tmpLLMAccountDecrypt = tmpLLMAccountLocal.decryptAccount();
        QSharedPointer<LLM> copilot = m_llmVendor.getCopilot(tmpLLMAccountDecrypt);
        copilot->setCreatedId(uuid);
        connect(m_q, &Session::executionAborted, copilot.data(), &LLM::aborted);

        m_runTaskIds << uuid;
        LLMThreadTaskMana::instance()->addRequestTask(uuid, copilot.toWeakRef());

        // 免费账号判断有效期和次数
        int errorType = -1;
        if (!checkLLMAccountStatus(uuid, tmpLLMAccountLocal, errorType)) {
            qWarning() << "Failed to check the validity period and usage times of the free account.";
            return uuid;
        }
        // 获取模型接口URL
        tmpLLMAccountDecrypt.url = tmpLLMAccountLocal.url;

        // 更新llm的账号
        copilot->updateAccount(tmpLLMAccountDecrypt);

        QMetaObject::invokeMethod(m_q, "chatAction", Qt::QueuedConnection, Q_ARG(QString, uuid), Q_ARG(int, ChatText2Image));

        if (errorType == AIServer::FREEACCOUNTTEXT2IMAGEUSAGELIMIT) {
            QMetaObject::invokeMethod(m_q, "error", Qt::QueuedConnection,
                Q_ARG(QString, uuid),
                Q_ARG(int, errorType),
                Q_ARG(QString, ServerCodeTranslation::serverCodeTranslation(errorType, "").toUtf8())
                );
            return uuid;
        }

#ifdef TEXT_TO_IMAGE
        QList<QByteArray> imgData;
        if (LLMServerProxy::llmManufacturer(tmpLLMAccountDecrypt.model) == ModelManufacturer::BAIDU_WXQF ||
            LLMServerProxy::llmManufacturer(tmpLLMAccountDecrypt.model) == ModelManufacturer::XUNFEI_SPARKDESK) {
            // baidu、xunfei调用自己的文生图接口
            imgData = copilot->text2Image(imageDesc, 1);//文生图 1张
        } else {
            QString imagePrompt = GeneratePrompt::Translate2EnPrompt(imageDesc);
            QJsonObject tmpResponse;
            if (!handleAiServerRequest(copilot, uuid, tmpResponse, imagePrompt, QJsonArray(), qreal(0.9f), tmpLLMAccountDecrypt))
                return uuid;
            QString imageDescription = tmpResponse.value("content").toString();

            /**
             * @brief Request the image generate interface.
             * @param imageDescription: Image Description
             * @param n: Image Count.
             *
             * TODO: imageGenerate interface
             *
             * return ImagePath / Image Base64
             */

            QString imagePath = "";
            QImage image(imagePath);
            if (image.isNull()) {
                qWarning() << "Failed to load image!";
                // onError()
                return uuid;
            }

            QByteArray byteArray;
            QBuffer buffer(&byteArray);
            buffer.open(QIODevice::WriteOnly);
            image.save(&buffer, "PNG");
            QString base64Data = byteArray.toBase64();

            imgData.append(base64Data.toUtf8());
        }
#else
        QList<QByteArray> imgData = copilot->text2Image(imageDesc, 1);//文生图 1张
#endif

        if (copilot->lastError() != AIServer::NoError) {
            handleRequestError(copilot, uuid);
            return uuid;
        }

        QMetaObject::invokeMethod(m_q, "text2ImageReceived", Qt::QueuedConnection, Q_ARG(QString, uuid), Q_ARG(QList<QByteArray>, imgData));

        if (tmpLLMAccountDecrypt.type == ModelType::FREE_NORMAL || tmpLLMAccountDecrypt.type == ModelType::FREE_KOL) {
            UosFreeAccounts::instance().increaseUse(tmpLLMAccountDecrypt.id.split("_")[0], ChatText2Image);
        }

        // 正常大部分场景不会进这里, 如果socket写入的字节比总字节还少，有可能还没写完，稍微延迟
        TimerEventLoop oneloop;
        oneloop.setTimeout(100);
        oneloop.exec();

        return uuid;
    });

    QFutureWatcher<QString> *futureWatcher = new QFutureWatcher<QString>(this);
    QObject::connect(futureWatcher, &QFutureWatcher<QString>::finished, this, &SessionPrivate::onRequestTaskFinished);
    futureWatcher->setFuture(future);

    return uuid;
}

QString SessionPrivate::searchRequest(LLMServerProxy llmAccount, const QString &ctx)
{
    QString uuid = QUuid::createUuid().toString(QUuid::Id128);

    if (!llmAccount.isValid()) {
        QString errInfo = QCoreApplication::translate("SessionPrivate", "UOS AI requires an AI model account to be configured before it can be used. Please configure a model account first.");
        onError(uuid, AIServer::AccountInvalid, errInfo);
        return uuid;
    }

    if (!NetworkMonitor::getInstance().isOnline()) {
        QString errInfo = ServerCodeTranslation::serverCodeTranslation(AIServer::NetworkError, "").toUtf8();
        onError(uuid, AIServer::NetworkError, errInfo);
        return uuid;
    }

    LLMServerProxy tmpLLMAccount = llmAccount;
    LLMServerProxy llmAccountDecrypt = tmpLLMAccount.decryptAccount();

    QSharedPointer<LLM> copilot = m_llmVendor.getCopilot(llmAccountDecrypt);
    if (copilot.isNull()) {
        onError(uuid, AIServer::ContentAccessDenied, "Invalid LLM Account.");
        return uuid;
    }
    copilot->setCreatedId(uuid);
    connect(m_q, &Session::executionAborted, copilot.data(), &LLM::aborted);

    m_runTaskIds << uuid;
    LLMThreadTaskMana::instance()->addRequestTask(uuid, copilot.toWeakRef());

    // 免费账号判断有效期和次数
    int errorType = -1;
    if (!checkLLMAccountStatus(uuid, tmpLLMAccount, errorType)) {
        qWarning() << "Failed to check the validity period and usage times of the free account.";
        return uuid;
    }
    // 获取模型接口URL
    llmAccountDecrypt.url = tmpLLMAccount.url;

    // 更新llm的账号
    copilot->updateAccount(llmAccountDecrypt);

    if (errorType == AIServer::FREEACCOUNTCHATUSAGELIMIT) {
        QMetaObject::invokeMethod(m_q, "error", Qt::QueuedConnection,
            Q_ARG(QString, uuid),
            Q_ARG(int, errorType),
            Q_ARG(QString, ServerCodeTranslation::serverCodeTranslation(errorType, "").toUtf8())
            );
        return uuid;
    }

    // 如果结束了，只有一种可能，此对象被销毁了，销毁了就不要继续下面的流程了
    if (LLMThreadTaskMana::instance()->isFinished(uuid))
        return uuid;

    QMetaObject::invokeMethod(m_q, "chatTextReceived", Qt::QueuedConnection, Q_ARG(QString, uuid), Q_ARG(QString, Conversation::conversationLastUserData(ctx)));

    return uuid;
}

void SessionPrivate::checkUpdateAssistantAccount(const QString &assistantId)
{
    QList<AssistantProxy> assistantLst = DbWrapper::localDbWrapper().queryAssistantList();
    assistantLst << m_llmVendor.queryAssistantList();

    const auto it = std::find_if(assistantLst.begin(), assistantLst.end(), [assistantId](const AssistantProxy & assistant) {
        return assistant.id == assistantId;
    });

    if (it != assistantLst.end()) {
        m_assistantProxy = *it;
    } else {
        m_assistantProxy = assistantLst.value(0);
    }
}

void SessionPrivate::onRequestTaskFinished()
{
    QFutureWatcher<QString> *watcher = dynamic_cast<QFutureWatcher<QString> *>(sender());
    if (watcher) {
        QString id = watcher->result();
        m_runTaskIds.removeAll(id);
        LLMThreadTaskMana::instance()->requestTaskFinished(id);
    }

    sender()->deleteLater();
}

void SessionPrivate::onError(const QString &uuid, int errCode, const QString &errInfo)
{
    QMetaObject::invokeMethod(m_q, "error",
                              Qt::QueuedConnection,
                              Q_ARG(QString, uuid),
                              Q_ARG(int, errCode),
                              Q_ARG(QString, errInfo));

}

QVariant SessionPrivate::getFAQ()
{
    return m_llmVendor.getFAQ(m_assistantProxy.id);
}
