ترکیب قابلیت vision با فراخوانی توابع

ترکیب قابلیت vision با فراخوانی توابع

function-call, vision
preview

مدل جدید GPT-4 Turbo، اکنون امکان فراخوانی توابع با قابلیت‌های دیداری (vision)و استدلال بهتر را فراهم می‌کند. استفاده از تصاویر با فراخوانی توابع، موارد کاربرد جدید را امکان‌پذیر می‌کند و به شما اجازه می‌دهد فراتر از OCR و توضیحات تصاویر بروید.

ما دو مثال را برای نشان دادن استفاده از فراخوانی توابع با GPT-4 Turbo با قابلیت دیداری بررسی خواهیم کرد:

  1. شبیه‌سازی یک دستیار خدمات مشتری
  2. تحلیل یک نمودار سازمانی برای استخراج اطلاعات کارکنان
برای اجرای کدهای زیر ابتدا باید یک کلید API را از طریق پنل کاربری گیلاس تولید کنید. برای این کار ابتدا یک حساب کاربری جدید بسازید یا اگر صاحب حساب کاربری هستید وارد پنل کاربری خود شوید. سپس، به صفحه کلید API بروید و با کلیک روی دکمه “ساخت کلید API” یک کلید جدید برای دسترسی به Gilas API بسازید.
 1!pip install pymupdf --quiet
 2!pip install openai --quiet
 3!pip install matplotlib --quiet
 4!pip install instructor --quiet
 5
 6import base64
 7import os
 8from enum import Enum
 9from io import BytesIO
10from typing import Iterable, List, Literal, Optional
11
12import fitz
13import instructor
14import matplotlib.pyplot as plt
15import pandas as pd
16from IPython.display import display
17from PIL import Image
18from openai import OpenAI
19from pydantic import BaseModel, Field

1. شبیه‌سازی یک دستیار خدمات مشتری #

ما یک دستیار خدمات مشتری را برای یک سرویس تحویل شبیه‌سازی خواهیم کرد که توانایی تحلیل تصاویر بسته‌ها را دارد. این دستیار اقدامات زیر را بر اساس تحلیل تصویر انجام خواهد داد:

  • اگر بسته در تصویر آسیب دیده باشد، به‌طور خودکار بازپرداخت را انجام می‌دهد.
  • اگر بسته خیس به نظر برسد، محصول جایگزینی را ارسال می‌کند.
  • اگر بسته به نظر عادی و بدون آسیب باشد، آن را به یک نماینده ارجاع می‌دهد.

بیایید نمونه‌هایی از تصاویر بسته‌ها را بررسی کنیم که دستیار خدمات مشتری آن‌ها را تحلیل خواهد کرد تا اقدام مناسب را تعیین کند. ما تصاویر را به عنوان رشته‌های base64 برای پردازش توسط مدل کدگذاری خواهیم کرد.

 1# تابع برای کدگذاری تصویر به صورت base64
 2def encode_image(image_path: str):
 3    if not os.path.exists(image_path):
 4        raise FileNotFoundError(f"Image file not found: {image_path}")
 5    with open(image_path, "rb") as image_file:
 6        return base64.b64encode(image_file.read()).decode('utf-8')
 7
 8# نمونه تصاویر برای تست
 9image_dir = "images"
10image_files = os.listdir(image_dir)
11image_data = {}
12for image_file in image_files:
13    image_path = os.path.join(image_dir, image_file)
14    image_data[image_file.split('.')[0]] = encode_image(image_path)
15    print(f"Encoded image: {image_file}")
16
17def display_images(image_data: dict):
18    fig, axs = plt.subplots(1, 3, figsize=(18, 6))
19    for i, (key, value) in enumerate(image_data.items()):
20        img = Image.open(BytesIO(base64.b64decode(value)))
21        ax = axs[i]
22        ax.imshow(img)
23        ax.axis("off")
24        ax.set_title(key)
25    plt.tight_layout()
26    plt.show()
27
28display_images(image_data)
preview

ما موفق به کدگذاری نمونه تصاویر به صورت رشته‌های base64 و نمایش آن‌ها شدیم. دستیار خدمات مشتری این تصاویر را تحلیل خواهد کرد تا اقدام مناسب را بر اساس وضعیت بسته تعیین کند.

