使用嵌入比较文本#

在本教程中,您将学习如何创建一个 Python 应用程序,该应用程序使用语义嵌入和莱文斯坦相似度来比较两个输入文本。该应用程序与 API 服务器通信以生成嵌入,并以编程方式计算相似度指标。

嵌入是文本字符串含义的数值表示。相似的文本字符串将具有相似的数字,并且数字越接近,主题的相关性就越高,即使单词不同也是如此。例如,由于“vision”和“sight”的含义相似,因此它们的嵌入在数值上可能非常接近。

先决条件
  • 在开始之前,请确保您的机器上已安装 conda 软件包管理器。您可以使用 Anaconda Distribution 或 Miniconda 安装 conda

  • 您必须在本地机器上下载 sentence-similarity 类型模型。

设置您的环境#

在处理新的 conda 项目时,建议您创建一个新的开发环境。按照以下步骤为您的嵌入应用程序设置环境

  1. 打开 Anaconda Prompt(macOS/Linux 上的终端)。

    提示

    如果需要,可以从 IDE(JupyterLab、PyCharm、VSCode、Spyder)中打开此终端。

  2. 创建 conda 环境以开发您的嵌入应用程序,并通过运行以下命令安装您需要的软件包

    conda create --name content-compare python numpy scikit-learn python-Levenshtein requests
    
  3. 通过运行以下命令激活您新创建的 conda 环境

    conda activate content-compare
    

有关管理环境的更多信息和最佳实践,请参阅 环境

构建文本比较器#

下面,您将找到构建文本比较器的必要代码片段,并为每个步骤提供解释,以帮助您了解应用程序的工作原理。文本比较器结合了两种比较文本的方法:使用嵌入的语义相似度和使用莱文斯坦距离的结构相似度。

语义相似度告诉我们两个文本的含义有多接近,而莱文斯坦距离则通过计算将一个字符串转换为另一个字符串所需的编辑次数来查看实际字符的相似程度。总之,这些方法帮助我们了解两个文本字符串的相似程度——它们看起来是否相似,含义是否相同,或两者兼而有之。

使用您首选的 IDE,创建一个新文件并将其命名为 similarian.py

导入库#

我们正在构建的应用程序需要库来处理 HTTP 请求、数值运算和字符串相似度计算。

将以下代码行添加到您的 similarian.py 文件的顶部

import requests
import numpy as np
from sklearn.metrics.pairwise import cosine_similarity
import Levenshtein

设置 base_url#

为了使应用程序能够以编程方式处理文本输入以运行服务器运行状况检查、生成嵌入和执行其他操作,至关重要的是,您需要正确构建应用程序以与 API 服务器及其端点进行交互。

这些 API 端点的 URL 是通过将 base_url 与每个功能的特定 /endpoint 组合而成的。base_URL 可以通过组合 Anaconda AI Navigator 中指定的服务器地址服务器端口来构建,如下所示:http://<SERVER_ADDRESS>:<SERVER_PORT>

设置 base_url 以指向默认服务器地址,方法是将以下行添加到您的文件中。

base_url = 'https://#:8080'

提示

localhost127.0.0.1 在语义上是相同的。

添加 API 调用#

AI Navigator 使用 llama.cpp 的 规范来与 API 服务器的 /embedding 端点进行交互。

提示

API 服务器也与 OpenAI 的 /embeddings API 规范兼容。

要使您的应用程序能够与 API 服务器通信,您必须以服务器可以理解的方式实现进行 API 调用的函数。

GET /health#

在向服务器发送任何请求之前,最好先验证服务器是否正在运行。此函数向 /health 端点发送 GET 请求,并返回一个 JSON 响应,告诉您服务器的状态。

将以下行添加到您的 similarian.py 文件

def get_server_health():
    response = requests.get(f'{base_url}/health')
    return response.json()

POST /embedding#

要与 sentence-similarity 模型交互,您必须有一个函数来访问服务器的 /embedding 端点。此函数处理输入文本并返回其向量表示(嵌入)。

将以下行添加到您的 similarian.py 文件

def get_embedding(input_text):
    data = {"content": input_text}
    headers = {"Content-Type": "application/json"}
    response = requests.post(f"{base_url}/embedding", json=data, headers=headers)

    if response.status_code == 200:
        return response.json()["embedding"]
    else:
        raise Exception(f"Error: {response.status_code}, {response.text}")

