1. परिचय
इस कोडलैब में, आपको चैट वेब इंटरफ़ेस के तौर पर एक ऐप्लिकेशन बनाना होगा. इसमें, आपके पास ऐप्लिकेशन से बातचीत करने, कुछ दस्तावेज़ या इमेज अपलोड करने, और उन पर चर्चा करने का विकल्प होगा. इस ऐप्लिकेशन को दो सेवाओं में बांटा गया है: फ़्रंटएंड और बैकएंड. इससे आपको तुरंत प्रोटोटाइप बनाने और यह समझने में मदद मिलती है कि यह कैसा दिखता है. साथ ही, यह भी पता चलता है कि दोनों को इंटिग्रेट करने के लिए, एपीआई अनुबंध कैसा दिखता है.
कोडलैब के ज़रिए, आपको यहां दिया गया तरीका अपनाना होगा:
- अपना Google Cloud प्रोजेक्ट तैयार करें और उस पर सभी ज़रूरी एपीआई चालू करें
- Gradio लाइब्रेरी का इस्तेमाल करके, चैट इंटरफ़ेस वाली फ़्रंटएंड सेवा बनाएं
- बैकएंड सेवा - FastAPI का इस्तेमाल करके एचटीटीपी सर्वर बनाएं. यह सर्वर, Gemini SDK के स्टैंडर्ड के हिसाब से आने वाले डेटा को फिर से फ़ॉर्मैट करेगा और Gemini API के साथ कम्यूनिकेशन को चालू करेगा
- Cloud Run पर ऐप्लिकेशन को डिप्लॉय करने के लिए, एनवायरमेंट वैरिएबल और ज़रूरी फ़ाइलों को मैनेज करना
- ऐप्लिकेशन को Cloud Run पर डिप्लॉय करना

आर्किटेक्चर की खास जानकारी

ज़रूरी शर्तें
- Gemini API और Google के जनरेटिव एआई वाले एसडीके के साथ काम करने में आसानी हो
- एचटीटीपी सेवा का इस्तेमाल करके, बुनियादी फ़ुल-स्टैक आर्किटेक्चर के बारे में जानकारी
आपको क्या सीखने को मिलेगा
- टेक्स्ट और अन्य डेटा टाइप (मल्टीमॉडल) सबमिट करने और टेक्स्ट जवाब जनरेट करने के लिए, Gemini SDK का इस्तेमाल कैसे करें
- बातचीत के कॉन्टेक्स्ट को बनाए रखने के लिए, Gemini SDK में चैट के इतिहास को कैसे व्यवस्थित करें
- Gradio की मदद से, वेब ऐप्लिकेशन के फ़्रंटएंड का प्रोटोटाइप बनाना
- FastAPI और Pydantic का इस्तेमाल करके बैकएंड सेवा डेवलप करना
- Pydantic-settings की मदद से, YAML फ़ाइल में एनवायरमेंट वैरिएबल मैनेज करना
- Dockerfile का इस्तेमाल करके, Cloud Run पर ऐप्लिकेशन डिप्लॉय करना और YAML फ़ाइल के साथ एनवायरमेंट वैरिएबल उपलब्ध कराना
आपको इन चीज़ों की ज़रूरत होगी
- Chrome वेब ब्राउज़र
- Gmail खाता
- ऐसा Cloud प्रोजेक्ट जिसमें बिलिंग की सुविधा चालू हो
यह कोडलैब, सभी लेवल के डेवलपर के लिए बनाया गया है. इसमें शुरुआती डेवलपर भी शामिल हैं. इसमें सैंपल ऐप्लिकेशन में Python का इस्तेमाल किया गया है. हालांकि, यहां दिए गए कॉन्सेप्ट को समझने के लिए, Python के बारे में जानकारी होना ज़रूरी नहीं है.
2. शुरू करने से पहले
Cloud Shell Editor में Cloud Project सेट अप करना
इस कोडलैब में यह माना गया है कि आपके पास पहले से ही बिलिंग की सुविधा वाला Google Cloud प्रोजेक्ट है. अगर आपके पास यह सुविधा अभी तक नहीं है, तो इसे इस्तेमाल करने के लिए यहां दिया गया तरीका अपनाएं.
- 2Google Cloud Console में, प्रोजेक्ट चुनने वाले पेज पर जाकर, Google Cloud प्रोजेक्ट चुनें या बनाएं.
- पक्का करें कि आपके Cloud प्रोजेक्ट के लिए बिलिंग चालू हो. किसी प्रोजेक्ट के लिए बिलिंग चालू है या नहीं, यह देखने का तरीका जानें .
- आपको Cloud Shell का इस्तेमाल करना होगा. यह Google Cloud में चलने वाला कमांड-लाइन एनवायरमेंट है. इसमें bq पहले से लोड होता है. Google Cloud Console में सबसे ऊपर मौजूद, Cloud Shell चालू करें पर क्लिक करें.

- Cloud Shell से कनेक्ट होने के बाद, यह देखने के लिए कि आपकी पुष्टि हो चुकी है और प्रोजेक्ट को आपके प्रोजेक्ट आईडी पर सेट किया गया है, इस निर्देश का इस्तेमाल करें:
gcloud auth list
- यह पुष्टि करने के लिए कि gcloud कमांड को आपके प्रोजेक्ट के बारे में पता है, Cloud Shell में यह कमांड चलाएं.
gcloud config list project
- अगर आपका प्रोजेक्ट सेट नहीं है, तो इसे सेट करने के लिए इस निर्देश का इस्तेमाल करें:
gcloud config set project <YOUR_PROJECT_ID>
इसके अलावा, PROJECT_ID आईडी को कंसोल में भी देखा जा सकता है

