משפרים את תהליך הפיתוח עם Gemini Code Assist

‫1. מבוא

e5b98fd4e417c877.png

ב-Codelab הזה, אפשר לראות איך Gemini Code Assist יכול לתמוך בך בשלבים החשובים במחזור החיים של פיתוח התוכנה (SDLC), כמו תכנון, פיתוח ובדיקה ופריסה. אנחנו נעצב ונפתח את האפליקציה כולה ונפרס אותה ב-Google Cloud.

אנחנו ניצור API ואפליקציה לחיפוש בסשנים שונים באירוע טכני. לכל סשן יהיו כותרת, סיכום, משך זמן, קטגוריות ודובר אחד או יותר.

מה תעשו

  • עיצוב, בנייה, בדיקה ופריסה של אפליקציית אינטרנט על סמך מפרט OpenAPI מאפס

מה תלמדו

  • איך משתמשים ב-Gemini Code Assist כדי ליצור מפרט OpenAPI
  • איך משתמשים בתכונות יצירת הקוד של Gemini Code Assist כדי לפתח אפליקציית Flask ב-Python למפרט OpenAPI
  • איך משתמשים ב-Gemini Code Assist כדי ליצור ממשק קצה של אינטרנט לאפליקציית Python Flask
  • איך להשתמש ב-Gemini Code Assist כדי לקבל עזרה בפריסה של האפליקציה ב-Google Cloud Run
  • להשתמש בתכונות של Gemini Code Assist, כמו הסבר על קוד, יצירת מקרה בדיקה, פיתוח ובדיקה של האפליקציה

מה צריך להכין

  • דפדפן האינטרנט Chrome
  • חשבון Gmail
  • פרויקט בענן שהופעל בו חיוב
  • Gemini Code Assist מופעל בפרויקט שלך ב-Cloud

שיעור ה-Lab הזה מיועד למפתחים בכל הרמות, כולל למתחילים. למרות שהאפליקציה לדוגמה היא בשפת Python, לא צריך להכיר תכנות Python כדי להבין מה קורה. נתמקד בהיכרות עם היכולות של Gemini Code Assist.

‫2. הגדרה של Gemini Code Assist

בחלק הזה נסביר את כל מה שצריך לעשות כדי להתחיל את שיעור ה-Lab הזה.

הפעלת Gemini Code Assist ב-Cloud Shell IDE

בשאר ימי ה-Codelab נשתמש ב-Cloud Shell IDE, סביבת פיתוח מנוהלת שמבוססת על Code OSS. אנחנו צריכים להפעיל ולהגדיר את Code Assist בסביבת הפיתוח המשולבת של Cloud Shell, כפי שמפורט בהמשך:

  1. צריך להיכנס לכתובת ide.cloud.google.com. יכול להיות שיעבור זמן מה עד שסביבת הפיתוח המשולבת תופיע. לכן צריך להמתין בסבלנות ולאשר את אפשרויות ברירת המחדל של ההגדרה. אם יוצגו לך כמה הוראות להגדרת סביבת הפיתוח המשולבת (IDE), צריך להשלים אותן עם הגדרות ברירת המחדל.
  2. לוחצים על הלחצן Cloud Code – כניסה בשורת הסטטוס התחתונה, כמו שמוצג. מאשרים את הפלאגין לפי ההוראות. אם בשורת הסטטוס כתוב Cloud Code – אין פרויקט, בוחרים את הפרויקט הספציפי ב-Google Cloud מרשימת הפרויקטים שבהם אתם מתכוונים לעבוד.

6f5ce865fc7a3ef5.png

  1. לוחצים על הלחצן Code Assist בפינה השמאלית התחתונה כמו שמוצג ובוחרים בפרויקט הנכון ב-Google Cloud. אם תתבקשו להפעיל את Cloud AI Companion API, צריך לעשות זאת ולהתקדם בתהליך.
  2. לאחר שבוחרים את הפרויקט ב-Google Cloud, מוודאים שאפשר לראות אותו בהודעת הסטטוס של Cloud Code בשורת הסטטוס, ושגם Code Assist מופעל בצד שמאל, בשורת הסטטוס שמוצגת בהמשך:

709e6c8248ac7d88.png

Gemini Code Assist מוכן לשימוש!

3. הגדרת Firestore

Cloud Firestore הוא מסד נתונים מנוהל למסמכים ללא שרת (serverless), שישמש כקצה העורפי לנתוני האפליקציות שלנו. הנתונים ב-Cloud Firestore מובנים באוספים של מסמכים.

אנחנו צריכים ליצור אוסף בשם sessions במסד הנתונים של Firestore שמוגדר כברירת מחדל. האוסף הזה יכלול נתונים לדוגמה (מסמכים) שנשתמש בהם לאחר מכן באפליקציה.

פותחים את Terminal מתוך סביבת הפיתוח המשולבת (IDE) של Cloud Shell דרך התפריט הראשי:

f1535e14c9beeec6.png

