다음을 통해 공유


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에 대한 자세한 내용을 보려면 여기로 이동합니다.
    • 엔드포인트, 키, 배포 이름을 기록해 둡니다.
  • MongoDB vCore 리소스용 Cosmos DB: 이 빠른 시작 가이드에 따라 무료로 Azure Cosmos DB for MongoDB vCore 리소스를 만들어 보겠습니다.

    • 연결 세부 정보(연결 문자열)를 기록해 둡니다.
  • numpy, openai, pymongo, python-dotenv, azure-core, azure-cosmos, tenacitygradio와 같은 패키지가 포함된 Python 환경(>= 3.9 버전).

  • 데이터 파일을 다운로드하여 지정된 데이터 폴더에 저장합니다.

스크립트 실행

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 API 및 Azure 서비스에 대한 요청을 인증하는 데 중요한 스크립트용 OpenAI 및 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에 연결하기 위해 MongoDB와 쉽게 상호 작용할 수 있는 pymongo 라이브러리를 사용합니다. 다음 코드 조각은 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
      }
    }
  ]
});

Important

벡터 속성당 하나의 인덱스만 만들 수 있습니다. 즉, 동일한 벡터 속성을 가리키는 인덱스를 두 개 이상 만들 수 없습니다. 인덱스 형식을 변경하려면(예: 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. 모든 항목 요약

광고 생성을 대화형으로 만들기 위해 간단한 웹 UI를 만들기 위한 Python 라이브러리 Gradio를 사용합니다. 사용자가 광고 항목을 입력하고 결과 광고를 동적으로 생성하고 표시할 수 있는 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()   

출력

출력 화면

다음 단계