حالا بیایید توابع/ابزارهای لازم برای پردازش سفارش، مانند ارجاع سفارش به نماینده، بازپرداخت سفارش و جایگزینی سفارش را تعریف کنیم. ما از مدل‌های Pydantic برای تعریف ساختار داده‌ها برای اقدامات سفارش استفاده خواهیم کرد.

 1MODEL = "gpt-4-turbo"
 2
 3class Order(BaseModel):
 4    """نمایانگر سفارشی با جزئیات مانند شناسه سفارش، نام مشتری، نام محصول، قیمت، وضعیت و تاریخ تحویل است."""
 5    order_id: str = Field(..., description="شناسه منحصر به فرد سفارش")
 6    product_name: str = Field(..., description="نام محصول")
 7    price: float = Field(..., description="قیمت محصول")
 8    status: str = Field(..., description="وضعیت سفارش")
 9    delivery_date: str = Field(..., description="تاریخ تحویل سفارش")
10
11# توابع جایگزین برای پردازش سفارش
12def get_order_details(order_id):
13    return Order(
14        order_id=order_id,
15        product_name="Product X",
16        price=100.0,
17        status="Delivered",
18        delivery_date="2024-04-10",
19    )
20
21def escalate_to_agent(order: Order, message: str):
22    return f"Order {order.order_id} has been escalated to an agent with message: `{message}`"
23
24def refund_order(order: Order):
25    return f"Order {order.order_id} has been refunded successfully."
26
27def replace_order(order: Order):
28    return f"Order {order.order_id} has been replaced with a new order."
29
30class FunctionCallBase(BaseModel):
31    rationale: Optional[str] = Field(..., description="دلیل برای اقدام.")
32    image_description: Optional[str] = Field(
33        ..., description="توضیحات دقیق تصویر بسته."
34    )
35    action: Literal["escalate_to_agent", "replace_order", "refund_order"]
36    message: Optional[str] = Field(
37        ...,
38        description="پیام به نماینده اگر اقدام به ارجاع به نماینده باشد",
39    )
40
41    def __call__(self, order_id):
42        order: Order = get_order_details(order_id=order_id)
43        if self.action == "escalate_to_agent":
44            return escalate_to_agent(order, self.message)
45        if self.action == "replace_order":
46            return replace_order(order)
47        if self.action == "refund_order":
48            return refund_order(order)
49
50class EscalateToAgent(FunctionCallBase):
51    """ارجاع به نماینده برای کمک بیشتر."""
52    pass
53
54class OrderActionBase(FunctionCallBase):
55    pass
56
57class ReplaceOrder(OrderActionBase):
58    """ابزار برای جایگزینی سفارش."""
59    pass
60
61class RefundOrder(OrderActionBase):
62    """ابزار برای بازپرداخت سفارش."""
63    pass

شبیه‌سازی پیام‌های کاربر و پردازش تصاویر بسته‌ها #

ما پیام‌های کاربر را که حاوی تصاویر بسته‌ها هستند شبیه‌سازی خواهیم کرد و تصاویر را با استفاده از مدل GPT-4 Turbo پردازش خواهیم کرد. مدل ابزار مناسب را بر اساس تحلیل تصویر و اقدامات پیش‌فرض برای بسته‌های آسیب دیده، خیس یا عادی شناسایی خواهد کرد. سپس اقدام شناسایی شده را بر اساس شناسه سفارش پردازش خواهیم کرد و نتایج را نمایش خواهیم داد.

 1ORDER_ID = "12345" 
 2INSTRUCTION_PROMPT = "You are a customer service assistant for a delivery service, equipped to analyze images of packages. If a package appears damaged in the image, automatically process a refund according to policy. If the package looks wet, initiate a replacement. If the package appears normal and not damaged, escalate to agent. For any other issues or unclear images, escalate to agent. You must always use tools!"
 3
 4def delivery_exception_support_handler(test_image: str):
 5    payload = {
 6        "model": MODEL,
 7        "response_model": Iterable[RefundOrder | ReplaceOrder | EscalateToAgent],
 8        "tool_choice": "auto",  
 9        "temperature": 0.0,  
10        "seed": 123, 
11    }
12    payload["messages"] = [
13        {
14            "role": "user",
15            "content": INSTRUCTION_PROMPT,
16        },
17        {
18            "role": "user",
19            "content": [
20                {
21                    "type": "image_url",
22                    "image_url": {
23                        "url": f"data:image/jpeg;base64,{image_data[test_image]}"
24                    }
25                },
26            ],
27        }
28    ]
29    function_calls = instructor.from_openai(
30        OpenAI(
31            api_key=os.environ.get(("GILAS_API_KEY", "<کلید API خود را اینجا بسازید https://dashboard.gilas.io/apiKey>")), 
32            base_url="https://api.gilas.io/v1/" # Gilas APIs
33        ), mode=instructor.Mode.PARALLEL_TOOLS
34    ).chat.completions.create(**payload)
35    for tool in function_calls:
36        print(f"- Tool call: {tool.action} for provided img: {test_image}")
37        print(f"- Parameters: {tool}")
38        print(f">> Action result: {tool(ORDER_ID)}")
39        return tool
40
41print("Processing delivery exception support for different package images...")
42
43print("\n===================== Simulating user message 1 =====================")
44assert delivery_exception_support_handler("damaged_package").action == "refund_order"
45
46print("\n===================== Simulating user message 2 =====================")
47assert delivery_exception_support_handler("normal_package").action == "escalate_to_agent"
48
49print("\n===================== Simulating user message 3 =====================")
50assert delivery_exception_support_handler("wet_package").action == "replace_order"

