Thúc đẩy quy trình phát triển bằng Gemini Code Assist

1. Giới thiệu

e5b98fd4e417c877.png

Trong lớp học lập trình này, bạn sẽ tìm hiểu cách Gemini Code Assist có thể hỗ trợ bạn trong các giai đoạn chính của Vòng đời phát triển phần mềm (SDLC), chẳng hạn như thiết kế, xây dựng và kiểm thử cũng như triển khai. Chúng ta sẽ thiết kế và phát triển toàn bộ ứng dụng, sau đó triển khai ứng dụng đó trên Google Cloud.

Chúng tôi sẽ xây dựng một API và ứng dụng để tìm kiếm các phiên trong một sự kiện kỹ thuật. Mỗi phiên sẽ có tiêu đề, nội dung tóm tắt, thời lượng, danh mục và một hoặc nhiều diễn giả.

Bạn sẽ thực hiện

  • Thiết kế, tạo, kiểm thử và triển khai một ứng dụng web dựa trên thông số kỹ thuật OpenAPI từ đầu

Kiến thức bạn sẽ học được

  • Cách dùng Gemini Code Assist để tạo một OpenAPI Specification
  • Cách sử dụng các tính năng tạo mã của Gemini Code Assist để phát triển một ứng dụng Python Flask cho quy cách OpenAPI
  • Cách sử dụng Gemini Code Assist để tạo giao diện người dùng web cho Ứng dụng Python Flask
  • Cách sử dụng Gemini Code Assist để được trợ giúp về cách triển khai ứng dụng lên Google Cloud Run
  • Sử dụng các tính năng của Gemini Code Assist như Giải thích mã, Tạo trường hợp kiểm thử trong khi tạo và kiểm thử ứng dụng

Bạn cần có

  • Trình duyệt web Chrome
  • Tài khoản Gmail
  • Một Dự án trên đám mây đã bật tính năng thanh toán
  • Gemini Code Assist được bật cho Dự án trên đám mây

Lớp học này dành cho nhà phát triển ở mọi cấp độ, kể cả người mới bắt đầu. Mặc dù ứng dụng mẫu này sử dụng ngôn ngữ Python, nhưng bạn không cần phải quen thuộc với việc lập trình bằng Python để hiểu những gì đang diễn ra. Chúng ta sẽ tập trung vào việc làm quen với các tính năng của Gemini Code Assist.

2. Thiết lập Gemini Code Assist

Phần này trình bày mọi việc bạn cần làm để bắt đầu với lớp học này.

Bật Gemini Code Assist trong Cloud Shell IDE

Chúng ta sẽ dùng Cloud Shell IDE, một môi trường phát triển dựa trên Code OSS được quản lý hoàn toàn, cho phần còn lại của lớp học lập trình. Chúng ta cần bật và định cấu hình Trợ lý mã trong Cloud Shell IDE. Các bước thực hiện như sau:

  1. Truy cập vào ide.cloud.google.com. Có thể mất một lúc để IDE xuất hiện, vì vậy, vui lòng kiên nhẫn và chấp nhận mọi lựa chọn mặc định khi thiết lập. Trong trường hợp bạn thấy một số hướng dẫn về cách thiết lập IDE, vui lòng hoàn tất các hướng dẫn đó bằng chế độ cài đặt mặc định.
  2. Nhấp vào nút Cloud Code – Sign in (Cloud Code – Đăng nhập) trong thanh trạng thái dưới cùng như minh hoạ. Uỷ quyền cho trình bổ trợ theo hướng dẫn. Nếu bạn thấy "Cloud Code – no project" (Cloud Code – không có dự án) trong thanh trạng thái, hãy chọn mục đó rồi chọn Dự án cụ thể trên Google Cloud trong danh sách các dự án mà bạn dự định làm việc.