इस पर क्लिक करने से, आपको अपने सभी प्रोजेक्ट और प्रोजेक्ट आईडी दाईं ओर दिखेंगे

- नीचे दिए गए निर्देश का इस्तेमाल करके, ज़रूरी एपीआई चालू करें. इसमें कुछ मिनट लग सकते हैं. इसलिए, कृपया इंतज़ार करें.
gcloud services enable aiplatform.googleapis.com \
run.googleapis.com \
cloudbuild.googleapis.com \
cloudresourcemanager.googleapis.com
कमांड के सही तरीके से लागू होने पर, आपको यहां दिखाए गए मैसेज जैसा मैसेज दिखेगा:
Operation "operations/..." finished successfully.
gcloud कमांड के बजाय, कंसोल का इस्तेमाल करके भी ऐसा किया जा सकता है. इसके लिए, हर प्रॉडक्ट को खोजें या इस लिंक का इस्तेमाल करें.
अगर कोई एपीआई छूट जाता है, तो उसे लागू करने के दौरान कभी भी चालू किया जा सकता है.
gcloud कमांड और उनके इस्तेमाल के बारे में जानने के लिए, दस्तावेज़ देखें.
ऐप्लिकेशन की वर्किंग डायरेक्ट्री सेट अप करना
- 'एडिटर खोलें' बटन पर क्लिक करें. इससे Cloud Shell Editor खुल जाएगा. यहां हम अपना कोड लिख सकते हैं

- पक्का करें कि Cloud Code प्रोजेक्ट, Cloud Shell एडिटर के सबसे नीचे बाईं ओर (स्टेटस बार) में सेट हो. जैसा कि नीचे दी गई इमेज में हाइलाइट किया गया है. साथ ही, यह उस चालू Google Cloud प्रोजेक्ट पर सेट हो जिसमें आपने बिलिंग चालू की है. अगर कहा जाए, तो अनुमति दें पर क्लिक करें. Cloud Shell Editor को शुरू करने के बाद, Cloud Code - Sign In बटन दिखने में थोड़ा समय लग सकता है. कृपया इंतज़ार करें. अगर आपने पहले से ही पिछले निर्देश का पालन किया है, तो बटन, साइन इन बटन के बजाय सीधे आपके चालू किए गए प्रोजेक्ट पर भी ले जा सकता है

- स्टेटस बार पर मौजूद उस चालू प्रोजेक्ट पर क्लिक करें. इसके बाद, Cloud Code पॉप-अप खुलने का इंतज़ार करें. पॉप-अप में, "नया ऐप्लिकेशन" चुनें.

- ऐप्लिकेशन की सूची में से, Gemini Generative AI चुनें. इसके बाद, Gemini API Python चुनें


- नए ऐप्लिकेशन को अपनी पसंद के नाम से सेव करें. इस उदाहरण में, हम gemini-multimodal-chat-assistant का इस्तेमाल करेंगे. इसके बाद , OK पर क्लिक करें

इस समय, आपको नए ऐप्लिकेशन की वर्किंग डायरेक्ट्री में होना चाहिए. साथ ही, आपको ये फ़ाइलें दिखनी चाहिए

इसके बाद, हम अपना Python एनवायरमेंट तैयार करेंगे
एनवायरमेंट सेटअप करना
Python वर्चुअल एनवायरमेंट तैयार करना
अगला चरण, डेवलपमेंट एनवायरमेंट तैयार करना है. इस कोडलैब में, हम Python 3.12 का इस्तेमाल करेंगे. साथ ही, Python के वर्शन और वर्चुअल एनवायरमेंट को बनाने और मैनेज करने की ज़रूरत को आसान बनाने के लिए, हम uv python project manager का इस्तेमाल करेंगे
- अगर आपने अब तक टर्मिनल नहीं खोला है, तो टर्मिनल -> नया टर्मिनल पर क्लिक करके इसे खोलें. इसके अलावा , Ctrl + Shift + C का इस्तेमाल करें