خروجی

Processing delivery exception support for different package images…

===================== Simulating user message 1 =====================

  • Tool call: refund_order for provided img: damaged_package
  • Parameters: rationale=‘The package is visibly damaged with significant tears and crushing, indicating potential harm to the contents.’ image_description=‘The package in the image shows extensive damage, including deep creases and tears in the cardboard. The package is also wrapped with extra tape, suggesting prior attempts to secure it after damage.’ action=‘refund_order’ message=None

Action result: Order 12345 has been refunded successfully.

===================== Simulating user message 2 =====================

  • Tool call: escalate_to_agent for provided img: normal_package
  • Parameters: rationale=‘The package appears normal and not damaged, requiring further assistance for any potential issues not visible in the image.’ image_description=‘A cardboard box on a wooden floor, appearing intact and undamaged, with no visible signs of wear, tear, or wetness.’ action=‘escalate_to_agent’ message=‘Please review this package for any issues not visible in the image. The package appears normal and undamaged.’

Action result: Order 12345 has been escalated to an agent with message: Please review this package for any issues not visible in the image. The package appears normal and undamaged.

===================== Simulating user message 3 =====================

  • Tool call: replace_order for provided img: wet_package
  • Parameters: rationale=‘The package appears wet, which may have compromised the contents, especially since it is labeled as fragile.’ image_description=“The package in the image shows significant wetness on the top surface, indicating potential water damage. The box is labeled ‘FRAGILE’, which suggests that the contents are delicate and may be more susceptible to damage from moisture.” action=‘replace_order’ message=None

Action result: Order 12345 has been replaced with a new order.

2. تحلیل نمودار سازمانی برای استخراج اطلاعات کارکنان #

برای مثال دوم، ما نمودار سازمانی را تحلیل خواهیم کرد تا اطلاعات کارکنان، مانند نام‌ها، نقش‌ها، مدیران و نقش‌های مدیران را استخراج کنیم.

ما از GPT-4 Turbo با قابلیت دیداری برای پردازش تصویر نمودار سازمانی و استخراج داده‌های ساختاریافته درباره کارکنان استفاده خواهیم کرد. در واقع، فراخوانی توابع به ما اجازه می‌دهد فراتر از OCR برویم و روابط سلسله مراتبی را درون نمودار ترجمه کنیم.

ما با یک نمونه نمودار سازمانی در فرمت PDF که می‌خواهیم تحلیل کنیم شروع خواهیم کرد و صفحه اول PDF را به یک تصویر JPEG برای تحلیل تبدیل خواهیم کرد.

 1# تابع برای تبدیل صفحه PDF به تصویر JPEG
 2def convert_pdf_page_to_jpg(pdf_path: str, output_path: str, page_number=0):
 3    if not os.path.exists(pdf_path):
 4        raise FileNotFoundError(f"PDF file not found: {pdf_path}")
 5    doc = fitz.open(pdf_path)
 6    page = doc.load_page(page_number) 
 7    pix = page.get_pixmap()
 8    pix.save(output_path)
 9
10def display_img_local(image_path: str):
11    img = Image.open(image_path)
12    display(img)
13
14pdf_path = 'data/org-chart-sample.pdf'
15output_path = 'org-chart-sample.jpg'
16
17convert_pdf_page_to_jpg(pdf_path, output_path)
18display_img_local(output_path)
preview

