当前位置: 首页 > news >正文

自然语言处理(NLP)—— Dialogflow ES聊天机器人

1. 背景介绍        

        这个实验室的目标是让你了解并使用Google的Dialogflow服务。Dialogflow是一个可以让你创建聊天机器人的服务,这个过程不需要或者只需要很少的编程技能。

1.1 账号的创建

        为了完成这个实验室,你需要在以下网站上创建账号:

1.1 Dialogflow

        Dialogflow: www.dialogflow.com (如果你有Google账号,可以直接使用它登录);

1.2 ngrok

        ngrok: www.ngrok.com (同样,如果你有Google账号,可以使用它登录)。

        完成ngrok的账号创建后,下载与你的操作系统相对应的安装程序,并在你的电脑上安装它。接着,访问网址https://dashboard.ngrok.com/get-started/setup/macos,找到“tab Authentication>Your Authtoken”标签页,并复制命令行。

        苹果系统

        使用以下命令通过 Homebrew 安装 ngrok:        

brew install ngrok/ngrok/ngrok

        运行以下命令将您的 authtoken 添加到默认的ngrok.yml配置文件中。 

ngrok config add-authtoken 2biVXhWVYnruFK4jVDsdEc6Eutp_3JcWjV6eQMvL32TtTf5VN
记录ngrok 下载地址
/usr/local/bin

        如果你打算在本地服务器上使用Python编程,那么你还需要安装Flask包:

pip3 install Flask --user

        要在Dialogflow下创建一个聊天机器人,你需要完成以下四个步骤:
        1. 在纸上设计对话流程;
        2. 在Dialogflow中创建一个代理(agent),添加意图(intentions)、动作(actions)、参数(parameters)、实体(entities)、上下文(contexts);
        3. 设置与你机器上的服务器的通讯;
        4. 在服务器层面编写代码,以便与聊天机器人对话并为其提供信息。

        我已经为一个旅行预订聊天机器人准备了一些数据,你可以使用这些数据,或者创建另一个难度相当的聊天机器人。

2. 设计对话

        设计对话的第一步是在纸上绘制出所有可能的交互图谱,展示在所需对话中两个参与者之间的所有可能互动。首先记录标准情况(即信息顺利提供,交流顺畅的情况),然后预测可能由人类给出错误答案的情况,以及人类对其决策进行反悔的情况等。

        一旦考虑了所有的分支情况,就需要用不同颜色标记两个参与者的意图以及交换的信息(即对应不同类型值的“实体”,如日期、数量、产品等)。

        只要人类的回答有所不同,我们就可以编写一个简单的对话,在这个对话中分析回答并检测意图。但是,一旦在对话的两个不同位置发现相同的潜在回答(例如“是”),我们就需要定义上下文。因此,意图的检测将在给定的上下文中进行,并导致转移到另一个上下文。

        当你的对话在纸上用回答、意图、实体和上下文标记完整后,就可以开始实施了。在实施过程中,保持这张纸张在身边,并在图谱上进行测试,看看Dialogflow如何跟随所绘制的图谱。尝试让聊天机器人陷入困境。

        在语言学课上我们会看到,Grice的会话原则支配着人类的对话,理想情况下聊天机器人也应遵循这些原则。

        我们的项目是建立一个旅行社预订对话:

• Human: Hi,
• Machine: What can I do for you?
• Human: I need to travel
• Machine: How would you like to travel?
• Human: By (plane|train|bus|...)
• Machine: Where are you leaving from?
• Human: From (Brest|...)
• Machine: What is your destination?
• Human: Honolulu
• Machine: When do you wish to travel?
• Human: Next Friday
• Machine, once all information has been gathered: So you wish to travel from [...] to [...] on [...], via [...], is that correct?
• Human: (Yes|No)
• Machine, if yes: Thank you very much for your booking. (Data are sent to the server.)
• Machine, if no: Sorry you changed your mind.

        我们的目标是实现这种行为,以及更好的功能:如果关于方式、起点、目的地和日期的信息同时给出,那么这些信息也会被收集。

3. 具体流程

        在Dialogflow的网页上,我们访问 https://dialogflow.cloud.google.com/#/getStarted 来开始创建一个代理。我们为其选择一个名称、一种语言以及一个时区。

创建完成后,我们需要提供:

3.1 实体(Entities)

        实体在Dialogflow中用于识别用户对话中的关键信息。在这个例子中,涉及两个主要实体:出行方式和二元答案(是或否)。

        步骤如下:

        1. 创建名为@travelmode的实体:我们首先点击“实体(Entities)”按钮,然后点击右侧的“+”号,输入实体名称“travelmode”。在接下来的空白行中,我们将输入所有可能的出行方式类型,并在右侧填写它们的同义词。例如,飞行(flight)的同义词包括飞机(plane)、飞机(aeroplane)和航班(airflight);火车(train)的同义词包括铁路(railways);公交车(bus)的同义词包括道路交通(road transportation);船(ship)的同义词包括海(sea)和小船(boat)。

        2. 保存实体:完成实体及其同义词的输入后,不要忘记点击“保存(Save)”以保存这些信息。

        3. 创建二元答案实体:我们还需要创建一个名为“choice”的实体,用于识别用户的是或否回答。点击“创建实体(CREATE ENTITY)”,并为其添加值“yes”和“no”,以及它们的同义词,比如“绝对是(absolutely)”、“绝对不(definitely not)”、“好的(ok)”、“当然(sure)”等。

        通过这样的设置,Dialogflow代理能够理解和处理用户关于出行方式的查询,以及接收用户的确认或否认回答。这对于创建流畅的对话体验至关重要。

3.2 意图(Intents)

        这段文字描述的是在Dialogflow中创建和配置意图(Intents)的过程,特别是默认欢迎意图(Default Welcome Intent)和默认后备意图(Default Fallback Intent)。意图包含一个或多个训练短语、一个动作名称、参数和响应:

3.2.1 默认欢迎意图(Default Welcome Intent)

        这是当用户开始与代理交互时触发的意图。它通常包含一系列的预定义问候语。在Dialogflow中设置这个意图时,选择the Default Welcome intent ,勾选这个复选框并双击相应的行,然后可以看到并编辑一系列预定义的问候语,比如:“What can I do for you?”设置完成后,记得保存。

3.2.2 默认后备意图(Default Fallback Intent)

        当代理不能匹配到用户说话中的任何其他意图时,将触发这个后备意图。它通常用于告诉用户代理没有理解他们的意图,并可以提示用户重新表述他们的请求。

3.2.3 创建新的意图

        在设置了默认欢迎意图之后,你需要创建具体的意图来处理用户的特定请求。例如,你可能会创建一个名为“Travel”的意图来处理与旅行相关的请求。要创建这样一个意图,你需要到“Intents”菜单,点击“创建意图(Create Intent)”并给它命名。

        接下来,你需要提供该意图的特征性句子,并确保其中的实体能被正确识别。这可以通过点击“添加用户表达(Add user expression)”来完成,并添加如“I have to go to Berlin”或“I need to travel from Nantes to Strasbourg”这样的句子。

        这个过程是为了让Dialogflow代理能够理解用户的意图并做出适当的响应。训练短语是教导代理如何识别特定用户请求的示例。动作名称、参数和响应则用于定义代理在识别到意图后应当执行的动作和给出的答复。通过这种方式,你可以为代理配置一系列不同的意图,以处理各种用户可能提出的请求。

        当你在Dialogflow中输入示例句子时,如果系统识别出了城市名称,它会自动将这些名称标记为内置系统实体@sys.geo-city的值。对于这些自动识别的值,你需要创建参数:

        对于第一个城市名称(起点),你需要创建一个参数并命名为“origin”,通常会用粉红色来标记。
        对于第二个城市名称(目的地),创建另一个参数并命名为“destination”,通常会用紫色来标记。
        你还需要为旅行方式和日期创建参数,这些参数的类型分别是`@travelmode`和`@sys.date`,并将它们分别命名为`travelmode`和`date`。

        在你将这些参数标记为“必需(REQUIRED)”之后,如果用户在对话中没有提供这些信息,系统就会询问用户这些问题来获取这些值。你设置的参数顺序将决定系统询问这些问题的顺序。

        此外,你还需要为用户提供一个响应。这个响应会在所有必要信息被收集完毕后给出。例如:“So you wish to travel from $origin to $destination on $date, via $travelmode, is that correct?”这里的带有美元符号的变量代表着收集到的参数值。

3.2.4 第二个意图        

        接下来,你需要构建一个名为“确认(Confirmation)”的第二个意图。当用户回复确认所提供的信息是正确的时,用户的回复将是二元的(即是或否),系统必须能够识别出这个“是”或“否”是对预订信息的确认。为了实现这一点,你需要使用上下文(Context)。上下文可以帮助系统理解这个简单的“是”或“否”回复是在确认预订的特定环境中给出的。

3.3 上下文(Contexts)

        在Dialogflow中,上下文(Contexts)是用来保存用户与代理之间对话的状态信息的。上下文分为输入上下文(Input Contexts)和输出上下文(Output Contexts)两种:

3.3.1 输出上下文(Output Context)

        可以附加到一个意图(Intent)上。
        当一个意图被触发后,它可以设置一个或多个输出上下文,这些上下文会影响接下来哪个意图可能会被激活。
        输出上下文相当于告诉Dialogflow:“在这个对话的下一个回合中,如果用户说了某些话,你应该考虑这个上下文信息来理解他们的意图”。

3.3.2 输入上下文(Input Context)

        在创建或编辑一个意图时,可以指定一个或多个输入上下文,这些输入上下文必须已经在之前的对话中被设置为输出上下文。
        输入上下文相当于一个先决条件,只有当这个上下文存在时,意图才能被触发。

        通过使用上下文,Dialogflow可以处理更复杂的对话流程,使得即使是非常通用的用户表达,如“是”或“否”,也能在对话的特定点得到正确的理解。例如,如果用户在预订流程的确认步骤中说“是”,Dialogflow可以理解这是对预订确认的肯定回答;而如果用户在被问及是否需要帮助时说“是”,Dialogflow则会理解这是在请求帮助。

        Dialogflow中的上下文有一个持续时间的概念,最长可以持续20分钟。如果在这段时间内没有被更新,那么上下文会自动清除,Dialogflow就会“忘记”这些上下文信息。这意味着代理不会永久记住对话的每个环节,除非开发者通过编程方式去维护和更新上下文的状态。

3.4 Fulfillment

        在Dialogflow中,Fulfillment是一个功能,它允许每个意图在被触发时与一个外部的服务器进行交云。这通常用于处理复杂的逻辑、与外部API交互、访问数据库或执行一些不适合直接在Dialogflow中处理的任务。

3.4.1 启用Fulfillment

        对于一个特定的意图,你可以选择是否启用Fulfillment。如果启用,当这个意图被触发时,Dialogflow会向你指定的URL发送一个webhook请求。

3.4.2 设置Fulfillment

        在Dialogflow的左侧面板中,找到并点击“Fulfillment”部分。
        在这里,你需要启用“Webhook”选项,并且输入你的服务器端点URL。

3.4.3 发送JSON数据

        当一个意图触发Fulfillment时,Dialogflow会使用POST方法向你的服务器发送JSON格式的数据。
        这个数据包含了触发意图的用户的原始输入、解析出的参数、意图的信心分数等信息。

3.4.4 Webhook响应

        你的服务器在接收到Dialogflow的请求后,需要对其进行处理并返回一个JSON格式的响应。
        这个响应可以包含返回给用户的文本消息,也可以包含其他复杂的指令,如设置上下文、触发事件等。

        例如,用户说“是的”,触发了名为“Confirmation”的意图,Dialogflow会发送一个包含所有必要预订参数的JSON数据到你的服务器。这个数据中包含了用户的确认信息、预订的起始地、目的地、旅行方式、日期等信息。

        然后你的webhook服务器简洁地回复了一条消息:

{"fulfillmentText": "Thank you very much for your booking."
}

        这条消息随后会被Dialogflow处理,并显示给用户作为回答。这样,Fulfillment就连接了Dialogflow代理和你的服务逻辑,实现了代理的扩展和集成。

        如下是一个事例:

{
"responseId": "ac201302-9fe4-4ba2-b83d-50de537ab5f8-59c3eb0f",
"queryResult": {
"queryText": "Yes",
"parameters": {
"choice": "yes"
},
"allRequiredParamsPresent": true,
"fulfillmentText": "Thank you very much for your booking.",
"fulfillmentMessages": [
{
"text": {
"text": [
"Thank you very much for your booking."
]
}
}
],
"outputContexts": [
{
"name": "projects/travel-lcky/agent/sessions/846564dc-8fc3-eae6-9349-8347e4a95b30/contexts/confirmation",
"lifespanCount": 5,
"parameters": {
"origin": "Caracas",
"origin.original": "Caracas",
"destination": "York",
"destination.original": "York",
"travelmode": "train",
"travelmode.original": "Train",
"date": "2021-02-03T12:00:00+01:00",
"date.original": "Tomorrow",
"choice": "yes",
"choice.original": "Yes"
}
},
{
"name": "projects/travel-lcky/agent/sessions/846564dc-8fc3-eae6-9349-8347e4a95b30/contexts/__system_counters__",
"parameters": {
"no-input": 0,
"no-match": 0,
5
"choice": "yes",
"choice.original": "Yes"
}
}
],
"intent": {
"name": "projects/travel-lcky/agent/intents/c718acfb-e050-4dda-8c9b-e7e0c940baf9",
"displayName": "Confirmation2",
"endInteraction": true
},
"intentDetectionConfidence": 1,
"languageCode": "en"
},
"originalDetectIntentRequest": {
"source": "DIALOGFLOW_CONSOLE",
"payload": {}
},
"session": "projects/travel-lcky/agent/sessions/846564dc-8fc3-eae6-9349-8347e4a95b30"
}
To this, our webhook (see Section 3 for the code) has answered very laconically by
{
"fulfillmentText": "Thank you very much for your booking."
}