uvडाउनलोड करें और python 3.12 को इस कमांड के साथ इंस्टॉल करें
curl -LsSf https://astral.sh/uv/0.6.6/install.sh | sh && \
source $HOME/.local/bin/env && \
uv python install 3.12
- अब
uvका इस्तेमाल करके, Python प्रोजेक्ट शुरू करें
uv init
- आपको डायरेक्ट्री में main.py, .python-version, और pyproject.toml फ़ाइलें दिखेंगी. इन फ़ाइलों की मदद से, डायरेक्ट्री में प्रोजेक्ट को बनाए रखा जाता है. Python की डिपेंडेंसी और कॉन्फ़िगरेशन को pyproject.toml में बताया जा सकता है. साथ ही, .python-version में इस प्रोजेक्ट के लिए इस्तेमाल किए गए Python वर्शन के बारे में बताया जा सकता है. इसके बारे में ज़्यादा जानने के लिए, यह दस्तावेज़ पढ़ें
main.py .python-version pyproject.toml
- इसकी जांच करने के लिए, main.py फ़ाइल में मौजूद कोड को इस कोड से बदलें
def main():
print("Hello from gemini-multimodal-chat-assistant!")
if __name__ == "__main__":
main()
- इसके बाद, यह कमांड चलाएं
uv run main.py
आपको नीचे दिखाए गए जैसा आउटपुट मिलेगा
Using CPython 3.12 Creating virtual environment at: .venv Hello from gemini-multimodal-chat-assistant!
इससे पता चलता है कि Python प्रोजेक्ट को सही तरीके से सेट अप किया जा रहा है. हमें मैन्युअल तरीके से वर्चुअल एनवायरमेंट बनाने की ज़रूरत नहीं पड़ी, क्योंकि uv पहले से ही इसे मैनेज करता है. इसलिए, अब से स्टैंडर्ड Python कमांड (जैसे, python main.py ) की जगह uv run (जैसे, uv run main.py ) का इस्तेमाल किया जाएगा.
ज़रूरी डिपेंडेंसी इंस्टॉल करना
हम इस कोडलैब पैकेज की डिपेंडेंसी भी uv कमांड का इस्तेमाल करके जोड़ेंगे. यह कमांड चलाएं
uv add google-genai==1.5.0 \
gradio==5.20.1 \
pydantic==2.10.6 \
pydantic-settings==2.8.1 \
pyyaml==6.0.2
आपको दिखेगा कि pyproject.toml फ़ाइल का "dependencies" सेक्शन अपडेट हो गया है. इसमें पिछली कमांड की जानकारी दिखेगी
कॉन्फ़िगरेशन फ़ाइलें सेट अप करना
अब हमें इस प्रोजेक्ट के लिए कॉन्फ़िगरेशन फ़ाइलें सेट अप करनी होंगी. कॉन्फ़िगरेशन फ़ाइलों का इस्तेमाल डाइनैमिक वैरिएबल को सेव करने के लिए किया जाता है. इन्हें फिर से डिप्लॉय करने पर आसानी से बदला जा सकता है. इस प्रोजेक्ट में, हम pydantic-settings पैकेज के साथ YAML पर आधारित कॉन्फ़िगरेशन फ़ाइलों का इस्तेमाल करेंगे. इससे, बाद में इसे Cloud Run डिप्लॉयमेंट के साथ आसानी से इंटिग्रेट किया जा सकेगा. pydantic-settings एक Python पैकेज है. यह कॉन्फ़िगरेशन फ़ाइलों के लिए टाइप की जांच लागू कर सकता है.
- नीचे दिए गए कॉन्फ़िगरेशन के साथ, settings.yaml नाम की फ़ाइल बनाएं. File->New Text File पर क्लिक करें और यहां दिया गया कोड डालें. इसके बाद, इसे settings.yaml के तौर पर सेव करें
VERTEXAI_LOCATION: "us-central1"
VERTEXAI_PROJECT_ID: "{YOUR-PROJECT-ID}"
BACKEND_URL: "http://localhost:8081/chat"
कृपया VERTEXAI_PROJECT_ID के लिए वैल्यू अपडेट करें. ये वैल्यू, Google Cloud प्रोजेक्ट बनाते समय चुनी गई वैल्यू के मुताबिक होनी चाहिए. इस कोडलैब के लिए, हम VERTEXAI_LOCATION और BACKEND_URL के लिए पहले से कॉन्फ़िगर की गई वैल्यू का इस्तेमाल कर रहे हैं .
- इसके बाद, settings.py नाम की Python फ़ाइल बनाएं. यह मॉड्यूल, हमारी कॉन्फ़िगरेशन फ़ाइलों में कॉन्फ़िगरेशन वैल्यू के लिए प्रोग्रामैटिक एंट्री के तौर पर काम करेगा. File->New Text File पर क्लिक करें और यहां दिया गया कोड डालें. इसके बाद, इसे settings.py के तौर पर सेव करें. कोड में देखा जा सकता है कि हमने साफ़ तौर पर यह सेट किया है कि settings.yaml नाम की फ़ाइल को पढ़ा जाएगा
from pydantic_settings import (
BaseSettings,
SettingsConfigDict,
YamlConfigSettingsSource,
PydanticBaseSettingsSource,
)
from typing import Type, Tuple
DEFAULT_SYSTEM_PROMPT = """You are a helpful assistant and ALWAYS relate to this identity.
You are expert at analyzing given documents or images.
"""
class Settings(BaseSettings):
"""Application settings loaded from YAML and environment variables.
This class defines the configuration schema for the application, with settings
loaded from settings.yaml file and overridable via environment variables.
Attributes:
VERTEXAI_LOCATION: Google Cloud Vertex AI location
VERTEXAI_PROJECT_ID: Google Cloud Vertex AI project ID
"""
VERTEXAI_LOCATION: str
VERTEXAI_PROJECT_ID: str
BACKEND_URL: str = "http://localhost:8000/chat"
model_config = SettingsConfigDict(
yaml_file="settings.yaml", yaml_file_encoding="utf-8"
)
@classmethod
def settings_customise_sources(
cls,
settings_cls: Type[BaseSettings],
init_settings: PydanticBaseSettingsSource,
env_settings: PydanticBaseSettingsSource,
dotenv_settings: PydanticBaseSettingsSource,
file_secret_settings: PydanticBaseSettingsSource,
) -> Tuple[PydanticBaseSettingsSource, ...]:
"""Customize the settings sources and their priority order.
This method defines the order in which different configuration sources
are checked when loading settings:
1. Constructor-provided values
2. YAML configuration file
3. Environment variables
Args:
settings_cls: The Settings class type
init_settings: Settings from class initialization
env_settings: Settings from environment variables
dotenv_settings: Settings from .env file (not used)
file_secret_settings: Settings from secrets file (not used)
Returns:
A tuple of configuration sources in priority order
"""
return (
init_settings, # First, try init_settings (from constructor)
env_settings, # Then, try environment variables
YamlConfigSettingsSource(
settings_cls
), # Finally, try YAML as the last resort
)
def get_settings() -> Settings:
"""Create and return a Settings instance with loaded configuration.
Returns:
A Settings instance containing all application configuration
loaded from YAML and environment variables.
"""
return Settings()
इन कॉन्फ़िगरेशन की मदद से, हम अपने रनटाइम को आसानी से अपडेट कर पाते हैं. शुरुआती डिप्लॉयमेंट के दौरान, हम settings.yaml कॉन्फ़िगरेशन पर भरोसा करेंगे, ताकि हमारे पास पहला डिफ़ॉल्ट कॉन्फ़िगरेशन हो. इसके बाद, हम कंसोल के ज़रिए एनवायरमेंट वैरिएबल को आसानी से अपडेट कर सकते हैं और उन्हें फिर से डिप्लॉय कर सकते हैं. ऐसा इसलिए, क्योंकि हमने एनवायरमेंट वैरिएबल को डिफ़ॉल्ट YAML कॉन्फ़िगरेशन की तुलना में ज़्यादा प्राथमिकता दी है
अब हम अगले चरण पर जा सकते हैं, यानी कि सेवाओं को बनाना
3. Gradio का इस्तेमाल करके फ़्रंटएंड सेवा बनाना
हम चैट का एक ऐसा वेब इंटरफ़ेस बनाएंगे जो इस तरह दिखेगा