6f5ce865fc7a3ef5.png

  1. Nhấp vào nút Code Assist (Trợ lý lập trình) ở góc dưới cùng bên phải như minh hoạ rồi chọn dự án Google Cloud chính xác thêm một lần nữa. Nếu được yêu cầu bật Cloud AI Companion API, vui lòng bật và tiếp tục.
  2. Sau khi chọn dự án Google Cloud, hãy đảm bảo rằng bạn có thể thấy dự án đó trong thông báo trạng thái Cloud Code trên thanh trạng thái và bạn cũng đã bật Trợ lý lập trình ở bên phải, trong thanh trạng thái như minh hoạ bên dưới:

709e6c8248ac7d88.png

Gemini Code Assist đã sẵn sàng để bạn sử dụng!

3. Thiết lập Firestore

Cloud Firestore là một cơ sở dữ liệu tài liệu không máy chủ, được quản lý toàn diện mà chúng ta sẽ dùng làm phần phụ trợ cho dữ liệu ứng dụng. Dữ liệu trong Cloud Firestore được cấu trúc thành tập hợp gồm tài liệu.

Chúng ta cần tạo một tập hợp có tên là sessions trong cơ sở dữ liệu Firestore mặc định. Tập hợp này sẽ chứa dữ liệu mẫu (tài liệu) mà sau đó chúng ta sẽ dùng trong ứng dụng.

Mở Terminal trong Cloud Shell IDE thông qua trình đơn chính như minh hoạ dưới đây:

f1535e14c9beeec6.png

Chúng ta cần tạo một bộ sưu tập có tên là sessions. Thư mục này sẽ chứa danh sách các tài liệu mẫu của phiên. Mỗi tài liệu sẽ có các thuộc tính sau:

  1. title: chuỗi
  2. categories: mảng chuỗi
  3. speakers: mảng chuỗi
  4. duration: string
  5. summary: chuỗi

Hãy điền dữ liệu mẫu vào bộ sưu tập này bằng cách sao chép một tệp chứa dữ liệu mẫu vào một vùng chứa trong dự án của riêng bạn. Từ đó, bạn có thể nhập bộ sưu tập thông qua lệnh gcloud firestore import.

Khởi chạy cơ sở dữ liệu Firestore

Truy cập vào trang Firestore trong bảng điều khiển Cloud.

Nếu bạn chưa khởi tạo cơ sở dữ liệu Firestore trong dự án, hãy tạo cơ sở dữ liệu default. Trong quá trình tạo cơ sở dữ liệu, hãy sử dụng các giá trị sau:

  • Chế độ Firestore: Native
  • Vị trí: Chọn loại Vị trí là Region rồi chọn khu vực phù hợp với ứng dụng của bạn. Hãy ghi lại vị trí này vì bạn sẽ cần vị trí này trong bước tiếp theo cho vị trí của nhóm.
  • Tạo cơ sở dữ liệu.

504cabdb99a222a5.png

Giờ đây, chúng ta sẽ tạo bộ sưu tập sessions bằng cách làm theo các bước dưới đây:

  1. Tạo một bộ chứa trong dự án bằng lệnh gsutil được cung cấp bên dưới. Thay thế biến <PROJECT_ID> trong lệnh bên dưới bằng mã dự án của bạn trên Google Cloud. Thay thế <BUCKET_LOCATION> bằng tên khu vực tương ứng với Khu vực địa lý của cơ sở dữ liệu Firestore mặc định (như đã lưu ý ở bước trước), có thể là US-WEST1, EUROPE-WEST1, ASIA-EAST1 :
gsutil mb -l <BUCKET-LOCATION> gs://<PROJECT_ID>-my-bucket
  1. Sau khi tạo vùng chứa, chúng ta cần sao chép dữ liệu xuất của cơ sở dữ liệu mà chúng ta đã chuẩn bị vào vùng chứa này, trước khi có thể nhập dữ liệu đó vào cơ sở dữ liệu Firebase. Sử dụng lệnh bên dưới:
gsutil cp -r gs://sessions-master-database-bucket/2024-03-26T09:28:15_95256  gs://<PROJECT_ID>-my-bucket

Bây giờ, khi đã có dữ liệu để nhập, chúng ta có thể chuyển sang bước cuối cùng là nhập dữ liệu vào cơ sở dữ liệu Firebase (default) mà chúng ta đã tạo.

  1. Sử dụng lệnh gcloud bên dưới:
gcloud firestore import gs://<PROJECT_ID>-my-bucket/2024-03-26T09:28:15_95256

Quá trình nhập sẽ mất vài giây và sau khi hoàn tất, bạn có thể xác thực cơ sở dữ liệu Firestore và tập hợp bằng cách truy cập vào https://console.cloud.google.com/firestore/databases, chọn cơ sở dữ liệu default và tập hợp sessions như minh hoạ bên dưới:

d3e294d46ba29cd5.png

Thao tác này sẽ hoàn tất việc tạo bộ sưu tập Firestore mà chúng ta sẽ sử dụng trong ứng dụng.

4. Tạo mẫu ứng dụng

Chúng ta sẽ tạo một ứng dụng mẫu (ứng dụng Python Flask) mà chúng ta sẽ dùng trong phần còn lại của lớp học lập trình này. Ứng dụng này sẽ tìm kiếm trong các phiên được cung cấp tại một hội nghị kỹ thuật.

Hãy làm theo các bước sau:

  1. Nhấp vào tên dự án trên Google Cloud trong thanh trạng thái bên dưới.

f151759c156c124e.png

  1. Một danh sách các lựa chọn sẽ xuất hiện. Nhấp vào Ứng dụng mới trong danh sách bên dưới.

91ea9836f38b7f74.png

  1. Chọn Ứng dụng Cloud Run (đây sẽ là thời gian chạy cho ứng dụng của chúng ta).
  2. Chọn mẫu ứng dụng Python (Flask): Cloud Run.
  3. Đặt tên cho ứng dụng rồi lưu vào vị trí bạn muốn.
  4. Một thông báo xác nhận rằng ứng dụng của bạn đã được tạo và một cửa sổ mới sẽ mở ra với ứng dụng của bạn được tải như minh hoạ dưới đây. Một tệp README.md sẽ mở ra. Bạn có thể đóng chế độ xem đó ngay bây giờ.

aaa3725b17ce27cf.png

5. Tương tác với Gemini Code Assist

Trong phòng thí nghiệm này, chúng ta sẽ sử dụng Gemini Code Assist Chat có trong Cloud Shell IDE trong phần mở rộng Cloud Code của VS Code. Bạn có thể mở tính năng này bằng cách nhấp vào nút Trợ lý lập trình trong thanh điều hướng bên trái. Tìm biểu tượng Trợ lý mã a489f98a34898727.pngtrong thanh công cụ điều hướng bên trái rồi nhấp vào biểu tượng đó.

Thao tác này sẽ mở ngăn trò chuyện Code Assist trong Cloud Shell IDE và bạn có thể trò chuyện với Code Assist.

14ad103efaa0ddaa.png

Hãy chú ý đến biểu tượng thùng rác ở trên cùng. Đây là cách để bạn đặt lại ngữ cảnh cho nhật ký trò chuyện của Code Assist. Cũng lưu ý rằng cuộc trò chuyện này có liên quan đến(các) tệp mà bạn đang làm việc trong IDE.

6. Thiết kế API

Bước đầu tiên của chúng ta sẽ là sử dụng Gemini Code Assist trong giai đoạn Thiết kế. Trong bước này, chúng ta sẽ tạo một quy cách OpenAPI cho các thực thể (phiên kỹ thuật trong một sự kiện) mà chúng ta muốn tìm kiếm.

Đưa ra câu lệnh sau:

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.

Thao tác này sẽ tạo ra một OpenAPI Specification để tìm kiếm trên các phiên thông qua nhiều tham số truy vấn. Dưới đây là mẫu quy cách:

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

Bạn có thể nhận thấy rằng quy cách có những điểm sau:

  • Một giản đồ được xác định cho Loại phiên.
  • Một số đường dẫn API được xác định:
  • /sessions
  • /sessions/{id}
  • /sessions/categories/{category}