تصویر نمودار سازمانی با موفقیت از فایل PDF استخراج و نمایش داده شد. حالا بیایید تابعی برای تحلیل تصویر نمودار سازمانی با استفاده از GPT-4 Turbo تعریف کنیم. این تابع اطلاعاتی درباره کارکنان، نقش‌های آن‌ها و مدیران آن‌ها از تصویر استخراج خواهد کرد. ما از فراخوانی توابع/ابزارها برای مشخص کردن پارامترهای ورودی ساختار سازمانی، مانند نام کارمند، نقش و نام و نقش مدیر استفاده خواهیم کرد. ما از مدل‌های Pydantic برای تعریف ساختار داده‌ها استفاده خواهیم کرد.

 1base64_img = encode_image(output_path)
 2
 3class RoleEnum(str, Enum):
 4    """تعریف نقش‌های ممکن در یک سازمان."""
 5    CEO = "CEO"
 6    CTO = "CTO"
 7    CFO = "CFO"
 8    COO = "COO"
 9    EMPLOYEE = "Employee"
10    MANAGER = "Manager"
11    INTERN = "Intern"
12    OTHER = "Other"
13
14class Employee(BaseModel):
15    employee_name: str = Field(..., description="نام کارمند")
16    role: RoleEnum = Field(..., description="نقش کارمند")
17    manager_name: Optional[str] = Field(None, description="نام مدیر، در صورت وجود")
18    manager_role: Optional[RoleEnum] = Field(None, description="نقش مدیر، در صورت وجود")
19
20class EmployeeList(BaseModel):
21    """لیستی از کارکنان در ساختار سازمانی."""
22    employees: List[Employee] = Field(..., description="لیستی از کارکنان")
23
24def parse_orgchart(base64_img: str) -> EmployeeList:
25    response = instructor.from_openai(OpenAI(
26            api_key=os.environ.get(("GILAS_API_KEY", "<کلید API خود را اینجا بسازید https://dashboard.gilas.io/apiKey>")), 
27            base_url="https://api.gilas.io/v1/" # Gilas APIs
28        )).chat.completions.create(
29        model='gpt-4-turbo',
30        response_model=EmployeeList,
31        messages=[
32            {
33                "role": "user",
34                "content": 'Analyze the given organizational chart and very carefully extract the information.',
35            },
36            {
37                "role": "user",
38                "content": [
39                    {
40                        "type": "image_url",
41                        "image_url": {
42                            "url": f"data:image/jpeg;base64,{base64_img}"
43                        }
44                    },
45                ],
46            }
47        ],
48    )
49    return response
50
51# call the functions to analyze the organizational chart and parse the response
52result = parse_orgchart(base64_img)
53
54# tabulate the extracted data
55df = pd.DataFrame([{
56    'employee_name': employee.employee_name,
57    'role': employee.role.value,
58    'manager_name': employee.manager_name,
59    'manager_role': employee.manager_role.value if employee.manager_role else None
60} for employee in result.employees])
61
62display(df)
employee_namerolemanager_namemanager_role
0Juliana SilvaCEONoneNone
1Kim Chun HeiCFOJuliana SilvaCEO
2Chad GibbonsCTOJuliana SilvaCEO
3Chiaki SatoCOOJuliana SilvaCEO
4Cahaya DewiManagerKim Chun HeiCFO
5Shawn GarciaManagerChad GibbonsCTO
6Aaron LoebManagerChiaki SatoCOO
7Drew FeigEmployeeCahaya DewiManager
8Richard SanchezEmployeeCahaya DewiManager
9Sacha DuboisInternCahaya DewiManager
10Olivia WilsonEmployeeShawn GarciaManager
11Matt ZhangInternShawn GarciaManager
12Avery DavisEmployeeAaron LoebManager
13Harper RussoEmployeeAaron LoebManager
14Taylor AlonsoInternAaron LoebManager

ما داده‌های استخراج شده از نمودار سازمانی را با موفقیت تحلیل کرده و در یک DataFrame نمایش دادیم. این روش به ما اجازه می‌دهد تا از قابلیت‌های GPT-4 Turbo برای استخراج اطلاعات ساختاریافته از تصاویر، مانند نمودارهای سازمانی و دیاگرام‌ها، استفاده کنیم و داده‌ها را برای تحلیل بیشتر پردازش کنیم. با استفاده از فراخوانی توابع، ما می‌توانیم قابلیت مدل‌های چند‌حالته را برای انجام وظایف خاص یا فراخوانی توابع خارجی گسترش دهیم.