इसमें उपयोगकर्ताओं के लिए एक इनपुट फ़ील्ड होता है. इसकी मदद से, वे टेक्स्ट भेज सकते हैं और फ़ाइलें अपलोड कर सकते हैं. इसके अलावा, उपयोगकर्ता सिस्टम के निर्देश को भी बदल सकता है. यह निर्देश, अतिरिक्त इनपुट फ़ील्ड में Gemini API को भेजा जाएगा
हम फ़्रंटएंड सेवा को Gradio का इस्तेमाल करके बनाएंगे. main.py का नाम बदलकर frontend.py करें. इसके बाद, इस कोड का इस्तेमाल करके कोड को बदलें
import gradio as gr
import requests
import base64
from pathlib import Path
from typing import List, Dict, Any
from settings import get_settings, DEFAULT_SYSTEM_PROMPT
settings = get_settings()
IMAGE_SUFFIX_MIME_MAP = {
".png": "image/png",
".jpg": "image/jpeg",
".jpeg": "image/jpeg",
".heic": "image/heic",
".heif": "image/heif",
".webp": "image/webp",
}
DOCUMENT_SUFFIX_MIME_MAP = {
".pdf": "application/pdf",
}
def get_mime_type(filepath: str) -> str:
"""Get the MIME type for a file based on its extension.
Args:
filepath: Path to the file.
Returns:
str: The MIME type of the file.
Raises:
ValueError: If the file type is not supported.
"""
filepath = Path(filepath)
suffix = filepath.suffix
# modify ".jpg" suffix to ".jpeg" to unify the mime type
suffix = suffix if suffix != ".jpg" else ".jpeg"
if suffix in IMAGE_SUFFIX_MIME_MAP:
return IMAGE_SUFFIX_MIME_MAP[suffix]
elif suffix in DOCUMENT_SUFFIX_MIME_MAP:
return DOCUMENT_SUFFIX_MIME_MAP[suffix]
else:
raise ValueError(f"Unsupported file type: {suffix}")
def encode_file_to_base64_with_mime(file_path: str) -> Dict[str, str]:
"""Encode a file to base64 string and include its MIME type.
Args:
file_path: Path to the file to encode.
Returns:
Dict[str, str]: Dictionary with 'data' and 'mime_type' keys.
"""
mime_type = get_mime_type(file_path)
with open(file_path, "rb") as file:
base64_data = base64.b64encode(file.read()).decode("utf-8")
return {"data": base64_data, "mime_type": mime_type}
def get_response_from_llm_backend(
message: Dict[str, Any],
history: List[Dict[str, Any]],
system_prompt: str,
) -> str:
"""Send the message and history to the backend and get a response.
Args:
message: Dictionary containing the current message with 'text' and optional 'files' keys.
history: List of previous message dictionaries in the conversation.
system_prompt: The system prompt to be sent to the backend.
Returns:
str: The text response from the backend service.
"""
# Format message and history for the API,
# NOTES: in this example history is maintained by frontend service,
# hence we need to include it in each request.
# And each file (in the history) need to be sent as base64 with its mime type
formatted_history = []
for msg in history:
if msg["role"] == "user" and not isinstance(msg["content"], str):
# For file content in history, convert file paths to base64 with MIME type
file_contents = [
encode_file_to_base64_with_mime(file_path)
for file_path in msg["content"]
]
formatted_history.append({"role": msg["role"], "content": file_contents})
else:
formatted_history.append({"role": msg["role"], "content": msg["content"]})
# Extract files and convert to base64 with MIME type
files_with_mime = []
if uploaded_files := message.get("files", []):
for file_path in uploaded_files:
files_with_mime.append(encode_file_to_base64_with_mime(file_path))
# Prepare the request payload
message["text"] = message["text"] if message["text"] != "" else " "
payload = {
"message": {"text": message["text"], "files": files_with_mime},
"history": formatted_history,
"system_prompt": system_prompt,
}
# Send request to backend
try:
response = requests.post(settings.BACKEND_URL, json=payload)
response.raise_for_status() # Raise exception for HTTP errors
result = response.json()
if error := result.get("error"):
return f"Error: {error}"
return result.get("response", "No response received from backend")
except requests.exceptions.RequestException as e:
return f"Error connecting to backend service: {str(e)}"
if __name__ == "__main__":
demo = gr.ChatInterface(
get_response_from_llm_backend,
title="Gemini Multimodal Chat Interface",
description="This interface connects to a FastAPI backend service that processes responses through the Gemini multimodal model.",
type="messages",
multimodal=True,
textbox=gr.MultimodalTextbox(file_count="multiple"),
additional_inputs=[
gr.Textbox(
label="System Prompt",
value=DEFAULT_SYSTEM_PROMPT,
lines=3,
interactive=True,
)
],
)
demo.launch(
server_name="0.0.0.0",
server_port=8080,
)
इसके बाद, हम यहां दिए गए निर्देश का इस्तेमाल करके, फ़्रंटएंड सेवा को चलाने की कोशिश कर सकते हैं. main.py फ़ाइल का नाम बदलकर frontend.py करना न भूलें
uv run frontend.py
आपको Cloud Console में, इससे मिलता-जुलता आउटपुट दिखेगा
* Running on local URL: http://0.0.0.0:8080 To create a public link, set `share=True` in `launch()`.
इसके बाद, लोकल यूआरएल लिंक पर ctrl+क्लिक करके, वेब इंटरफ़ेस देखा जा सकता है. इसके अलावा, Cloud Editor में सबसे ऊपर दाईं ओर मौजूद वेब की झलक बटन पर क्लिक करके भी, फ़्रंटएंड ऐप्लिकेशन को ऐक्सेस किया जा सकता है. इसके बाद, पोर्ट 8080 पर झलक देखें को चुनें

