Müşterinizin Telegram üzerinden etkileşim kurabileceği bir ajan tabanlı yapay zeka uygulaması oluşturma

1. Giriş

Müşterilerinizin halihazırda kullandıkları mesajlaşma uygulamasından doğrudan etkileşim kurabileceği sorunsuz ve etkileşimli ajan tabanlı yapay zeka deneyimleri oluşturun. Web arayüzlerinde ve modern mesajlaşma kanallarında sorunsuz çalışan akıllı uygulamaları nasıl geliştireceğinizi ve dağıtacağınızı öğrenin.

Ne oluşturacaksınız?

Gemini destekli, ADK tabanlı bir uygulama olan ve müşterilerin restoran menüsüne göz atıp rezervasyon yapmasına yardımcı olan tam teşekküllü bir "Restoran Asistanı" ile Telegram sohbet uygulaması arasındaki entegrasyon. Telegram botuyla etkileşim kurabilir ve "Acı ve vejetaryen bir şeyler istiyorum" gibi doğal dil açıklamaları isteyebilirsiniz. Ardından bot, ADK aracısına bağlanır. Bu aracı, vektör araması için otomatik yerleştirme oluşturma da dahil olmak üzere tüm veritabanı erişimini işleyen MCP Toolbox for Databases aracılığıyla Cloud SQL PostgreSQL veritabanından okuma ve bu veritabanına yazma işlemleri yapar. Bu sırada kullanıcı, botun mesajı aldığını ve ADK aracısından yanıt beklerken yanıt için ... typing yazdığını görebilir.

c1d28343ed68358a.png

Neler öğreneceksiniz?

  • Gemini destekli, ADK tabanlı çalışan bir "Restoran Konsiyerji" uygulaması dağıtma
  • BotFather'ı kullanarak Telegram sohbet botu oluşturma
  • Bot web kancasını dinlemek için Python uygulamaları yazma
  • Kullanıcı mesajı hakkında Telegram'da ... typing bildirim göndermek için sohbet işlemi gönderin ve gerçek yanıt beklenirken ... typing periyodik olarak göndermek için anket yapın.
  • Kullanıcının sorgusunu işlemek için Restaurant Concierge cloud run uç noktasını çağırın
  • ADK aracısından gelen yanıtı işleme, Telegram'a mesaj gönderme ve arabelleği kapatma
  • Python uygulamasını Cloud Run'a dağıtma
  • Telegram bot'unuzla etkileşim kurma

Ön koşullar

2. Ortam Kurulumu - Önceki Codelab'den devam etme

Bu codelab'de sunduğumuz anlatılar aslında ön koşul codelab'i olan: ADK, MCP Toolbox ve Cloud SQL ile Ajan Tabanlı RAG veya Ölçeklenebilir Ajanlar: Ajan Çalışma Zamanında A2A Protokolü ve ADK Entegrasyonu ile Çok Ajanlı Mimari'nin devamıdır. Önceki codelab'deki çalışmanıza devam edebilirsiniz.

Önceki codelab'in çalışma dizininde ( çalışma dizini build-agent-adk-toolbox-cloudsql veya adk-a2a-agent-runtime-starter olmalıdır) oluşturmaya başlayabiliriz. Karışıklığı önlemek için dizini, yeni bir projeye başladığımızda kullandığımız dizin adıyla yeniden adlandıralım.

ADK, MCP Toolbox ve Cloud SQL ile Ajan Tabanlı RAG laboratuvarından devam ediyorsanız :

mv ~/build-agent-adk-toolbox-cloudsql ~/build-agent-adk-telegram

Aksi takdirde, Ölçekli Temsilciler: Agent Runtime ve ADK Entegrasyonunda A2A Protokolü ile Çok Temsilcili Mimari adlı laboratuvardan devam ediyorsanız

mv ~/adk-a2a-agent-runtime-starter ~/build-agent-adk-telegram

Ardından, çalışma dizinimizi bu dizinle değiştirin.

cloudshell workspace ~/build-agent-adk-telegram && cd ~/build-agent-adk-telegram
source .env

Ardından, restaurant-agent öğenizin dağıtıldığını ve erişilebilecek herkese açık bir URL'ye sahip olduğunu doğrulayın.

AGENT_URL=$(gcloud run services describe restaurant-agent \
    --region="$REGION" \
    --format='value(status.url)')

echo "      ✓ Agent service deployed"
echo "      Agent URL: $AGENT_URL"
echo ""

URL'ye erişebiliyorsanız bir sonraki bölüme geçebilirsiniz: Create Telegram Bot

3. Ortam Kurulumu - Başlangıç deposuyla yeni bir başlangıç yapma

