Lộ trình
Google gần đây đã công bố Gemini 2.0, với mô hình Gemini 2.0 Flash ở trung tâm—một phiên bản nhanh hơn, mạnh hơn được thiết kế để cải thiện xử lý hình ảnh và âm thanh.
Trong hướng dẫn này, tôi sẽ dẫn bạn qua các bước sử dụng Gemini 2.0 Flash để tạo một trợ lý trực quan có thể đọc nội dung hiển thị trên màn hình và trả lời các câu hỏi về nội dung đó.
Dưới đây là bản demo về những gì chúng ta sẽ xây dựng:
Bước 1: Thiết lập API Key cho Google AI Studio
Để thiết lập API key, hãy truy cập Google AI Studio và nhấp nút “Create API Key”. Hãy nhớ sao chép khóa và dán vào tệp có tên .env với định dạng sau:
GOOGLE_API_KEY=replace_this_with_api_key
Nếu bạn đã từng làm việc với Google Cloud Platform bằng cùng tài khoản Google, Google AI Studio sẽ nhắc bạn chọn một trong các dự án của mình để kích hoạt API.
Để theo dõi hướng dẫn này, mã Python phải nằm trong cùng thư mục với tệp .env.
Bước 2: Cài đặt các phụ thuộc Python
Trong dự án này, chúng ta sẽ dùng các gói sau:
google-genai: Thư viện Python để tích hợp các mô hình AI sinh của Google vào ứng dụng.pyautogui: Thư viện đa nền tảng để điều khiển chuột và bàn phím bằng mã nhằm tự động hóa tác vụ. Trường hợp của chúng ta, dùng để cung cấp nội dung màn hình cho mô hình AI.python-dotenv: Thư viện quản lý biến môi trường bằng cách nạp chúng từ tệp .env vào ứng dụng Python.sounddevice: Thư viện Python để ghi và phát âm thanh bằng các API đơn giản cho đầu vào/đầu ra audio.numpy: Thư viện nền tảng cho tính toán số trong Python, hỗ trợ mảng, ma trận và nhiều phép toán toán học.
Để cài đặt các phụ thuộc, chúng ta có thể dùng pip:
pip install google-genai pyautogui python-dotenv sounddevice numpy
Hoặc tải tệp requirements.txt từ kho GitHub tôi đã thiết lập cho dự án này và dùng nó để tạo môi trường Conda:
conda create --name gemini python=3.11
conda activate gemini
pip install -r requirements.txt
Bước 3: Tạo chatbot văn bản với Google GenAI API
Hãy bắt đầu bằng việc tạo giao diện chat AI dòng lệnh đơn giản sử dụng mô hình Gemini 2 Flash của Google với thư viện google.genai. Tôi khuyến nghị bạn xem tài liệu chính thức của Gemini 2.0 nếu gặp trục trặc trong quá trình thực hiện.
Mã đầy đủ cho ví dụ này có trong tệp text.py tại kho GitHub của tôi.
Tạo và kết nối tới client Google GenAI
Bước đầu tiên là nạp API key một cách an toàn và khởi tạo client Google GenAI. Script sử dụng dotenv để nạp biến môi trường từ tệp .env.
Cách thiết lập client với thông tin xác thực cần thiết như sau:
from google import genai
from dotenv import load_dotenv
import os
# Load environment variables from a .env file
load_dotenv()
client = genai.Client(
api_key=os.getenv("GOOGLE_API_KEY"),
http_options={"api_version": "v1alpha"},
)
print("Connected to the AI model!")
Thực hiện gọi API bất đồng bộ
Khi làm việc với các API như Google GenAI, chúng ta thường cần xử lý các thao tác bất đồng bộ. Lập trình bất đồng bộ cho phép các thao tác khác tiếp tục trong khi chờ yêu cầu mạng, giúp ứng dụng phản hồi tốt hơn. Điều này đặc biệt quan trọng khi xử lý các tác vụ có độ trễ cao như yêu cầu mạng.
Trong Python, lập trình bất đồng bộ được hỗ trợ bởi thư viện asyncio và cú pháp async/await.
Cách gửi một yêu cầu bất đồng bộ tới Google GenAI như sau:
from google import genai
from dotenv import load_dotenv
import os
import asyncio
# Load environment variables from a .env file
load_dotenv()
async def main():
client = genai.Client(
api_key=os.getenv("GOOGLE_API_KEY"),
http_options={"api_version": "v1alpha"},
)
# Define the AI model and configuration
model_id = "gemini-2.0-flash-exp"
config = {"response_modalities": ["TEXT"]}
async with client.aio.live.connect(model=model_id, config=config) as session:
await session.send("Hello", end_of_turn=True)
# Process responses from the AI
async for response in session.receive():
if not response.server_content.turn_complete:
for part in response.server_content.model_turn.parts:
print(part.text, end="", flush=True)
# Run the main function
asyncio.run(main())
Phiên bản này kết nối tới mô hình AI và gửi một thông điệp “Hello”. Phản hồi sẽ được in ra từng từ trong console.
Biến nó thành tương tác
Để ứng dụng trở nên tương tác, cho phép người dùng trò chuyện qua lại với mô hình AI, chúng ta thêm một vòng lặp để người dùng gửi nhiều tin nhắn. Vòng lặp tiếp tục cho đến khi người dùng gõ "exit".
from google import genai
from dotenv import load_dotenv
import os
import asyncio
# Load environment variables from a .env file
load_dotenv()
async def main():
client = genai.Client(
api_key=os.getenv("GOOGLE_API_KEY"),
http_options={"api_version": "v1alpha"},
)
# Define the AI model and configuration
model_id = "gemini-2.0-flash-exp"
config = {"response_modalities": ["TEXT"]}
async with client.aio.live.connect(model=model_id, config=config) as session:
while True:
message = input("> ")
print()
# Exit the loop if the user types "exit"
if message == "exit":
print("Exiting...")
break
# Send the user's message to the AI model, marking the end of the turn
await session.send(message, end_of_turn=True)
# Receive responses asynchronously and process each response
async for response in session.receive():
if not response.server_content.turn_complete:
for part in response.server_content.model_turn.parts:
print(part.text, end="", flush=True)
print()
# Run the main function
asyncio.run(main())
Vậy là xong! Với script trên, chúng ta đã tạo một chatbot AI dòng lệnh bằng Google GenAI API. Nó trông như thế này:
Bước 4: Thêm chế độ âm thanh
Chế độ âm thanh cho phép mô hình phản hồi bằng giọng nói thay vì văn bản. Để điều chỉnh ví dụ trước nhằm xử lý phản hồi âm thanh, chúng ta:
- Import
sounddeviceđể phát âm thanh vànumpyđể xử lý dữ liệu audio. - Đổi phương thức phản hồi từ
TEXTsangAUDIO:
config = {"response_modalities": ["AUDIO"]}
- Khởi tạo luồng âm thanh trước khi kết nối tới client:
with sd.OutputStream(
samplerate=24000,
channels=1,
dtype="int16",
) as audio_stream:
- Truy cập dữ liệu âm thanh từ phần phản hồi và ghi vào luồng để phát lại:
for part in response.server_content.model_turn.parts:
# Get the audio data from the response part and add it to the steam
inline_data = part.inline_data
audio_data = np.frombuffer(inline_data.data, dtype="int16")
audio_stream.write(audio_data)
Tệp audio.py trong kho mã chứa toàn bộ script với các thay đổi này. Script có chú thích tại các dòng đã sửa.
Bước 5: Thêm thực thi mã bằng Tools
Một trong những tính năng tuyệt vời của các mô hình AI hiện đại là khả năng tự động gọi các hàm tùy chỉnh trong mã của chúng ta, và Gemini 2 cũng không ngoại lệ.
Cách hoạt động là chúng ta cho mô hình biết các hàm nào có thể được gọi bằng cách đăng ký chúng như các công cụ (tools). Sau đó, bằng cách phân tích prompt, tên hàm và mô tả, mô hình sẽ quyết định có muốn gọi hàm hay không. Khi quyết định gọi, nó sẽ gửi phản hồi đặc biệt với tên hàm và các đối số cần thiết.
Để định nghĩa một tool, chúng ta cần:
- Viết một hàm Python với cùng tên và đối số như khai báo trong schema.
- Tạo schema của hàm, là một dictionary chứa siêu dữ liệu về hàm như tên, mô tả văn bản và đặc tả các đối số.
- Cung cấp schema của hàm cho mô hình AI.
- Thực thi hàm khi mô hình yêu cầu.
Để minh họa, hãy định nghĩa một tool có thể đọc tệp, cho phép mô hình trả lời câu hỏi về các tệp trên máy cục bộ của chúng ta.
Định nghĩa hàm
Phần này chỉ là mã Python thông thường. Mô hình kỳ vọng câu trả lời là một dictionary với khóa ”result” nếu hàm thành công và ”error” nếu thất bại.
def load_file_content(filename):
try:
with open(filename, "rt") as f:
return {
"result": f.read()
}
except Exception as e:
return {
"error": "Could not load file content",
}
Chỉ định schema
Cách định nghĩa schema cho hàm này như sau:
load_file_content_schema = {
"name": "load_file_content",
"description": "Load the content of a file",
"parameters": {
"type": "object",
"properties": {
"filename": {
"type": "string",
"description": "The name of the file",
},
},
"required": ["filename"],
},
"output": {
"type": "string",
"description": "The text content of the file",
},
}
Chúng ta cung cấp bốn trường:
”name”: Tên của hàm.”description”: Mô tả văn bản. Mục này được mô hình dùng để quyết định có gọi hàm hay không.”properties”: Mô tả các đối số của hàm.”output”: Mô tả đầu ra của hàm.
Xem tài liệu chính thức để biết thêm thông tin về schema của hàm.
Cung cấp hàm cho mô hình
Để mô hình biết về hàm của chúng ta, hãy cung cấp schema của hàm trong cấu hình mô hình:
config = {
"tools": [{"function_declarations": [load_file_content_schema]}],
"response_modalities": ["TEXT"]
}
Xử lý yêu cầu gọi hàm từ mô hình
Khi mô hình quyết định thực hiện một lời gọi hàm, nó sẽ thêm một tool_call vào response. Mục này chứa tên hàm và các đối số. Có thể có nhiều yêu cầu gọi, vì vậy chúng ta cần lặp qua tất cả, gọi các hàm tương ứng và gửi kết quả lại cho mô hình:
# A dictionary mapping the function names to the actual functions
FUNCTIONS = {"load_file_content": load_file_content}
if response.tool_call is not None:
for fc in tool_call.function_calls:
f = FUNCTIONS.get(fc.name)
tool_response = types.LiveClientToolResponse(
function_responses=[
types.FunctionResponse(
name=fc.name,
id=fc.id,
response=f(**fc.args),
)
]
)
await session.send(tool_response)
Triển khai đầy đủ ví dụ này có trong tệp tool.py tại kho mã chứa toàn bộ script với các thay đổi này. Định nghĩa hàm và schema nằm trong tệp tool_spec.py.
Truy cập web
Với tools, chúng ta cũng có thể trao cho mô hình khả năng truy cập web bằng cách thêm công cụ tìm kiếm Google:
search_tool = {"google_search": {}}
config = {
"tools": [search_tool],
"response_modalities": ["TEXT"],
}
Công cụ này là tích hợp sẵn, vì vậy chúng ta không cần cung cấp một hàm.
Thực thi mã
Một chức năng tích hợp sẵn khác là thực thi mã. Thực thi mã cho phép mô hình viết và chạy mã Python để trả lời các câu hỏi phức tạp, thường liên quan đến toán học. Ví dụ, với công cụ này, nếu yêu cầu tính tổng của 10 số nguyên tố đầu tiên, nó sẽ viết mã Python để tính toán, thực thi mã đó, rồi cung cấp câu trả lời.
Để kích hoạt công cụ, chúng ta làm như sau:
code_execution_tool = {"code_execution": {}}
config = {
"tools": [code_execution_tool],
"response_modalities": ["TEXT"],
}
Ví dụ về hành vi của mô hình khi thực thi mã:
> add the first 10 prime numbers
Okay, I understand. You want me to add the first 10 prime numbers.
Here's my plan:
1. **Identify the first 10 prime numbers:** I will use a python code to find prime numbers.
2. **Sum the prime numbers:** I will also sum them using python.
3. **Report the result**
The first 10 prime numbers are 2, 3, 5, 7, 11, 13, 17, 19, 23, and 29. Their sum is 129.
Bước 6: Xây dựng trợ lý trực quan
Trong phần cuối này, chúng ta khám phá khả năng xử lý hình ảnh của Gemini 2. Mục tiêu là tạo một trợ lý AI có thể hiểu nội dung trên màn hình và trả lời câu hỏi về nội dung đó. Điều này hữu ích, chẳng hạn khi yêu cầu giải thích một lỗi hiển thị trong terminal hoặc cung cấp thông tin về thứ gì đó đang hiển thị trên màn hình.
Ở các ví dụ trước, chúng ta dùng lập trình bất đồng bộ để kết nối với mô hình AI và gửi/nhận dữ liệu trong khi xử lý phản hồi theo thời gian thực. Đáng tiếc, phiên bản SDK hiện tại chưa hỗ trợ giao tiếp thời gian thực với hình ảnh. Thay vào đó, chúng ta cung cấp dữ liệu hình ảnh qua quy trình yêu cầu-phản hồi. Lưu ý đây không phải là hạn chế của chính Gemini 2.0—chỉ là API beta hiện tại chưa hỗ trợ tính năng đó.
Gửi yêu cầu đồng bộ tới Google GenAI
Hãy bắt đầu bằng việc học cách gửi yêu cầu kèm dữ liệu hình ảnh tới Google GenAI API. Cách gửi một yêu cầu đồng bộ như sau:
from google import genai
from dotenv import load_dotenv
import os
load_dotenv()
client = genai.Client(
api_key=os.getenv("GOOGLE_API_KEY"),
http_options={"api_version": "v1alpha"},
)
response = client.models.generate_content(
model="gemini-2.0-flash-exp",
contents=["Hello"],
)
print(response.text)
Khác biệt chính ở ví dụ này là chúng ta dùng client.models.generate_content để gửi yêu cầu tới API. Đây là yêu cầu đồng bộ, tức là không mang lại trải nghiệm hội thoại thời gian thực.
Gửi một hình ảnh
Chúng ta có thể gửi một hình ảnh bằng cách nạp và thêm nó vào danh sách contents. Ta dùng gói PIL để tạo hàm load_and_resize_image() nạp và thay đổi kích thước ảnh.
from PIL import Image
def load_and_resize_image(image_path):
with Image.open(image_path) as img:
aspect_ratio = img.height / img.width
new_height = int(img.width * aspect_ratio)
return img.resize((img.width, new_height), Image.Resampling.LANCZOS)
image = load_and_resize_image("example_image.jpeg")
response = client.models.generate_content(
model="gemini-2.0-flash-exp",
contents=["Describe the image", image],
)
print(response.text)
Tạo trợ lý AI trực quan
Trợ lý AI trực quan xử lý prompt dạng văn bản cùng với ảnh chụp màn hình để giúp trả lời câu hỏi về những gì đang hiển thị. Tôi đã thử nghiệm rất nhiều và mô hình có thể hiểu nội dung màn hình ngay cả khi có nhiều cửa sổ mở.
Cách đơn giản nhất để cung cấp nội dung màn hình cho mô hình là chụp ảnh màn hình. Để làm điều này, chúng ta dùng gói pyautogui, một thư viện đa nền tảng để điều khiển chuột và bàn phím bằng mã nhằm tự động hóa tác vụ. Trường hợp này, chúng ta chỉ dùng để chụp ảnh màn hình, dù có thể mở rộng để AI tự động thực hiện tác vụ trên máy tính của chúng ta.
Hàm chụp ảnh màn hình như sau:
def capture_screen():
timestamp = time.strftime("%Y%m%d-%H%M%S")
filename = f"screenshot_{timestamp}.jpeg"
screenshot = pyautogui.screenshot()
screenshot = screenshot.convert("RGB")
screenshot.save(filename, format="JPEG")
return filename
Để tương tác, chúng ta lặp lại các bước sau cho đến khi người dùng quyết định thoát ứng dụng:
- Yêu cầu người dùng nhập một prompt.
- Chụp ảnh màn hình và gửi cùng prompt tới mô hình AI.
- Hiển thị kết quả cho người dùng.
Có một điều cần lưu ý với cách tiếp cận này. Ứng dụng sẽ chạy trong terminal, vốn cũng hiển thị trên màn hình. Do đó, tốt hơn là hướng dẫn mô hình bỏ qua cửa sổ terminal. Việc này có thể thực hiện bằng cách thêm system_instruction vào cấu hình:
client.models.generate_content(
model="gemini-2.0-flash-exp",
contents=[prompt, screen],
config=types.GenerateContentConfig(
system_instruction="Ignore the terminal window in the image when analyzing the image",
),
)
Gộp tất cả lại, đây là trợ lý AI trực quan của chúng ta. Tệp mã đầy đủ cũng có sẵn dưới tên vision.py trong kho mã.
from google import genai
from google.genai import types
from PIL import Image
import pyautogui
import time
import os
from dotenv import load_dotenv
load_dotenv()
# Initialize the GenAI client
client = genai.Client(
api_key=os.getenv("GOOGLE_API_KEY"),
http_options={"api_version": "v1alpha"},
)
def capture_screen():
timestamp = time.strftime("%Y%m%d-%H%M%S")
filename = f"screenshot_{timestamp}.jpeg"
screenshot = pyautogui.screenshot()
screenshot = screenshot.convert("RGB")
screenshot.save(filename, format="JPEG")
return filename
def load_and_resize_image(image_path):
with Image.open(image_path) as img:
aspect_ratio = img.height / img.width
new_height = int(img.width * aspect_ratio)
return img.resize((img.width, new_height), Image.Resampling.LANCZOS)
def get_genai_response(prompt):
print("Analyzing screen...")
screen = load_and_resize_image(capture_screen())
response = client.models.generate_content(
model="gemini-2.0-flash-exp",
contents=[prompt, screen],
config=types.GenerateContentConfig(
system_instruction="Ignore the terminal window in the image when analyzing the image",
),
)
return response.text
def main():
while True:
prompt = input("> ")
print()
if prompt == "exit":
break
answer = get_genai_response(prompt)
print(answer)
print()
if __name__ == "__main__":
main()
Phiên bản hiện tại còn hơi vướng vì cần mở terminal đè lên giao diện hiện tại để kích hoạt. Bước tiếp theo tự nhiên là cho chạy nền và dùng đầu vào/đầu ra giọng nói thay cho văn bản.
Kết luận
Chúng ta đã học cách sử dụng mô hình Gemini 2.0 Flash cho nhiều ứng dụng, như phát triển chatbot có thể trò chuyện thời gian thực bằng văn bản và giọng nói, cho phép mô hình AI thực hiện hành động thông qua lời gọi hàm, và một trợ lý trực quan có khả năng phân tích nội dung màn hình máy tính.
Nếu muốn khám phá thêm, Google cung cấp hai ví dụ trình diễn khả năng của mô hình trong việc phát hiện đối tượng trong ảnh bằng cách đưa ra hộp giới hạn cùng nhãn. Ví dụ này tập trung vào hiểu biết không gian 2D bằng cách yêu cầu mô hình xác định và gắn nhãn bánh cupcake trong ảnh. Gemini cũng có thể hiểu ngữ cảnh 3D của một hình ảnh, như được trình diễn tại đây.
Nhìn chung, Gemini 2.0 rất hứa hẹn dù phiên bản API hiện tại vẫn chưa cho phép khai thác hết tiềm năng. Tôi rất mong sớm được sử dụng đầy đủ các khả năng đa phương thức thời gian thực.