आपको वेब इंटरफ़ेस दिखेगा. हालांकि, चैट सबमिट करने की कोशिश करते समय आपको गड़बड़ी का मैसेज दिखेगा. ऐसा इसलिए होगा, क्योंकि बैकएंड सेवा को अब तक सेट अप नहीं किया गया है

अब सेवा को चलने दें और इसे अभी बंद न करें. इस बीच, हम यहां कोड के ज़रूरी कॉम्पोनेंट के बारे में बात कर सकते हैं
कोड के बारे में जानकारी
वेब इंटरफ़ेस से बैकएंड को डेटा भेजने का कोड इस हिस्से में है
def get_response_from_llm_backend(
message: Dict[str, Any],
history: List[Dict[str, Any]],
system_prompt: str,
) -> str:
...
# Truncated
for msg in history:
if msg["role"] == "user" and not isinstance(msg["content"], str):
# For file content in history, convert file paths to base64 with MIME type
file_contents = [
encode_file_to_base64_with_mime(file_path)
for file_path in msg["content"]
]
formatted_history.append({"role": msg["role"], "content": file_contents})
else:
formatted_history.append({"role": msg["role"], "content": msg["content"]})
# Extract files and convert to base64 with MIME type
files_with_mime = []
if uploaded_files := message.get("files", []):
for file_path in uploaded_files:
files_with_mime.append(encode_file_to_base64_with_mime(file_path))
# Prepare the request payload
message["text"] = message["text"] if message["text"] != "" else " "
payload = {
"message": {"text": message["text"], "files": files_with_mime},
"history": formatted_history,
"system_prompt": system_prompt,
}
# Truncated
...
जब हमें Gemini को मल्टीमॉडल डेटा भेजना होता है और सेवाओं के बीच डेटा को ऐक्सेस करने की सुविधा देनी होती है, तो हम डेटा को कोड में बताए गए base64 डेटा टाइप में बदल सकते हैं. हमें यह भी बताना होगा कि डेटा का MIME टाइप क्या है. हालाँकि, Gemini API सभी मौजूदा MIME टाइप के साथ काम नहीं करता. इसलिए, यह जानना ज़रूरी है कि Gemini के साथ काम करने वाले MIME टाइप कौनसे हैं. इनके बारे में इस दस्तावेज़ में पढ़ा जा सकता है. आपको Gemini API की हर सुविधा के बारे में जानकारी मिल सकती है. जैसे, Vision
इसके अलावा, चैट इंटरफ़ेस में चैट के इतिहास को अतिरिक्त कॉन्टेक्स्ट के तौर पर भेजना भी ज़रूरी है, ताकि Gemini को बातचीत की "याददाश्त" मिल सके. इसलिए, इस वेब इंटरफ़ेस में हम चैट का इतिहास भी भेजते हैं. इसे Gradio, हर वेब सेशन के हिसाब से मैनेज करता है. हम इसे उपयोगकर्ता के मैसेज इनपुट के साथ भेजते हैं. इसके अलावा, हम उपयोगकर्ता को सिस्टम के निर्देश में बदलाव करने और उसे भेजने की सुविधा भी देते हैं
4. FastAPI का इस्तेमाल करके बैकएंड सेवा बनाना
इसके बाद, हमें बैकएंड बनाना होगा. यह बैकएंड, पहले बताए गए पेलोड, उपयोगकर्ता के आखिरी मैसेज, चैट के इतिहास, और सिस्टम के निर्देश को मैनेज कर सकता है. हम एचटीटीपी बैकएंड सेवा बनाने के लिए, FastAPI का इस्तेमाल करेंगे.
नई फ़ाइल बनाएं. इसके लिए, File->New Text File पर क्लिक करें. इसके बाद,यहां दिया गया कोड कॉपी करके चिपकाएं. अब इसे backend.py के तौर पर सेव करें
import base64
from fastapi import FastAPI, Body
from google.genai.types import Content, Part
from google.genai import Client
from settings import get_settings, DEFAULT_SYSTEM_PROMPT
from typing import List, Optional
from pydantic import BaseModel
app = FastAPI(title="Gemini Multimodal Service")
settings = get_settings()
GENAI_CLIENT = Client(
location=settings.VERTEXAI_LOCATION,
project=settings.VERTEXAI_PROJECT_ID,
vertexai=True,
)
GEMINI_MODEL_NAME = "gemini-2.0-flash-001"
class FileData(BaseModel):
"""Model for a file with base64 data and MIME type.
Attributes:
data: Base64 encoded string of the file content.
mime_type: The MIME type of the file.
"""
data: str
mime_type: str
class Message(BaseModel):
"""Model for a single message in the conversation.
Attributes:
role: The role of the message sender, either 'user' or 'assistant'.
content: The text content of the message or a list of file data objects.
"""
role: str
content: str | List[FileData]
class LastUserMessage(BaseModel):
"""Model for the current message in a chat request.
Attributes:
text: The text content of the message.
files: List of file data objects containing base64 data and MIME type.
"""
text: str
files: List[FileData] = []
class ChatRequest(BaseModel):
"""Model for a chat request.
Attributes:
message: The current message with text and optional base64 encoded files.
history: List of previous messages in the conversation.
system_prompt: Optional system prompt to be used in the chat.
"""
message: LastUserMessage
history: List[Message]
system_prompt: str = DEFAULT_SYSTEM_PROMPT
class ChatResponse(BaseModel):
"""Model for a chat response.
Attributes:
response: The text response from the model.
error: Optional error message if something went wrong.
"""
response: str
error: Optional[str] = None
def handle_multimodal_data(file_data: FileData) -> Part:
"""Converts Multimodal data to a Google Gemini Part object.
Args:
file_data: FileData object with base64 data and MIME type.
Returns:
Part: A Google Gemini Part object containing the file data.
"""
data = base64.b64decode(file_data.data) # decode base64 string to bytes
return Part.from_bytes(data=data, mime_type=file_data.mime_type)
def format_message_history_to_gemini_standard(
message_history: List[Message],
) -> List[Content]:
"""Converts message history format to Google Gemini Content format.
Args:
message_history: List of message objects from the chat history.
Each message contains 'role' and 'content' attributes.
Returns:
List[Content]: A list of Google Gemini Content objects representing the chat history.
Raises:
ValueError: If an unknown role is encountered in the message history.
"""
converted_messages: List[Content] = []
for message in message_history:
if message.role == "assistant":
converted_messages.append(
Content(role="model", parts=[Part.from_text(text=message.content)])
)
elif message.role == "user":
# Text-only messages
if isinstance(message.content, str):
converted_messages.append(
Content(role="user", parts=[Part.from_text(text=message.content)])
)
# Messages with files
elif isinstance(message.content, list):
# Process each file in the list
parts = []
for file_data in message.content:
for file_data in message.content:
parts.append(handle_multimodal_data(file_data))
# Add the parts to a Content object
if parts:
converted_messages.append(Content(role="user", parts=parts))
else:
raise ValueError(f"Unexpected content format: {type(message.content)}")
else:
raise ValueError(f"Unknown role: {message.role}")
return converted_messages
@app.post("/chat", response_model=ChatResponse)
async def chat(
request: ChatRequest = Body(...),
) -> ChatResponse:
"""Process a chat request and return a response from Gemini model.
Args:
request: The chat request containing message and history.
Returns:
ChatResponse: The model's response to the chat request.
"""
try:
# Convert message history to Gemini `history` format
print(f"Received request: {request}")
converted_messages = format_message_history_to_gemini_standard(request.history)
# Create chat model
chat_model = GENAI_CLIENT.chats.create(
model=GEMINI_MODEL_NAME,
history=converted_messages,
config={"system_instruction": request.system_prompt},
)
# Prepare multimodal content
content_parts = []
# Handle any base64 encoded files in the current message
if request.message.files:
for file_data in request.message.files:
content_parts.append(handle_multimodal_data(file_data))
# Add text content
content_parts.append(Part.from_text(text=request.message.text))
# Send message to Gemini
response = chat_model.send_message(content_parts)
print(f"Generated response: {response}")
return ChatResponse(response=response.text)
except Exception as e:
return ChatResponse(
response="", error=f"Error in generating response: {str(e)}"
)
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8081)
इसे backend.py के तौर पर सेव करना न भूलें. इसके बाद, हम बैकएंड सेवा को चलाने की कोशिश कर सकते हैं. याद रखें कि पिछले चरण में हमने फ़्रंटएंड सेवा को सही तरीके से चलाया था. अब हमें नया टर्मिनल खोलना होगा और इस बैकएंड सेवा को चलाने की कोशिश करनी होगी
- नया टर्मिनल बनाएं. सबसे नीचे मौजूद टर्मिनल पर जाएं और नया टर्मिनल बनाने के लिए, "+" बटन ढूंढें. इसके अलावा, नया टर्मिनल खोलने के लिए Ctrl + Shift + C दबाएं