Bu adımda Cloud Shell ortamınız hazırlanır, Google Cloud projeniz yapılandırılır ve başlangıç deposu klonlanır.

Cloud Shell'i açma

Tarayıcınızda Cloud Shell'i açın. Cloud Shell, bu codelab için ihtiyacınız olan tüm araçların bulunduğu önceden yapılandırılmış bir ortam sağlar. İstendiğinde Yetkilendir'i tıklayın.

Ardından, terminali açmak için "Görünüm" -> "Terminal"i tıklayın. Arayüzünüz aşağıdaki gibi görünmelidir.

86307fac5da2f077.png

Bu, ana arayüzümüz olacak. Üstte IDE, altta terminal yer alacak.

Çalışma dizininizi ayarlama

Başlangıç deposunu klonlayın. Bu codelab'de yazdığınız tüm kodlar burada yer alır:

rm -rf ~/build-agent-adk-telegram
git clone https://github.com/alphinside/adk-a2a-agent-runtime-starter.git build-agent-adk-telegram
cloudshell workspace ~/build-agent-adk-telegram && cd ~/build-agent-adk-telegram

Sağlanan şablondan .env dosyasını oluşturun:

cp .env.example .env

Terminalinizde proje kurulumunu basitleştirmek için bu proje kurulum komut dosyasını çalışma dizininize indirin:

curl -sL https://raw.githubusercontent.com/alphinside/cloud-trial-project-setup/main/setup_verify_trial_project.sh -o setup_verify_trial_project.sh

Komut dosyasını çalıştırın. Bu komut, deneme faturalandırma hesabınızı doğrular, yeni bir proje oluşturur (veya mevcut bir projeyi doğrular), proje kimliğinizi geçerli dizindeki bir .env dosyasına kaydeder ve gcloud'de etkin projeyi ayarlar.

bash setup_verify_trial_project.sh && source .env

Komut dosyası:

  1. Etkin bir deneme faturalandırma hesabınız olduğunu doğrulayın.
  2. .env içinde mevcut bir proje olup olmadığını kontrol edin (varsa)
  3. Yeni bir proje oluşturun veya mevcut projeyi yeniden kullanın
  4. Deneme faturalandırma hesabını projenize bağlama
  5. Proje kimliğini .env dosyasına kaydedin.
  6. Projeyi etkin gcloud projesi olarak ayarlayın

Cloud Shell terminal isteminde çalışma dizininizin yanındaki sarı metni kontrol ederek projenin doğru şekilde ayarlandığını doğrulayın. Proje kimliğiniz gösterilmelidir.

5c515e235ee1179f.png

Başlangıç Altyapı Kurulumu

Öncelikle, Rust ile yazılmış hızlı bir Python paketi ve proje yöneticisi olan uv kullanarak Python bağımlılıklarını yüklememiz gerekir ( uv belgeleri). Bu codelab, Python projesini korumada hız ve basitlik için bu aracı kullanır.

uv sync

Ardından, Cloud SQL örneğini oluşturan, verileri yerleştiren ve restoran temsilcimizin ilk durumu olarak hareket edecek Toolbox hizmetini dağıtan tam kurulum komut dosyasını çalıştırın.

bash scripts/full_setup.sh > logs/full_setup.log 2>&1 &

Bu, şu işlemi gerçekleştirecek:

  • Cloud SQL örneği oluşturma ve veritabanını başlatma (1. Aşama)
  • Aracı ortamı yapılandırmasını oluşturma ve yerel araç kutusu hizmetini başlatma (2. Aşama)
  • Toolbox ve Agent hizmetlerini Cloud Run'a dağıtma (3. Aşama)

Bu dağıtım tamamlandıktan sonra Cloud Run URL'sinde ADK Dev kullanıcı arayüzüne erişebilirsiniz.

source .env
AGENT_URL=$(gcloud run services describe restaurant-agent \
    --region="$REGION" \
    --format='value(status.url)')

echo "      ✓ Agent service deployed"
echo "      Agent URL: $AGENT_URL"
echo ""

ADK geliştirici kullanıcı arayüzünü açın, restaurant_agent simgesini seçin ve aşağıdaki örnekteki gibi sorgularla test edin:

What Italian dishes do you have?

Ya da

I want something spicy and creamy

Şimdi ise yalnızca web geliştirme arayüzünden Telegram mesajlaşma kanalına nasıl geçebileceğimiz sorusuna cevap arayacağız.

4. Telegram botu oluşturma

Telegram, topluluk tabanlı etkileşim için yaygın olarak kullanılan, iyi bilinen ücretsiz bir mesajlaşma platformudur. Bunun nedenlerinden biri, kolayca entegre olmanın birçok yolunu sunmasıdır. Bu sayede kullanıcılar, çok çeşitli işlevlere sahip kendi botlarını kolayca oluşturabilir.

