#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 "agentfactory.h"

#include <QtConcurrent>
#include <QImage>
#include <QLoggingCategory>

Q_DECLARE_LOGGING_CATEGORY(logWrapper)

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) {
            qCDebug(logWrapper) << "No LLM ID found for UOS AI assistant, trying app's configured model";
            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()) {
                    qCWarning(logWrapper) << "Configured LLM" << llmId << "not supported for UOS AI assistant";
                    llmId.clear();
                }
            } else {
                llmId.clear();
            }
        }

        m_appServerProxy = m_llmVendor.queryValidServerAccount(llmId);
        if (!m_appServerProxy.isValid()) {
            if (!supLLM.isEmpty()) {
                qCDebug(logWrapper) << "Using first available LLM for assistant";
                m_appServerProxy = supLLM.first();
            } else {
                qCWarning(logWrapper) << "No LLM available for assistant:" 
                                    << m_assistantProxy.id 
                                    << "name:" << m_assistantProxy.displayName;
            }
        }
    }

    FileWatcher *watcher = new FileWatcher(this);
    watcher->addPath(FunctionHandler::functionPluginPath());
    qCDebug(logWrapper) << "Watching function plugin path:" << FunctionHandler::functionPluginPath();

    connect(watcher, &FileWatcher::directoryChanged, this, [=](const QString &path) {
        qCDebug(logWrapper) << "Function plugin directory changed:" << path;
        m_needQueryFunctions = true;
    });

    connect(watcher, &FileWatcher::fileChanged, this, [=](const QString &path) {
        qCDebug(logWrapper) << "Function plugin file changed:" << 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)
{
    qCDebug(logWrapper) << "Cancelling request task:" << 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()) {
        qCWarning(logWrapper) << "Network offline, request aborted:" << uuid;
        errorCode = AIServer::NetworkError;
        errorString = ServerCodeTranslation::serverCodeTranslation(errorCode, "");
    } else {
        errorCode = copilot->lastError();
        errorString = copilot->lastErrorString();
        qCWarning(logWrapper) << "Request error - uuid:" << uuid << "code:" << errorCode << "message:" << errorString;
    }

    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) {
        qCDebug(logWrapper) << "Function call not supported for app:" << qApp->applicationName();
        return false;
    }

    if (LLMServerProxy::llmManufacturer(account.model) == ModelManufacturer::BAIDU_WXQF) {
        qCDebug(logWrapper) << "Function call supported for Baidu WXQF model";
        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
    qCDebug(logWrapper) << "Handling AI server request for" << uuid 
                       << "model:" << LLMServerProxy::llmName(llmAccount.model);
#endif

    QString maybeResponse = ChatFixedResponse::checkRequestText(conversation);
    if (!maybeResponse.isEmpty()) {
        qCDebug(logWrapper) << "Using fixed response for request:" << uuid;
        response["content"] = maybeResponse;

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

        copilot->textChainContent(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;
        }

        qCWarning(logWrapper) << "Rate limit or timeout for request" << uuid 
                            << "attempt:" << i + 1;
        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
    qCWarning(logWrapper) << "ChatSeesion Response = " << response;
#endif

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

    if (copilot->lastError() != AIServer::NoError) {
        qCWarning(logWrapper) << "AI server request error for" << uuid 
                            << "code:" << copilot->lastError() 
                            << "message:" << 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)
{
    qCDebug(logWrapper) << "Checking LLM account status for" << uuid 
                       << "model:" << LLMServerProxy::llmName(llmAccount.model);
                       
    // 免费账号判断有效期和次数
    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) {
            qCWarning(logWrapper) << "Network error checking account status:" << errorCode;
            errorType = AIServer::NetworkError;
            serverCodeTranslation(errorType);
            return false;
        }
        switch (available) {
        case 1:
            qCWarning(logWrapper) << "Free account expired";
            errorType = AIServer::FREEACCOUNTEXPIRED;
            serverCodeTranslation(errorType);
            return false;
        case 2:
            qCWarning(logWrapper) << "Free account usage limit reached";
            errorType = AIServer::FREEACCOUNTUSAGELIMIT;
            serverCodeTranslation(errorType);
            return false;
        case 5:
            qCDebug(logWrapper) << "Free account chat usage limit";
            errorType = AIServer::FREEACCOUNTCHATUSAGELIMIT;
            serverCodeTranslation(errorType);
            return false;
        case 6:
            qCDebug(logWrapper) << "Free account text2image usage limit";
            errorType = AIServer::FREEACCOUNTTEXT2IMAGEUSAGELIMIT;
            break;
        default:
            qCDebug(logWrapper) << "Account status check passed";
            break;
        }
    }
    return true;
}