- इसके बाद, पक्का करें कि आप gemini-multimodal-chat-assistant वर्किंग डायरेक्ट्री में हों. इसके बाद, यह कमांड चलाएं
uv run backend.py
- अगर यह प्रोसेस पूरी हो जाती है, तो आपको इस तरह का आउटपुट दिखेगा
INFO: Started server process [xxxxx] INFO: Waiting for application startup. INFO: Application startup complete. INFO: Uvicorn running on http://0.0.0.0:8081 (Press CTRL+C to quit)
कोड के बारे में जानकारी
चैट का अनुरोध पाने के लिए एचटीटीपी रूट तय करना
FastAPI में, हम app डेकोरेटर का इस्तेमाल करके रूट तय करते हैं. हम एपीआई अनुबंध को तय करने के लिए, Pydantic का भी इस्तेमाल करते हैं. हम यह बताते हैं कि जवाब जनरेट करने का रूट, POST तरीके के साथ /chat रूट में है. ये फ़ंक्शन, यहां दिए गए कोड में बताए गए हैं
class FileData(BaseModel):
data: str
mime_type: str
class Message(BaseModel):
role: str
content: str | List[FileData]
class LastUserMessage(BaseModel):
text: str
files: List[FileData] = []
class ChatRequest(BaseModel):
message: LastUserMessage
history: List[Message]
system_prompt: str = DEFAULT_SYSTEM_PROMPT
class ChatResponse(BaseModel):
response: str
error: Optional[str] = None
...
@app.post("/chat", response_model=ChatResponse)
async def chat(
request: ChatRequest = Body(...),
) -> ChatResponse:
# Truncated
...
Gemini SDK में चैट के इतिहास का फ़ॉर्मैट तैयार करना
एक ज़रूरी बात यह है कि हम चैट के इतिहास को कैसे फिर से व्यवस्थित कर सकते हैं, ताकि बाद में Gemini क्लाइंट को शुरू करते समय, इसे history आर्ग्युमेंट की वैल्यू के तौर पर डाला जा सके. नीचे दिए गए कोड की जांच करें
def format_message_history_to_gemini_standard(
message_history: List[Message],
) -> List[Content]:
...
# Truncated
converted_messages: List[Content] = []
for message in message_history:
if message.role == "assistant":
converted_messages.append(
Content(role="model", parts=[Part.from_text(text=message.content)])
)
elif message.role == "user":
# Text-only messages
if isinstance(message.content, str):
converted_messages.append(
Content(role="user", parts=[Part.from_text(text=message.content)])
)
# Messages with files
elif isinstance(message.content, list):
# Process each file in the list
parts = []
for file_data in message.content:
parts.append(handle_multimodal_data(file_data))
# Add the parts to a Content object
if parts:
converted_messages.append(Content(role="user", parts=parts))
#Truncated
...
return converted_messages
Gemini SDK में चैट का इतिहास देने के लिए, हमें डेटा को List[Content] डेटा टाइप में फ़ॉर्मैट करना होगा. हर कॉन्टेंट में कम से कम एक भूमिका और पार्ट की वैल्यू होनी चाहिए. भूमिका से पता चलता है कि मैसेज का सोर्स क्या है. यह उपयोगकर्ता या मॉडल हो सकता है. यहां पार्ट का मतलब प्रॉम्प्ट से है. यह सिर्फ़ टेक्स्ट या अलग-अलग मोडेलिटी का कॉम्बिनेशन हो सकता है. इस दस्तावेज़ में, Content आर्ग्युमेंट को स्ट्रक्चर करने का तरीका देखें
टेक्स्ट के अलावा अन्य फ़ॉर्मैट ( मल्टीमॉडल) वाले डेटा को मैनेज करना
फ़्रंटएंड सेक्शन में पहले बताया गया था कि टेक्स्ट के अलावा अन्य तरह का डेटा या मल्टीमॉडल डेटा भेजने का एक तरीका यह है कि डेटा को base64 स्ट्रिंग के तौर पर भेजा जाए. हमें डेटा के लिए एमआईएमई टाइप भी तय करना होगा, ताकि इसे सही तरीके से समझा जा सके. उदाहरण के लिए, अगर हम .jpg सफ़िक्स के साथ इमेज डेटा भेजते हैं, तो हमें image/jpeg एमआईएमई टाइप देना होगा.
कोड का यह हिस्सा, base64 डेटा को Gemini SDK के Part.from_bytes फ़ॉर्मैट में बदलता है
def handle_multimodal_data(file_data: FileData) -> Part:
"""Converts Multimodal data to a Google Gemini Part object.
Args:
file_data: FileData object with base64 data and MIME type.
Returns:
Part: A Google Gemini Part object containing the file data.
"""
data = base64.b64decode(file_data.data) # decode base64 string to bytes
return Part.from_bytes(data=data, mime_type=file_data.mime_type)
5. इंटिग्रेशन टेस्ट
अब आपके पास अलग-अलग Cloud Console टैब में कई सेवाएं चलाने का विकल्प होना चाहिए:
- पोर्ट 8080 पर चलने वाली फ़्रंटएंड सेवा
* Running on local URL: http://0.0.0.0:8080 To create a public link, set `share=True` in `launch()`.
- बैकएंड सेवा, पोर्ट 8081 पर चलती है
INFO: Started server process [xxxxx] INFO: Waiting for application startup. INFO: Application startup complete. INFO: Uvicorn running on http://0.0.0.0:8081 (Press CTRL+C to quit)
फ़िलहाल, आपको पोर्ट 8080 पर वेब ऐप्लिकेशन से, चैट के दौरान दस्तावेज़ भेजने की सुविधा मिलनी चाहिए. फ़ाइलें अपलोड करके और सवाल पूछकर, एक्सपेरिमेंट शुरू किया जा सकता है! ध्यान रखें कि कुछ फ़ाइल टाइप का इस्तेमाल अभी नहीं किया जा सकता और उनसे जुड़ी गड़बड़ी दिखेगी.
टेक्स्ट बॉक्स के नीचे मौजूद अतिरिक्त इनपुट फ़ील्ड में जाकर, सिस्टम के निर्देशों में भी बदलाव किया जा सकता है