אנחנו צריכים ליצור אוסף בשם sessions. תיפתח רשימה של מסמכי סשן לדוגמה. לכל מסמך יהיו המאפיינים הבאים:

  1. title: מחרוזת
  2. categories: מערך מחרוזות
  3. speakers: מערך מחרוזות
  4. duration: מחרוזת
  5. סיכום: מחרוזת

כדי לאכלס את האוסף הזה בנתונים לדוגמה, מעתיקים קובץ שמכיל את הנתונים לדוגמה לקטגוריה בפרויקט שלכם, ומשם אפשר לייבא את האוסף באמצעות הפקודה gcloud firestore import.

אתחול של מסד הנתונים ב-Firestore

נכנסים לדף Firestore במסוף Cloud.

אם עדיין לא אתחלתם מסד נתונים של Firestore בעבר בפרויקט, עליכם ליצור את מסד הנתונים default. במהלך יצירת מסד הנתונים, מזינים את הערכים הבאים:

  • מצב Firestore: Native
  • מיקום: בוחרים את סוג המיקום בתור Region ואז בוחרים את האזור שמתאים לאפליקציה שלכם. רושמים בצד את המיקום הזה כי תצטרכו אותו בשלב הבא של מיקום הקטגוריה.
  • יוצרים את מסד הנתונים.

504cabdb99a222a5.png

עכשיו ניצור את האוסף sessions לפי השלבים הבאים:

  1. יוצרים קטגוריה בפרויקט באמצעות הפקודה gsutil שמופיעה בהמשך. מחליפים את המשתנה <PROJECT_ID> בפקודה שבהמשך במזהה הפרויקט שלכם ב-Google Cloud. מחליפים את <BUCKET_LOCATION> בשם אזור שמתאים לאזור הגיאוגרפי של מסד הנתונים של Firestore שמוגדר כברירת מחדל (כפי שצוין בשלב הקודם). השם יכול להיות US-WEST1 , EUROPE-WEST1 , ASIA-EAST1 :
gsutil mb -l <BUCKET-LOCATION> gs://<PROJECT_ID>-my-bucket
  1. עכשיו, אחרי שהקטגוריה נוצרה, אנחנו צריכים להעתיק את הייצוא של מסד הנתונים שהכנו לקטגוריה הזו, לפני שנוכל לייבא אותו למסד הנתונים של Firebase. משתמשים בפקודה הבאה:
gsutil cp -r gs://sessions-master-database-bucket/2024-03-26T09:28:15_95256  gs://<PROJECT_ID>-my-bucket

עכשיו, אחרי שיש לנו את הנתונים לייבוא, אנחנו יכולים לעבור לשלב האחרון של ייבוא הנתונים למסד הנתונים של Firebase (default) שיצרנו.

  1. משתמשים בפקודה ב-gcloud הבאה:
gcloud firestore import gs://<PROJECT_ID>-my-bucket/2024-03-26T09:28:15_95256

הייבוא יימשך כמה שניות ולאחר מכן יהיה מוכן, כדי לאמת את מסד הנתונים ואת האוסף שלך ב-Firestore בכתובת https://console.cloud.google.com/firestore/databases, בוחרים את מסד הנתונים default ואת האוסף sessions כפי שמוצג בהמשך:

d3e294d46ba29cd5.png

סיימת ליצור את אוסף Firestore שבו נשתמש באפליקציה שלנו.

‫4. יצירת תבנית האפליקציה

אנחנו ניצור אפליקציה לדוגמה (אפליקציית Python Flask) שנשתמש בה בשאר הקורס. האפליקציה הזו תחפש בסשנים שהוצעו בכנס טכני.

כך עושים זאת:

  1. לוחצים על שם הפרויקט ב-Google Cloud בשורת הסטטוס שלמטה.

f151759c156c124e.png

  1. תופיע רשימה של אפשרויות. ברשימה הבאה, לוחצים על New Application (אפליקציה חדשה).

91ea9836f38b7f74.png

  1. בוחרים באפשרות Cloud Run application (זה יהיה זמן הריצה של האפליקציה שלנו).
  2. בוחרים את תבנית האפליקציה Python (Flask): Cloud Run.
  3. נותנים לאפליקציה שם ושומרים אותו במיקום המועדף.
  4. הודעה מאשרת שהאפליקציה נוצרה, וחלון חדש נפתח שבו האפליקציה נטענת כפי שמוצג בהמשך. נפתח קובץ README.md. אתם יכולים לסגור את התצוגה בינתיים.

aaa3725b17ce27cf.png

5. אינטראקציה עם Gemini Code Assist

לצורך שיעור ה-Lab הזה, נשתמש ב-Gemini Code Assist Chat שזמין ב-Cloud Shell IDE כחלק מהתוסף של Cloud Code ב-VS Code. אפשר להעלות את הקוד על ידי לחיצה על הלחצן Code Assist בסרגל הניווט הימני. מחפשים את הסמל Code Assist a489f98a34898727.png בסרגל הניווט הימני ולוחצים עליו.