Tạo một tệp có tên là sessionsapi.yaml trong thư mục trên cùng và sao chép nội dung từ cửa sổ trò chuyện của Trợ lý mã bằng cách sử dụng "lựa chọn chèn vào tệp hiện tại" (nút +) và giữ cho tệp mở trong Cloud Shell IDE.

Đến đây, bạn có thể lưu ý một tính năng thú vị của Gemini Code Assist: trích dẫn. Thông tin này sẽ được cung cấp cho nhà phát triển khi mã được tạo trích dẫn trực tiếp và dài dòng từ một nguồn khác, chẳng hạn như mã nguồn mở hiện có. Nó cung cấp nguồn và giấy phép để nhà phát triển quyết định cách sử dụng.

Giả sử chúng ta hài lòng với nội dung được tạo, giờ đây, chúng ta có thể sử dụng tài liệu đặc tả này để tạo một Ứng dụng Python Flask cho nội dung đó.

7. Tạo ứng dụng

Bây giờ, chúng ta sẽ yêu cầu Trợ lý lập trình tạo ứng dụng. Đưa ra lời nhắc sau đây khi mở tệp 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.

Thao tác này sẽ cung cấp cho bạn một cấu trúc cơ bản cho Ứng dụng Python Flask dựa trên chức năng và đường dẫn đã được chỉ định trong tệp đặc tả OpenAPI.

Mã xử lý ứng dụng Python Flask được cung cấp phải tương tự như mã sau:

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()

Có một tệp app.py hiện có được tạo trong bước trước. Bạn chỉ cần thay thế nội dung của tệp bằng mã do Trợ lý lập trình tạo rồi lưu tệp.

Chúng ta muốn thay đổi dòng app.run() để sử dụng cổng 8080, địa chỉ máy chủ lưu trữ 0.0.0.0 và cũng chạy ở chế độ Gỡ lỗi trong quá trình thực thi cục bộ.Sau đây là cách thực hiện. Trước tiên, hãy đánh dấu/chọn dòng sau:

app.run()

Sau đó, trong giao diện Code Assist Chat, hãy nhập câu lệnh: Explain this.

Thao tác này sẽ cho thấy nội dung giải thích chi tiết về dòng cụ thể đó, ví dụ như nội dung được minh hoạ bên dưới:

58ec896a32a4fb68.png

Bây giờ, hãy sử dụng câu lệnh sau:

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

Mã đề xuất được tạo sẽ có dạng như sau: :

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

Hãy nhớ cập nhật tệp app.py bằng đoạn mã này.

Chạy ứng dụng cục bộ

Bây giờ, hãy chạy ứng dụng cục bộ để xác thực các yêu cầu của ứng dụng theo những gì chúng ta đã bắt đầu.

Bước đầu tiên là tạo một môi trường Python ảo với các phần phụ thuộc của gói Python trong requirements.txt để cài đặt trong môi trường ảo. Để làm việc đó, hãy chuyển đến Bảng lệnh (Ctrl+Shift+P) trong Cloud Shell IDE rồi nhập Tạo môi trường Python. Làm theo một vài bước tiếp theo để chọn Môi trường ảo (venv), trình thông dịch Python 3.x và tệp requirements.txt.

