你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

使用 Azure Cosmos DB for MongoDB vCore 的 AI 增强广告生成

本指南演示如何使用个性化 AI 助手 Heelie 创建与受众产生共鸣的动态广告内容。 通过 Azure Cosmos DB for MongoDB vCore,我们利用矢量相似性搜索功能在语义上分析库存描述,并将其与广告主题匹配。 通过使用 OpenAI 嵌入技术为库存描述生成矢量来实现此目的,从而显著增强其语义深度。 然后,这些矢量在 Cosmos DB for MongoDB vCore 资源中存储和编制索引。 生成广告内容时,我们会矢量化广告主题,以查找最匹配的库存项目。 随后是检索增强生成 (RAG) 过程,其中顶级匹配项被发送到 OpenAI 以制作引人注目的广告。 GitHub 存储库中提供了应用程序的整个代码库以供参考。

功能

  • 矢量相似性搜索:使用 Azure Cosmos DB for MongoDB vCore 强大的矢量相似性搜索来改进语义搜索功能,从而使基于广告内容查找相关库存项目更容易
  • OpenAI 嵌入:利用 OpenAI 中的先进嵌入技术来为库存描述生成矢量。 此方法允许在库存和广告内容之间进行更微妙和语义更丰富的匹配。
  • 内容生成:采用 OpenAI 的高级语言模型来生成引人入胜、聚焦潮流的广告。 此方法可确保内容不仅相关,而且吸引目标受众。

先决条件

  • Azure OpenAI:让我们设置 Azure OpenAI 资源。 应用程序当前仅提供对此服务的访问权限。 可以通过在 https://aka.ms/oai/access 上填写表单来申请对 Azure OpenAI 的访问权限。 获得访问权限后,请完成以下步骤:
    • 按照本快速入门创建 Azure OpenAI 资源。
    • 部署 completionsembeddings 模型。
      • 有关 completions 的详细信息,请转到此处
      • 有关 embeddings 的详细信息,请转到此处
    • 记下终结点、密钥和部署名称。
  • Cosmos DB for MongoDB vCore 资源:首先,请遵循本快速入门指南免费创建 Azure Cosmos DB for MongoDB vCore 资源。
    • 记下连接详细信息。
  • Python 环境(>= 3.9 版本),其中包含各种包,例如 numpyopenaipymongopython-dotenvazure-coreazure-cosmostenacitygradio
  • 下载数据文件并将其保存在指定的数据文件夹中。

运行脚本

在深入了解生成 AI 增强型广告的精彩部分之前,我们需要设置环境。 此设置涉及安装必要的包,以确保脚本顺利运行。 下面是一个做好所有工作的分步指南。

1.1 安装必要的包

首先,我们需要安装几个 Python 包。 打开终端并运行以下命令:

 pip install numpy
 pip install openai==1.2.3
 pip install pymongo
 pip install python-dotenv
 pip install azure-core
 pip install azure-cosmos
 pip install tenacity
 pip install gradio
 pip show openai

1.2 设置 OpenAI 和 Azure 客户端

安装必要的包后,下一步涉及为脚本设置 OpenAI 和 Azure 客户端,这对于验证对 OpenAI API 和 Azure 服务的请求至关重要。

import json
import time
import openai

from dotenv import dotenv_values
from openai import AzureOpenAI

# Configure the API to use Azure as the provider
openai.api_type = "azure"
openai.api_key = "<AZURE_OPENAI_API_KEY>"  # Replace with your actual Azure OpenAI API key
openai.api_base = "https://<OPENAI_ACCOUNT_NAME>.openai.azure.com/"  # Replace with your OpenAI account name
openai.api_version = "2023-06-01-preview"

# Initialize the AzureOpenAI client with your API key, version, and endpoint
client = AzureOpenAI(
    api_key=openai.api_key,
    api_version=openai.api_version,
    azure_endpoint=openai.api_base
)

解决方案体系结构