חלונית הצ'אט של Code Assist תופיע ב-Cloud Shell IDE ותוכלו להתכתב בצ'אט עם Code Assist.

14ad103efaa0ddaa.png

שימו לב לסמל פח האשפה שבחלק העליון של המסך. זו הדרך לאפס את ההקשר של היסטוריית הצ'אט של Code Assist. חשוב גם לשים לב שהאינטראקציה הזו בצ'אט מבוססת על ההקשר של הקבצים שאתם עובדים עליהם בסביבת הפיתוח המשולבת(IDE).

6. תכנון API

בשלב הראשון אנחנו נעזרים ב-Gemini Code Assist בשלב העיצוב. בשלב הזה ניצור מפרט OpenAPI לישויות (סשנים טכניים באירוע) שבהן רוצים לחפש.

נותנים את ההנחיה הבאה:

Generate an Open API spec that will allow me to retrieve all sessions, sessions by category, session by id. Each session has the following attributes: id, title, list of speakers, list of categories, summary and duration.

הפעולה הזו אמורה ליצור מפרט OpenAPI לחיפוש בסשנים שונים באמצעות פרמטרים שונים של שאילתות. דוגמת המפרט מוצגת למטה:

openapi: 3.0.0
info:
 title: Sessions API
 description: This API allows you to retrieve all sessions, sessions by category, and session by id.
 version: 1.0.0
servers:
 - url: https://sessions.example.com
paths:
 /sessions:
   get:
     summary: Get all sessions
     operationId: getSessions
     responses:
       '200':
         description: OK
         content:
           application/json:
             schema:
               type: array
               items:
                 $ref: '#/components/schemas/Session'
 /sessions/{id}:
   get:
     summary: Get session by id
     operationId: getSessionById
     parameters:
       - name: id
         in: path
         required: true
         description: The id of the session
         schema:
           type: string
     responses:
       '200':
         description: OK
         content:
           application/json:
             schema:
               $ref: '#/components/schemas/Session'
 /sessions/categories/{category}:
   get:
     summary: Get sessions by category
     operationId: getSessionsByCategory
     parameters:
       - name: category
         in: path
         required: true
         description: The category of the sessions
         schema:
           type: string
     responses:
       '200':
         description: OK
         content:
           application/json:
             schema:
               type: array
               items:
                 $ref: '#/components/schemas/Session'
components:
 schemas:
   Session:
     type: object
     properties:
       id:
         type: string
         description: The id of the session
       title:
         type: string
         description: The title of the session
       speakers:
         type: array
         items:
           type: string
         description: The list of speakers for the session
       categories:
         type: array
         items:
           type: string
         description: The list of categories for the session
       summary:
         type: string
         description: The summary of the session
       duration:
         type: string
         description: The duration of the session

תוכל לראות במפרט את הפרטים הבאים:

  • סכימה שהוגדרה עבור סוג הסשן.
  • הוגדרו כמה נתיבי API:
  • /sessions
  • /sessions/{id}
  • /sessions/categories/{category}

יוצרים קובץ בשם sessionsapi.yaml בתיקייה העליונה ומעתיקים את התוכן מחלון הצ'אט של Code Assist באמצעות האפשרות 'insert in current file option' (הלחצן +) ומשאירים את הקובץ פתוח בסביבת הפיתוח המשולבת של Cloud Shell.

בשלב הזה תוכלו לראות תכונה מעניינת של Gemini Code Assist: ציטוט. המידע הזה מוצג למפתח כשהקוד שנוצר מצטט קטע ארוך ישירות ממקור אחר, כמו קוד פתוח קיים. המפתח מציע את המקור ואת הרישיון כדי להחליט מה לעשות איתו.

בהנחה שהתוכן שנוצר מתאים לנו, אנחנו יכולים עכשיו להשתמש במסמך המפרט הזה כדי ליצור עבורו אפליקציית Python Flask.

‫7. יצירת האפליקציה

עכשיו נבקש מ-Code Assist ליצור את האפליקציה. אומרים את הבקשה הבאה כשהקובץ sessionsapi.yaml פתוח.

Generate a Python Application using the Flask framework, based on the sessionsapi.yaml file. This application uses a local in memory list of sessions. Do not use any Flask extensions.

הפקודה הזו אמורה לספק שלד של אפליקציית Python Flask, שמבוסס על הפונקציונליות והנתיבים שצוינו בקובץ המפרט של OpenAPI.

הקוד של אפליקציית Python Flask שסופק צריך להיות דומה לקוד הבא:

from flask import Flask, jsonify, request

app = Flask(__name__)

sessions = [
    {
        "id": "1",
        "title": "Session 1",
        "speakers": ["Speaker 1", "Speaker 2"],
        "categories": ["Category 1", "Category 2"],
        "summary": "This is a summary of session 1.",
        "duration": "1 hour",
    },
    {
        "id": "2",
        "title": "Session 2",
        "speakers": ["Speaker 3", "Speaker 4"],
        "categories": ["Category 3", "Category 4"],
        "summary": "This is a summary of session 2.",
        "duration": "1 hour 30 minutes",
    },
]