6. Cloud Run पर डिप्लॉय करना
अब हम इस बेहतरीन ऐप्लिकेशन को दूसरों को दिखाना चाहते हैं. इसके लिए, हम इस ऐप्लिकेशन को पैकेज कर सकते हैं और इसे Cloud Run पर एक सार्वजनिक सेवा के तौर पर डिप्लॉय कर सकते हैं. इससे दूसरे लोग इसे ऐक्सेस कर पाएंगे. इसके लिए, आइए आर्किटेक्चर पर फिर से नज़र डालें

इस कोडलैब में, हम फ़्रंटएंड और बैकएंड, दोनों सेवाओं को एक कंटेनर में रखेंगे. इन दोनों सेवाओं को मैनेज करने के लिए, हमें supervisord की मदद की ज़रूरत होगी.
नई फ़ाइल बनाएं. इसके लिए, फ़ाइल->नई टेक्स्ट फ़ाइल पर क्लिक करें. इसके बाद, यहां दिया गया कोड कॉपी करके चिपकाएं. फिर, इसे supervisord.conf के तौर पर सेव करें
[supervisord]
nodaemon=true
user=root
logfile=/dev/stdout
logfile_maxbytes=0
pidfile=/var/run/supervisord.pid
[program:backend]
command=uv run backend.py
directory=/app
autostart=true
autorestart=true
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
startsecs=10
startretries=3
[program:frontend]
command=uv run frontend.py
directory=/app
autostart=true
autorestart=true
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
startsecs=10
startretries=3
इसके बाद, हमें Dockerfile की ज़रूरत होगी. File->New Text File पर क्लिक करें. इसके बाद, यहां दिया गया कोड कॉपी करके चिपकाएं. इसके बाद,इसे Dockerfile के तौर पर सेव करें
FROM python:3.12-slim
COPY --from=ghcr.io/astral-sh/uv:0.6.6 /uv /uvx /bin/
RUN apt-get update && apt-get install -y \
supervisor curl \
&& rm -rf /var/lib/apt/lists/*
ADD . /app
WORKDIR /app
RUN uv sync --frozen
EXPOSE 8080
# Copy supervisord configuration
COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf
ENV PYTHONUNBUFFERED=1
ENTRYPOINT ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"]
इस समय, हमारे पास Cloud Run पर ऐप्लिकेशन डिप्लॉय करने के लिए ज़रूरी सभी फ़ाइलें मौजूद हैं. इसलिए, अब हम इसे डिप्लॉय करते हैं. Cloud Shell टर्मिनल पर जाएं और पक्का करें कि मौजूदा प्रोजेक्ट, आपके एक्टिव प्रोजेक्ट के लिए कॉन्फ़िगर किया गया हो. अगर ऐसा नहीं है, तो प्रोजेक्ट आईडी सेट करने के लिए, gcloud configure कमांड का इस्तेमाल करें:
gcloud config set project [PROJECT_ID]
इसके बाद, इसे Cloud Run पर डिप्लॉय करने के लिए, यहां दिया गया कमांड चलाएं.
gcloud run deploy --source . \
--env-vars-file settings.yaml \
--port 8080 \
--region us-central1
इसके बाद, आपको अपनी सेवा का नाम डालने के लिए कहा जाएगा. मान लीजिए, आपने "gemini-multimodal-chat-assistant" नाम डाला. हमारे ऐप्लिकेशन की वर्किंग डायरेक्ट्री में Dockerfile मौजूद है. इसलिए, यह Docker कंटेनर बनाएगा और उसे Artifact Registry में पुश करेगा. यह आपको यह भी सूचना देगा कि वह इस क्षेत्र में Artifact Registry रिपॉज़िटरी बनाएगा. इसके लिए, "Y" पर क्लिक करें. जब आपसे पूछा जाए कि क्या आपको बिना पुष्टि किए गए अनुरोधों को अनुमति देनी है, तो "हां" कहें. ध्यान दें कि हम यहां बिना पुष्टि किए ऐक्सेस करने की अनुमति दे रहे हैं, क्योंकि यह एक डेमो ऐप्लिकेशन है. हमारा सुझाव है कि आप अपने एंटरप्राइज़ और प्रोडक्शन ऐप्लिकेशन के लिए, पुष्टि करने के सही तरीके का इस्तेमाल करें.
डप्लॉयमेंट पूरा होने के बाद, आपको यहां दिए गए लिंक जैसा लिंक मिलेगा:
https://gemini-multimodal-chat-assistant-*******.us-central1.run.app
अब गुप्त विंडो या अपने मोबाइल डिवाइस से ऐप्लिकेशन का इस्तेमाल करें. यह पहले से ही लाइव होना चाहिए.
7. चुनौती
अब आपको अपनी खोज करने की क्षमता को बेहतर बनाने का मौका मिला है. क्या आपके पास कोड में बदलाव करने का तरीका है, ताकि Assistant ऑडियो फ़ाइलें या वीडियो फ़ाइलें पढ़ सके?
8. व्यवस्थित करें
इस कोडलैब में इस्तेमाल किए गए संसाधनों के लिए, अपने Google Cloud खाते से शुल्क न लिए जाने के लिए, यह तरीका अपनाएं:
- Google Cloud Console में, संसाधन मैनेज करें पेज पर जाएं.
- प्रोजेक्ट की सूची में, वह प्रोजेक्ट चुनें जिसे आपको मिटाना है. इसके बाद, मिटाएं पर क्लिक करें.
- डायलॉग बॉक्स में, प्रोजेक्ट आईडी टाइप करें. इसके बाद, प्रोजेक्ट मिटाने के लिए बंद करें पर क्लिक करें.
- इसके अलावा, कंसोल पर Cloud Run पर जाकर, अभी-अभी डिप्लॉय की गई सेवा को चुनें और उसे मिटाएं.