4. 与本地服务器的通信

        本节讲述了如何与本地服务器进行通信,我们使用Python设置本地服务器。当然,你也可以选择其他编程语言,主要任务是读取JSON数据,分析它,并以JSON格式响应。例如,除了本地Python服务器,还可以使用学校的PHP平台,并通过ngrok进行重定向。

    我们开始搭建一个能够处理Dialogflow webhook请求的本地服务器环境。通过这样的服务器,你可以对Dialogflow从用户那里收集到的数据进行更复杂的处理,并根据分析结果返回响应。这对于创建更加动态和交互性强的对话体验非常有帮助。

        使用Python是因为它的简洁性和广泛的应用,但核心概念和流程对于使用其他语言(如PHP)的服务器设置同样适用。关键在于正确处理进来的JSON格式的请求数据,并返回一个符合Dialogflow webhook格式要求的JSON响应。

具体步骤:

4.1 选择工作目录

        首先,你需要去到一个用于存放文件的目录。需要注意的是,出于安全考虑,不应选择存放个人数据的目录。

4.2 创建Python文件

        在选定的目录中创建一个名为`app.py`的Python文件。如下

# import flask dependencies
from flask import Flask, request, make_response, jsonify# initialize the flask app
app = Flask(__name__)# default route
@app.route('/')
def hello_world():return 'Hello World!'# function for responses
def results():# build a request objectreq = request.get_json(force=True)# fetch action from jsonaction = req.get('queryResult').get('parameters').get("pizza")# return a fulfillment responsereturn {'fulfillmentText': u'La pizza qui vous intéresse est : '+str(action)}# create a route for webhook
@app.route('/webhook', methods=['POST', 'GET'])
def webhook():# return responsereturn make_response(jsonify(results()))# run the app
if __name__ == '__main__':app.run(debug=True)

4.3 设置Flask应用

        在控制台中,导航到你放置`app.py`文件的目录。
        通过输入以下命令来设置Flask环境变量:

export FLASK_APP=app.py

        指定Flask应用的入口文件。

export FLASK_ENV=development

        设置Flask运行在开发环境,启用调试模式。
        输入flask run来启动Flask服务器。如果提示找不到`flask`命令,可能是因为Flask安装在系统路径之外的目录中。你可能需要找到Flask的安装位置并相应地调整系统路径。

        例如:

/usr/local/Cellar/python@3.9/3.9.1/Frameworks/Python.framework/Versions/3.9/bin/flask

4.4 Flask服务器运行情况

        控制台将显示服务器运行的信息,包括环境设置、调试模式状态和服务运行的本地地址(默认是http://127.0.0.1:5000)。

 * Serving Flask app "app.py" (lazy loading)* Environment: development* Debug mode: on* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)* Restarting with watchdog (fsevents)* Debugger is active!* Debugger PIN: 496-665-426

        保持这个控制台窗口开启,不要关闭。

4.5 使用ngrok进行外部访问转发

        在另一个终端窗口中,导航到你解压ngrok的位置。

