NDD(notepad--)的AI机器人插件制作过程

兴趣是最好的老师。周末晚上熬夜到半夜十二点多,花了几个钟头给NDD制作了一款AI搜索问答插件,时间仓促界面较丑,后续插件代码开源并维护和美化。Notepad记事本工具挺常用的,把AI接口接入进来使用起来方便多啦,直接在上面搜索问答。这里记录下详细过程,分享给有需要的小伙伴。

想要体验的小伙伴可以点赞加评论,首页关注公众号,回复666获取体验码。

无需注册和配置,只需我把动态库发您,放入插件目录即可,使用我的后台服务可以直接使用。

ndd-chat-ai: NDD(NotePad--)的聊天机器人插件

实现效果截图:

 

环境准备

首先得有一个AI的后台接口服务。好在我已具备,部署在了免费的replit。如果你有公有云服务器资源,可以也部署一个AI的后台接口服务。如果没有,免费的repit也很好用。

下载NDD源码,准备好编译环境(msvc2019工具链+QT5.12以上版本)。

以下是我的replit后台截图: 

NDD插件制作

插件主要功能实现类

按照NDD插件制作说明制作一个插件,点击菜单后弹出一个QDockWidget停靠窗口(实用工具窗口)。停靠在主窗口的左侧。NDDMyPlugin主功能实现类如下:

//
// Created by Administrator on 2023/3/19.
//#ifndef HELLOWORLD_NDDMYPLUGIN_H
#define HELLOWORLD_NDDMYPLUGIN_H
#include <QAction>
#include <QObject>
#include <QWidget>
#include <qsciscintilla.h>
class QDockWidget;class NDDMyPlugin  : public QObject{
Q_OBJECT
public:explicit NDDMyPlugin(QWidget *mainWidget, const QString &pluginPath, QsciScintilla *pEdit,QObject *parent = nullptr);~NDDMyPlugin() override = default;void getViewMenu(QMenu *menu);void setScintilla(const std::function<QsciScintilla *()> &cb);private:QWidget *mainWidget_;QDockWidget *dockWidget_;private:std::function<QsciScintilla *()> scintillaCallback_;
};#endif //HELLOWORLD_NDDMYPLUGIN_H
//
// Created by yangyongzhen 2023/3/19.
//#include "NDDMyPlugin.h"
#include "mysetting.h"
#include <docktitlewidget.h>
#include <QDockWidget>
#include <QHeaderView>
#include <QMainWindow>
#include <QMenuBar>NDDMyPlugin::NDDMyPlugin(QWidget *mainWidget, const QString &pluginPath, QsciScintilla *pEdit, QObject *parent): QObject(parent),dockWidget_(new QDockWidget("AI窗口")),mainWidget_(mainWidget)
{dockWidget_->setFeatures(QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetClosable|QDockWidget::DockWidgetMovable);dockWidget_->setAllowedAreas(Qt::LeftDockWidgetArea);dockWidget_->hide();auto dockWidgetTitle = new DockTitleWidget;//dockWidget_->setTitleBarWidget(dockWidgetTitle);dockWidget_->setWidget(dockWidgetTitle);auto mainWindow = dynamic_cast<QMainWindow *>(mainWidget);mainWindow->addDockWidget(Qt::LeftDockWidgetArea, dockWidget_);
}
void NDDMyPlugin::getViewMenu(QMenu *menu)
{menu->addAction("Show Chat Window", this, [this] {dockWidget_->show();});menu->addAction("快捷按键(Ctrl+F8)", this, [this] {}, Qt::CTRL + Qt::Key_F8);menu->addAction("Settings", this, [this] {//参数设置MySettingDlg* p = new MySettingDlg(mainWidget_,scintillaCallback_());//主窗口关闭时,子窗口也关闭。避免空指针操作p->setWindowFlag(Qt::Window);p->show();});
}void NDDMyPlugin::setScintilla(const std::function<QsciScintilla *()> &cb)
{if(scintillaCallback_== nullptr){scintillaCallback_ = cb;}
}

插件接口类

该类主要是插件框架层接口的实现。这个简单,基本就是按NDD插件的说明文档制作。

#include <qobject.h>
#include <qstring.h>
#include <pluginGl.h>
#include <functional>
#include <qsciscintilla.h>
#include "qttestclass.h"
#include "NDDMyPlugin.h"#define NDD_EXPORTDLL#if defined(Q_OS_WIN)#if defined(NDD_EXPORTDLL)#define NDD_EXPORT __declspec(dllexport)#else#define NDD_EXPORT __declspec(dllimport)#endif
#else#define NDD_EXPORT __attribute__((visibility("default")))
#endif#ifdef __cplusplusextern "C" {
#endifNDD_EXPORT bool NDD_PROC_IDENTIFY(NDD_PROC_DATA* pProcData);NDD_EXPORT int NDD_PROC_MAIN(QWidget* pNotepad, const QString& strFileName, std::function<QsciScintilla* ()>getCurEdit, NDD_PROC_DATA* procData);#ifdef __cplusplus}
#endif
NDDMyPlugin *nddMyPlugin = nullptr;
static NDD_PROC_DATA s_procData;
static QWidget* s_pMainNotepad = nullptr;
std::function<QsciScintilla* ()> s_getCurEdit;bool NDD_PROC_IDENTIFY(NDD_PROC_DATA* pProcData)
{if(pProcData == NULL){return false;}pProcData->m_strPlugName = QObject::tr("Chat AI Plug");pProcData->m_strComment = QObject::tr("chat tool use openai GPT-3.5");pProcData->m_version = QString("v1.0");pProcData->m_auther = QString("yangyongzhen");pProcData->m_menuType = 1;return true;
}//则点击菜单栏按钮时,会自动调用到该插件的入口点函数。
//pNotepad:就是CCNotepad的主界面指针
//strFileName:当前插件DLL的全路径,如果不关心,则可以不使用
//getCurEdit:从NDD主程序传递过来的仿函数,通过该函数获取当前编辑框操作对象QsciScintilla
//pProcData:如果pProcData->m_menuType = 0 ,则该指针为空;如果pProcData->m_menuType = 1,则该指针有值。目前需要关心s_procData.m_rootMenu
//开发者可以在该菜单下面,自行创建二级菜单
int NDD_PROC_MAIN(QWidget* pNotepad, const QString &strFileName, std::function<QsciScintilla*()>getCurEdit, NDD_PROC_DATA* pProcData)
{//务必拷贝一份pProcData,在外面会释放。if (pProcData == nullptr){return 1;}s_pMainNotepad = pNotepad;s_procData = *pProcData;s_getCurEdit = getCurEdit;//如果pProcData->m_menuType = 1;是自己要创建二级菜单的场景。则通过s_procData.m_rootMenu 获取该插件的菜单根节点。//插件开发者自行在s_procData.m_rootMenu下添加新的二级菜单项目//QMenu* menu = s_procData.m_rootMenu;if (!nddMyPlugin){nddMyPlugin = new NDDMyPlugin(s_pMainNotepad, strFileName, nullptr, s_pMainNotepad);nddMyPlugin->getViewMenu(s_procData.m_rootMenu);nddMyPlugin->setScintilla(s_getCurEdit);}return 0;
}

cmake编译脚本

cmake_minimum_required(VERSION 3.16)
project(mychatai)set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_PREFIX_PATH "D:/Qt5.12.11/Qt5.12.11/5.12.11/msvc2015_64/lib/cmake")find_package(Qt5 REQUIRED COMPONENTS Core Gui Widgets Concurrent Network PrintSupport XmlPatterns)add_definitions(-D_UNICODE -DUNICODE)# win下需要开启UNICODE进行支持TCHAR
if(CMAKE_HOST_WIN32)add_definitions(-D_UNICODE -DUNICODE)
endif()file(GLOB UI_SRC ${PROJECT_SOURCE_DIR}/*.ui)
file(GLOB SRC ${PROJECT_SOURCE_DIR}/*.cpp)
file(GLOB MOC_HEADER ${PROJECT_SOURCE_DIR}/*.h)
# add_executable(${PROJECT_NAME} ${IS_WIN} ${SRC} ${UI_SRC} ${PROJECT_SOURCE_DIR}/src/RealCompare.qrc)
link_directories(${CMAKE_CURRENT_SOURCE_DIR}/
)
#find_library(QSCINT_LIB qmyedit_qt5d PATH ${CMAKE_CURRENT_SOURCE_DIR}/)
#add_library( qmyedit_qt5d SHARED IMPORTED )
#set_target_properties( qmyedit_qt5d PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/qmyedit_qt5d.dll )
add_library(${PROJECT_NAME} SHARED ${SRC} ${UI_SRC} ${MOC_HEADER})target_include_directories(${PROJECT_NAME} PRIVATE
${PROJECT_SOURCE_DIR}${PROJECT_SOURCE_DIR}/../../include
${PROJECT_SOURCE_DIR}/../../qscint/src
${PROJECT_SOURCE_DIR}/../../qscint/src/Qsci
${PROJECT_SOURCE_DIR}/../../qscint/scintilla/src
${PROJECT_SOURCE_DIR}/../../qscint/scintilla/include
${PROJECT_SOURCE_DIR}/../../qscint/scintilla/lexlib
${PROJECT_SOURCE_DIR}/../../qscint/scintilla/boostregex
)#set(QSCINT_LIB ${CMAKE_CURRENT_SOURCE_DIR}/qmyedit_qt5d.lib)target_link_libraries(${PROJECT_NAME} PRIVATEdebug qmyedit_qt5doptimized qmyedit_qt5)link_directories(${CMAKE_CURRENT_SOURCE_DIR}/
)
target_link_libraries(${PROJECT_NAME} PRIVATE  Qt5::Core Qt5::Gui Qt5::Widgets Qt5::Concurrent Qt5::Network  Qt5::PrintSupport Qt5::XmlPatterns)

QT的https访问

void DockTitleWidget::slotBtn_SendClick() {//设置头信息QNetworkRequest m_url;//m_url.setUrl(QUrl("https://pmp.eloam.net/api/ota/findFadVersion"));m_url.setUrl(QUrl("https://xxxxx/xxxx"));m_url.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");QSslConfiguration m_sslConfig = QSslConfiguration::defaultConfiguration();m_sslConfig.setPeerVerifyMode(QSslSocket::VerifyNone);m_sslConfig.setProtocol(QSsl::TlsV1_2);m_url.setSslConfiguration(m_sslConfig);//char cByte[1024] = "{\"as\":\"123456\", \"ks\": \"123456\", \"productCode\": \"HSPS\", \"version\": \"V1.2.3\"}";auto send = QString(u8"{\"user\":\"%1\",\"msg\":\"%2\"}").arg("yang").arg(ui->te_send->toPlainText());QByteArray bate = send.toUtf8();//QByteArray bate(send);//发送数据QString fromName = QString(u8"我问:");fromName = QString("<font color = blue>%1</font>").arg(fromName);//必须用br作为换行符ui->te_recv->append(fromName);ui->te_recv->append(ui->te_send->toPlainText());m_resp = m_http->post(m_url, bate);connect(m_resp, &QNetworkReply::finished, this, &DockTitleWidget::slotNet_Received);}void DockTitleWidget::slotNet_Received() {QString fromName = QString(u8"\nchat-Ai回答:");fromName = QString("<font color = green>%1</font>").arg(fromName);//必须用br作为换行符ui->te_recv->append(fromName);if (m_resp->error() == QNetworkReply::NoError) {QString strReceive = m_resp->readAll();      // 自行解析接口返回数据//ui->te_recv->append(ba);//QMessageBox::warning(this, "123", ba);QJsonParseError json_error;QJsonDocument doc = QJsonDocument::fromJson(strReceive.toUtf8(), &json_error);if (!doc.isNull() && json_error.error == QJsonParseError::NoError) {if (doc.isObject()) {QJsonObject object = doc.object();if (object.contains("text")) {  // 包含指定的 keyQJsonValue value = object.value("text");if (value.isString()) {ui->te_recv->append(value.toString());}}}} else {ui->te_recv->append(strReceive);}//auto recv = QJsonDocument::fromJson(strReceive);} else {ui->te_recv->append(m_resp->errorString());//QMessageBox::warning(this, "123", m_resp->errorString());}
}

完整实现

// You may need to build the project (run Qt uic code generator) to get "ui_DockTitleWidget.h" resolved
#pragma execution_character_set("utf-8")#include "docktitlewidget.h"
#include "ui_DockTitleWidget.h"
#include <QMessageBox>
#include <QJsonDocument>
#include <QJsonArray>
#include <QJsonObject>
#include <QJsonParseError>DockTitleWidget::DockTitleWidget(QWidget *parent) : QWidget(parent), ui(new Ui::DockTitleWidget) {ui->setupUi(this);ui->te_recv->setStyleSheet("QTextEdit{padding-top:2px;background:#f7f7f7;border:none;border-radius:5px;font-size:12px;color:#292421;""font-family:Microsoft YaHei;padding-left:5px;padding-right:5px;}");//无边框ui->te_send->setStyleSheet("QTextEdit{padding-top:2px;background:#f7f7f7;border:none;border-radius:5px;font-size:12px;color:#292421;""font-family:Microsoft YaHei;padding-left:5px;padding-right:5px;}");//无边框connect(ui->pb_send, SIGNAL(clicked(bool)), this, SLOT(slotBtn_SendClick()));connect(ui->te_recv, SIGNAL(textChanged()), this, SLOT(slotEdtReceiveTextChanged()));connect(this,SIGNAL(sigAppendText(QString)),this,SLOT(slotAppendText(QString)));m_http = new QNetworkAccessManager();
}DockTitleWidget::~DockTitleWidget() {delete ui;delete m_http;if (m_resp != nullptr) {delete m_resp;}
}void DockTitleWidget::slotBtn_SendClick() {//设置头信息QNetworkRequest m_url;//m_url.setUrl(QUrl("https://pmp.eloam.net/api/ota/findFadVersion"));m_url.setUrl(QUrl("https://weixx.xxx.repl.co/xxxx"));m_url.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");QSslConfiguration m_sslConfig = QSslConfiguration::defaultConfiguration();m_sslConfig.setPeerVerifyMode(QSslSocket::VerifyNone);m_sslConfig.setProtocol(QSsl::TlsV1_2);m_url.setSslConfiguration(m_sslConfig);//char cByte[1024] = "{\"as\":\"123456\", \"ks\": \"123456\", \"productCode\": \"HSPS\", \"version\": \"V1.2.3\"}";auto send = QString(u8"{\"user\":\"%1\",\"msg\":\"%2\"}").arg("yang").arg(ui->te_send->toPlainText());QByteArray bate = send.toUtf8();//QByteArray bate(send);//发送数据QString fromName = QString(u8"我问:");fromName = QString("<font color = blue>%1</font>").arg(fromName);//必须用br作为换行符ui->te_recv->append(fromName);ui->te_recv->append(ui->te_send->toPlainText());m_resp = m_http->post(m_url, bate);connect(m_resp, &QNetworkReply::finished, this, &DockTitleWidget::slotNet_Received);}void DockTitleWidget::slotNet_Received() {QString fromName = QString(u8"\nchat-Ai回答:");fromName = QString("<font color = green>%1</font>").arg(fromName);//必须用br作为换行符ui->te_recv->append(fromName);if (m_resp->error() == QNetworkReply::NoError) {QString strReceive = m_resp->readAll();      // 自行解析接口返回数据//ui->te_recv->append(ba);//QMessageBox::warning(this, "123", ba);QJsonParseError json_error;QJsonDocument doc = QJsonDocument::fromJson(strReceive.toUtf8(), &json_error);if (!doc.isNull() && json_error.error == QJsonParseError::NoError) {if (doc.isObject()) {QJsonObject object = doc.object();if (object.contains("text")) {  // 包含指定的 keyQJsonValue value = object.value("text");if (value.isString()) {ui->te_recv->append(value.toString());}}}} else {ui->te_recv->append(strReceive);}//auto recv = QJsonDocument::fromJson(strReceive);} else {ui->te_recv->append(m_resp->errorString());//QMessageBox::warning(this, "123", m_resp->errorString());}
}void DockTitleWidget::slotEdtReceiveTextChanged() {QTextCursor cursor = ui->te_recv->textCursor();cursor.movePosition(QTextCursor::End);ui->te_recv->setTextCursor(cursor);
}void DockTitleWidget::slotAppendText(const QString &text) {}

注意事项

由于使用了https访问网络,默认情况下会缺少两个库(libcrypto-1_1-x64.dll和libssl-1_1-x64.dll)。打包时需要把这两个动态库添加进来,否则运行不起来,运行会报错Process finished with exit code -1073741701 (0xC000007B)。该错误通常是由于所需的库文件(例如.dll文件)不存在或无法加载造成的,有可能是程序需要的特定版本的运行库缺少或者缺失了 32 位或 64 位的运行库。

其他资源

Qt--解析Json_qt json解析_Qt程序员的博客-CSDN博客

qt中的toUtf8, toLatin1, Local8bit, toUcs4_顺其自然~的博客-CSDN博客

各种常见颜色的RGB数值|RGB数值,rgb颜色表,金色rgb,rgb颜色,rgb颜色代码,各种颜色的rgb,常用颜色rgb,金属颜色rgb,rgb颜色对照表

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/32486.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Qt常用的按钮控件编程(四)-- QCheckBox 按钮

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言6、QCheckBox 按钮6.1 例程功能和程序执行效果6.2 生成项目6.3 添加资源文件6.3.1 添加图片资源6.3.2 添加 qss 文件 6.4 完成代码编辑6.4.1 修改项目文件 _rad…

chatgpt赋能python:Python按键控制灯:简单易用的物联网解决方案

Python按键控制灯&#xff1a;简单易用的物联网解决方案 随着物联网技术的快速发展&#xff0c;人们对智能家居的需求也越来越高。本文将介绍如何使用Python按键控制灯&#xff0c;轻松实现家居自动化控制&#xff0c;为您的生活带来方便与舒适。 Python语言简介 Python是一…

chatgpt赋能python:Python中按下某个按键的实现方法

Python中按下某个按键的实现方法 Python是一种广泛应用于各种领域的高级编程语言&#xff0c;可以用于编写各种类型的应用程序和工具。其中&#xff0c;它在游戏开发方面有着广泛的应用。而在游戏开发过程中&#xff0c;按键响应是至关重要的一个组成部分。本文将带领读者了解…

chatgpt赋能python:Python校验用户按键的方法

Python校验用户按键的方法 在Python编程中&#xff0c;我们有时需要校验用户按键的输入。这对于需要用户输入特定字符或按键组合的程序来说是非常必要的。本文将介绍一些Python校验用户按键的方法。 使用getch()函数 Python的getch()函数可以用于校验用户的按键输入。这个函…

chatgpt赋能python:Python编程中的按键事件

Python编程中的按键事件 在Python编程中&#xff0c;按键事件是一项非常有用的功能。通过监控按下键盘中的特定键&#xff0c;您可以触发程序的某些特定操作&#xff0c;这些操作可用于增强应用程序的功能和用户体验。 按键事件的基本工作原理 Python中的按键事件基于图形用…

网站日志蜘蛛在线分析工具源码 日志可视化管理工具源码 快速分析搜索引擎网络爬虫抓取记录

简介&#xff1a; 网站日志蜘蛛在线分析工具源码 日志可视化管理工具源码 快速分析搜索引擎网络爬虫抓取记录 如果是 linux 宝塔面板 的服务器自然环境&#xff0c;大家登陆宝塔面板linux控制面板后&#xff0c;点一下左边“文件”&#xff0c;在www下的wwwlogs文件目录中就能…

如何用ChatGPT做品牌项目的二手信息搜集?

该场景对应的关键词库&#xff08;25个&#xff09;&#xff1a; 品牌案例、竞品、信息来源、项目分析、官方渠道、品类、品牌、节日节庆、明星、国家、奖项、代理商、项目名称、项目描述、品牌介绍、竞争情况、运营数据、财务信息、交易信息、法律问题、网络平台、行业人士、品…

金山办公的WPS AI将引入大模型能力(LLM)到表格、文字、演示和PDF四大组件

&#x1f680; 金山办公的WPS AI将引入大模型能力&#xff08;LLM&#xff09;到表格、文字、演示和PDF四大组件&#xff0c;并支持桌面电脑和移动设备。 金山办公的WPS AI将引入大模型能力&#xff08;LLM&#xff09;到表格、文字、演示和PDF四大组件&#xff0c;并支持桌面…

系统内的在线协同富文本,如何寻求解决方案?

如果只是普通的富文本编辑&#xff0c;前端市面上已经有成熟的解决方案&#xff0c; 来自国产的富文本编辑器&#xff0c;开源 Web 富文本编辑器&#xff0c;开箱即用&#xff0c;配置简单。支持 JS Vue React 。 GitHub - wangeditor-team/wangEditor: wangEditor —— 开源…

WPS Office AI 开放内测,名额有限,先到先到

没等来Microsoft 365 Copilot&#xff0c;等来了 WPS AI&#xff0c;作为国内第一款集成多类AI功能的日常办公多件套应用&#xff0c;真是广大用户的福音。内测申请入口已经放开了&#xff0c;想一睹风采且想让自己的Office灵动起来的&#xff0c;抓紧行动&#xff08;文末获取…

WPS Office AI实战:AI带来的文档智能化体验

前面我们已经了解过 AI 在PPT制作、Word写作方面带来的革命性效率提供&#xff0c;今天一起来聊聊在线文档的AI应用。如果你习惯用在线文档的话&#xff0c;一样也可以享受到AI的强大优势。金山在线智能云文档已经接入WPS Office AI套件大家庭&#xff0c;用AI来改造写作的新时…

不用等微软了!实测:全线接入AI的WPS,做PPT就是一句话的事

金磊 梦晨 发自 凹非寺量子位 | 公众号 QbitAI 要问现在办公、学习最最最fashion的姿势是什么&#xff1f; 那必然是跟AI来一个深度合体。 例如老板丢过来一份纸质合同&#xff08;还是全英文的&#xff09;&#xff0c;让你快速浏览并做总结。 此时不必惊慌&#xff0c;遇事掏…

与ChatGPT 技术对话 42 天后,30多岁男子过于焦虑自杀身亡...

点击“开发者技术前线”&#xff0c;选择“星标” 让一部分开发者看到未来 来自&#xff1a;极目新闻 最近ChatGPT的飞速发展引起了世界范围的广泛关注&#xff0c;有人兴奋&#xff0c;也有人担忧。 据比利时媒体LAvenir3月28日报道&#xff0c;一名热衷于环境问题的比利时男子…

影刀知识点总结

判断字符串之间的包含关系&#xff0c;用if条件就可以。影刀社区&#xff1a;https://www.winrobot360.com/community/homePage启动excel的意思是&#xff0c;如果没有打开&#xff0c;就打开&#xff0c;如果打开了&#xff0c;就激活已打开的excel&#xff0c;输入内容&#…

影刀Rpa 、英佑科技面试总结

文章目录 1、dubbo spi 都使用过哪些? Java Spi 的缺点有哪些?2、dubbo的负载均衡策略有哪些3、设计一个rpc,有哪些模块4、Dubbo注册中心有哪些5、apollo框架,如何保证容错6、List线程安全实现方式有哪些?7、mysql 索引& 优化CSDN话题挑战赛第2期 参赛话题: 面试宝典…

day13- 影刀的基本操作

day13- 影刀的基本操作 影刀 - rpa软件开发工具(开发软件机器人) 软件机器人: 代替人类控制计算机完成流程固定且大量重复的作用 01搭建网页机器人 主流程 常见标签的控制方法 分支和循环 获取当前选中网页 变量和循环

影刀学习抓取网页详情

学习目标&#xff1a;影刀学习 1.爬取网页详情&#xff1a;点击网页&#xff0c;循环设置&#xff0c;点击其中一个超链接&#xff0c;进入超链接内容&#xff0c;点击其中一个超链接&#xff0c;获取里面的信息&#xff0c;写入表格&#xff0c;关闭网页。 2.在1的基础上&a…

huike汇客CRM项目实战-并肩作战

任务目录&#xff1a; 任务一&#xff1a;添加线索跟进记录 任务二&#xff1a;查询线索跟进记录列表 任务三&#xff1a;添加商机跟进记录 任务四&#xff1a;查询商机跟进记录列表 任务一&#xff1a;新增线索跟进记录 实体类&#xff1a; Data public class TableDataInfo i…

CSDN分类专栏操作演示

专栏没有消失&#xff01; CSDN仍然保留专栏功能&#xff0c;与分类功能合并&#xff0c;改名为分类专栏。文章目录 分类专栏的入口分类专栏的功能演示如何新建一个二级分类专栏如何快速编辑分类专栏名称在哪管理分类专栏内的文章如何编辑分类专栏内的单篇文章如何对分类专栏内…

重复造轮子的百模大战:两极热,中间空

文&#xff5c;光锥智能&#xff0c;作者&#xff5c;周文斌&#xff0c;编辑&#xff5c;王一粟 “不敢下手&#xff0c;现在中国还没跑出来一家绝对有优势的大模型&#xff0c;上层应用没法投&#xff0c;担心押错宝。”投资人Jucy&#xff08;化名&#xff09;向光锥智能表…