解决方案体系结构

2.创建嵌入和设置 Cosmos DB

设置环境和 OpenAI 客户端后,我们将迁移到 AI 增强型广告生成项目的核心部分。 以下代码基于产品的文本描述创建矢量嵌入,并在 Azure Cosmos DB for MongoDB vCore 中设置数据库以存储和搜索这些嵌入。

2.1 创建嵌入

为了生成引人注目的广告,我们首先需要了解库存中的项目。 我们根据项目描述创建矢量嵌入以执行此操作,这使我们能够以计算机可以理解和处理的形式捕获它们的语义含义。 下面介绍如何使用 Azure OpenAI 为项目描述创建矢量嵌入:

import openai

def generate_embeddings(text):
    try:
        response = client.embeddings.create(
            input=text, model="text-embedding-ada-002")
        embeddings = response.data[0].embedding
        return embeddings
    except Exception as e:
        print(f"An error occurred: {e}")
        return None

embeddings = generate_embeddings("Shoes for San Francisco summer")

if embeddings is not None:
    print(embeddings)

该函数采用文本输入(如产品描述),并使用 OpenAI API 中 client.embeddings.create 方法为该文本生成矢量嵌入。 我们在此处使用 text-embedding-ada-002 模型,但可以根据你的要求选择其他模型。 如果过程成功,它将输出生成的嵌入;否则,它会通过输出错误消息来处理异常。

3.连接并设置 Cosmos DB for MongoDB vCore

随着嵌入准备就绪,下一步是将它们存储在支持矢量相似性搜索的数据库中并对其编制索引。 Azure Cosmos DB for MongoDB vCore 非常适合此任务,因为它专用于在一个位置存储事务数据和执行矢量搜索。

3.1 设置连接

若要连接到 Cosmos DB,我们使用 pymongo 库,这使我们能够轻松与 MongoDB 交互。 以下代码片段与 Cosmos DB for MongoDB vCore 实例建立连接:

import pymongo

# Replace <USERNAME>, <PASSWORD>, and <VCORE_CLUSTER_NAME> with your actual credentials and cluster name
mongo_conn = "mongodb+srv://<USERNAME>:<PASSWORD>@<VCORE_CLUSTER_NAME>.mongocluster.cosmos.azure.com/?tls=true&authMechanism=SCRAM-SHA-256&retrywrites=false&maxIdleTimeMS=120000"
mongo_client = pymongo.MongoClient(mongo_conn)

<USERNAME><PASSWORD><VCORE_CLUSTER_NAME> 分别替换为实际的 MongoDB 用户名、密码和 vCore 群集名称。

4.在 Cosmos DB 中设置数据库和矢量索引

与 Azure Cosmos DB 建立连接后,后续步骤将涉及设置数据库和集合,然后创建矢量索引以启用高效的矢量相似性搜索。 让我们演练这些步骤。

4.1 设置数据库和集合

首先,我们在 Cosmos DB 实例中创建数据库和集合。 方法如下:

DATABASE_NAME = "AdgenDatabase"
COLLECTION_NAME = "AdgenCollection"

mongo_client.drop_database(DATABASE_NAME)
db = mongo_client[DATABASE_NAME]
collection = db[COLLECTION_NAME]

if COLLECTION_NAME not in db.list_collection_names():
    # Creates a unsharded collection that uses the DBs shared throughput
    db.create_collection(COLLECTION_NAME)
    print("Created collection '{}'.\n".format(COLLECTION_NAME))
else:
    print("Using collection: '{}'.\n".format(COLLECTION_NAME))

4.2 创建矢量索引

若要在集合中执行高效的矢量相似性搜索,我们需要创建矢量索引。 Cosmos DB 支持不同类型的矢量索引,下面我们将讨论这两种:IVF 和 HNSW。

IVF