@app.route('/sessions', methods=['GET'])
def get_sessions():
    return jsonify(sessions)

@app.route('/sessions/<id>', methods=['GET'])
def get_session_by_id(id):
    session = next((session for session in sessions if session['id'] == id), None)
    if session is None:
        return jsonify({}), 404
    return jsonify(session)

@app.route('/sessions/categories/<category>', methods=['GET'])
def get_sessions_by_category(category):
    sessions_by_category = [session for session in sessions if category in session['categories']]
    return jsonify(sessions_by_category)

if __name__ == '__main__':
    app.run()

יש קובץ app.py קיים שנוצר כחלק מהשלב הקודם. פשוט מחליפים את התוכן שלו בקוד שנוצר על ידי Code Assist ושומרים את הקובץ.

אנחנו רוצים לשנות את השורה של app.run() כך שתשתמש ביציאה 8080 בכתובת המארח 0.0.0.0, וגם בהרצה במצב ניפוי באגים במהלך ביצוע מקומי.כך ניתן לעשות זאת. קודם כול, נדגיש או נבחר את השורה:

app.run()

לאחר מכן, בממשק Code Assist Chat, מקלידים את ההנחיה: Explain this.

הקטע הזה אמור להציג הסבר מפורט לגבי השורה הספציפית. למשל, אפשר לראות אותו בדוגמה הבאה:

58ec896a32a4fb68.png

בשלב הזה, משתמשים בהנחיה הבאה:

update the code to run the application on port 8080, host address 0.0.0.0, and in debug mode

הקוד המוצע אמור להיות כך:

app.run(host='0.0.0.0', port=8080, debug=True)

חשוב לעדכן את הקובץ app.py באמצעות קטע הקוד הזה.

הפעלה מקומית של האפליקציה

עכשיו נריץ את האפליקציה באופן מקומי כדי לאמת את דרישות הבקשה, בהתאם למה שהתחלנו איתו.

השלב הראשון יהיה יצירת סביבת Python וירטואלית עם יחסי התלות של חבילת Python בקובץ requirements.txt, שתותקן בסביבה הווירטואלית. כדי לעשות את זה, עוברים אל Command Palette (Ctrl+Shift+P) ב-Cloud Shell IDE ומקלידים Create Python table. כדי לבחור סביבה וירטואלית (venv), תרגום של Python 3.x ואת הקובץ requirements.txt, פועלים לפי השלבים הבאים.