Bu örnekte, ilk kez kendi botumuzu oluşturmak için BotFather'ı kullanacağız. Bu oturumda Telegram'ı kullanıyor olsak da aynı yöntemin WhatsApp veya tercih ettiğiniz diğer mesajlaşma platformlarında da kullanılabileceğini unutmayın.

Kendi Botunuzu Oluşturmak İçin BotFather'ı Kullanma

Web tarayıcınızı kullanarak https://telegram.me/BotFather adresini ziyaret edin ve kendi Telegram botunuzu oluşturmaya başlayın.

1b817e758c699a79.png

The BotFather ile etkileşime başlama

ad3daa08e73502db.png

/start komutunu gönderme

BotFather'ı kullanmaya başlamak ve ilk botunuzu oluşturmak için BotFather'a /start mesajını göndermeniz gerekir. BotFather, daha fazla etkileşim kurabilmeniz için tüm komutlarını sizinle paylaşır.

/start

/newbot komutuyla bot oluşturma işlemini başlatma

BotFather'a /newbot komutunu göndererek yeni botumuzu oluşturalım. Bot'unuza ad vermenizi ve ardından bot'a username vermenizi ister. Bu, her zaman bot ile bitmesini gerektirir. Örneğin, TetrisBot veya tetris_bot. Bu değer benzersiz olmalıdır.

1f6a74f494d48986.png

Bot başarıyla oluşturulduğunda BotFather'dan aşağıdaki mesajı alırsınız:

Done! Congratulations on your new bot. You will find it at t.me/AdkTelegramTest_bot. You can now add a description, about section and profile picture for your bot, see /help for a list of commands. By the way, when you've finished creating your cool bot, ping our Bot Support if you want a better username for it. Just make sure the bot is fully operational before you do this.

Use this token to access the HTTP API:
<YOUR_TELEGRAM_API_KEY>
Keep your token secure and store it safely, it can be used by anyone to control your bot.

For a description of the Bot API, see this page: https://core.telegram.org/bots/api

YOUR_TELEGRAM_API_KEY değerini not edin. Bu değeri sonraki bölümde kullanacağız.

5. Telegram Webhook Uygulamasını Geliştirme

Telegram webhook uygulamanızı geliştirmeye başlamak için çalışma dizinini hazırlayalım

mkdir ~/build-agent-adk-telegram/telegram-integration
cd ~/build-agent-adk-telegram

Gerekli bağımlılıkları ekleme

Telegram webhook dinleyici komut dosyası için yeterli bağımlılıkları sağlamak üzere aşağıdaki içeriğe sahip bir requirements.txt komut dosyası oluşturun.

cloudshell edit ./telegram-integration/requirements.txt

Ardından aşağıdaki bağımlılıkları ekleyin

python-telegram-bot[webhooks]
httpx

Telegram Webhook Listener için komut dosyası oluşturma

Bağımlılık yüklendikten sonra Şimdi entegrasyon uygulaması için bir Python komut dosyası main.py oluşturabiliriz.

cloudshell edit ~/build-agent-adk-telegram/telegram-integration/main.py

Ardından, aşağıdaki kodu kopyalayıp bu dosyaya yapıştırın.

# ./telegram-integration/main.py

import asyncio
import os
import sys
from telegram import Update
from telegram.ext import Application, CommandHandler, MessageHandler, filters, CallbackContext
from telegram.constants import ChatAction
import httpx

# Read token from environment variable
TOKEN = os.environ.get("TELEGRAM_BOT_TOKEN")
ADK_SERVER_URL = os.environ.get("ADK_SERVER_URL", "http://localhost:8000")
ADK_APP_NAME = os.environ.get("ADK_APP_NAME", "restaurant_agent")

# Parse base URL out of ADK_SERVER_URL
BASE_URL = ADK_SERVER_URL.rstrip('/')
if BASE_URL.endswith('/run'):
    BASE_URL = BASE_URL[:-4]
elif BASE_URL.endswith('/query'):
    BASE_URL = BASE_URL[:-6]

if not TOKEN:
    print("Error: TELEGRAM_BOT_TOKEN environment variable not set.")
    print("Please set it before running the application.")
    sys.exit(1)

async def start(update: Update, context: CallbackContext) -> None:
    """Send a message when the command /start is issued."""
    await update.message.reply_text('Hi! I am your ADK Integration Bot. Send me a message and I will forward it to the ADK server.')

