Erişilebilir Çoklu Modlu Yapay Zeka Temsilcisi Oluşturma: Ses, Görme ve Sohbet

1. Giriş

Bu eğitimde, dünyayı görebilen ve size açıklayabilen, eller serbest ve sesle çalışan bir yapay zeka aracısı olan ClarityCam'i oluşturacaksınız. ClarityCam, erişilebilirlik temel alınarak tasarlanmıştır ve görme engelli veya az gören kullanıcılar için güçlü bir araç sunar. Ancak öğreneceğiniz ilkeler, modern ve genel amaçlı tüm ses uygulamalarını oluşturmak için gereklidir.

Atölye karakteri ve başlığıyla birlikte atölyenin tamamının başlığı

Bu proje, Doğal Olarak Uyarlanabilir Arayüz (NAI) adı verilen güçlü bir tasarım felsefesi üzerine kurulmuştur. NAI, erişilebilirliği sonradan eklenen bir özellik olarak ele almak yerine temel olarak kabul eder. Bu yaklaşımla, yapay zeka aracısı arayüz olarak işlev görür. Farklı kullanıcılara uyum sağlar, ses ve görüntü gibi çok formatlı girişleri işler ve benzersiz ihtiyaçlarına göre kullanıcılara proaktif olarak rehberlik eder.

NAI ile İlk Yapay Zeka Ajanınızı Oluşturma:

Bu aracının nasıl çalıştığını hikaye anlatma yöntemiyle gösteren kullanıcı arayüzü

Bu oturumun sonunda şunları yapabileceksiniz:

  • Erişilebilirliği Varsayılan Olarak Tasarlama: Tüm kullanıcılara eşdeğer deneyimler sunan yapay zeka sistemleri oluşturmak için Yerel Olarak Uyarlanabilir Arayüz (NAI) ilkelerini uygulayın.
  • Kullanıcı Amacını Sınıflandırma: Doğal dil komutlarını aracınız için yapılandırılmış işlemlere çeviren güçlü bir amaç sınıflandırıcı oluşturun.
  • Sohbet Bağlamını Koruma: Aracınızın takip sorularını ve referans komutlarını (ör. "Ne renk?").
  • Etkili istemler oluşturun: Doğru ve güvenilir görüntü analizi için Gemini gibi çok formatlı bir modelde odaklanmış, bağlam açısından zengin istemler oluşturun.
  • Belirsizliği Ele Alma ve Kullanıcıya Yol Gösterme: Kapsam dışı istekler için zarif bir hata işleme tasarımı yapın ve güven oluşturmak için kullanıcıları proaktif bir şekilde dahil edin.
  • Çoklu aracı sistemini düzenleme: Uygulamanızı, ses işleme, analiz ve konuşma sentezi gibi karmaşık görevleri yönetmek için birlikte çalışan bir dizi uzmanlaşmış aracı kullanarak yapılandırın.

2. Üst Düzey Tasarım

ClarityCam, temelde kullanıcı için basit olacak şekilde tasarlanmıştır ancak işbirliği yapan yapay zeka aracıları tarafından desteklenen gelişmiş bir sistemle çalışır. Mimariyi inceleyelim.

Bu uygulamanın işleyiş şeklinin tanıtımı

Kullanıcı Deneyimi

Öncelikle, kullanıcının ClarityCam ile nasıl etkileşimde bulunduğuna bakalım. Tüm deneyim eller serbest ve sohbet odaklıdır. Kullanıcı bir komut veriyor ve temsilci, sözlü bir açıklama veya işlemle yanıt veriyor. Bu sıra şeması, kullanıcının ilk sesli komutundan cihazın son sesli yanıtına kadar olan tipik bir etkileşim akışını gösterir.

Bu uygulamanın akışının sıra diyagramı

Yapay Zeka Temsilcisi Mimarisi

Yüzeyin altında, deneyimi hayata geçirmek için çoklu aracı sistemi uyum içinde çalışır. Bir komut alındığında merkezi bir Orchestrator aracısı, görevleri amacı anlamak, görüntüleri analiz etmek ve yanıt oluşturmaktan sorumlu uzmanlaşmış aracılara devreder. Bu yapay zeka akış şeması, bu aracıların nasıl ortak çalıştığına dair ayrıntılı bilgi sağlar. Bu mimariyi aşağıdaki bölümlerde uygulayacağız.

ai flow of this application

Proje Dosyalarına Hızlı Bir Bakış

Kod yazmaya başlamadan önce projemizin dosya yapısını tanıyalım. Çok sayıda dosya varmış gibi görünebilir ancak bu eğitimin tamamı için yalnızca iki belirli alana odaklanmanız gerekir.

Projemizin basitleştirilmiş haritasını aşağıda bulabilirsiniz.

accessibilityAI/src/
├── 📁 app/
   ├── layout.tsx      # An overall page shell (you can ignore this).
   └── page.tsx        # ⬅️ MODIFY THIS: The main user interface for our app.

├── 📁 ai/
   ├── 📁flows         # ⬅️ MODIFY THIS: The core AI logic and server functions.
   └── intent-classifier.ts     # ⬅️ MODIFY THIS: Where we'll edit our AI prompts.
|   └── ai-instance.ts
|   └── dev.ts

├── 📁 components/       # Contains pre-built UI components (ignore this).

├── 📁 hooks/

├── 📁 lib/

└── 📁 types/

Teknoloji Yığını