QString SessionPrivate::handleLocalModel(QSharedPointer<LLM> copilot, const QString &uuid, const QString &conversation, const LLMServerProxy &llmAccount)
{
    qCDebug(logWrapper) << "Handling local model request for" << uuid;
    
    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) {
        qCWarning(logWrapper) << "Local model error for" << uuid 
                            << "code:" << copilot->lastError() 
                            << "message:" << copilot->lastErrorString();
        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);
    qCInfo(logWrapper) << "Starting general request:" << uuid;
    
    if (!tmpLLMAccount.isValid()) {
        qCWarning(logWrapper) << "Invalid LLM account for request:" << uuid;
        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();
    qCDebug(logWrapper) << "Request" << uuid << "stream mode:" << stream;

    // 这里如果开启了管道，需要等管道完全开启才能返回
    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()) {
            qCWarning(logWrapper) << "Failed to get copilot instance - uuid:" << uuid;
            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;
        }
        qCDebug(logWrapper) << "Initializing copilot for request:" << 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) {
            qCInfo(logWrapper) << "Handling local text2image model - uuid:" << uuid;
            eventloop.quit();
            isLoopQuit = true;
            return handleLocalModel(copilot, uuid, conversation, tmpLLMAccountDecrypt);
        }

        AppSocketServer socketServer(uuid, params.value(PREDICT_PARAM_NOJSONOUTPUT, false).toBool());
        qCDebug(logWrapper) << "Socket server created - uuid:" << uuid << socketServer.outputWithJson();

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

        // 免费账号判断有效期和次数
        int errorType = -1;
        if (!checkLLMAccountStatus(uuid, tmpLLMAccountLocal, errorType)) {
            qCWarning(logWrapper) << "Account status check failed - uuid:" << uuid 
                                << "error type:" << errorType;
            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);
        qCDebug(logWrapper) << "Functions prepared - uuid:" << uuid 
                           << "count:" << functions.size();

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

        int chatAction = FunctionHandler::chatAction(response);
        qCDebug(logWrapper) << "Chat action determined - uuid:" << uuid 
                           << "action:" << chatAction;
        QMetaObject::invokeMethod(m_q, "chatAction", Qt::QueuedConnection, Q_ARG(QString, uuid), Q_ARG(int, chatAction));

        if (chatAction & ChatText2Image) {
            qCInfo(logWrapper) << "Processing text2image request - uuid:" << uuid;
            if (errorType == AIServer::FREEACCOUNTTEXT2IMAGEUSAGELIMIT) {
                qCWarning(logWrapper) << "Text2image usage limit reached - uuid:" << uuid;
                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);
            qCDebug(logWrapper) << "Stream disconnected for text2image - uuid:" << uuid;

            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) {
                qCWarning(logWrapper) << "Image generation failed - uuid:" << uuid 
                                    << "error:" << copilot->lastErrorString();
                handleRequestError(copilot, uuid);
                return uuid;
            }

            qCInfo(logWrapper) << "Image generation completed - uuid:" << 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) {
                qCDebug(logWrapper) << "Increasing free account usage - uuid:" << uuid;
                UosFreeAccounts::instance().increaseUse(tmpLLMAccountDecrypt.id.split("_")[0], chatAction);
            }
            return uuid;
        }

        if (tmpLLMAccountDecrypt.type == ModelType::FREE_NORMAL || tmpLLMAccountDecrypt.type == ModelType::FREE_KOL) {
            qCDebug(logWrapper) << "Increasing free account usage - uuid:" << uuid;
            UosFreeAccounts::instance().increaseUse(tmpLLMAccountDecrypt.id.split("_")[0], chatAction);
        }

        if (chatAction & ChatAction::ChatFunctionCall) {
            qCInfo(logWrapper) << "Processing function call - uuid:" << uuid;
            QString directReply;
            const QJsonArray &functionCalls = FunctionHandler::functionCall(response, conversation, &directReply);
            if (directReply.isEmpty()) {
                qCDebug(logWrapper) << "No direct reply, sending function calls - uuid:" << uuid;
                QJsonDocument document(functionCalls);
                if (!handleAiServerRequest(copilot, uuid, response, document.toJson(QJsonDocument::Compact), functions, tmpLLMAccountDecrypt))
                    return uuid;
            } else {
                qCDebug(logWrapper) << "Using direct reply - uuid:" << uuid;
                response["content"] = directReply;
                copilot->textChainContent(directReply);
            }
        }

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

        qCInfo(logWrapper) << "Sending chat text response - uuid:" << uuid;
        QMetaObject::invokeMethod(m_q, "chatTextReceived", Qt::QueuedConnection, Q_ARG(QString, uuid), Q_ARG(QString, response.value("content").toString()));

        qCInfo(logWrapper) << "Request processing completed - uuid:" << uuid;
        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);
    qCInfo(logWrapper) << "Starting instruction function request:" << uuid;
    
    if (!tmpLLMAccount.isValid()) {
        qCWarning(logWrapper) << "Invalid LLM account for instruction function request:" << uuid;
        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();
    qCDebug(logWrapper) << "Request" << uuid << "stream mode:" << stream;

    // 这里如果开启了管道，需要等管道完全开启才能返回
    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()) {
            qCWarning(logWrapper) << "Failed to get copilot instance - uuid:" << uuid;
            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;
        }

        qCInfo(logWrapper) << "Initializing copilot - uuid:" << uuid 
                          << "model:" << LLMServerProxy::llmName(tmpLLMAccountDecrypt.model);
        copilot->loadParams(params);
        copilot->setCreatedId(uuid);
        copilot->switchStream(stream);
        qCDebug(logWrapper) << "Copilot initialized with stream mode:" << stream << " - uuid:" << uuid;

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

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

        if (tmpLLMAccountDecrypt.model == LLMChatModel::LOCAL_TEXT2IMAGE) {
            qCInfo(logWrapper) << "Handling local text2image model - uuid:" << uuid;
            eventloop.quit();
            isLoopQuit = true;
            return handleLocalModel(copilot, uuid, conversation, tmpLLMAccountDecrypt);
        }

        AppSocketServer socketServer(uuid, params.value(PREDICT_PARAM_NOJSONOUTPUT, false).toBool());
        qCDebug(logWrapper) << "Socket server created - uuid:" << uuid << socketServer.outputWithJson();

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

        // 免费账号判断有效期和次数
        int errorType = -1;
        if (!checkLLMAccountStatus(uuid, tmpLLMAccountLocal, errorType)) {
            qCWarning(logWrapper) << "Account status check failed - uuid:" << uuid 
                                << "error type:" << errorType;
            return uuid;
        }
        qCDebug(logWrapper) << "Account status check passed - uuid:" << uuid;

        // 获取模型接口URL
        tmpLLMAccountDecrypt.url = tmpLLMAccountLocal.url;

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

        QJsonObject response;

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

        int chatAction = FunctionHandler::chatAction(response);
        qCDebug(logWrapper) << "Chat action determined - uuid:" << uuid 
                           << "action:" << chatAction;
        QMetaObject::invokeMethod(m_q, "chatAction", Qt::QueuedConnection, Q_ARG(QString, uuid), Q_ARG(int, chatAction));

        if (chatAction != ChatFunctionCall) {
            qCWarning(logWrapper) << "Invalid function call action - uuid:" << uuid 
                                << "action:" << chatAction;
            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 (tmpLLMAccountDecrypt.type == ModelType::FREE_NORMAL || tmpLLMAccountDecrypt.type == ModelType::FREE_KOL) {
            qCDebug(logWrapper) << "Increasing free account usage - uuid:" << uuid;
            UosFreeAccounts::instance().increaseUse(tmpLLMAccountDecrypt.id.split("_")[0], chatAction);
        }

        qCInfo(logWrapper) << "Processing function call - uuid:" << uuid;
        QString directReply;
        const QJsonArray &functionCalls = FunctionHandler::instFuncCall(response, conversation, &directReply);
        if (directReply.isEmpty()) {
            qCDebug(logWrapper) << "No direct reply, sending function calls - uuid:" << uuid;
            QJsonDocument document(functionCalls);
            if (!handleAiServerRequest(copilot, uuid, response, document.toJson(QJsonDocument::Compact), funcs, tmpLLMAccountDecrypt))
                return uuid;
        } else {
            qCDebug(logWrapper) << "Using direct reply - uuid:" << uuid;
            response["content"] = directReply;
            copilot->textChainContent(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);
    qCInfo(logWrapper) << "Starting plugin request:" << uuid;
    
    bool stream = params.value(PREDICT_PARAM_STREAM, false).toBool();
    qCDebug(logWrapper) << "Request" << uuid << "stream mode:" << stream;

    // 这里如果开启了管道，需要等管道完全开启才能返回
    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);
        qCDebug(logWrapper) << "Copilot initialized with stream mode:" << stream << " - uuid:" << uuid;

        // AppSocketServer 在本线程中需要一个eventloop处理事件。
        AppSocketServer socketServer(uuid, params.value(PREDICT_PARAM_NOJSONOUTPUT, false).toBool());
        qCDebug(logWrapper) << "Socket server created - uuid:" << uuid << socketServer.outputWithJson();

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

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

        QJsonArray functions;
        QString role = m_assistantProxy.id;
        qCDebug(logWrapper) << "Preparing request with role:" << role << " - uuid:" << uuid;

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

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

        if (copilot->lastError() != AIServer::NoError) {
            qCWarning(logWrapper) << "Plugin chat error - uuid:" << uuid 
                                << "code:" << copilot->lastError() 
                                << "message:" << 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") ) {
            qCInfo(logWrapper) << "Processing references for assistant:" << m_assistantProxy.id << " - uuid:" << uuid;
            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));
            qCDebug(logWrapper) << "References processed and sent - uuid:" << uuid;
        }

        // 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);
}