async def send_typing_loop(chat_id: int, bot, stop_event: asyncio.Event):
    """Send typing action periodically until the stop event is set."""
    while not stop_event.is_set():
        try:
            await bot.send_chat_action(chat_id=chat_id, action=ChatAction.TYPING)
            # The research suggested repeating every 4 seconds
            await asyncio.sleep(4)
        except Exception as e:
            print(f"Error sending chat action: {e}")
            await asyncio.sleep(1) # Wait a bit before retrying if error

async def handle_message(update: Update, context: CallbackContext) -> None:
    """Handle incoming user messages."""
    user_message = update.message.text
    chat_id = update.message.chat_id
    raw_user_id = str(update.message.from_user.id)
    
    # Derive unique user_id and session_id for this user
    user_id = f"tg_{raw_user_id}"
    session_id = f"tg_sess_{raw_user_id}"

    print(f"Received message from {user_id}: {user_message}")

    # Create a stop event for the typing loop
    stop_event = asyncio.Event()
    
    # Start the typing loop as a background task
    typing_task = asyncio.create_task(send_typing_loop(chat_id, context.bot, stop_event))

    try:
        async with httpx.AsyncClient() as client:
            # 1. Check if the session exists
            session_url = f"{BASE_URL}/apps/{ADK_APP_NAME}/users/{user_id}/sessions/{session_id}"
            session_check = await client.get(session_url, timeout=10.0)
            
            if session_check.status_code == 404:
                # 2. If session doesn't exist, create it
                print(f"Session {session_id} not found. Creating session...")
                session_create = await client.post(session_url, json={}, timeout=10.0)
                if session_create.status_code != 200:
                    raise Exception(f"Failed to create session: {session_create.status_code} {session_create.text}")
            elif session_check.status_code != 200:
                raise Exception(f"Error checking session: {session_check.status_code} {session_check.text}")
            
            # 3. Run the ADK agent
            run_url = f"{BASE_URL}/run"
            payload = {
                "appName": ADK_APP_NAME,
                "userId": user_id,
                "sessionId": session_id,
                "newMessage": {
                    "role": "user",
                    "parts": [{"text": user_message}]
                }
            }
            response = await client.post(run_url, json=payload, timeout=60.0)
            
        if response.status_code == 200:
            events = response.json()
            if isinstance(events, list) and len(events) > 0:
                # The last event contains the final text response
                last_event = events[-1]
                content = last_event.get("content", {})
                parts = content.get("parts", [])
                if parts and "text" in parts[0]:
                    reply_text = parts[0]["text"]
                else:
                    reply_text = "ADK agent returned an empty or non-text response."
            else:
                reply_text = "No events returned from ADK agent."
        else:
            reply_text = f"Error communicating with ADK server (Status: {response.status_code})."
            
    except Exception as e:
        reply_text = f"Failed to connect to ADK server: {e}"
    finally:
        # Stop the typing loop
        stop_event.set()
        await typing_task

    # Send the final response back to the user
    await update.message.reply_text(reply_text)

def main() -> None:
    """Start the bot."""
    # Create the Application and pass it your bot's token.
    application = Application.builder().token(TOKEN).build()

    # on different commands - answer in Telegram
    application.add_handler(CommandHandler("start", start))

    # on non command i.e message - echo the message on Telegram
    application.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, handle_message))

    # Check if running in webhook mode (e.g., on Cloud Run)
    port = os.environ.get("PORT")
    service_url = os.environ.get("SERVICE_URL")

    if port and service_url:
        if not service_url.startswith("http"):
            service_url = f"https://{service_url}"
        
        print(f"Starting bot in WEBHOOK mode on port {port} with url {service_url}")
        
        application.run_webhook(
            listen="0.0.0.0",
            port=int(port),
            url_path=TOKEN,
            webhook_url=f"{service_url}/{TOKEN}",
            allowed_updates=Update.ALL_TYPES
        )
    else:
        print("Starting bot in POLLING mode")
        # Run the bot until the user presses Ctrl-C
        application.run_polling(allowed_updates=Update.ALL_TYPES)


if __name__ == "__main__":
    main()

Telegram Bot Entegrasyon kodunu anlama

23b346f5ceb4712a.png

Bir kullanıcı mesaj gönderdiğinde aşağıdaki işlem hattı handle_message() altında çalışır.

1. adım: Kimlik ve oturum türetme

Bot, kullanıcı oturumlarını ayrı tutmak için Telegram kullanıcı kimliğini benzersiz ADK tanımlayıcılarıyla eşler:

user_id = f"tg_{raw_user_id}"
session_id = f"tg_sess_{raw_user_id}"

2. adım: Asenkron "Yazma" durumu (53-58. satırlar)