IVF 全称为 Inverted File Index(倒排文件索引),是默认的矢量索引算法,适用于所有群集层。 这是一种近似最近邻域 (ANN) 方法,该方法使用聚类分析来加快对数据集中类似矢量的搜索速度。 若要创建 IVF 索引,请使用以下命令:

db.command({
  'createIndexes': COLLECTION_NAME,
  'indexes': [
    {
      'name': 'vectorSearchIndex',
      'key': {
        "contentVector": "cosmosSearch"
      },
      'cosmosSearchOptions': {
        'kind': 'vector-ivf',
        'numLists': 1,
        'similarity': 'COS',
        'dimensions': 1536
      }
    }
  ]
});

重要

每个矢量属性只能创建一个索引。 也就是说,不能创建指向同一矢量属性的多个索引。 如果要更改索引类型(例如,从 IVF 更改为 HNSW),必须先删除索引,然后再创建新索引。

HNSW

HNSW 代表分层可导航小型世界,这是一种基于图形的数据结构,用于将矢量分区为群集和子群集。 使用 HNSW,执行近似近邻搜索时速度更快,精度更高。 HNSW 是一种近似 (ANN) 方法。 设置方式如下:

db.command(
{ 
    "createIndexes": "ExampleCollection",
    "indexes": [
        {
            "name": "VectorSearchIndex",
            "key": {
                "contentVector": "cosmosSearch"
            },
            "cosmosSearchOptions": { 
                "kind": "vector-hnsw", 
                "m": 16, # default value 
                "efConstruction": 64, # default value 
                "similarity": "COS", 
                "dimensions": 1536
            } 
        } 
    ] 
}
)

注意

HNSW 索引仅在 M40 群集层及更高层上可用。

5.将数据插入集合

现在,将库存数据(包括描述及其相应的矢量嵌入)插入到新创建的集合中。 若要将数据插入集合中,我们使用 pymongo 库提供的insert_many() 方法。 该方法允许我们一次性将多个文档插入到集合中。 我们的数据存储在一个 JSON 文件中,我们将加载该文件,然后将其插入到数据库中。

从 GitHub 存储库下载 shoes_with_vectors.json 文件,并将其存储在项目文件夹中的 data 目录中。

data_file = open(file="./data/shoes_with_vectors.json", mode="r") 
data = json.load(data_file)
data_file.close()

result = collection.insert_many(data)

print(f"Number of data points added: {len(result.inserted_ids)}")

6.Cosmos DB for MongoDB vCore 中的矢量搜索

成功上传数据后,现在可以应用矢量搜索的强大功能基于查询查找最相关的项目。 我们之前创建的矢量索引使我们能够在数据集中执行语义搜索。

为了执行矢量搜索,我们定义了函数 vector_search,该函数接收查询和要返回的结果数。 该函数使用前面定义的 generate_embeddings 函数为查询生成矢量,然后使用 Cosmos DB 的 $search 功能根据其矢量嵌入查找最接近的匹配项目。

# Function to assist with vector search
def vector_search(query, num_results=3):
    
    query_vector = generate_embeddings(query)

    embeddings_list = []
    pipeline = [
        {
            '$search': {
                "cosmosSearch": {
                    "vector": query_vector,
                    "numLists": 1,
                    "path": "contentVector",
                    "k": num_results
                },
                "returnStoredSource": True }},
        {'$project': { 'similarityScore': { '$meta': 'searchScore' }, 'document' : '$$ROOT' } }
    ]
    results = collection.aggregate(pipeline)
    return results

6.2 执行矢量搜索查询

最后,我们使用特定的查询执行矢量搜索函数,并处理结果以显示它们:

query = "Shoes for Seattle sweater weather"
results = vector_search(query, 3)

print("\nResults:\n")
for result in results: 
    print(f"Similarity Score: {result['similarityScore']}")  
    print(f"Title: {result['document']['name']}")  
    print(f"Price: {result['document']['price']}")  
    print(f"Material: {result['document']['material']}") 
    print(f"Image: {result['document']['img_url']}") 
    print(f"Purchase: {result['document']['purchase_url']}\n")