QPair<AIServer::ErrorType, QStringList> SessionPrivate::requestAgent(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);
    }

    // 这里如果开启了管道，需要等管道完全开启才能返回
    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;

            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;
        }

        QSharedPointer<AgentRequestHandler> agent = AgentFactory::instance()->getAgent("default-agent");
        copilot->loadParams(params);
        copilot->setCreatedId(uuid);

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

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

        AppSocketServer socketServer(uuid);

        // 开启流格式了，才会开启管道
        socketServer.startServer();
        connect(agent.data(), &AgentRequestHandler::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);

        if (!agent->initClient()) {
            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, tr("Agent server is not available.")));
            return uuid;
        }

        QJsonObject response;
        {
            auto ary = QJsonDocument::fromJson(conversation.toUtf8()).array();
            auto question = ary.last();
            ary.pop_back();
            agent->processRequest(question.toObject(), ary, copilot, params);

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

            if (copilot->lastError() != AIServer::NoError) {
                qCWarning(logWrapper) << "Chat error - uuid:" << uuid
                                    << "code:" << copilot->lastError()
                                    << "message:" << copilot->lastErrorString();
                handleRequestError(copilot, uuid);
                return uuid;
            }
        }

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

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

        // 正常大部分场景不会进这里, 如果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 (!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);
    qCInfo(logWrapper) << "Starting chat request:" << uuid;

    bool stream = params.value(PREDICT_PARAM_STREAM, false).toBool();
    bool increaseUse = params.value(PREDICT_PARAM_INCREASEUSE, false).toBool();
    qCDebug(logWrapper) << "Request" << uuid << "stream mode:" << stream << "increase use:" << increaseUse;

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

    QFuture<QString> future = QtConcurrent::run(LLMThreadTaskMana::instance()->threadPool(llmAccount.id), [=, &eventloop, &isLoopQuit]() {
        if (!llmAccount.isValid()) {
            qCWarning(logWrapper) << "Invalid LLM account for request:" << uuid;
            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()) {
            qCWarning(logWrapper) << "Failed to get copilot instance - uuid:" << uuid;
            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, params.value(PREDICT_PARAM_NOJSONOUTPUT, false).toBool());
        qCDebug(logWrapper) << "Socket server created - uuid:" << uuid << socketServer.outputWithJson();
        // 开启流格式了，才会开启管道
        if (stream) {
            socketServer.startServer();
            connect(copilot.data(), &LLM::readyReadChatDeltaContent, &socketServer, &AppSocketServer::sendDataToClient);
            eventloop.quit();
            isLoopQuit = true;
            qCDebug(logWrapper) << "Stream mode initialized - uuid:" << uuid;
        }

        // 免费账号判断有效期和次数
        int errorType = -1;
        if (!checkLLMAccountStatus(uuid, tmpLLMAccount, errorType)) {
            qCWarning(logWrapper) << "Account status check failed - uuid:" << uuid 
                                << "error type:" << errorType;
            return uuid;
        }
        // 获取模型接口URL
        llmAccountDecrypt.url = tmpLLMAccount.url;

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

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

        if (copilot->lastError() != AIServer::NoError) {
            qCWarning(logWrapper) << "Chat error - uuid:" << uuid 
                                << "code:" << copilot->lastError() 
                                << "message:" << copilot->lastErrorString();
            handleRequestError(copilot, uuid);
            return uuid;
        }

        if ((llmAccountDecrypt.type == ModelType::FREE_NORMAL || llmAccountDecrypt.type == ModelType::FREE_KOL) && increaseUse) {
            qCDebug(logWrapper) << "Increasing free account usage - uuid:" << uuid;
            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);
    qCInfo(logWrapper) << "Starting image generation request:" << uuid;

    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)) {
            qCWarning(logWrapper) << "Account status check failed - uuid:" << uuid 
                                << "error type:" << errorType;
            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) {
            qCWarning(logWrapper) << "Text2image usage limit reached - uuid:" << uuid;
            QMetaObject::invokeMethod(m_q, "error",
                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) {
            qCWarning(logWrapper) << "Image generation error - uuid:" << uuid 
                                << "code:" << copilot->lastError() 
                                << "message:" << copilot->lastErrorString();
            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) {
            qCDebug(logWrapper) << "Increasing free account usage - uuid:" << uuid;
            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);
    qCInfo(logWrapper) << "Starting search request:" << uuid;

    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()) {
        qCWarning(logWrapper) << "Network offline, request aborted:" << uuid;
        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)) {
        qCWarning(logWrapper) << "Failed to check free account validity period and usage times";
        return uuid;
    }
    // 获取模型接口URL
    llmAccountDecrypt.url = tmpLLMAccount.url;

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

    // 如果结束了，只有一种可能，此对象被销毁了，销毁了就不要继续下面的流程了
    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)
{
    qCInfo(logWrapper) << "Checking and updating assistant account for ID:" << 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()) {
        qCDebug(logWrapper) << "Found assistant:" << it->id << "name:" << it->displayName;
        m_assistantProxy = *it;
    } else {
        qCWarning(logWrapper) << "Assistant" << assistantId << "not found, using first available";
        m_assistantProxy = assistantLst.value(0);
    }
}

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

    sender()->deleteLater();
}

void SessionPrivate::onError(const QString &uuid, int errCode, const QString &errInfo)
{
    qCWarning(logWrapper) << "Request error - uuid:" << uuid 
                         << "code:" << errCode 
                         << "message:" << errInfo;
                         
    QMetaObject::invokeMethod(m_q, "error",
                              Qt::QueuedConnection,
                              Q_ARG(QString, uuid),
                              Q_ARG(int, errCode),
                              Q_ARG(QString, errInfo));

}

QVariant SessionPrivate::getFAQ()
{
    qCInfo(logWrapper) << "Getting FAQ for assistant:" << m_assistantProxy.id;
    return m_llmVendor.getFAQ(m_assistantProxy.id);
}