ADK aracısı istemi işlerken (bu işlem birkaç saniye sürebilir) yüksek düzeyde duyarlı bir kullanıcı deneyimi sağlamak için bot, eşzamansız bir arka plan döngüsü başlatır:

  • asyncio.Event, stop_event olarak oluşturulur.
  • asyncio.create_task, arka planda send_typing_loop(...) oluşturur.
  • Döngü, stop_event ayarlanana kadar her 4 saniyede bir Telegram'a ChatAction.TYPING işlemi gönderir.

3. adım: ADK oturum doğrulama ve oluşturma (61-72. satırlar)

Bot, temsilciyi yürütmeden önce mevcut bir oturum olup olmadığını kontrol eder:

  1. /apps/{appName}/users/{userId}/sessions/{sessionId} uygulamasına GET isteği gönderir.
  2. Yanıt 404 Not Found ise aynı URL'ye boş bir JSON gövdesiyle POST isteği göndererek oturum oluşturur.
  3. 200 veya 404 dışında bir durum döndürülürse istisna oluşturulur.

4. Adım: Acenteye İstek Gönderme (74-85. satırlar)

Mesaj yükü, ADK /run uç noktasına yönlendirilir:

  • Uç nokta: POST /run
  • İsteğin zaman aşımı süresi, karmaşık muhakeme veya yukarı akış gecikmesine izin vermek için 60.0 saniye olarak ayarlanır.
  • Yük Yapısı:
{
  "appName": "restaurant_agent",
  "userId": "tg_<user_id>",
  "sessionId": "tg_sess_<user_id>",
  "newMessage": {
    "role": "user",
    "parts": [{"text": "<user_message>"}]
  }
}

5. adım: Yanıtı ayrıştırma (87-101. satırlar)

ADK sunucusu, ileti etkinliklerinin bir listesini döndürür. Bot, döndürülen diziyi inceler:

  • Listedeki son etkinliği (events[-1]) alır.
  • event["content"]["parts"][0]["text"] aracılığıyla metin içeriğine gider.
  • Etkinlik döndürülmezse veya metin yapısı eksikse açıklayıcı bir yer tutucu metin ayarlanır.

6. adım: Ayrıntılı Analiz ve Yanıt Gönderme (103-111. satırlar)

  • finally bloğunda stop_event ayarlanır ve yazma işlemi döngüsü durdurulur.
  • Bot, temiz kaynaklar sağlamak için typing_task tamamlanmasını bekler.
  • Son olarak bot, ayrıştırılan yanıt metniyle Telegram sohbetine yanıt verir.

6. Telegram Webhook Uygulamasını Cloud Run'a dağıtma

Ardından, botumuzun Telegram Webhook Listener ile iletişim kurabilmesi için bu işleyiciyi Cloud Run'a dağıtacağız.

Dockerfile'ı oluşturma

Öncelikle Dockerfile'ı oluşturmamız gerekir.

cloudshell edit ~/build-agent-adk-telegram/telegram-integration/Dockerfile

Ardından, aşağıdaki kodu kopyalayıp bu dosyaya yapıştırın.

# Use an official Python runtime as a parent image
FROM python:3.11-slim

# Prevent Python from writing pyc files to disc and buffering stdout/stderr
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1

# Set the working directory in the container
WORKDIR /app