Sistemimiz, güçlü bulut hizmetlerini ve son teknoloji yapay zeka modellerini bir araya getiren modern ve ölçeklenebilir bir teknoloji yığını üzerine kurulmuştur. Kullanacağımız temel bileşenler şunlardır:

  • Google Cloud Platform (GCP): Aracılarımız için sunucusuz altyapı sağlar.
    • Cloud Run: Ayrı ayrı aracıları container'a alınmış, ölçeklenebilir mikro hizmetler olarak dağıtır.
    • Artifact Registry: Aracıları için Docker görüntülerini güvenli bir şekilde depolar ve yönetir.
    • Secret Manager: Hassas kimlik bilgilerini ve API anahtarlarını güvenli bir şekilde işler.
  • Büyük dil modelleri (LLM'ler): Sistemin "beyni" olarak işlev görür.
    • Google'ın Gemini Modelleri: Kullanıcı amacını sınıflandırmaktan görsel içeriği analiz etmeye ve akıllı açıklamalar sağlamaya kadar her şey için Gemini ailesinin güçlü çok formatlı özelliklerini kullanırız.

3. Kurulum ve Ön Koşullar

Faturalandırma hesabını etkinleştirme

Yeni bir GCP projesi oluşturma

  • Google Cloud Console'a gidip yeni bir proje oluşturun.

yeni bir GCP hesabı oluşturabilirsiniz

  • Google Cloud Console'a gidip yeni bir proje oluşturun.
  • Sol paneli açın, Billing simgesini tıklayın ve faturalandırma hesabının bu GCP hesabına bağlı olup olmadığını kontrol edin.

Faturalandırma hesabını GCP hesabına bağlama

Bu sayfayı görüyorsanız manage billing account seçeneğini işaretleyin, Google Cloud deneme sürümünü seçin ve bu sürüme bağlayın.

Gemini API anahtarınızı oluşturma

Anahtarı güvence altına alabilmek için önce bir anahtarınızın olması gerekir.

  • Google Yapay Zeka Studio'ya gidin : https://aistudio.google.com/
  • Google hesabınızla oturum açın.
  • Genellikle soldaki gezinme bölmesinde veya sağ üst köşede bulunan "API anahtarı al" düğmesini tıklayın.
  • "API anahtarları" iletişim kutusunda "Yeni projede API anahtarı oluştur"u tıklayın.
  • Sizin için yeni bir API anahtarı oluşturulur. Bu anahtarı hemen kopyalayın ve geçici olarak güvenli bir yerde (ör. şifre yöneticisi veya güvenli not) saklayın. Bu, sonraki adımlarda kullanacağınız değerdir.

Yerel Geliştirme İş Akışı (Makinenizde Test Etme)

npm run dev komutunu çalıştırabilmeniz ve uygulamanızın çalışması gerekir. Bu noktada .env devreye girer.

  • API anahtarını dosyaya ekleyin: .env adlı yeni bir dosya oluşturun ve bu dosyaya aşağıdaki satırı ekleyin.

YOUR_API_KEY_HERE yerine, AI Studio'dan aldığınız ve .env konumuna kaydettiğiniz anahtarı eklediğinizden emin olun:

GOOGLE_GENAI_API_KEY="YOUR_API_KEY_HERE"

[İsteğe bağlı] IDE ve ortamı ayarlama

Bu eğitimde, yerel terminalinizle birlikte VS Code veya IntelliJ gibi tanıdık bir geliştirme ortamında çalışabilirsiniz. Ancak standartlaştırılmış ve önceden yapılandırılmış bir ortam sağlamak için Google Cloud Shell'i kullanmanızı önemle tavsiye ederiz.

Aşağıdaki adımlar Cloud Shell bağlamı için yazılmıştır. Bunun yerine yerel ortamınızı kullanmayı tercih ederseniz lütfen git, nvm, npm ve gcloud'ün yüklendiğinden ve doğru şekilde yapılandırıldığından emin olun.

Cloud Shell Düzenleyici'de çalışma

👉Google Cloud Console'un üst kısmındaki Cloud Shell'i etkinleştir'i tıklayın (Cloud Shell bölmesinin üst kısmındaki terminal şeklindeki simge). Cloud Shell

👉 "Open Editor" (Düzenleyiciyi Aç) düğmesini tıklayın (kalemli açık bir klasöre benzer). Bu işlemle pencerede Cloud Shell kod düzenleyici açılır. Sol tarafta bir dosya gezgini görürsünüz. Cloud Shell

👉Gösterildiği gibi, alt durum çubuğundaki Cloud Code ile oturum açma düğmesini tıklayın. Eklentiyi talimatlara göre yetkilendirin. Durum çubuğunda Cloud Code - no project (Cloud Code - proje yok) ifadesini görüyorsanız bunu seçin, ardından açılır listede "Select a Google Cloud Project" (Bir Google Cloud projesi seçin) seçeneğini ve oluşturduğunuz projeler listesinden belirli bir Google Cloud projesini seçin. Cloud Shell

👉Bulut IDE'sinde terminali açın. Cloud Shell

👉Terminalde, aşağıdaki komutu kullanarak kimliğinizin doğrulandığını ve projenin proje kimliğinize ayarlandığını doğrulayın:

gcloud auth list

👉 natively-accessible-interface projesini GitHub'dan kopyalayın:

git clone https://github.com/cuppibla/AccessibilityAgent.git

👉Ayrıca <YOUR_PROJECT_ID> yerine proje kimliğinizi yazdığınızdan emin olun (proje kimliğinizi Google Cloud Console'un proje bölümünde bulabilirsiniz. ❗️❗️project id ile project number'ı karıştırmamaya dikkat edin❗️❗️):

echo <YOUR_PROJECT_ID> > ~/project_id.txt
gcloud config set project $(cat ~/project_id.txt)

👉Gerekli Google Cloud API'lerini etkinleştirmek için aşağıdaki komutu çalıştırın: (Bu komutun çalışması yaklaşık 2 dakika sürebilir)

gcloud services enable compute.googleapis.com  \
                        storage.googleapis.com  \
                        run.googleapis.com  \
                        artifactregistry.googleapis.com  \
                        aiplatform.googleapis.com \
                        eventarc.googleapis.com \
                        sqladmin.googleapis.com \
                        secretmanager.googleapis.com \
                        cloudbuild.googleapis.com \
                        cloudresourcemanager.googleapis.com \
                        cloudfunctions.googleapis.com \
                        cloudaicompanion.googleapis.com

Bu işlem birkaç dakika sürebilir.

İzin ayarlama

👉Hizmet hesabı iznini ayarlayın. Terminalde şunu çalıştırın :

gcloud config set project $(cat ~/project_id.txt)
export PROJECT_ID=$(gcloud config get project)
export SERVICE_ACCOUNT_NAME=$(gcloud compute project-info describe --format="value(defaultServiceAccount)")

echo "Here's your SERVICE_ACCOUNT_NAME $SERVICE_ACCOUNT_NAME"

👉 İzin verin. Terminalde şunu çalıştırın :

#Cloud Storage (Read/Write):
gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:$SERVICE_ACCOUNT_NAME" \
  --role="roles/storage.objectAdmin"

#Pub/Sub (Publish/Receive):
gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:$SERVICE_ACCOUNT_NAME" \
  --role="roles/pubsub.publisher"

gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:$SERVICE_ACCOUNT_NAME" \
  --role="roles/pubsub.subscriber"


#Cloud SQL (Read/Write):
gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:$SERVICE_ACCOUNT_NAME" \
  --role="roles/cloudsql.editor"


#Eventarc (Receive Events):
gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:$SERVICE_ACCOUNT_NAME" \
  --role="roles/iam.serviceAccountTokenCreator"

gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:$SERVICE_ACCOUNT_NAME" \
  --role="roles/eventarc.eventReceiver"

#Vertex AI (User):
gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:$SERVICE_ACCOUNT_NAME" \
  --role="roles/aiplatform.user"

#Secret Manager (Read):
gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:$SERVICE_ACCOUNT_NAME" \
  --role="roles/secretmanager.secretAccessor"

4. Kullanıcı Girişini Anlama - Amaç Sınıflandırıcı

Yapay zeka aracımızın harekete geçebilmesi için önce kullanıcının ne istediğini doğru bir şekilde anlaması gerekir. Gerçek dünyadaki girişler genellikle karmaşıktır. Belirsiz olabilir, yazım hataları içerebilir veya sohbet dilinde olabilir.

Bu bölümde, ham kullanıcı girişini net ve uygulanabilir bir komuta dönüştüren kritik "dinleme" bileşenlerini oluşturacağız.

Amaca yönelik sınıflandırıcının işleyiş şeklini gösteren giriş akışı

Amaç sınıflandırıcı ekleme

Şimdi sınıflandırıcımızı destekleyen yapay zeka mantığını tanımlayacağız.

👉 İşlem: Cloud Shell IDE'nizde ~/src/ai/intent-classifier/ dizinine gidin.

1. adım: Aracının kelime dağarcığını tanımlayın (IntentCategory)

Öncelikle, aracımızın gerçekleştirebileceği her olası işlemin kesin bir listesini oluşturmamız gerekir.

👉 İşlem: Yer tutucu // REPLACE ME PART 1: add IntentCategory here öğesini aşağıdaki kodla değiştirin:

👉 Aşağıdaki kodla:

export type IntentCategory =
  // Image Analysis Intents
  | "DescribeImage"
  | "AskAboutImage"
  | "ReadTextInImage"
  | "IdentifyColorsInImage"
  // Control Intents
  | "TakePicture"
  | "StartCamera"
  | "SelectImage"
  | "StopSpeaking"
  // Preference Intents
  | "SetDescriptionDetailed"
  | "SetDescriptionConcise"
  // Fallback Intents
  | "GeneralInquiry"       // User has a general question about the agent's functions or polite interaction
  | "OutOfScopeRequest"    // User's request is clearly outside the agent's defined capabilities
  | "Unknown";             // Intent could not be determined with confidence

Açıklama

Bu TypeScript kodu, IntentCategory adlı özel bir tür oluşturur. Bu liste, temsilcimizin anlayabileceği her olası işlemi veya "amacı" tanımlayan katı bir listedir. Bu, olası sonsuz sayıda kullanıcı ifadesini ("Ne görüyorsun?", "Resimde ne var?") temiz ve tahmin edilebilir bir komut grubuna dönüştürdüğü için çok önemli bir ilk adımdır. Sınıflandırıcımızın amacı, tüm kullanıcı sorgularını bu belirli kategorilerden biriyle eşlemektir.

2. Adım

Yapay zekamızın doğru kararlar verebilmesi için kendi yeteneklerini ve sınırlamalarını bilmesi gerekir. Bu bilgileri ayrıntılı bir metin bloğu olarak sunacağız.

👉 İşlem: Yer tutucu REPLACE ME PART 2: add AGENT_CAPABILITIES_AND_LIMITATIONS here ifadesini aşağıdaki kodla değiştirin:

Aşağıdaki kodu değiştirin: // REPLACE ME PART 2: add AGENT_CAPABILITIES_AND_LIMITATIONS here:

👉 Aşağıdaki kodla

const AGENT_CAPABILITIES_AND_LIMITATIONS = `
**Core Capabilities (What the Agent CAN DO):**
* **Image Analysis:**
    * DescribeImage: Provide a general description of the current image.
    * AskAboutImage: Answer a specific question about the visual content of the current image (e.g., "Is there a dog?", "What color is the car?").
    * ReadTextInImage: Read any text found in the current image.
    * IdentifyColorsInImage: Identify the dominant colors of the current image.
* **Image Input Control:**
    * TakePicture: Capture an image using the currently active camera stream.
    * StartCamera: Activate the camera (e.g., "use camera", "take another picture").
    * SelectImage: Allow the user to choose an image file from their device.
* **Voice & Audio Control:**
    * StopSpeaking: Stop the current text-to-speech output.
* **Preference Management:**
    * SetDescriptionDetailed: Make future image descriptions more detailed.
    * SetDescriptionConcise: Make future image descriptions less detailed or concise.
* **General Interaction:**
    * GeneralInquiry: Handle conversational phrases (e.g., "hello", "thank you") or questions about its own capabilities (e.g., "what can you do?", "help").

**Limitations (What the Agent CANNOT DO and should be classified as OutOfScopeRequest):**
* Cannot generate or create new images.
* Cannot edit or modify existing images (e.g., "remove background," "make the car blue").
* Cannot analyze video files or live video beyond capturing a single frame.
* Cannot provide general knowledge or answer questions unrelated to the provided image's visual content (e.g., "What's the weather?", "Who is the president?", "Tell me a joke", "What time is it?").
* Cannot perform mathematical calculations or complex data analysis.
* Cannot translate languages as a primary function.
* Cannot remember information from past images or vastly different previous queries in the same session.
* Cannot control other device settings or applications.
* Cannot perform web searches.
`;

Bu neden önemli?

Bu metin, kullanıcıların okuması için değil, yapay zeka modelimiz için hazırlanmıştır. Dil modeline (LLM) doğru kararlar vermesi için gereken bağlamı sağlamak amacıyla bu "iş açıklamasını" doğrudan istemimize (bir sonraki adımda) aktaracağız. Bu bağlam olmadan, LLM "hava nasıl?" sorusunu AskAboutImage olarak yanlış sınıflandırabilir. Bu bağlam sayesinde, hava durumunun resimdeki bir görsel öğe olmadığını anlar ve bunu kapsam dışı olarak doğru şekilde sınıflandırır.

3. Adım

Şimdi, Gemini modelinin sınıflandırma işlemini gerçekleştirmek için uygulayacağı talimatların tamamını yazacağız.

👉 İşlem: // REPLACE ME PART 3 - classifyIntentPrompt yerine aşağıdaki kodu kullanın:

aşağıdaki kodla

const classifyIntentPrompt = ai.definePrompt({
  name: 'classifyIntentPrompt',
  input: { schema: ClassifyIntentInputSchema },
  output: { schema: ClassifyIntentOutputSchema },
  prompt: `You are classifying the user's intent for ClarityCam, a voice-controlled AI application focused on image analysis.
Analyze the user query: '{userQuery}'.

First, understand ClarityCam's capabilities and limitations:
${AGENT_CAPABILITIES_AND_LIMITATIONS}

Now, classify the user's PRIMARY intent into ONE of the following categories:
* **DescribeImage**: User wants a general description of the current image.
* **AskAboutImage**: User is asking a specific question directly related to the visual content of the current image.
* **ReadTextInImage**: User wants any text read from the current image.
* **IdentifyColorsInImage**: User wants the dominant colors of the current image.
* **TakePicture**: User wants to capture an image using an active camera.
* **StartCamera**: User wants to activate the camera.
* **SelectImage**: User wants to choose an image file.
* **StopSpeaking**: User wants the current text-to-speech output to stop.
* **SetDescriptionDetailed**: User wants future image descriptions to be more detailed.
* **SetDescriptionConcise**: User wants future image descriptions to be less detailed.
* **GeneralInquiry**: The query is a simple conversational filler (e.g., "hello", "thanks"), a polite closing, or a direct question about the agent's functions (e.g., "what can you do?", "how does this work?", "help").
* **OutOfScopeRequest**: The query asks the agent to perform an action clearly listed under its "Limitations" or otherwise demonstrably outside its defined image analysis and control functions. Examples: "Tell me a joke," "What's the weather in London?", "Generate an image of a cat," "Can you edit my photo to make it brighter?", "Send this image to my friends","Translate 'hello' to Spanish."

Output ONLY the category name.
If the query is ambiguous but seems generally related to polite interaction or asking about the agent itself, prefer 'GeneralInquiry'.
If the query is clearly asking for something the agent CANNOT do, use 'OutOfScopeRequest'.
If truly unclassifiable even with these guidelines, use 'Unknown'.`,
  config: {
    temperature: 0.05, // Very low temperature for highly deterministic classification
  }
});

İşte sihrin gerçekleştiği yer burası. Bu, sınıflandırıcımızın "beyni"dir. Yapay zekaya rolünü söyler, gerekli bağlamı sağlar ve istenen çıktıyı tanımlar. Aşağıdaki önemli istem mühendisliği tekniklerine dikkat edin:

  • Rol yapma: Net bir görev belirlemek için "Şunu sınıflandırıyorsun..." ile başlar.
  • Bağlam Ekleme: AGENT_CAPABILITIES_AND_LIMITATIONS değişkenini isteme dinamik olarak ekler.
  • Katı Çıkış Biçimlendirmesi: "YALNIZCA kategori adını çıkış olarak ver" talimatı, kodumuzda kolayca kullanabileceğimiz temiz ve tahmin edilebilir bir yanıt almak için çok önemlidir.
  • Düşük sıcaklık: Sınıflandırma için yaratıcı değil, belirleyici ve mantıklı yanıtlar istiyoruz. Sıcaklığı çok düşük bir değere (0,05) ayarlamak modelin son derece odaklanmış ve tutarlı olmasını sağlar.

4. adım: Uygulamayı yapay zeka akışına bağlayın

Son olarak, yeni yapay zeka sınıflandırıcımızı ana uygulama dosyasından çağıralım.

👉 İşlem: ~/src/app/page.tsx dosyanıza gidin. processVoiceCommand işlevinin içinde, // REPLACE ME PART 1: add classificationResult ifadesini aşağıdakilerle değiştirin:

const classificationResult = await classifyIntentFlow({ userQuery: commandToProcess });
        intent = classificationResult.intent as IntentCategory;

Bu kod, ön uç uygulamanız ile arka uç yapay zeka mantığınız arasındaki önemli köprüdür. Kullanıcının sesli komutunu (commandToProcess) alır, yeni oluşturduğunuz classifyIntentFlow'e gönderir ve yapay zekanın sınıflandırılmış amacı döndürmesini bekler.

Niyet değişkeni artık temiz ve yapılandırılmış bir komut (ör. DescribeImage) içeriyor. Bu sonuç, uygulamanın mantığını yönlendirmek ve bir sonraki adımda hangi işlemin yapılacağına karar vermek için kullanılan switch ifadesinde kullanılır. Bu, yapay zekanın "düşünme" sürecinin uygulamanın "yapma" sürecine dönüştürülme şeklidir.

Kullanıcı arayüzünü başlatma

Uygulamamızı iş başında görme zamanı geldi. Geliştirme sunucusunu başlatalım.

👉 Terminalinizde aşağıdaki komutu çalıştırın: npm run dev Not: npm run dev komutunu çalıştırmadan önce npm install komutunu çalıştırmanız gerekebilir.

Bir süre sonra aşağıdakine benzer bir çıkış görürsünüz. Bu, sunucunun başarıyla çalıştığı anlamına gelir:

   ▲ Next.js 15.2.3 (Turbopack)
   - Local:        http://localhost:9003
   - Network:      http://10.88.0.4:9003
   - Environments: .env

 ✓ Starting...
 ✓ Ready in 1512ms
 ○ Compiling / ...
 ✓ Compiled / in 26.6s

Şimdi uygulamayı tarayıcınızda açmak için yerel URL'yi (http://localhost:9003) tıklayın.

SightGuide kullanıcı arayüzünü görmeniz gerekir. Şimdilik düğmeler herhangi bir mantığa bağlı olmadığından tıklamak hiçbir işe yaramaz. Bu aşamada tam olarak bunu bekliyoruz. Bir sonraki bölümde bunları nasıl kullanacağımızı göreceğiz.

Kullanıcı arayüzünü gördüğünüz için artık terminalinize dönüp Ctrl + C tuşuna basarak geliştirme sunucusunu durdurabilirsiniz.

5. Kullanıcı Girişini Anlama - Kusurlu Sorgu Kontrolü

Eksik Sorgu Kontrolü Ekleme

1. Bölüm: İstem Tanımlama ("Ne")

Öncelikle yapay zekamızın talimatlarını tanımlayalım. İstem, yapay zeka çağrımızın "tarifi"dir. Modele tam olarak ne yapmasını istediğimizi söyler.

👉 İşlem: IDE'nizde ~/src/ai/flows/check_typo/ konumuna gidin.

Aşağıdaki kodu değiştirin: // REPLACE ME PART 1: add prompt here:

👉 Aşağıdaki kodla

const prompt = ai.definePrompt({
  name: 'checkTypoPrompt',
  input: {
    schema: CheckTypoInputSchema,
  },
  output: {
    schema: CheckTypoOutputSchema,
  },
  prompt: `You are a helpful AI assistant that checks user text for typos and suggests corrections.
- If you find typos, respond with the corrected text.
- If there are no typos, or if you are unsure about a correction, respond with the original text unchanged.

User text: {text}

Corrected text:
`,
});

Bu kod bloğu, checkTypoPrompt adlı yapay zekamız için yeniden kullanılabilir bir şablon tanımlar. Giriş ve çıkış şemaları, bu görev için veri sözleşmesini tanımlar. Bu sayede hatalar önlenir ve sistemimiz tahmin edilebilir hale gelir.

2. Bölüm: Akışı Oluşturma ("Nasıl")

Artık "tarifimiz" (istem) olduğuna göre, bunu gerçekten yürütebilecek bir işlev oluşturmamız gerekiyor. Genkit'te buna akış denir. Akış, istemimizi uygulamamızın geri kalanının kolayca çağırabileceği yürütülebilir bir işlevle sarmalar.

👉 İşlem: Aynı ~/src/ai/flows/check_typo/ dosyasında aşağıdaki kodu // REPLACE ME PART 2: add flow here ile değiştirin:

👉 Aşağıdaki kodla

const checkTypoFlow = ai.defineFlow<
  typeof CheckTypoInputSchema,
  typeof CheckTypoOutputSchema
>(
  {
    name: 'checkTypoFlow',
    inputSchema: CheckTypoInputSchema,
    outputSchema: CheckTypoOutputSchema,
  },
  async input => {
    const {output} = await prompt(input);
    return output!;
  }
);

3. Bölüm: Yazım Hatası Denetleyicisi'ni kullanma

Yapay zeka akışımız tamamlandığına göre artık bunu uygulamamızın ana mantığına entegre edebiliriz. Kullanıcı komutunu aldıktan hemen sonra metni temizleyerek başka bir işleme tabi tutarız.

👉İşlem: ~/src/app/ai/flows/check-typo.ts bölümüne gidin ve export async function checkTypo işlevini bulun. Dönüş ifadesinin yorumunu kaldırın:

return; yerine return checkTypoFlow(input); yapın.

👉İşlem: ~/src/app/page.tsx bölümüne gidin ve processVoiceCommand işlevini bulun. Aşağıdaki kodu değiştirin: REPLACE ME PART 2: add typoResult here:

👉 Aşağıdaki kodla

const typoResult = await checkTypo({ text: rawCommand });
        if (typoResult && typoResult.correctedText && typoResult.correctedText.trim().length > 0) {
            const originalTrimmedLower = rawCommand.trim().toLowerCase();
            const correctedTrimmedLower = typoResult.correctedText.trim().toLowerCase();
            if (correctedTrimmedLower !== originalTrimmedLower) {
                commandToProcess = typoResult.correctedText;
                typoCorrectionAnnouncement = `I think you said: ${commandToProcess}. `;
            }
        }

Bu değişiklikle birlikte, her kullanıcı komutu için daha sağlam bir veri işleme hattı oluşturduk.

Sesli Komut Akışı (Yalnızca Okuma, İşlem Gerekmez)

Sesli komut akışındaki transkript akışı

Temel "anlama" bileşenlerimizi (Yazım Denetleyici ve Amaç Sınıflandırıcı) ele aldığımıza göre, bunların uygulamanın ana ses işleme mantığına nasıl uyduğunu görelim.

Her şey kullanıcının konuşmasıyla başlar. Tarayıcının Web Speech API'si konuşmayı dinler ve kullanıcı konuşmayı bitirdiğinde duyduklarının metin transkriptini sağlar. Bu işlem aşağıdaki kodla gerçekleştirilir.

👉Salt Okuma: ~/src/app/page.tsx ve handleResult işlevine gidin. Aşağıdaki kodu bulun:

for (let i = event.resultIndex; i < event.results.length; ++i) {
        if (event.results[i].isFinal) {
          finalTranscript += event.results[i][0].transcript;
        }
      }
      if (finalTranscript) {
        console.log("Final Transcript:", finalTranscript);
        processVoiceCommand(finalTranscript);
      }

Yazım Hatası Düzeltme Özelliğimizi Test Etme

Şimdi de işin eğlenceli kısmına geçelim. Yeni yazım hatası düzeltme özelliğimizin hem mükemmel hem de kusurlu sesli komutları nasıl işlediğine bakalım.

Uygulamayı başlatma

Öncelikle geliştirme sunucusunu tekrar çalıştıralım. Terminalinizde şu komutu çalıştırın: npm run dev

Uygulamayı açma

Sunucu hazır olduğunda tarayıcınızı açın ve yerel adrese (ör. http://localhost:9003).

Sesli komutları etkinleştirme

Start Listening düğmesini tıklayın. Tarayıcınız büyük olasılıkla mikrofonunuzu kullanmak için izin isteyecektir. Lütfen İzin ver'i tıklayın.

Kusurlu bir komutu test etme

Şimdi de yapay zekamızın bunu anlayıp anlamayacağını görmek için kasıtlı olarak biraz hatalı bir komut verelim. Mikrofonunuza net bir şekilde konuşun:

"Picture take of me" (Benim fotoğrafımı çek)

Sonucu Gözlemleme

Tüm sihir burada gerçekleşir! "Fotoğrafımı çek" dediğinizde uygulama kamerayı doğru şekilde etkinleştirmelidir. checkTypo akışı, ifadenizi arka planda "take a picture" (fotoğraf çek) olarak düzeltir. classifyIntentFlow ise düzeltilen komutu anlar.

Bu sayede, yazım hatası düzeltme özelliğimizin mükemmel şekilde çalıştığını ve uygulamayı çok daha sağlam ve kullanıcı dostu hale getirdiğini doğruladık. İşiniz bittiğinde fotoğraf çekerek kamerayı durdurabilir veya terminalinizde sunucuyu durdurabilirsiniz (Ctrl + C).

6. Yapay Zeka Destekli Resim Analizi - Resmi Açıklama

Temsilcimiz artık istekleri anlayabildiğine göre ona göz verme zamanı geldi. Bu bölümde, tüm görüntü analizlerinden sorumlu temel bileşen olan Vision Agent'ımızın özelliklerini geliştireceğiz. Öncelikle en önemli özelliği olan görüntü açıklamasıyla başlayacak, ardından metin okuma özelliğini ekleyeceğiz.

Sesli temsilcinin image_analysis&#39;i

1. Özellik: Resim Açıklama

Bu, aracının birincil işlevidir. Yalnızca statik bir açıklama oluşturmayız. Ayrıntı düzeyini kullanıcı tercihlerine göre ayarlayabilen dinamik bir akış oluştururuz. Bu, Natively Adaptive Interface (NAI) felsefesinin önemli bir parçasıdır.

👉 İşlem: Cloud Shell IDE'nizde ~/src/ai/flows/describe_image/ dosyasına gidin ve aşağıdaki kodun yorumunu kaldırın.

1. adım: Dinamik istem şablonu oluşturma

İlk olarak, aldığı girişe göre talimatlarını değiştirebilen gelişmiş bir istem şablonu oluşturacağız.

Aşağıdaki kodun yorum işaretini kaldırın.

describe_image part of ai flow

Bu kod, Dot-Mustache adlı bir şablon dilini kullanan bir dize değişkeni (istem) tanımlar. Bu sayede, koşullu mantığı doğrudan istemimize yerleştirebiliriz.

{#if isDetailed}...{else}...{/if}: Bu, koşullu bir bloktur. Bu isteme gönderdiğimiz giriş verileri isDetailed: true özelliğini içeriyorsa yapay zeka, "çok ayrıntılı" talimat grubunu alır. Aksi takdirde, "özlü" talimatlar alır. Ajanımız, kullanıcı tercihine bu şekilde uyum sağlar.

{#if question}...{/if}: Bu blok yalnızca giriş verilerimizde soru özelliği varsa eklenir. Bu sayede hem genel açıklamalar hem de belirli sorular için aynı güçlü istemi kullanabiliriz.

{media url=photoDataUri}: Bu, çok formatlı modelin analiz etmesi için görüntü verilerini doğrudan isteme yerleştirmeye yönelik özel Genkit söz dizimidir.

2. adım: Akıllı akışı oluşturma

Ardından, istemi ve yeni şablonumuzu kullanacak akışı tanımlıyoruz. Bu akış, kullanıcının tercihini şablonumuzun anlayabileceği bir boole değerine çevirmek için biraz mantık içerir.

👉 İşlem: Cloud Shell IDE'nizde aynı ~/src/ai/flows/describe_image/ dosyadaki aşağıdaki kodu değiştirin. // REPLACE ME PART 1: add flow here

👉 Aşağıdaki kodla:

// Define the prompt using the template from Step 1
const prompt = ai.definePrompt({
  name: 'describeImagePrompt',
  input: { schema: DescribeImagePromptInputSchema },
  output: { schema: DescribeImageOutputSchema },
  prompt: promptTemplate,
});

// Define the flow
const describeImageFlow = ai.defineFlow<
  typeof DescribeImageInputSchema,
  typeof DescribeImageOutputSchema
>(
  {
    name: 'describeImageFlow',
    inputSchema: DescribeImageInputSchema,
    outputSchema: DescribeImageOutputSchema,
  },
  async (pageInput) => {
    const preference = pageInput.detailPreference || "concise";

    // Prepare the input for the prompt, including the new boolean flag
    const promptInputData = {
      ...pageInput,
      isDetailed: preference === "detailed",
    };

    const { output } = await prompt(promptInputData);
    return output!;
  }
);

Bu, ön uç ile yapay zeka istemi arasında akıllı bir aracı görevi görür.

  • Uygulamamızdan pageInput alır.Bu, kullanıcının tercihlerini dize olarak içerir (ör. "detailed").
  • Ardından, promptInputData adlı yeni bir nesne oluşturur.
  • En önemli satır isDetailed: preference === "detailed"'dır. Bu satır, tercih dizesine göre true veya false Boole değeri oluşturma gibi önemli bir işlevi yerine getirir.
  • Son olarak, bu geliştirilmiş verilerle prompt işlevini çağırır. 1. adımdaki istem şablonu artık yapay zekaya gönderilen talimatları dinamik olarak değiştirmek için isDetailed boole değerini kullanabilir.

3. adım: Ön ucu bağlama

Şimdi bu akışı page.tsx dosyasındaki kullanıcı arayüzümüzden tetikleyelim.

👉İşlem: ~/src/app/ai/flows/describe-image.ts bölümüne gidin ve export async function describeImage işlevini bulun. Dönüş ifadesinin yorumunu kaldırın:

return; yerine return describeImageFlow(input); yapın.

👉İşlem: ~/src/app/page.tsx içinde handleAnalyze işlevini bulun, // REPLACE ME PART 2: DESCRIBE IMAGE kodunu aşağıdaki kodla değiştirin:

👉 aşağıdaki kodla:

case "description":
    result = await describeImage({ 
        photoDataUri, 
        question, 
        detailPreference: descriptionPreference 
    });
    outputText = question ? `Answer: ${result.description}` : `Description: ${result.description}`;
    break;

Kullanıcının amacı açıklama almak olduğunda bu kod yürütülür. describeImage akışımızı çağırır, resim verilerini ve en önemlisi descriptionPreference React bileşenimizdeki durum değişkenini iletir. Bu, bulmacanın son parçasıdır. Kullanıcı arayüzünde depolanan kullanıcı tercihini, davranışını buna göre uyarlayacak yapay zeka akışına doğrudan bağlar.

Görüntü Açıklaması Özelliğini Test Etme

Fotoğraf çekmekten yapay zekanın gördüklerini dinlemeye kadar, resim açıklaması işlevimizin nasıl çalıştığını görelim.

Uygulamayı başlatma

Öncelikle geliştirme sunucusunu tekrar çalıştıralım. 👉 Terminalinizde aşağıdaki komutu çalıştırın: npm run dev Not: npm run dev komutunu çalıştırmadan önce npm install komutunu çalıştırmanız gerekebilir.

Uygulamayı açma

Sunucu hazır olduğunda tarayıcınızı açın ve yerel adrese (ör. http://localhost:9003).

Kamerayı etkinleştirme

Dinlemeye Başla düğmesini tıklayın ve istenirse mikrofona erişim izni verin. Ardından ilk komutunuzu söyleyin:

"Fotoğraf çek"

Uygulama, cihazınızın kamerasını etkinleştirir. Artık ekranda canlı video feed'ini görmeniz gerekir.

Fotoğrafı Çekme

Kamerayı etkinleştirin ve açıklamak istediğiniz nesneye doğru tutun. Şimdi, resmi çekmek için komutu ikinci kez söyleyin:

"Fotoğraf çek"

Canlı video, az önce çektiğiniz statik fotoğrafla değiştirilir.

Açıklama isteme

Ekranda yeni fotoğrafınız varken son komutu verin:

"Resmi açıkla"

Sonucu Dinleme

Uygulama, işleme durumunu gösterir. Ardından, resminizin yapay zeka tarafından üretilmiş açıklamasını duyarsınız. Metin, "Durum ve Sonuç" kartında da gösterilir.

İşlemi tamamladığınızda fotoğraf çekerek veya terminalinizde sunucuyu durdurarak (Ctrl + C) kamerayı kapatabilirsiniz.

7. Yapay Zeka Destekli Resim Analizi - Metin Açıklama (OCR)

Resimdeki metni açıklamak için koşullar akışı

Ardından, Vision Aracımıza Optik Karakter Tanıma (OCR) özelliği ekleyeceğiz. Bu sayede, herhangi bir resimdeki metni okuyabilir.

👉 İşlem: IDE'nizde ~/src/ai/flows/read-text-in-image/ bölümüne gidin ve aşağıdaki kodun yorum satırını kaldırın:

text_in_image flow of agent

👉 İşlem: IDE'nizde, aynı ~/src/ai/flows/read-text-in-image/ dosyasında // REPLACE ME: Creating Prmopt

👉 Aşağıdaki kodla:

const readTextInImageFlow = ai.defineFlow<
  typeof ReadTextInImageInputSchema,
  typeof ReadTextInImageOutputSchema
>(
  {
    name: 'readTextInImageFlow',
    inputSchema: ReadTextInImageInputSchema,
    outputSchema: ReadTextInImageOutputSchema,
  },
  async input => {
    const {output} = await prompt(input);
    return output!;
  }
);

Bu yapay zeka akışı çok daha basittir ve belirli işler için odaklanılmış araçlar kullanma ilkesini vurgular.

  • İstem: Açıklama istemimizden farklı olarak bu istem statik ve son derece spesifiktir. Tek görevi, yapay zekaya OCR motoru gibi davranması talimatını vermektir: "Resimde bulunan tüm metinleri ayıkla."
  • Şemalar: Giriş ve çıkış şemaları da basittir. Giriş olarak bir resim beklenir ve çıkış olarak tek bir metin dizesi döndürülür.

OCR için ön ucu bağlama

Son olarak, page.tsx'daki bu yeni özelliği bağlayalım.

👉İşlem: ~/src/app/ai/flows/read-text-in-image.ts bölümüne gidin ve export async function readTextInImage işlevini bulun. Dönüş ifadesinin yorumunu kaldırın:

return; yerine return readTextInImageFlow(input); yapın.

👉 İşlem: ~/src/app/page.tsx içinde handleAnalyze işlevini ve switch ifadesini bulun.

REPLACE ME PART 3: READ TEXT sütununu değiştirin

aşağıdaki kodla:

 case "text":
            result = await readTextInImage({ photoDataUri });
            outputText = result.text ? `Text Found: ${result.text}` : "No text found.";
            break;

Kullanıcının amacı ReadTextInImage olduğunda bu kod tetiklenir. Basit readTextInImage akışımızı çağırır. result.text ? ... : ... satırı, çıktıyı temiz bir şekilde işlemek için kullanılır. Yapay zeka, resimde herhangi bir metin bulamazsa kullanıcıya faydalı bir mesaj gösterir.

Metni Okuma (OCR) Özelliğini Test Etme

Metin okuma özelliğini test etmek için aşağıdaki adımları uygulayın. Kameranızı net metin içeren bir nesneye doğru tutmayı unutmayın.

  • Uygulamayı npm run dev ile çalıştırın ve tarayıcınızda açın.
  • Dinlemeye Başla'yı tıklayın ve istendiğinde mikrofon erişimine izin verin.
  • Kamerayı etkinleştirin. "Fotoğraf çek" komutunu söyleyin. Canlı video feed'inin ekranda görünmesi gerekir.
  • Fotoğrafı çekin. Kameranızı okumak istediğiniz metne doğru tutun ve komutu tekrar söyleyin: "Fotoğraf çek". Video, statik bir fotoğrafla değiştirilir.
  • Metni isteyin. Fotoğraf çekildikten sonra son komutu verin: "Resimdeki metin nedir?"
  • Sonucu kontrol edin. Uygulama, kısa bir süre sonra fotoğrafı analiz eder ve algılanan metni sesli olarak okur. Metin bulamazsa sizi bilgilendirir.

Bu, güçlü OCR özelliğinin çalıştığını doğrular. İşiniz bittiğinde Ctrl + C ile sunucuyu durdurun.

8. Gelişmiş Yapay Zeka Geliştirmeleri - Yalnızca Okuma ✨

İyi bir yapay zeka aracısı talimatları uygulayabilir. İyi bir yapay zeka aracısı sezgisel, güvenilir ve faydalı olmalıdır. Bu bölümde, temsilcimizin yeteneklerini artıran üç gelişmiş geliştirmeye odaklanacağız.

Bu makalede aşağıdaki konuları ele alacağız:

  • Add Context & Memory ile doğal ve sohbet tarzında ek soruları yanıtlayın.
  • Reduce Hallucination daha güvenilir bir aracı oluşturmak için kullanılır.
  • Make the Agent Proactive daha erişilebilir ve kullanıcı dostu bir deneyim sunmak için
  • Add preference setting simgesini tıklayarak resim açıklamasını özelleştirin.

Geliştirme 1: Bağlam ve Bellek

Doğal bir sohbet, birbirinden bağımsız komutlar dizisi değildir; akıcıdır. Bir kullanıcı "Resimde ne var?" diye sorarsa ve temsilci "Kırmızı bir araba" diye yanıt verirse kullanıcı, "araba" kelimesini tekrar kullanmadan "Hangi renk?" diye sorabilir. Temsilcimizin bu bağlamı anlaması için kısa süreli hafızaya ihtiyacı var.

Nasıl Uyguladık? (Özet)

Bu özelliği, describeImage akışımıza ekledik. Bu bölümde, söz konusu kalıbın işleyişi özetlenmektedir. describeImage işlevimizi page.tsx dosyasından çağırdığımızda, bu işleve görüşme geçmişini iletiyoruz.

👉 Code Showcase (page.tsx tarihinden itibaren):

const result = await describeImage({
    photoDataUri,
    question: commandToProcess,
    detailPreference: descriptionPreference,
    previousUserQueryOnImage: lastUserQuery ?? undefined,
    previousAIResponseOnImage: lastAIResponse ?? undefined,
});
  • previousUserQueryOnImage ve previousAIResponseOnImage: Bu iki özellik, aracımızın kısa süreli hafızasıdır. Son etkileşimi yapay zekaya ileterek, belirsiz veya referans içeren takip sorularını anlaması için gereken bağlamı sağlarız.
  • Uyarlanabilir İstem: Bu bağlam, describe_image akışımızdaki istem tarafından kullanılır. İstem, yeni bir yanıt oluştururken önceki görüşmeyi dikkate alacak şekilde tasarlanmıştır. Böylece temsilci akıllıca yanıt verebilir.

Geliştirme 2: Halüsinasyonları Azaltma

Yapay zeka, gerçekleri uydurduğunda veya sahip olmadığı yeteneklere sahip olduğunu iddia ettiğinde "halüsinasyon" görüyor demektir. Kullanıcıların güvenini kazanmak için aracımızın kendi sınırlarını bilmesi ve kapsam dışı istekleri nazikçe reddedebilmesi çok önemlidir.

Nasıl Uyguladık? (Özet)

Halüsinasyonu önlemenin en etkili yolu, modele net sınırlar vermektir. Bu özelliği, Amaç Sınıflandırıcımızı oluştururken geliştirdik.

👉 Kod vitrini (intent-classifier akışından):

// Define Agent Capabilities and Limitations for the prompt
const AGENT_CAPABILITIES_AND_LIMITATIONS = `
**Core Capabilities (What the Agent CAN DO):**
* **Image Analysis:**
    * DescribeImage: Provide a general description of the current image...

**Limitations (What the Agent CANNOT DO...):**
* Cannot generate or create new images.
* Cannot provide general knowledge or answer questions unrelated to the image...
* Cannot perform web searches.
`;

Bu sabit, sınıflandırma isteminde yapay zekaya sağladığımız bir "iş açıklaması" görevi görür.

  • Modeli Temellendirme: Yapay zekaya ne yapamayacağını açıkça söyleyerek onu gerçeklikle "temellendiririz". "Hava nasıl?" gibi bir sorgu gördüğünde, bunu sınırlamalar listesiyle güvenle eşleştirebilir ve amacı OutOfScopeRequest olarak sınıflandırabilir.
  • Güven Oluşturma: "Bu konuda yardımcı olamıyorum" diyebilen bir temsilci, tahmin etmeye çalışıp yanlış cevap veren bir temsilciye kıyasla çok daha güvenilirdir. Bu, güvenli ve güvenilir yapay zeka tasarımının temel ilkesidir. `

Geliştirme 3: Proaktif bir temsilci oluşturma

Önceliği erişilebilirlik olan bir uygulamada görsel ipuçlarına güvenemeyiz. Kullanıcılar dinleme modunu etkinleştirdiğinde, temsilcinin hazır olduğunu ve komut beklediğini anında ve görsel olmayan bir şekilde onaylamaları gerekir. Bu önemli geri bildirimi sağlamak için artık proaktif bir giriş ekleyeceğiz.

1. adım: İlk dinlemeyi izlemek için bir durum ekleyin

Öncelikle, kullanıcının oturumu sırasında "Start Listening" düğmesine ilk kez basıp basmadığını bilmemiz gerekir.

👉 ~/src/app/page.tsx içinde, ClarityCam bileşeninizin üst kısmına yakın bir yerde aşağıdaki yeni durum değişkenini göreceksiniz.

export default function ClarityCam() {
  // ... other state variables
  const [descriptionPreference, setDescriptionPreference] = useState<DescriptionPreference>("concise");
  
  // Add this new line
  const [isFirstListen, setIsFirstListen] = useState(true);

  // ... rest of the component
}

Yeni bir durum değişkeni olan isFirstListen'yı kullanıma sunduk ve true olarak başlattık. Bu işareti, tek seferlik karşılama mesajımızı tetiklemek için kullanırız.

2. adım: toggleListening işlevini güncelleyin

Şimdi, selamlama mesajımızı oynatmak için mikrofonu işleyen işlevi değiştirelim.

👉 ~/src/app/page.tsx içinde toggleListening işlevini bulun ve aşağıdaki if bloğunu inceleyin.

const toggleListening = useCallback(() => {
    // ... existing logic to setup speech recognition

    if (isListening || isAttemptingStart) {
        // ... existing logic to stop listening
    } else {
        stopSpeaking(); // Stop any ongoing TTS

        // Add this new block
        if (isFirstListen) {
            setIsFirstListen(false);
            const introMessage = "Hello! I am ClarityCam, your AI assistant. I'm now listening. You can ask me to 'describe the image', 'read text', 'take a picture', or ask questions about what's in an image.";
            speakText(introMessage);
        } else {
            speakText("Listening..."); // Optional: provide feedback on subsequent clicks
        }
        
        // ... rest of the logic to start listening
    }
}, [/*...existing dependencies...*/, isFirstListen]); // Don't forget to add isFirstListen to the dependency array!
  • İşareti Kontrol Edin: if (isFirstListen) bloğu, bunun ilk etkinleştirme olup olmadığını kontrol eder.
  • Tekrarı Önleme: Blok içinde yapılan ilk işlem, setIsFirstListen(false) işlevini çağırmaktır. Bu sayede, tanıtım mesajı oturum başına yalnızca bir kez oynatılır.
  • Rehberlik sağlama: introMessage, olabildiğince faydalı olacak şekilde dikkatle hazırlanır. Kullanıcıyı karşılıyor, temsilciyi adıyla tanımlıyor, etkin olduğunu onaylıyor ("Artık dinliyorum") ve kullanabileceği sesli komutlarla ilgili net örnekler veriyor.
  • İşitsel geri bildirim: Son olarak, speakText(introMessage) bu önemli bilgiyi sunarak kullanıcının ekrana bakmasını gerektirmeden anında güvence ve rehberlik sağlar.

Geliştirme 4: Kullanıcı Tercihlerine Uyarlanma (Özet)

Gerçekten akıllı bir temsilci yalnızca yanıt vermekle kalmaz, kullanıcının ihtiyaçlarını öğrenir ve bunlara uyum sağlar. Geliştirdiğimiz en güçlü özelliklerden biri, kullanıcının "Daha ayrıntılı ol" gibi komutlarla resim açıklamalarının ayrıntı düzeyini anında değiştirebilmesidir.

Nasıl Uyguladık? (Özet) Bu özellik, describeImage akışımız için oluşturduğumuz dinamik istem tarafından desteklenir. Kullanıcının tercihine göre yapay zekaya gönderilen talimatları değiştirmek için koşullu mantık kullanır.

👉 Code Showcase (describe_image içindeki promptTemplate):

const settingPreferenceTemplate = `
{#if isDetailed}
Provide a very detailed and comprehensive description of the image. Focus on specifics, including subtle elements, spatial relationships, and textures if apparent.
{else}
Provide a concise description of the image. Focus on the main subject, key objects, and primary activities or context.
{/if}

Highlight the main objects, activities, and colors.
...
`;
  • Koşullu Mantık: {#if isDetailed}...{else}...{/if} bloğu önemlidir. describeImageFlow, ön uçtan detailPreference değerini aldığında isDetailed adlı bir boole değeri (doğru veya yanlış) oluşturur.
  • Uyarlanabilir Talimatlar: Bu boole işareti, yapay zeka modelinin hangi talimat grubunu alacağını belirler. isDetailed doğruysa modele son derece açıklayıcı olması talimatı verilir. Yanlışsa kısa olması istenir.
  • Kullanıcı Kontrolü: Bu kalıp, kullanıcının sesli komutunu (ör. "Açıklamaları kısa yap" (SetDescriptionConcise amacı olarak sınıflandırılır) gibi basit bir değişiklikten, yapay zekanın davranışında temel bir değişikliğe kadar (bu değişiklik, aracının gerçekten yanıt vermesini ve kişiselleştirilmesini sağlar)

9. Buluta dağıtım

Google Cloud Build'i kullanarak Docker görüntüsü oluşturma

gcloud builds submit . --tag gcr.io/$PROJECT_ID/accessibilityai-nextjs-app:latest
  • accessibilityai-nextjs-app, önerilen bir resim adıdır.
  • Kendisi Derleme kaynağı olarak geçerli dizini (accessibilityAI/) kullanır.

Görüntüyü Google Cloud Run'a dağıtma

  • API anahtarlarınızın ve diğer gizli anahtarlarınızın Secret Manager'da hazır olduğundan emin olun. Örneğin, GOOGLE_GENAI_API_KEY.

Bu YOUR_ACTUAL_GOOGLE_AI_KEY_VALUE kısmını gerçek Gemini API anahtarınızın değeriyle değiştirin.

echo "YOUR_ACTUAL_GOOGLE_AI_KEY_VALUE" | gcloud secrets create GOOGLE_GENAI_API_KEY --data-file=- --project=YOUR_PROJECT_ID

Cloud Run hizmetinizin çalışma zamanı hizmet hesabına (ör. PROJECT_NUMBER-compute@developer.gserviceaccount.com veya özel bir hizmet hesabı) için "Secret Manager Gizli Anahtar Erişeni" rolünü atayın.

  • Dağıtma komutu:
gcloud run deploy accessibilityai-app-service \
  --image gcr.io/$PROJECT_ID/accessibilityai-nextjs-app:latest \
  --platform managed \
  --region us-central1 \
  --allow-unauthenticated \
  --port 3000 \
  --set-secrets=GOOGLE_GENAI_API_KEY=GOOGLE_GENAI_API_KEY:latest \
  --set-env-vars NODE_ENV="production"