7.使用 GPT-4 和 DALL.E 生成广告内容

我们结合使用所有开发组件制作引人注目的广告,使用 OpenAI 的 GPT-4 撰写文本,使用 DALL·E 3 绘制图像。 它们与矢量搜索结果一起组成完整的广告。 我们还介绍了我们的智能助手 Heelie,它负责创建引人入胜的广告标语。 通过即将发布的代码,你将看到 Heelie 在增强我们的广告创建过程方面所发挥的作用。

from openai import OpenAI

def generate_ad_title(ad_topic):
    system_prompt = '''
    You are Heelie, an intelligent assistant for generating witty and cativating tagline for online advertisement.
        - The ad campaign taglines that you generate are short and typically under 100 characters.
    '''

    user_prompt = f'''Generate a catchy, witty, and short sentence (less than 100 characters) 
                    for an advertisement for selling shoes for {ad_topic}'''
    messages=[
        {"role": "system", "content": system_prompt},
        {"role": "user", "content": user_prompt},
    ]

    response = client.chat.completions.create(
        model="gpt-4",
        messages=messages
    )
    
    return response.choices[0].message.content

def generate_ad_image(ad_topic):
    daliClient = OpenAI(
        api_key="<DALI_API_KEY>"
    )

    image_prompt = f'''
        Generate a photorealistic image of an ad campaign for selling {ad_topic}. 
        The image should be clean, with the item being sold in the foreground with an easily identifiable landmark of the city in the background.
        The image should also try to depict the weather of the location for the time of the year mentioned.
        The image should not have any generated text overlay.
    '''

    response = daliClient.images.generate(
        model="dall-e-3",
        prompt= image_prompt,
        size="1024x1024",
        quality="standard",
        n=1,
        )

    return response.data[0].url

def render_html_page(ad_topic):

    # Find the matching shoes from the inventory
    results = vector_search(ad_topic, 4)
    
    ad_header = generate_ad_title(ad_topic)
    ad_image_url = generate_ad_image(ad_topic)


    with open('./data/ad-start.html', 'r', encoding='utf-8') as html_file:
        html_content = html_file.read()

    html_content += f'''<header>
            <h1>{ad_header}</h1>
        </header>'''    

    html_content += f'''
            <section class="ad">
            <img src="{ad_image_url}" alt="Base Ad Image" class="ad-image">
        </section>'''

    for result in results: 
        html_content += f''' 
        <section class="product">
            <img src="{result['document']['img_url']}" alt="{result['document']['name']}" class="product-image">
            <div class="product-details">
                <h3 class="product-title" color="gray">{result['document']['name']}</h2>
                <p class="product-price">{"$"+str(result['document']['price'])}</p>
                <p class="product-description">{result['document']['description']}</p>
                <a href="{result['document']['purchase_url']}" class="buy-now-button">Buy Now</a>
            </div>
        </section>
        '''

    html_content += '''</article>
                    </body>
                    </html>'''

    return html_content

8.汇总

为了以交互方式生成广告,我们使用用于创建简单 Web UI 的 Python 库 Gradio。 我们定义了一个 UI,该 UI 让用户输入广告主题,然后动态生成并显示生成的广告。

import gradio as gr

css = """
    button { background-color: purple; color: red; }
    <style>
    </style>
"""

with gr.Blocks(css=css, theme=gr.themes.Default(spacing_size=gr.themes.sizes.spacing_sm, radius_size="none")) as demo:
    subject = gr.Textbox(placeholder="Ad Keywords", label="Prompt for Heelie!!")
    btn = gr.Button("Generate Ad")
    output_html = gr.HTML(label="Generated Ad HTML")

    btn.click(render_html_page, [subject], output_html)

    btn = gr.Button("Copy HTML")

if __name__ == "__main__":
    demo.launch()   

输出

输出屏幕

下一步