./ngrok http http://127.0.0.1:5000

        输入上方命令来启动ngrok,它会创建一个公网可访问的URL,并将请求转发到你的本地服务器。
        ngrok会提供一个HTTPS格式的公网URL(例如:https://27f95cd2.ngrok.io),这是用于外部访问你的本地服务器的地址。例如:

ngrok                                                                                                                                  (Ctrl+C to quit)Build better APIs with ngrok. Early access: ngrok.com/early-access                                                                                     Session Status                online                                                                                                                   
Account                       liujingze888888@gmail.com (Plan: Free)                                                                                   
Version                       3.5.0                                                                                                                    
Region                        Europe (eu)                                                                                                              
Latency                       41ms                                                                                                                     
Web Interface                 http://127.0.0.1:4040                                                                                                    
Forwarding                    https://269d-89-234-160-214.ngrok-free.app -> http://127.0.0.1:5000                                                      Connections                   ttl     opn     rt1     rt5     p50     p90                                                                              0       0       0.00    0.00    0.00    0.00                                                                             

4.6 在Dialogflow中配置Fulfillment

        将ngrok提供的HTTPS URL加上`/webhook`后缀(非常重要,不要遗忘`/webhook`),复制到Dialogflow的Fulfillment页面中的URL字段。
        点击“保存”完成配置。

4.7 开始修改代码吧!

        现在,你的本地服务器就可以接收来自Dialogflow的请求,并返回响应了。我们拥有了完全的自由来编写Python代码,分析传入的请求并做出适当的响应.这为你提供了极大的自由度来编写Python代码,分析传入的请求,并做出适当的响应你可以在https://cloud.google.com/dialogflow/docs/fulfillment-how 上找到更多信息,包括本地服务器的响应也可以改变上下文(使用output_contexts[]键)、发送一个将触发另一个意图的“事件”等。响应必须在64kb以下,并且在收到请求后的10秒内到达(Dialogflow对响应时间有要求)。

  1. 主要基于Dialogflow的使用,只需要很少的本地编程,或者
  2. 使用Dialogflow作为仅识别意图的外壳,并且所有其他的处理都在本地完成

5. 分析python代码

        这段代码是一个简单的Flask应用的示例,用于创建一个本地服务器。以下是该Python代码的详细解释:

5.1 导入Flask依赖

        使用from flask import Flask, request, make_response, jsonify来导入Flask框架所需的依赖项。

5.2 初始化Flask应用

        app = Flask(__name__)`初始化一个Flask应用实例。

5.3 默认路由

        使用`@app.route('/')装饰器定义一个路由。当访问http://127.0.0.1:5000/时,这个路由会被触发。
        def hello_world(): return 'Hello World!'定义了一个函数,当访问根路径('/')时,返回"Hello World!"字符串。

5.4 路由装饰器

        @app.route 是一个Python装饰器,用于修改紧随其后的函数。它的参数是查询中请求的路径。在这里,它指的是Flask执行的“目录”的根路径。当我们看到以/webhook结尾的URL时,我们可能会误以为我们将进入一个名为webhook的目录,实际上并非如此:Flask拦截我们向服务器请求的URL,并使用它来执行紧随装饰器之后的函数,这里是`hello_world`(函数名可以是任意的)。

5.5 响应函数

        定义了一个`results`函数,该函数用于检索附加到请求的JSON数据并将其存储在`req`中。然后它遵循JSON结构来获取键值`choice`并将其存储在`resu`中。注意,当变量`resu`接收其值时,其类型为None,使用它之前必须将其转换为字符串。最后,我们创建一个字典条目,其键是`fulfillmentText`,其值是我们想要发送的字符串;最后我们将这个字典作为函数的输出返回。

5.6 为webhook创建路由

        使用`@app.route('/webhook', methods=['POST', 'GET'])`装饰器定义一个webhook路由,并激活POST和GET方法。我们给它的函数是`make_response`,并向其提供`results`函数(如上定义)的json化输出。

5.7 运行应用

        if __name__ == '__main__: app.run(debug=True)`这段代码表明,如果应用作为主程序执行(而不是作为另一个应用的模块),则名称将是`__main__`,因此我们将启动应用。这三行代码对我们来说并不重要。

        总的来说,这段代码展示了如何使用Flask创建一个简单的Web服务器,以及如何定义路由来处理不同的HTTP请求,并根据请求返回相应的响应。

6. 修改后的python代码

# import flask dependencies
from flask import Flask, request, jsonify# initialize the flask app
app = Flask(__name__)# default route
@app.route('/')
def hello_world():return 'Hello World!'# function for responses
def results():# build a request objectreq = request.get_json(force=True)# fetch parameters from jsonparameters = req.get('queryResult').get('parameters')# Check if the user's choice or queryText is 'yes'user_says = req.get('queryResult').get('queryText').lower()  # Convert to lower case to ensure consistency# Initialize an empty response_dataresponse_data = {}# Check if the user said 'yes'if user_says == 'yes':# Construct the response for 'yes'response_data = {'fulfillmentText': 'Thank you very much for your booking.'}else:# Handle other inputs: you might want to fetch other parameters or construct a default responseorigin = parameters.get('origin')destination = parameters.get('destination')travelmode = parameters.get('travelmode')date = parameters.get('date')response_data = {'origin': origin,'destination': destination,'travelmode': travelmode,'date': date,}print("Sending response data to Dialogflow:")print(response_data)# Directly return the constructed JSON datareturn response_data# create a route for webhook
@app.route('/webhook', methods=['POST', 'GET'])
def webhook():# directly return jsonify of results()return jsonify(results())# run the app
if __name__ == '__main__':app.run(debug=True)

记得开启

7. 测试结果

8. 知识拓展——Small Talk

        "小谈话"(Small Talk)在Dialogflow的上下文中指的是一种社交性的对话模式,旨在进行非信息性的社交互动,而不是交换实际信息。这种模式更多地是关于日常的寒暄或打招呼,比如聊天气、个人感受等。这与Smalltalk编程语言不同,后者是一种在1972年于施乐公司(Xerox)创建,并曾经在一些学校教授的面向对象编程语言。

        在Dialogflow中,可以通过侧边栏中的“Small Talk”选项来激活这个功能。启用后,代理(Agent)将能够自动处理用户的常见非信息性问题,如“我睡不着”或“你多大了”。Dialogflow的小谈话功能内置了一系列预定义的回答,用于响应用户的这类问题,从而不需要开发者额外编写这部分对话逻辑。

        Eliza是一个更早的程序,用于模拟罗杰斯心理治疗师(Rogerian psychotherapist),它通过反问用户来引导对话。它是人工智能早期的一个里程碑,展示了机器能够如何模仿人类的非信息性交流。

        两者的区别在于:

        Dialogflow的小谈话功能提供了更加人性化和多样化的预设回复,让聊天机器人能够更自然地融入日常对话中。
        Eliza通过特定的对话模式来模仿心理治疗师,通过反问用户的问题,旨在让用户自己探索自己的想法和感受。

        如果你有兴趣了解这些早期的人工智能对话系统,Eliza是一个很好的起点,它提供了一个简单的模型来理解机器是如何尝试模拟人类的对话的。而Dialogflow的小谈话功能则体现了在这方面取得的进步,它提供了更多预设的社交寒暄回复,可以直接集成在现代的聊天机器人中。

相关文章:

自然语言处理(NLP)—— Dialogflow ES聊天机器人

1. 背景介绍 这个实验室的目标是让你了解并使用Google的Dialogflow服务。Dialogflow是一个可以让你创建聊天机器人的服务,这个过程不需要或者只需要很少的编程技能。 1.1 账号的创建 为了完成这个实验室,你需要在以下网站上创建账号&#xff1a…...

C++俄罗斯方块 -- 菜单展示和选择 -- 方法

short Menu() //选中开始游戏返回1&#xff0c;离开则返回2 {short choice 1;//跟踪用户选中的选项char c; //记录用户按键信息system("cls");SetPos(9, 12); //设置输出坐标&#xff0c;12行9列cout << "┌────────┐";SetPos(9, 13);cou…...

面试150 颠倒二进制位 位运算分治 逻辑右移

Problem: 190. 颠倒二进制位 文章目录 思路复杂度位运算分治法 思路 &#x1f468;‍&#x1f3eb; 参考题解 >>>&#xff1a;逻辑右移&#xff08;符号位一起移动&#xff0c;高位补零&#xff09; 复杂度 时间复杂度: O ( log ⁡ n ) O(\log{n}) O(logn) 空间…...

php 函数三

一 对称加密 1.1 openssl 1.1.1 openssl_get_cipher_methods(bool $aliases false) 获取可用的加密算法。包含可用加密算法的array。 请注意&#xff1a;在 OpenSSL 1.1.1 版本之前&#xff0c;返回加密算法的拼法大小写都有&#xff1b; 从 OpenSSL 1.1.1 开始&#xff0c…...

Windows下配置多个账号的git ssh

生成密钥 已经有一个密钥的情况下&#xff0c;用下面的命令生成一个新密钥&#xff0c;注意为了防止原始密钥文件被覆盖&#xff0c;需要给一个新名字&#xff1a; ssh-keygen -t rsa -f C:\\Users\\xxx\\.ssh\\id_rsa_xxx -C "xxxemail.com"给GitHub配置SSH Key …...

【漏洞复现】电信网关配置管理系统SQL注入漏洞

Nx01 产品简介 电信网关配置管理系统是一个用于管理和配置电信网络中网关设备的软件系统。它可以帮助网络管理员实现对网关设备的远程监控、配置、升级和故障排除等功能&#xff0c;从而确保网络的正常运行和高效性能。 Nx02 漏洞描述 电信网关配置管理系统存在SQL注入漏洞,攻…...

2018年苏州大学837复试机试C/C++

2018年苏州大学复试机试 要求 要求用C/C编程&#xff1b;对程序中必要的地方进行注释。上机规则 请在电脑桌面上新建一个文件夹文件夹名为考试姓名&#xff08;中文&#xff09;&#xff1b;考试完毕后&#xff0c;将所编写的文件放在上述文件中。 第一题&#xff08;20分&…...

【Jenkins】pipeline基本使用

目录 一、pipeline 二、创建pipeline项目 1、安装pipeline插件 2、创建pipeline项目 三、pipeline语法 1、pipeline组成 2、agent&#xff1a;指定流水线的执行位置&#xff0c;流水线中每个阶段都必须在某个地方执行 3、stage&#xff1a;阶段&#xff0c;代表流水线的…...

Bytebase 签约 Vianova,助力欧洲城市交通智能平台中 Snowflake 和 PG 的变更自动化及版本控制

在数字化发展的浪潮中&#xff0c;自动化数据库变更管理成为提升产品上线效率、降低人为失误风险的关键工具&#xff0c;同时促进流程的一致性与标准化&#xff0c;确保合规性和变更的可追溯性。近日&#xff0c;数据库 DevOps 团队协同管理工具 Bytebase 签约欧洲交通数据管理…...

SpringBoot 事务管理Transactional 数据回滚 数据一致性

介绍 SpringBoot当中的事物他保证了一致性&#xff0c;要么全部一起成功&#xff08;提交&#xff09;&#xff0c;要么一起失败&#xff0c;失败&#xff08;回滚&#xff09;后数据会回到当初的样子&#xff0c;是一组操作的集合。 事物类型 开启事物提交事物回滚事物 案…...

vue使用pdf.js实现在线查看pdf文件

需求&#xff1a;有一个列表页&#xff0c;用户点击查看&#xff0c;弹层展示后台接口返回的pdf内容(不是文件、地址之类的&#xff0c;乱码的pdf铭文(二进制文件流)) 1、pdf.js安装 npm install --save vue-pdf2、正文代码 <template><div><el-table :data&q…...

java---查找算法(二分查找,插值查找,斐波那契[黄金分割查找] )-----详解 (ᕑᗢᓫ∗)˒

目录 一. 二分查找&#xff08;递归&#xff09;&#xff1a; 代码详解&#xff1a; 运行结果&#xff1a; 二分查找优化&#xff1a; 优化代码&#xff1a; 运行结果&#xff08;返回对应查找数字的下标集合&#xff09;&#xff1a; ​编辑 二分查找&#xff08;非递归…...

鸿蒙应用/元服务开发-窗口(Stage模型)设置悬浮窗

一、设置悬浮窗说明 悬浮窗可以在已有的任务基础上&#xff0c;创建一个始终在前台显示的窗口。即使创建悬浮窗的任务退至后台&#xff0c;悬浮窗仍然可以在前台显示。通常悬浮窗位于所有应用窗口之上&#xff1b;开发者可以创建悬浮窗&#xff0c;并对悬浮窗进行属性设置等操…...

springboot集成easypoi导出多sheet页

pom文件 <dependency><groupId>cn.afterturn</groupId><artifactId>easypoi-base</artifactId><version>4.1.0</version> </dependency> 导出模板&#xff1a; 后端代码示例&#xff1a; /*** 导出加油卡进便利店大额审批列…...

自己动手打包element UI官方手册文档教程

经常用element ui朋友开发的比较郁闷&#xff0c;官方文档网基本上都是打不开的&#xff0c; 官方&#xff1a;https://element.eleme.io/ 一直打不开&#xff0c;分析下是里面用的cdn链接ssl证书无效。 就想着自己搭建一个element UI文档 自己搭建的&#xff1a; Element文档网…...

《计算机网络简易速速上手小册》第5章:无线网络和移动通信(2024 最新版)

5.1 WLAN的工作原理 - 揭秘无线局域网络的魔法 5.1.1 基础知识 无线局域网络&#xff08;WLAN&#xff09;允许设备通过无线方式连接到一个局部区域网络&#xff0c;主要基于IEEE 802.11标准&#xff0c;俗称Wi-Fi。WLAN的核心是无线路由器&#xff0c;它不仅充当着网络中各设…...

2024PMP考试新考纲-近年PMP真题练一练和很详细解析(3)

今天华研荟继续为您分享和解析PMP真题&#xff0c;一方面让大家感受实际的PMP考试和出题形式&#xff0c;另一方面是通过较详细的解题思路和知识讲解帮助大家最后一个多月有效备考&#xff0c;一次性3A通过2024年PMP考试。 2024年PMP考试新考纲-近年真题随机练一练 (注&#x…...

java SpringBoot2.7整合Elasticsearch(ES)7 进行文档增删查改

首先 我们在 ES中加一个 books 索引 且带有IK分词器的索引 首先 pom.xml导入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-elasticsearch</artifactId> </dependency>applicatio…...

动态内存管理(2)

文章目录 4. 几个经典的笔试题4.1 题目14.2 题目24.3 题目34.4 题目4 5. C/C程序的内存开辟6. 动态通讯录7. 柔性数组7.1 柔性数组的特点7.2 柔性数组的使用7.3 柔性数组的优势 4. 几个经典的笔试题 4.1 题目1 #include <stdio.h> #include <stdlib.h> #include …...

使用 git 上传文件时,运行 命令 git pull origin 时未成功,出现报错信息

项目场景&#xff1a; 背景&#xff1a; 使用 git 上传文件时&#xff0c;运行 命令 git pull origin 时未成功&#xff0c;出现报错信息 问题描述 问题&#xff1a; $ git pull origin print --allow-unrelated-histories error: Pulling is not possible because you hav…...

Linux文件编译

目录 一、GCC编译 1.直接编译 2.分步编译 预处理&#xff1a; 编译&#xff1a; 汇编&#xff1a; 链接&#xff1a; 3.多文件编译 4.G 二、Make 1.概述 2.使用步骤 3.makefile创建规则 3.1一个基本规则 3.2两个常用函数 4.示例文件 三、GDB 示例&#xff1a;…...

homeword_day1

第一章 命名空间 一&#xff0e;选择题 1、编写C程序一般需经过的几个步骤依次是&#xff08; B &#xff09; A. 编辑、调试、编译、连接 B. 编辑、编译、连接、运行 C. 编译、调试、编辑、连接 D. 编译、编辑、连接、运行 2、所谓数据封装就是将一组数据和与这组数据…...

ChatGPT论文指南|ChatGPT论文写作过程中6个润色与查重提示词

论文完成初稿之后&#xff0c;一般情况下&#xff0c;宝子们还需要找专家给我们提出评审意见。找专家评审其实并不容易&#xff0c;即使对老师来说&#xff0c;找人评审论文也是一件苦活。我们这个时候可以通过文字提示让 ChatGPT充当我们的评审专家&#xff0c;为论文提出问题…...

论文阅读:Learning Lens Blur Fields

这篇文章是对镜头模糊场进行表征学习的研究&#xff0c;镜头的模糊场也就是镜头的 PSF 分布&#xff0c;镜头的 PSF 与物距&#xff0c;焦距&#xff0c;光学系统本身的像差都有关系&#xff0c;实际的 PSF 分布是非常复杂而且数量也很多&#xff0c;这篇文章提出用一个神经网络…...

SpringBoot整合Knife4j接口文档生成工具

一个好的项目&#xff0c;接口文档是非常重要的&#xff0c;除了能帮助前端和后端开发人员更快地协作完成开发任务&#xff0c;接口文档还能用来生成资源权限&#xff0c;对权限访问控制的实现有很大的帮助。 这篇文章介绍一下企业中常用的接口文档工具Knife4j&#xff08;基于…...

爬虫(三)

1.JS逆向实战破解X-Bogus值 X-Bogus:以DFS开头&#xff0c;总长28位 答案是X-Bogus,因为会把负载里面所有的值打包生成X-Boogus 1.1 找X-Bogus加密位置&#xff08;请求堆栈&#xff09; 1.1.1 绝招加高级断点&#xff08;日志断点&#xff09; 日志断点看有没有X-B值 日志…...

03 动力云客项目之登录功能后端实现

1 准备工作 1.1 创建项目 使用Spring initializr初始化项目 老师讲的是3.2.0, 但小版本之间问题应该不大. 1.2 项目结构 根据阿里巴巴Java开发手册确定项目结构 1.3 分层领域模型 【参考】分层领域模型规约&#xff1a; • DO&#xff08;Data Object&#xff09;&am…...

时光峰峦文物璀璨,预防性保护筑安全

在璀璨的历史长河中&#xff0c;珍贵文物如同时间的印记&#xff0c;承载着过往的辉煌。《人文山水时光峰峦——多彩贵州历史文化展》便是这样一场文化的盛宴&#xff0c;汇聚了众多首次露面的宝藏。然而&#xff0c;文物的保存对环境要求极为苛刻&#xff0c;温湿度波动都可能…...

Redis面试题43

人工智能在未来会有哪些可能的发展趋势&#xff1f; 答&#xff1a;人工智能在未来将继续迎来许多可能的发展趋势&#xff0c;以下是一些可能的方向&#xff1a; 更强大的算法和模型&#xff1a;人工智能算法和模型将不断改进和优化&#xff0c;为更复杂的数据和问题提供更强大…...

Redis -- list列表

只有克服了情感的波动&#xff0c;才能专心致志地追求事业的成功 目录 列表 list命令 lpush lpushx rpush rpushx lrange lpop rpop lindex linsert llen lrem ltrim 阻塞命令 小结 列表 列表相当于 数组或者顺序表。 列表类型是用来存储多个有序的字符串&…...