构建函数#

现在我们已经添加了 API 调用以与 API 服务器通信,我们需要构建应用程序的核心功能:比较两个文本字符串。这涉及测量它们的语义(基于含义的)和结构(基于字符的)相似度。

compare_texts#

此函数从 main 函数获取两个文本输入,并计算语义和结构相似度得分。

将以下行添加到您的 similarian.py 文件

def compare_texts(text1, text2):
    # Get embeddings and calculate semantic similarity
    emb1 = get_embedding(text1)
    emb2 = get_embedding(text2)
    semantic_sim = cosine_similarity(
        np.array(emb1).reshape(1, -1),
        np.array(emb2).reshape(1, -1)
    )[0][0]

    # Calculate Levenshtein similarity
    distance = Levenshtein.distance(text1.lower(), text2.lower())
    max_length = max(len(text1), len(text2))
    levenshtein_sim = 1 - (distance / max_length)

    return semantic_sim, levenshtein_sim

main#

main 函数将其余函数联系在一起并处理用户输入。它从用户那里获取两个输入,并显示来自相似度计算的结果。

将以下行添加到您的 similarian.py 文件

def main():
    print("Enter two sentences to compare:")
    text1 = input("Sentence 1: ")
    text2 = input("Sentence 2: ")

    print("\nCalculating similarities...")

    try:
        semantic_sim, levenshtein_sim = compare_texts(text1, text2)
        print("\nResults:")
        print(f"Semantic (embedding) similarity: {semantic_sim:.2%}")
        print(f"Levenshtein (string) similarity: {levenshtein_sim:.2%}")
    except requests.exceptions.ConnectionError:
        print("\nError: Could not connect to embedding server at localhost:8080")
        print("Make sure your local embedding server is running")

if __name__ == "__main__":
    main()

与 API 服务器交互#

构建好文本比较器后,就可以比较一些文本了!

  1. 打开 Anaconda AI Navigator 并将模型加载到 API 服务器中

    注意

    必须sentence-similarity 类型模型!

  2. 服务器地址服务器端口保留为默认值,然后单击 启动.

  3. 打开终端并导航到您存储 similarian.py 文件的目录。

    提示

    确保您仍然在 content-compare conda 环境中。

  4. 通过运行以下命令启动文本比较器

    python similarian.py
    

    注意

    每次要运行文本比较器时,都需要运行此命令。

  5. 输入文本字符串,然后按 Enter(Windows)/Return(Mac)。

  6. 输入您要与前一个字符串进行比较的文本字符串,然后再次按 Enter(Windows)/Return(Mac)。

  7. 查看 Anaconda AI Navigator API 服务器日志。如果一切设置正确,服务器日志将填充来自应用程序的流量,从运行状况检查开始。

以下是与文本比较器交互的示例,假设您之前已导航到包含 similarian.py 文件的目录

(content-compare) ➜ python similarian.py
Sentence 1: That book was amazing! I did not see that twist coming!
Sentence 2: That tome was naught but wondrous! The twist therein didst elude mine keenest foresight.

Calculating similarities...

Results:
Semantic (embedding) similarity: 72.61%
Levenshtein (string) similarity: 31.82%

比较句子#

以下是一些示例,您可以使用它们来更好地理解和感受文本比较的工作原理

同义词和释义

尝试用两种不同的方式写出相同的短语,看看语义意义相似度如何保持较高,即使结构相似度差异很大。

The quick brown fox jumped over the lazy dog.
The swift auburn fox leaped above the sluggish canine.
错别字的影响

尝试使用少量错别字来观察语义相似度如何保持一致,而结构相似度由于编辑距离增加而下降。

The quick brown fox jumps over the lazy dog.
The quikc brn fox jumpd ovr the lazy dog.
相反的含义

比较结构相似但含义相反的句子。这突出了即使莱文斯坦相似度保持较高,语义相似度也可能下降。

I love dogs; they are the best.
I hate dogs; they are the worst.

后续步骤#

您可以继续开发和扩展此文本比较器,以处理更高级的用例,例如实施数据库以存储嵌入,从而实现大规模高效比较,从而使您可以构建重复内容检测器、推荐系统或文档聚类应用程序等工具。

或者,如果您已完成此项目,可以删除该文件并通过运行以下命令清理您的 conda 环境

conda deactivate
conda remove --name content-compare --all