# Install system dependencies if needed
RUN apt-get update && apt-get install -y --no-install-recommends \
    build-essential \
    && rm -rf /var/lib/apt/lists/*

# Copy the dependencies file to the working directory
COPY requirements.txt .

# Install any needed packages specified in requirements.txt
RUN pip install --no-cache-dir -r requirements.txt

# Copy the rest of the application code
COPY main.py .

# Expose the port that Cloud Run will provide via environment variable
EXPOSE 8080

# Run main.py when the container launches
CMD ["python", "main.py"]

Hizmet, görüntü ayak izini küçük tutmak için python:3.11-slim kullanılarak kapsülleştirilir:

  • requirements.txt (python-telegram-bot[webhooks] ve httpx) bağımlılıklarını yükler.
  • Standart bağlantı noktası 8080'yı kullanıma sunar.
  • Lansmanlar python main.py.

Ortam Değişkenlerini Hazırlama

Ardından, aracımızın başarıyla dağıtılıp dağıtılmadığını tekrar kontrol edelim.

AGENT_URL=$(gcloud run services describe restaurant-agent \
    --region="$REGION" \
    --format='value(status.url)')

echo "      ✓ Agent service deployed"
echo "      Agent URL: $AGENT_URL"
echo ""

Ardından, daha önce aldığımız TELEGRAM_BOT_TOKEN'ı .env içine yerleştirelim.

echo "TELEGRAM_BOT_TOKEN=YOUR_TELEGRAM_API_KEY" >> .env

Ardından, .env verilerini ihtiyacımız olan diğer değerlerle dolduralım.

echo "ADK_SERVER_URL=$AGENT_URL" >> .env
echo "ADK_APP_NAME=restaurant_agent" >> .env
echo "SERVICE_NAME=telegram-integration" >> .env
source .env

Dağıtım komut dosyası oluşturma

Tam kontroller sağlayacak ve uygulamayı Cloud Run'a dağıtacak bir dağıtım komut dosyası oluşturalım.

cloudshell edit ~/build-agent-adk-telegram/telegram-integration/deploy.sh

Aşağıdaki kodu dosyaya kopyalayın.

#!/usr/bin/env bash
# ./telegram-integration/deploy.sh

# Exit immediately if a command exits with a non-zero status
set -euo pipefail

# Color codes for neat terminal output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0;37m' # No Color
# Load environment variables from .env if it exists
if [ -f .env ]; then
    echo -e "${GREEN}✔ Loading environment variables from .env...${NC}"
    export $(grep -v '^#' .env | xargs)
fi

echo -e "${BLUE}====================================================${NC}"
echo -e "${BLUE}   Google Cloud Run Deployment: Telegram Bot        ${NC}"
echo -e "${BLUE}====================================================${NC}"

# 1. Check for gcloud CLI
if ! command -v gcloud &> /dev/null; then
    echo -e "${RED}Error: 'gcloud' CLI is not installed.${NC}"
    echo "Please install the Google Cloud SDK and try again."
    echo "See: https://cloud.google.com/sdk/docs/install"
    exit 1
fi

# 2. Check active gcloud account/auth
ACTIVE_ACCOUNT=$(gcloud auth list --filter=status:ACTIVE --format="value(account)" 2>/dev/null || true)
if [ -z "$ACTIVE_ACCOUNT" ]; then
    echo -e "${RED}Error: No active Google Cloud account found.${NC}"
    echo "Please run: gcloud auth login"
    exit 1
fi

# 3. Detect / Prompt for GCP Project
DEFAULT_PROJECT=${GCP_PROJECT_ID:-$(gcloud config get-value project 2>/dev/null || true)}
if [ -n "${DEFAULT_PROJECT}" ]; then
    echo -e "${GREEN}✔ Using GCP Project: $DEFAULT_PROJECT${NC}"
    GCP_PROJECT="$DEFAULT_PROJECT"
else
    echo -n "Enter GCP Project ID: "
    read -r GCP_PROJECT
fi

if [ -z "$GCP_PROJECT" ]; then
    echo -e "${RED}Error: GCP Project ID is required.${NC}"
    exit 1
fi

# Set active project
gcloud config set project "$GCP_PROJECT" &> /dev/null

# 4. Configure Service Parameters
DEFAULT_SERVICE=${SERVICE_NAME:-"telegram-integration"}
if [ -n "${SERVICE_NAME:-}" ]; then
    echo -e "${GREEN}✔ Using Cloud Run Service Name: $SERVICE_NAME${NC}"
else
    echo -n "Enter Cloud Run Service Name [Default: $DEFAULT_SERVICE]: "
    read -r SERVICE_NAME
    SERVICE_NAME=${SERVICE_NAME:-$DEFAULT_SERVICE}
fi

DEFAULT_REGION=${REGION:-"us-central1"}
if [ -n "${REGION:-}" ]; then
    echo -e "${GREEN}✔ Using Cloud Run Region: $REGION${NC}"
else
    echo -n "Enter Cloud Run Region [Default: $DEFAULT_REGION]: "
    read -r REGION
    REGION=${REGION:-$DEFAULT_REGION}
fi

DEFAULT_ADK_APP=${ADK_APP_NAME:-"restaurant_agent"}
if [ -n "${ADK_APP_NAME:-}" ]; then
    echo -e "${GREEN}✔ Using ADK App Name: $ADK_APP_NAME${NC}"
    ADK_APP="$ADK_APP_NAME"
else
    echo -n "Enter ADK App Name [Default: $DEFAULT_ADK_APP]: "
    read -r ADK_APP
    ADK_APP=${ADK_APP:-$DEFAULT_ADK_APP}
fi

# 5. Retrieve/Prompt for Telegram Bot Token
if [ -n "${TELEGRAM_BOT_TOKEN:-}" ]; then
    echo -e "${GREEN}✔ Found TELEGRAM_BOT_TOKEN in environment.${NC}"
    BOT_TOKEN="$TELEGRAM_BOT_TOKEN"
else
    echo -e "${YELLOW}TELEGRAM_BOT_TOKEN is not set in your environment.${NC}"
    echo -n "Enter your Telegram Bot Token (input will be hidden): "
    read -s -r BOT_TOKEN
    echo ""
fi

if [ -z "$BOT_TOKEN" ]; then
    echo -e "${RED}Error: Telegram Bot Token is required.${NC}"
    exit 1
fi

# 6. Retrieve/Prompt for ADK Server URL
DEFAULT_ADK_URL="http://localhost:8000"
if [ -n "${ADK_SERVER_URL:-}" ]; then
    echo -e "${GREEN}✔ Found ADK_SERVER_URL in environment: $ADK_SERVER_URL${NC}"
    ADK_URL="$ADK_SERVER_URL"
else
    echo -n "Enter your ADK Server URL [Default: $DEFAULT_ADK_URL]: "
    read -r ADK_URL
    ADK_URL=${ADK_URL:-$DEFAULT_ADK_URL}
fi

# Enable required GCP services
echo -e "\n${YELLOW}Checking and enabling required GCP services...${NC}"
gcloud services enable run.googleapis.com cloudbuild.googleapis.com artifactregistry.googleapis.com --project "$GCP_PROJECT"

# Determine source directory dynamically
SOURCE_DIR="."
if [ -d "telegram-integration" ]; then
    SOURCE_DIR="telegram-integration"
    echo -e "${GREEN}✔ Found source directory: telegram-integration${NC}"
elif [ -f "Dockerfile" ]; then
    SOURCE_DIR="."
    echo -e "${GREEN}✔ Dockerfile found in current directory. Using current directory as source.${NC}"
else
    echo -e "${RED}Error: Could not find source directory 'telegram-integration' or Dockerfile in current directory.${NC}"
    exit 1
fi

# 7. First-pass Deployment with placeholder SERVICE_URL
# This boots the container in Webhook mode (so health check binds to port)
# but uses a high-reliability placeholder URL (google.com) to pass DNS verification checks.
echo -e "\n${YELLOW}Deploying to Cloud Run (Step 1/2: Initial Deploy)...${NC}"
gcloud run deploy "$SERVICE_NAME" \
  --source "$SOURCE_DIR" \
  --region "$REGION" \
  --allow-unauthenticated \
  --set-env-vars "TELEGRAM_BOT_TOKEN=$BOT_TOKEN,ADK_SERVER_URL=$ADK_URL,ADK_APP_NAME=$ADK_APP,SERVICE_URL=https://google.com" \
  --project "$GCP_PROJECT"

# 8. Retrieve the actual service URL
echo -e "\n${YELLOW}Retrieving service URL...${NC}"
SERVICE_URL=$(gcloud run services describe "$SERVICE_NAME" --region "$REGION" --project "$GCP_PROJECT" --format 'value(status.url)')
echo -e "${GREEN}✔ Service URL is: $SERVICE_URL${NC}"

# 9. Update service environment variables with the real SERVICE_URL
# This triggers a rolling update and registers the correct webhook with Telegram automatically!
echo -e "\n${YELLOW}Updating configuration with final Webhook URL (Step 2/2)...${NC}"
gcloud run services update "$SERVICE_NAME" \
  --region "$REGION" \
  --set-env-vars "TELEGRAM_BOT_TOKEN=$BOT_TOKEN,ADK_SERVER_URL=$ADK_URL,ADK_APP_NAME=$ADK_APP,SERVICE_URL=$SERVICE_URL" \
  --project "$GCP_PROJECT"

echo -e "\n${GREEN}====================================================${NC}"
echo -e "${GREEN}   Deployment Completed Successfully! 🎉            ${NC}"
echo -e "${GREEN}====================================================${NC}"
echo -e "Service Name:   ${BLUE}$SERVICE_NAME${NC}"
echo -e "Region:         ${BLUE}$REGION${NC}"
echo -e "Active URL:     ${BLUE}$SERVICE_URL${NC}"
echo -e "Webhook Path:   ${BLUE}$SERVICE_URL/<bot-token>${NC}"
echo -e "ADK Backend:    ${BLUE}$ADK_URL${NC}"
echo -e "ADK App Name:   ${BLUE}$ADK_APP${NC}"
echo -e "${GREEN}====================================================${NC}"
echo "Your Telegram Bot has been configured to use webhooks."
echo "Any message sent to your bot will now trigger this Cloud Run instance."

Çift dağıtım komut dosyası (deploy.sh)

Google Cloud Run'a dağıtılırken botun, Telegram'da webhook hedefi olarak kaydedebilmesi için kendi URL'sini (SERVICE_URL) ortamında belirtmesi gerekir. Bu döngüsel bağımlılığı (URL, dağıtıma kadar bilinmez ancak hizmetin, sistemin başlatılması için URL'nin sağlık durumu kontrolü hatası olmadan başlatılmasını gerektirir) çözmek için deploy.sh iki aşamalı bir dağıtım gerçekleştirir:

  1. 1. adım: İlk dağıtım: Hizmetin başarıyla başlatılması, yerel bağlantı noktasına bağlanması ve ilk Cloud Run durum denetimlerini geçmesi için kapsayıcıyı yer tutucu DNS (https://google.com) ile başlatır.
  2. 2. adım: URL'yi getirin: gcloud run services describe kullanarak yeni oluşturulan Cloud Run uç noktasını programatik olarak ayıklar.
  3. 3. adım: Yapılandırmayı güncelleme: Ortam değişkenlerini gerçek canlı hizmet URL'siyle günceller. Bu işlem, Cloud Run'da temiz bir periyodik güncellemeyi tetikler ve doğru webhook hedefini Telegram API'ye güvenli bir şekilde kaydeder.

Cloud Run'a dağıtma

Dağıtım komut dosyası, aracı URL'sini yazdırır. Cloud Run'da çalışan aynı ADK geliştirici kullanıcı arayüzüne erişmek için tarayıcınızda açın.

cd ~/build-agent-adk-telegram
bash ./telegram-integration/deploy.sh

Her şey yolunda giderse bu aşamada, Telegram sohbet uygulamasından doğrudan botunuzla sohbet etmeye başlayabilirsiniz. Yeni oluşturduğunuz botu bulup etkileşim kurmaya başlayın:

What Italian dishes do you have?

Ya da

I want something spicy and creamy

Botun "...yazıyor" gönderme durumunu izleyin. Kısa süre sonra, daha önce oluşturduğunuz ADK'dan gelen mesajı döndürür.

c62fd4016ddd3c9b.png

7. Tebrikler!

HTTP istemci sunucu iletişimi aracılığıyla akıllı restoran menüsü asistanı ADK tabanlı yapay zeka aracımızı oluşturup dağıttınız ve Telegram ile tamamen entegre ettiniz. Ayrıca, kullanıcıların favori menülerini sorgulamasına ve restoranda rezervasyon yapmasına olanak tanıyorsunuz.

Öğrendikleriniz

  • Restaurant Concierge, ADK tabanlı aracı ve MCP Toolbox'ı Cloud Run'a dağıtma ve yapılandırma
  • BotFather'ı kullanarak Telegram botu oluşturma
  • Telegram webhook'unu dinlemek ve kullanıcı sorgusunu ve yanıtını buna göre iletmek için ADK aracısıyla etkileşim kurmak üzere Python komut dosyaları yazma
  • ADK aracısının yanıt vermesini beklerken iletilerin gerçek zamanlı geri bildirim olarak işlendiğini kullanıcılara bildirmek için Telegram'da "... typing" nasıl uygulanır?
  • Python komut dosyasını Cloud Run'a dağıtma ve komut dosyasıyla etkileşim kurma

Temizleme

Google Cloud hesabınızın ücretlendirilmesini önlemek için bu codelab'de oluşturulan kaynakları silin.

gcloud projects delete $GOOGLE_CLOUD_PROJECT

2. seçenek: Kaynakları tek tek silme

# If you follow from previous A2A Agent Runtime codelab
# Delete the Agent Runtime deployment (skip if not found)
uv run python -c "
import vertexai
from google.genai import types
vertexai.init(project='$GOOGLE_CLOUD_PROJECT', location='$REGION')
client = vertexai.Client(
    project='$GOOGLE_CLOUD_PROJECT', location='$REGION',
    http_options=types.HttpOptions(api_version='v1beta1'),
)
try:
    agent = client.agent_engines.get(name='$RESERVATION_AGENT_RESOURCE_NAME')
    agent.delete(force=True)
    print('Agent Runtime deployment deleted.')
except Exception as e:
    print(f'No agent deployment found or already deleted, skipping. ({e})')
"

# Delete GCS staging bucket (skip if STAGING_BUCKET is not set)
if [ -n "$STAGING_BUCKET" ]; then
  gsutil rm -r gs://$STAGING_BUCKET
else
  echo "STAGING_BUCKET not set, skipping bucket deletion."
fi

# Delete Cloud Run services
gcloud run services delete restaurant-agent --region=$REGION --quiet
gcloud run services delete toolbox-service --region=$REGION --quiet
gcloud run services delete telegram-integration --region=$REGION --quiet

# Delete Cloud SQL instance
gcloud sql instances delete $DB_INSTANCE --quiet