אחרי שיוצרים את הסביבה, מפעילים חלון טרמינל חדש (Ctrl+Shift+`) ומזינים את הפקודה הבאה:

python app.py

דוגמה לביצוע:

(.venv) romin@cloudshell: $ python app.py 
 * Serving Flask app 'app'
 * Debug mode: on
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on all addresses (0.0.0.0)
 * Running on http://127.0.0.1:8080
 * Running on http://10.88.0.3:8080
Press CTRL+C to quit
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 132-247-368

עכשיו ניתן לראות תצוגה מקדימה של ה-API בכתובות ה-URL הבאות. אנחנו מניחים ששרת הפיתוח פועל ביציאה 8080. אם לא, צריך לשנות אותו למספר היציאה המתאים.

  • https://<host-name>:8080/sessions
  • https://<host-name>:8080/sessions/{id}
  • https://<host-name>:8080/sessions/categories/{category}

כדי לוודא שאפשר לאחזר באמצעות כתובות ה-URL האלה, צריך לבצע את השלבים שבהמשך: נתוני ה-JSON שנכללים בקובץ app.py:

פותחים חלון טרמינל חדש ומנסים אחת מהפקודות הבאות:

curl -X GET http://127.0.0.1:8080/sessions
curl -X GET http://127.0.0.1:8080/sessions/<ID>
curl -X GET http://127.0.0.1:8080/sessions/categories/<CATEGORY_NAME> 

‫8. ארגון קוד מחדש

במקום שהשדה app.py יכלול את נתוני ה-JSON לדוגמה שמופיעים בתוך הקוד, כנראה שנרצה להפריד או לחלץ אותם למודול אחר כדי שנוכל לשמור על הפרדה ברורה בין הקוד לבין הנתונים. קדימה!

משאירים את הקובץ app.py פתוח ומזינים את ההנחיה הבאה:

Can I improve this code and separate out the sessions data from this app.py file?

מופיעות כאן הצעות לפעולות שאפשר לבצע. הצעה לדוגמה שקיבלנו ושאתם אמורים לקבל הצעה דומה, מוצגת כאן:

9b9c56cb527dac4c.png

לאחר מכן, נפריד את הנתונים לקובץ sessions.py כפי שהוצע על ידי Code Assist.

יצירת קובץ חדש בשם sessions.py

, התוכן שלו הוא רשימת ה-JSON, בהתאם לנתונים שנוצרו, מופיע בהמשך:

sessions = [
   {
       "id": "1",
       "title": "Session 1",
       "speakers": ["Speaker 1", "Speaker 2"],
       "categories": ["Category 1", "Category 2"],
       "summary": "This is a summary of session 1.",
       "duration": "1 hour",
   },
   {
       "id": "2",
       "title": "Session 2",
       "speakers": ["Speaker 3", "Speaker 4"],
       "categories": ["Category 3", "Category 4"],
       "summary": "This is a summary of session 2.",
       "duration": "1 hour 30 minutes",
   },
]

הקובץ app.py פשוט יותר עכשיו והוא מוצג למטה:

from flask import Flask, jsonify, request
from sessions import sessions

app = Flask(__name__)

@app.route('/sessions', methods=['GET'])
def get_sessions():
   return jsonify(sessions.sessions)

@app.route('/sessions/<id>', methods=['GET'])
def get_session_by_id(id):
   session = next((session for session in sessions.sessions if session['id'] == id), None)
   if session is None:
       return jsonify({}), 404
   return jsonify(session)

@app.route('/sessions/categories/<category>', methods=['GET'])
def get_sessions_by_category(category):
   sessions_by_category = [session for session in sessions.sessions if category in session['categories']]
   return jsonify(sessions_by_category)

if __name__ == '__main__':
   app.run(host='0.0.0.0', port=8080, debug=True)

ודאו שעדיין יש לכם אפשרות להריץ את האפליקציה באופן מקומי ולהפעיל את ה-API עם השינויים שנערכו מחדש. סביר להניח ששרת הפיתוח של python עדיין פועל, לכן צריך לזכור רק את פקודות curl מהשלב הקודם.

‫9. שילוב עם Firestore Collection

בשלב הבא מחליפים את רשימת ה-JSON המקומית בזיכרון שמכילה את הסשנים שלנו ומקשרים את האפליקציה לאוסף הסשנים במסד הנתונים של Firestore, שיצרנו בתחילת השיעור הזה ב-Codelab.

משאירים את הקובץ sessions.py פתוח ומזינים את ההנחיה הבאה:

Can you further refactor the sessions.py code to read from a Firestore database that has a collection named sessions. The collection has the same attributes as the session object that we have defined. Use the Python module google-cloud-firestore. 

קיבלנו את ההצעה הבאה לקרוא את כל הסשנים מהאוסף של Firestore:

import google.cloud.firestore

# Create a Firestore client
db = google.cloud.firestore.Client()

# Get the sessions collection
sessions_collection = db.collection("sessions")

# Create a list of sessions
sessions = []

# Iterate over the documents and add them to the list
for doc in sessions_collection.stream():
   session = doc.to_dict()
   session["id"] = doc.id
   sessions.append(session)

אפשר להטמיע את הקוד ב-sessions.py.

אם השרת של Flask Development פועל באופן מקומי, יכול להיות שהאפליקציה נסגרה בגלל תלונה על כך שמודול Python לא נמצא.

לדוגמה, אפשר לשאול את Code Assist ולבחור איזה מודול Python צריך להוסיף לקובץ requirements.txt, באופן הבא:

Which Python package needs to be installed to make the firestore code work?

יוצג לכם השם של מודול Python (לדוגמה, google-cloud-firestore). מוסיפים אותו לקובץ requirements.txt.

צריך ליצור מחדש את סביבת Python עם המודול החדש שנוסף (google-cloud-firestore). כדי לעשות זאת, מזינים את הפקודה הבאה בחלון הטרמינל הקיים:

pip install -r requirements.txt

מפעילים שוב את האפליקציה (מפעילים אותה מחדש עם python app.py) ונכנסים לכתובת ה-URL ב-/sessions. עכשיו אמורים להופיע המסמכים לדוגמה שהוספנו לאוסף sessions.

975d05e6518f1a6a.png

אתם יכולים להריץ שאילתות על מזהי URI אחרים כדי לאחזר סשנים ספציפיים או את כל הסשנים בקטגוריה מסוימת, כמו שמתואר בשלבים הקודמים.

10. הסבר על הקוד

עכשיו כדאי להשתמש בתכונה "Explain this" ב-Gemini Code Assist כדי להבין את הקוד בצורה טובה יותר. אפשר להיכנס לכל אחד מהקבצים או לבחור קטעי קוד ספציפיים ולשאול את Code Assist עם ההנחיה הבאה: Explain this.

במהלך תרגול, נכנסים לקובץ sessions.py, מדגישים את הקוד הספציפי של Firestore ומקבלים הסבר על הקוד. נסו להשתמש בתכונה הזו גם בקבצים אחרים בפרויקט, לא רק בקוד python.

11. יצירת אפליקציית האינטרנט

עכשיו, לאחר שיצרנו את ה-API ושילבנו אותו עם אוסף Firestore פעיל, אפשר עכשיו ליצור ממשק קצה מבוסס-אינטרנט לאפליקציה. נכון לעכשיו, ממשק הקצה של האינטרנט שלנו ישמור על פונקציונליות מינימלית, כלומר הוא יוכל לחפש סשנים ששייכים לקטגוריה ספציפית. חשוב לזכור שיש לנו נתיב API למטרה הזו, כלומר /sessions/categories/{category}, לכן אפליקציית האינטרנט שלנו צריכה להפעיל את האפשרות הזו ולאחזר את התוצאות.

שנתחיל? שולחים ל-Code Assist את ההנחיה הבאה:

Generate a web application that allows me to search for sessions by category and uses the Flask application that we created. Please use basic HTML, CSS and JS. Embed all the Javascript and CSS code into a single HTML file only.

הפעולה הזו תיצור את ה-HTML של אפליקציית האינטרנט שכוללת את ה-JavaScript וה-CSS שמוטמעים בו. בנוסף, תתבקשו להוסיף נתיב חדש לקובץ app.py, כדי שכל משתמש שמבקר בכתובת ה-URL הבסיסית או בכתובת ה-URL הבסיסית יראה דף הבית. אם המידע הזה לא מוזכר, שואלים עליו או משתמשים בקטע הקוד שמופיע בהמשך:

@app.route('/')
def index():
   return render_template('index.html')

אתם יכולים לשמור את הקובץ בתור index.html, אבל יכול להיות שיש לכם שאלה איפה כדאי לשמור את הקובץ (כלומר, איזו תיקייה?). אנחנו יכולים לשלוח ל-Code Assist שאלת המשך.

Given that I am using the flask framework, where should I put the index.html file?

אמור לספק מידע ברור שהוא משתמש במסגרת render_template, ולכן יהיה צורך למקם את קובץ index.html בתוך התיקייה templates. התיקייה הזו תהיה זמינה כי יצרנו אפליקציה שמבוססת על תבנית Flask בתחילת ה-Codelab הזה. כתוצאה מכך, יש קובץ index.html קיים וצריך להחליף את התוכן שלו בקובץ החדש שנוצר כאן. ב-Code Assist יש גם אזכור של render_template בקובץ app.py שמשמש לייבוא.

שומרים את הקוד של אפליקציית האינטרנט בקובץ index.html, וחשוב לזכור למקם את הקובץ בתיקייה templates.

הפעלה מקומית של האפליקציה

עכשיו נריץ את האפליקציה באופן מקומי כדי לאמת את דרישות הבקשה, בהתאם למה שהתחלנו איתו.

צריך לוודא ששרת Flask המקומי עדיין פועל ולא מציג שגיאות. אם יש שגיאות, טפלו בהן והפעילו את השרת.

לאחר ההפעלה, עוברים לכתובת ה-URL של דף הבית של האפליקציה. אמור להופיע הקובץ index.html כפי שמוצג בהמשך:

8ca586acc4536879.png

מציינים אחת מהקטגוריות מהנתונים כקלט (למשל, AI) ולוחצים על הלחצן Search. יוצגו הסשנים שתויגו עם הקטגוריה AI.

165faded790a6c.png

תרגיל אופציונלי הוא להציג מטא נתונים נוספים, כגון משך הפגישה, קטגוריות, דוברים וסיכום עבור כל אחד מהמפגשים.

12. יצירת מקרי בדיקה

יצרנו את ה-API של הסשנים, והגיע הזמן להשתמש ב-Gemini Code Assist כבר עכשיו כדי ליצור תרחישים לבדיקת יחידות עבור נתיבי ה-API השונים.

משאירים את הקובץ app.py פתוח ומזינים את ההנחיה הבאה:

Generate unit test cases for app routes. Use unittest module.

קיבלנו את התגובה הבאה:

import unittest
from app import app

class FlaskAppTestCase(unittest.TestCase):

    def test_index(self):
        tester = app.test_client()
        response = tester.get('/')
        self.assertEqual(response.status_code, 200)

    def test_get_sessions(self):
        tester = app.test_client()
        response = tester.get('/sessions')
        self.assertEqual(response.status_code, 200)

    def test_get_session_by_id(self):
        tester = app.test_client()
        response = tester.get('/sessions/1')
        self.assertEqual(response.status_code, 200)

    def test_get_sessions_by_category(self):
        tester = app.test_client()
        response = tester.get('/sessions/categories/category1')
        self.assertEqual(response.status_code, 200)

if __name__ == '__main__':
    unittest.main()

יוצרים קובץ בשם tests.py עם הקוד שלמעלה.

הערה לגבי יצירת תרחישי בדיקה

יכול להיות שתראו קוד שונה מזה שמופיע למעלה, וזה עלול לגרום לבעיות בהפעלת מקרי הבדיקה. לדוגמה: ראינו שבחלק מההפעלות שלנו הוחמצו קטעי הקוד העיקריים הבאים:

from app import app

הקוד שלמעלה נדרש כדי לייבא את אפליקציית Flask הקיימת, שדרכה נפעיל את מקרי הבדיקה.

if __name__ == '__main__':

`unittest.main()`

הקוד שלמעלה נדרש כדי להריץ את מקרי הבדיקה.

אנחנו ממליצים לעיין בכל מקרי הבדיקה, לעיין assertEqual ותנאים אחרים בקוד שנוצר כדי לוודא שהוא יפעל. מכיוון שהנתונים הם חיצוניים באיסוף של Firestore, יכול להיות שאין להם גישה אליהם וכתוצאה מכך הם עלולים להשתמש בנתוני דמה וכתוצאה מכך הבדיקות עלולות להיכשל. לכן, מומלץ לשנות את מקרי הבדיקה בהתאם או להוסיף הערות לגבי חלק ממקרי הבדיקה שייתכן שאין בהם צורך באופן מיידי.

לצורך הדגמה, רצנו את מקרי הבדיקה באמצעות הפקודה הבאה (חשוב להקפיד להפעיל את שרת הפיתוח המקומי, מאחר שיבוצעו קריאות לנקודות הקצה המקומיות של ה-API):

python tests.py

קיבלנו את תוצאת הסיכום הבאה:

Ran 4 tests in 0.274s

FAILED (failures=2)

זה נכון כי מזהה הסשן היה שגוי בבדיקה השלישית, ואין קטגוריה בשם category1

.

לכן מומלץ לשנות את מקרי הבדיקה בהתאם ולבדוק אותם.

13. פיתוח מבוסס-בדיקה

עכשיו נראה איך מוסיפים שיטת חיפוש חדשה ב-API של הסשנים, לפי המתודולוגיה 'פיתוח מבוסס-בדיקה' (TDD). המטרה היא קודם כל לכתוב תרחישים לדוגמה, כדי שהם ייכשלו עקב היעדר הטמעה, ומשתמשים ב-Gemini Code Assist כדי ליצור את ההטמעה החסרה כדי שהבדיקה תעבור בהצלחה.

עוברים אל test.py (בהנחה שתיקנת את הקובץ tests.py כך שכל הבדיקות יעברו בהצלחה). מבקשים מ-Code Assist את ההנחיה הבאה:

Generate a new test case to search for sessions by speaker

בעקבות זאת קיבלנו את ההטמעה של תרחיש הניסיון הבא, שהוספנו לקובץ tests.py.

  def test_get_sessions_by_speaker(self):
        tester = app.test_client()
        response = tester.get('/sessions/speakers/speaker1')
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.json, [sessions.sessions[0], sessions.sessions[1]])

אם מריצים את הבדיקות, אמורה להופיע השגיאה הבאה:

$ python tests.py 
.F.
======================================================================
FAIL: test_get_sessions_by_speaker (__main__.FlaskAppTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/romin/hello-world-5/tests.py", line 21, in test_get_sessions_by_speaker
    self.assertEqual(response.status_code, 200)
AssertionError: 404 != 200

----------------------------------------------------------------------
Ran 3 tests in 0.010s

FAILED (failures=1)

הסיבה לכך היא שבמקרה הבדיקה הופעל הנתיב הבא (/sessions/speakers/), ואין הטמעה של הנתיב הזה ב-app.py.

אפשר לבקש מ-Code Assist לספק לנו הטמעה. נכנסים לקובץ app.py ומעבירים את הבקשה הבאה ל-Code Assist:

Add a new route to search for sessions by a specific speaker

קיבלנו את ההטמעה הבאה שהוצעה על ידי Code Assist, שהוספנו לקובץ app.py:

@app.route('/sessions/speakers/<speaker>', methods=['GET'])
def get_sessions_by_speaker(speaker):
    sessions_by_speaker = [session for session in sessions.sessions if speaker in session['speakers']]
    return jsonify(sessions_by_speaker)

אפשר לחזור לקובץ tests.py ולבצע את השינויים הבאים כדי לבצע בדיקה מהירה:

   def test_get_sessions_by_speaker(self):
       tester = app.test_client()
       response = tester.get('/sessions/speakers/Romin Irani')
       self.assertEqual(response.status_code, 200)
       self.assertEqual(len(response.json), 1)

הבדיקה פעלה כמו שצריך. אנחנו משאירים לכם את האפשרות לבחון את מקרי הבדיקה שנוצרו, לשנות אותם קצת בהתאם לנתונים שיש לכם ב-Firestore ולהשתמש בשיטות assert* המתאימות במקרים של Python Unit Test.

14. פריסה ב-Google Cloud Run

עכשיו, אחרי שאנחנו מרגישים טוב לגבי איכות הפיתוח שלנו, השלב האחרון יהיה פריסת האפליקציה ב-Google Cloud Run. אבל אולי, לשם כך, כדאי שנשאל את Code Assist אם שכחנו משהו. כאשר app.py פתוח, שולחים את ההנחיה הבאה :

Is there something here I should change before I deploy to production?

טוב ששאלת, מכיוון שלמעשה שכחנו להשבית את הסימון לניפוי באגים :

2f87ed3a811fb218.png

כפי שצוין, צריך להשבית את ניפוי הבאגים ולהמשיך לבקש עזרה מ-Gemini Code Assist עם הפקודה gcloud שניתן להשתמש בה לפריסת האפליקציה ב-Cloud Run ישירות מהמקור (בלי צורך לפתח קונטיינר קודם).

נותנים את ההנחיה הבאה:

I would like to deploy the application to Cloud Run directly from source. What is the gcloud command to do that?

כדאי לנסות כמה וריאציות להנחיה שלמעלה. התנסות נוספת הייתה:

I would like to deploy this application to Cloud Run. I don't want to build a container image locally but deploy directly from source to Cloud Run. What is the gcloud command for that?

במצב אידיאלי אתם אמורים לקבל את הפקודה הבאה gcloud:

gcloud run deploy sessions --source .

יכול להיות שתקבלו גם:

gcloud run deploy <service-name> --source . \
—-platform managed \
—-allow-unauthenticated

מריצים את הפקודה שלמעלה מתיקיית הבסיס של האפליקציה. כשמוצגת הבקשה region, בוחרים us-central1 וכשמוצגת בקשה לתת הרשאה ל-unauthenticated invocations, בוחרים באפשרות Y. יכול להיות גם שתתבקשו להפעיל את ממשקי ה-API של Google Cloud כמו Artifact Registry, Cloud Build ו-Cloud Run, ולקבל הרשאה ליצירת מאגר של Artifact Registry. צריך לתת את ההרשאה.

תהליך הפריסה יימשך כ-2 דקות, ויש להתאזר בסבלנות.

לאחר הפריסה בהצלחה, תופיע כתובת ה-URL של השירות של Cloud Run. נכנסים לכתובת ה-URL הציבורית הזו, ואתם אמורים לראות את אותה אפליקציית אינטרנט פרוסה ופועלת בהצלחה.

c5322d0fd3e0f616.png

כל הכבוד!

15. (אופציונלי) שימוש ב-Cloud Logging

אנחנו יכולים להציג את הרישום ביומן באפליקציה שלנו כך שיומני האפליקציות ירוכזו באחד משירותי Google Cloud (Cloud Logging). אחר כך נוכל להשתמש בתכונה 'ניראות (Gemini)' של Gemini כדי להבין גם את הרשומות ביומן.

כדי לעשות את זה, קודם צריך להשתמש בספריית Python Cloud Logging קיימת מ-Google Cloud ולהשתמש בה לרישום הודעות אינפורמטיביות, הודעות אזהרה או הודעות שגיאה (בהתאם לרמת היומן או החומרה).

בואו ננסה קודם לבקש זאת ל-Code Assist. נסו את ההנחיה הבאה:

How do I use the google-cloud-logging package in Python?

אמורה להתקבל תשובה עם מידע נוסף, כמפורט בהמשך:

2472e1ccaf8a217d.png

בואו נוסיף משפטי רישום ביומן לפונקציה שמחפשת סשנים לפי קטגוריה.

קודם כול, מוסיפים את חבילת ה-Python google-cloud-logging לקובץ requirements.txt.

לפניכם קטע קוד שמראה איך שילבנו את הקוד כדי להטמיע את הרישום ביומן:

...
from google.cloud import logging
...
app = Flask(__name__)

# Create a logger
logger = logging.Client().logger('my-log')

@app.route('/sessions/categories/<category>', methods=['GET'])
def get_sessions_by_category(category):
   logger.log_text(f"Fetching sessions with category {category}")
   sessions_by_category = [session for session in sessions.sessions if category in session['categories']]
   logger.log_text(f'Found {len(sessions_by_category)} sessions with category {category}')
   return jsonify(sessions_by_category)

# # Other App Routes

פורסים שוב את השירות ב-Cloud Run באמצעות אותה פקודה כמו בסעיף הקודם, ולאחר הפריסה, מבצעים כמה קריאות לנקודת הקצה (endpoint) /sessions/categories/<category>.

עוברים אל Cloud Console → Logs Explorer.

59e297577570695.png

...ואתם אמורים להיות מסוגלים לסנן לפי הצהרות הרישום ביומן באופן הבא:

914f1fb6cac30a89.png

אתם יכולים ללחוץ על כל אחת מהצהרות היומן, להרחיב אותה ואז ללחוץ על הסמל Explain this log entry. המודל הזה ישתמש ב-Gemini כדי להסביר את הרשומה ביומן. לתשומת ליבך: אם לא הפעלת את Gemini ל-Google Cloud, תתבקשו להפעיל את Cloud AI Companion API. יש לבצע זאת בהתאם להוראות.

בהמשך מוצגת תגובה לדוגמה:

7fc9783910fa92cc.png

16. מזל טוב

כל הכבוד, פיתחת אפליקציה מאפס והשתמשת ב-Gemini Code Assist בהיבטים רבים של ה-SDLC, כולל עיצוב, build, בדיקה ופריסה.

מה השלב הבא?

כדאי לנסות כמה מ-Codelabs האלה...

מסמכי עזר