Sau khi tạo môi trường, hãy khởi chạy một cửa sổ dòng lệnh mới (Ctrl+Shift+`) và đưa ra lệnh sau:

python app.py

Dưới đây là một ví dụ về quá trình thực thi:

(.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

Giờ đây, bạn có thể xem trước API tại các URL sau. Chúng tôi giả định rằng máy chủ phát triển của bạn đang chạy trên cổng 8080. Nếu không, vui lòng thay đổi thành số cổng thích hợp.

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

Hãy làm theo các bước dưới đây để đảm bảo rằng bạn có thể truy xuất bằng các URL này, dữ liệu JSON có trong tệp app.py:

Mở một cửa sổ dòng lệnh mới và thử một trong các lệnh sau:

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. Tái cấu trúc mã

Thay vì để app.py chứa dữ liệu JSON mẫu được cố định giá trị trong mã, có lẽ chúng ta nên tách/trích xuất dữ liệu này vào một mô-đun khác để có thể duy trì sự tách biệt rõ ràng giữa mã và dữ liệu. Hãy cùng làm điều đó!

Mở tệp app.py và đưa ra lời nhắc sau:

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

Thao tác này sẽ đưa ra một số đề xuất về cách thực hiện. Dưới đây là một ví dụ về đề xuất mà chúng tôi nhận được và bạn sẽ nhận được đề xuất tương tự:

9b9c56cb527dac4c.png

Hãy làm theo hướng dẫn đó và tách dữ liệu của chúng ta thành một tệp sessions.py như Code Assist đề xuất.

Tạo một tệp mới có tên là sessions.py

, nội dung là danh sách JSON, theo dữ liệu mà chúng tôi tạo ra như sau:

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",
   },
]

Tệp app.py hiện đã được đơn giản hoá rất nhiều và xuất hiện bên dưới:

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)

Đảm bảo rằng bạn vẫn có thể chạy ứng dụng cục bộ và thực hiện API với những thay đổi được tái cấu trúc này. Máy chủ phát triển Python có thể vẫn đang chạy, vì vậy, bạn chỉ cần gọi lại các lệnh curl từ bước trước.

9. Tích hợp với bộ sưu tập trên Firestore

Bước tiếp theo là chuyển từ danh sách JSON trong bộ nhớ cục bộ mà chúng ta có cho các phiên và kết nối ứng dụng của chúng ta với tập hợp sessions trong cơ sở dữ liệu Firestore mà chúng ta đã tạo ở đầu lớp học lập trình này.

Mở tệp sessions.py và đưa ra lời nhắc sau:

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. 

Chúng tôi nhận được đề xuất sau đây để đọc tất cả các phiên từ tập hợp 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)

Hãy kết hợp mã trong sessions.py.

Nếu bạn đang chạy máy chủ phát triển Flask cục bộ, thì ứng dụng của bạn có thể đã đóng và báo lỗi rằng không tìm thấy mô-đun Python.

Ví dụ: bạn có thể hỏi Trợ lý lập trình về mô-đun Python cần thêm vào tệp requirements.txt, như sau:

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

Thao tác này sẽ cung cấp cho bạn tên của mô-đun Python (ví dụ: google-cloud-firestore). Hãy thêm tên đó vào tệp requirements.txt.

Bạn sẽ cần tạo lại môi trường Python bằng mô-đun mới được thêm (google-cloud-firestore). Để làm như vậy, hãy đưa ra lệnh sau trong cửa sổ dòng lệnh hiện có:

pip install -r requirements.txt

Chạy lại ứng dụng (khởi động lại bằng python app.py) rồi truy cập vào URL /sessions. Giờ đây, bạn sẽ nhận được các tài liệu mẫu mà chúng tôi đã thêm vào bộ sưu tập sessions.

975d05e6518f1a6a.png

Bạn có thể thoải mái truy vấn các URI khác để truy xuất các phiên cụ thể hoặc tất cả các phiên cho một danh mục nhất định như mô tả trong các bước trước đó.

10. Giải thích mã

Bây giờ là thời điểm thích hợp để sử dụng tính năng "Explain this" của Gemini Code Assist nhằm hiểu rõ hơn về mã. Bạn có thể truy cập vào bất kỳ tệp nào hoặc chọn các đoạn mã cụ thể rồi yêu cầu Trợ lý lập trình bằng câu lệnh sau: Explain this.

Để thực hành, hãy truy cập vào tệp sessions.py, đánh dấu mã cụ thể của Firestore và xem phần giải thích mã trên tệp đó. Hãy thử dùng tính năng này trên các tệp khác trong dự án của bạn, không chỉ mã Python.

11. Tạo ứng dụng web

Giờ đây, sau khi tạo API và tích hợp API đó với một bộ sưu tập Firestore đang hoạt động, hãy tạo một giao diện người dùng dựa trên web cho ứng dụng. Giao diện người dùng Web của chúng tôi hiện sẽ duy trì chức năng ở mức tối thiểu, tức là có thể tìm kiếm các phiên thuộc một danh mục cụ thể. Xin lưu ý rằng chúng tôi có một đường dẫn API cho việc đó, tức là /sessions/categories/{category}, vì vậy, ứng dụng web của chúng tôi sẽ gọi đường dẫn đó và truy xuất kết quả.

Hãy cùng bắt đầu ngay nhé. Đưa ra câu lệnh sau cho 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.

Thao tác này sẽ tạo HTML của ứng dụng Web với JavaScript và CSS được nhúng trong đó. Thao tác này cũng sẽ yêu cầu bạn thêm một tuyến đường mới vào tệp app.py, để mọi người dùng truy cập vào URL gốc hoặc URL cơ sở sẽ được chuyển đến trang chủ. Nếu không đề cập đến thông tin đó, hãy hỏi về thông tin đó hoặc sử dụng đoạn trích bên dưới:

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

Bạn có thể lưu tệp này dưới dạng index.html nhưng có thể thắc mắc về vị trí lưu tệp này (tức là thư mục nào?). Chúng ta có thể đặt câu hỏi nối tiếp cho Trợ lý lập trình.

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

Thông tin này phải cho bạn biết rõ rằng ứng dụng sử dụng khung render_template và do đó, tệp index.html sẽ cần được đặt bên trong thư mục templates. Bạn sẽ thấy thư mục này vì chúng ta đã tạo một Ứng dụng dựa trên mẫu Flask ở đầu lớp học lập trình này. Do đó, có một tệp index.html hiện có và bạn chỉ cần thay thế nội dung của tệp đó bằng nội dung mới đã được tạo ở đây. Trợ lý mã cũng đề cập đến việc nhập render_template trong tệp app.py.

Hãy lưu mã xử lý ứng dụng Web trong tệp index.html và nhớ đặt tệp đó vào thư mục templates.

Chạy ứng dụng cục bộ

Bây giờ, hãy chạy ứng dụng cục bộ để xác thực các yêu cầu của ứng dụng theo những gì chúng ta đã bắt đầu.

Đảm bảo rằng máy chủ Flask cục bộ vẫn đang chạy và không hiển thị bất kỳ lỗi nào. Trong trường hợp có lỗi, hãy giải quyết và khởi động máy chủ.

Sau khi ứng dụng chạy, hãy truy cập vào URL trang chủ của ứng dụng. Thao tác này sẽ cho bạn thấy tệp index.html được phân phát như minh hoạ dưới đây:

8ca586acc4536879.png

Cung cấp một trong các danh mục từ dữ liệu làm đầu vào (ví dụ: AI) rồi nhấp vào nút Search. Thao tác này sẽ hiển thị các phiên được gắn thẻ bằng danh mục AI.

165faded790a6c.png

Bạn có thể chọn hiển thị thêm siêu dữ liệu như thời lượng, danh mục, người nói và nội dung tóm tắt cho từng phiên.

12. Tạo trường hợp kiểm thử

Chúng ta đã tạo API phiên và giờ là lúc sử dụng Gemini Code Assist để tạo các trường hợp kiểm thử đơn vị cho các đường dẫn API khác nhau.

Mở tệp app.py và đưa ra lời nhắc sau:

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

Chúng tôi nhận được phản hồi như sau:

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()

Tạo một tệp có tên là tests.py bằng mã ở trên.

Lưu ý về việc tạo trường hợp kiểm thử

Bạn có thể thấy một danh sách mã khác với danh sách ở trên và điều đó có thể gây ra một số vấn đề khi chạy các trường hợp kiểm thử. Ví dụ: chúng tôi nhận thấy trong một số lần chạy, các đoạn mã khoá sau đây đã bị bỏ sót:

from app import app

Bạn cần có mã ở trên để nhập Ứng dụng Flask hiện có mà chúng ta sẽ gọi các trường hợp kiểm thử.

if __name__ == '__main__':

`unittest.main()`

Bạn cần có mã ở trên để chạy các trường hợp kiểm thử.

Bạn nên xem xét từng trường hợp kiểm thử, kiểm tra assertEqual và các điều kiện khác trong mã được tạo để đảm bảo mã đó sẽ hoạt động. Vì dữ liệu nằm bên ngoài trong tập hợp Firestore, nên có thể bạn không có quyền truy cập vào dữ liệu đó và có thể sử dụng một số dữ liệu giả. Do đó, các kiểm thử có thể không thành công. Vì vậy, hãy sửa đổi các trường hợp kiểm thử cho phù hợp hoặc nhận xét về một số trường hợp kiểm thử mà bạn có thể không cần ngay lập tức.

Để minh hoạ, chúng tôi đã chạy các trường hợp kiểm thử bằng lệnh sau (Nhớ chạy máy chủ phát triển cục bộ vì các lệnh gọi sẽ được thực hiện đến Điểm cuối API cục bộ):

python tests.py

Chúng tôi nhận được kết quả tóm tắt như sau:

Ran 4 tests in 0.274s

FAILED (failures=2)

Điều đó thực sự chính xác vì mã phiên không chính xác trong lần kiểm thử thứ 3 và không có danh mục nào có tên là category1

.

Vì vậy, hãy điều chỉnh các trường hợp kiểm thử cho phù hợp và kiểm thử.

13. Phát triển dựa trên kiểm thử

Bây giờ, hãy xem cách thêm một phương thức tìm kiếm mới vào API phiên của chúng ta theo phương pháp Phát triển dựa trên kiểm thử (TDD). Phương pháp này là về việc viết các trường hợp kiểm thử trước, khiến chúng thất bại do thiếu quá trình triển khai và sử dụng Gemini Code Assist để tạo quá trình triển khai còn thiếu để kiểm thử thành công.

Chuyển đến tệp tests.py (giả sử bạn đã sửa tệp tests.py để có tất cả các bài kiểm thử đạt). Hãy đặt cho Trợ lý lập trình câu hỏi sau:

Generate a new test case to search for sessions by speaker

Điều này mang đến cho chúng ta quá trình triển khai trường hợp kiểm thử sau đây mà chúng ta đã chèn vào tệp 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]])

Nếu chạy các kiểm thử, bạn sẽ thấy lỗi sau:

$ 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)

Điều này là do trường hợp kiểm thử đã gọi đường dẫn (/sessions/speakers/) và không có cách triển khai nào cho đường dẫn đó trong app.py.

Hãy yêu cầu Code Assist cung cấp cho chúng ta một cách triển khai. Chuyển đến tệp app.py rồi đưa ra lời nhắc sau cho Trợ lý lập trình:

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

Chúng ta đã nhận được phương thức triển khai sau đây do Trợ lý mã đề xuất và chúng ta đã thêm phương thức này vào tệp 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)

Hãy xem lại tệp tests.py và chúng tôi đã sửa đổi trường hợp kiểm thử như sau để kiểm tra nhanh:

   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)

Thử nghiệm đã chạy tốt. Bạn có thể xem xét các trường hợp kiểm thử đã tạo, điều chỉnh một chút tuỳ thuộc vào dữ liệu mà bạn có thể có trong Firestore và có các phương thức assert* thích hợp trong các trường hợp kiểm thử đơn vị Python.

14. Triển khai lên Google Cloud Run

Giờ đây, khi đã hài lòng về chất lượng của quá trình phát triển, bước cuối cùng của chúng ta sẽ là triển khai ứng dụng này lên Google Cloud Run. Nhưng có lẽ, để chắc chắn, chúng ta nên hỏi Trợ lý lập trình xem chúng ta có quên điều gì không. Khi app.py mở, hãy gửi câu lệnh sau :

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

Rất may là bạn đã hỏi vì chúng tôi quên tắt cờ gỡ lỗi :

2f87ed3a811fb218.png

Như đã nêu, hãy tắt tính năng gỡ lỗi và tiếp tục yêu cầu Gemini Code Assist trợ giúp về lệnh gcloud. Bạn có thể dùng lệnh này để triển khai ứng dụng vào Cloud Run ngay từ nguồn (mà không cần tạo vùng chứa trước).

Đưa ra câu lệnh sau:

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

Hãy thử một vài biến thể của câu lệnh trên. Một cách khác mà chúng tôi đã thử là:

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?

Lý tưởng nhất là bạn nên nhận được lệnh gcloud sau đây:

gcloud run deploy sessions --source .

Bạn cũng có thể nhận được:

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

Thực thi lệnh trên từ thư mục gốc của ứng dụng. Khi được hỏi về region, hãy chọn us-central1 và khi được hỏi về việc cho phép unauthenticated invocations, hãy chọn Y. Bạn cũng có thể được yêu cầu bật các Cloud API của Google như Artifact Registry, Cloud Build và Cloud Run, cũng như cấp quyền tạo kho lưu trữ Artifact Registry. Vui lòng cấp quyền này.

Quá trình triển khai sẽ mất khoảng 2 phút để hoàn tất, vì vậy, vui lòng kiên nhẫn chờ đợi.

Sau khi triển khai thành công, bạn sẽ thấy URL dịch vụ Cloud Run. Truy cập vào URL công khai đó và bạn sẽ thấy ứng dụng web tương tự được triển khai và chạy thành công.

c5322d0fd3e0f616.png

Xin chúc mừng, bạn đã làm rất tốt!

15. (Không bắt buộc) Sử dụng Cloud Logging

Chúng ta có thể giới thiệu tính năng đăng nhập trong ứng dụng để các nhật ký ứng dụng được tập trung vào một trong các dịch vụ của Google Cloud (Cloud Logging). Sau đó, chúng ta có thể sử dụng tính năng Observability Gemini để hiểu rõ các mục nhật ký.

Để làm việc này, trước tiên, chúng ta sẽ phải sử dụng một thư viện Cloud Logging hiện có của Python từ Google Cloud và sử dụng thư viện đó để ghi nhật ký thông tin, cảnh báo hoặc thông báo lỗi (tuỳ thuộc vào nhật ký / mức độ nghiêm trọng).

Trước tiên, hãy thử hỏi Code Assist. Hãy thử câu lệnh sau:

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

Bạn sẽ nhận được phản hồi cung cấp một số thông tin về vấn đề này, như dưới đây:

2472e1ccaf8a217d.png

Hãy thêm các câu lệnh ghi nhật ký vào hàm tìm kiếm phiên theo danh mục.

Trước tiên, hãy thêm gói Python google-cloud-logging vào tệp requirements.txt.

Tiếp theo là một đoạn mã cho thấy cách chúng tôi tích hợp mã để triển khai tính năng ghi nhật ký:

...
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

Triển khai lại dịch vụ này vào Cloud Run bằng cách sử dụng cùng một lệnh như trong phần trước. Sau khi triển khai, hãy thực hiện một vài lệnh gọi đến điểm cuối /sessions/categories/<category>.

Truy cập vào Cloud Console → Logs Explorer

59e297577570695.png

...và bạn có thể lọc các câu lệnh ghi nhật ký này như minh hoạ bên dưới:

914f1fb6cac30a89.png

Bạn có thể nhấp vào bất kỳ câu lệnh nhật ký nào, mở rộng câu lệnh đó rồi nhấp vào Explain this log entry. Thao tác này sẽ sử dụng Gemini để giải thích mục nhập nhật ký. Xin lưu ý rằng nếu chưa bật Gemini cho Google Cloud, bạn sẽ được yêu cầu bật Cloud AI Companion API. Vui lòng thực hiện theo hướng dẫn.

Dưới đây là một phản hồi mẫu:

7fc9783910fa92cc.png

16. Xin chúc mừng

Chúc mừng bạn đã tạo thành công một ứng dụng từ đầu và sử dụng Gemini Code Assist trong nhiều khía cạnh của SDLC, bao gồm cả thiết kế, xây dựng, kiểm thử và triển khai.

Tiếp theo là gì?

Hãy xem một số lớp học lập trình này...

Tài liệu tham khảo