คู่มือเวิร์กช็อปแนะนำด้านเทคนิคสำหรับ Duet AI สำหรับนักพัฒนาซอฟต์แวร์ Codelab

1. วัตถุประสงค์

เวิร์กช็อปนี้มีจุดประสงค์เพื่อให้การศึกษา Duet AI ผ่านการลงมือปฏิบัติแก่ผู้ใช้และผู้ปฏิบัติงาน

ใน Codelab นี้ คุณจะได้ทราบสิ่งต่อไปนี้

  1. เปิดใช้งาน Duet AI ในโปรเจ็กต์ GCP แล้วกำหนดค่าเพื่อใช้ใน IDE และ Cloud Console
  2. ใช้ Duet AI ในการสร้าง ดำเนินการโค้ด และเขียนคำอธิบาย
  3. ใช้ Duet AI เพื่ออธิบายและแก้ปัญหาเกี่ยวกับแอปพลิเคชัน
  4. ฟีเจอร์ Duet AI เช่น แชท IDE และการแชทแบบมัลติเทิร์น การแชทเทียบกับการสร้างโค้ดในหน้า การดำเนินการอัจฉริยะ เช่น คำอธิบายโค้ด การรับทราบการบรรยาย และอีกมากมาย

การบรรยาย

กิจกรรมเวิร์กช็อปนี้จะจัดขึ้นในรูปแบบการเล่าเรื่อง เพื่อแสดงให้เห็นว่ามีการใช้ Duet AI สำหรับนักพัฒนาแอปอย่างเป็นธรรมชาติในการพัฒนาในแต่ละวัน

มีนักพัฒนาซอฟต์แวร์รายใหม่เข้าร่วมบริษัทอีคอมเมิร์ซ โดยได้รับมอบหมายให้เพิ่มบริการใหม่ลงในแอปพลิเคชันอีคอมเมิร์ซที่มีอยู่ (ประกอบด้วยบริการหลายรายการ) บริการใหม่จะให้ข้อมูลเพิ่มเติม (ขนาด น้ำหนัก ฯลฯ) เกี่ยวกับผลิตภัณฑ์ในแคตตาล็อกผลิตภัณฑ์ บริการนี้จะช่วยให้ค่าจัดส่งถูกกว่า/ถูกลงโดยอิงตามขนาดและน้ำหนักของผลิตภัณฑ์

เนื่องจากนักพัฒนาซอฟต์แวร์ยังไม่คุ้นเคยกับบริษัท จึงใช้ Duet AI ในการสร้างโค้ด สร้างคำอธิบาย และจัดทำเอกสารประกอบ

หลังจากเขียนโค้ดบริการแล้ว ผู้ดูแลระบบแพลตฟอร์มจะใช้ Duet AI (แชท) เพื่อช่วยสร้างอาร์ติแฟกต์ (คอนเทนเนอร์ Doker) และทรัพยากรที่จำเป็นต่อการทำให้อาร์ติแฟกต์ใช้งานได้กับ GCP (เช่น Artifact Registry, สิทธิ์ IAM, ที่เก็บโค้ด, โครงสร้างพื้นฐานในการประมวลผล เช่น GKE หรือ CloudRun เป็นต้น)

เมื่อทำให้แอปพลิเคชันใช้งานได้กับ GCP แล้ว โอเปอเรเตอร์แอปพลิเคชัน/SRE จะใช้ Duet AI (และ Cloud Ops) เพื่อช่วยแก้ไขข้อผิดพลาดในบริการใหม่

ลักษณะตัวตน

เวิร์กช็อปจะครอบคลุมลักษณะตัวตนต่อไปนี้

  1. นักพัฒนาแอปพลิเคชัน - ต้องมีความรู้ด้านการเขียนโปรแกรมและการพัฒนาซอฟต์แวร์อยู่บ้าง

เวิร์กช็อป Duet AI รูปแบบใหม่นี้มีไว้สำหรับนักพัฒนาซอฟต์แวร์เท่านั้น โดยไม่จำเป็นต้องมีความรู้เกี่ยวกับทรัพยากรระบบคลาวด์ของ GCP ดูสคริปต์สำหรับวิธีสร้างทรัพยากร GCP ที่จำเป็นสำหรับการเรียกใช้แอปพลิเคชันนี้ได้ที่นี่ คุณสามารถทำตามวิธีการในคู่มือนี้เพื่อติดตั้งใช้งานทรัพยากร GCP ที่จำเป็น

2. เตรียมสภาพแวดล้อม

กำลังเปิดใช้งาน Duet AI

คุณเปิดใช้งาน Duet AI ในโปรเจ็กต์ GCP ได้ผ่าน API (เครื่องมือ gcloud หรือ IaC เช่น Terraform) หรือผ่าน UI ของ Cloud Console

หากต้องการเปิดใช้งาน Duet AI ในโปรเจ็กต์ Google Cloud คุณจะต้องเปิดใช้ Cloud AI Companion API และมอบบทบาทผู้ใช้ Cloud AI Companion และบทบาทผู้มีสิทธิ์ดูและการจัดการการเข้าถึง (IAM) ของบริการแก่ผู้ใช้

ผ่าน GCloud

เปิดใช้งาน Cloud Shell:

กำหนดค่า PROJECT_ID, USER และเปิดใช้ Cloud AI Companion API

export PROJECT_ID=<YOUR PROJECT ID>
export USER=<YOUR USERNAME> # Use your full LDAP, e.g. name@example.com
gcloud config set project ${PROJECT_ID}
gcloud services enable cloudaicompanion.googleapis.com --project ${PROJECT_ID}

ผลลัพธ์ที่ได้มีดังต่อไปนี้

Updated property [core/project].
Operation "operations/acat.p2-60565640195-f37dc7fe-b093-4451-9b12-934649e2a435" finished successfully.

มอบบทบาทผู้ใช้ Cloud AI Companion และผู้ดูการใช้บริการและ Identity and Access Management (IAM) ให้กับบัญชีผู้ใช้ Cloud Companion API อยู่เบื้องหลังฟีเจอร์ต่างๆ ทั้งใน IDE และคอนโซลที่เราจะใช้งาน สิทธิ์ผู้ดูการใช้บริการใช้เป็นการตรวจสอบอย่างรวดเร็วก่อนเปิดใช้ UI ในคอนโซล (เพื่อให้ Duet UI ปรากฏในโปรเจ็กต์ที่เปิดใช้ API เท่านั้น)

gcloud projects add-iam-policy-binding  ${PROJECT_ID} \
--member=user:${USER} --role=roles/cloudaicompanion.user

gcloud projects add-iam-policy-binding  ${PROJECT_ID} \
--member=user:${USER} --role=roles/serviceusage.serviceUsageViewer

ผลลัพธ์ที่ได้มีดังต่อไปนี้

...
- members:
  - user:<YOUR USER ACCOUNT>
  role: roles/cloudaicompanion.user

...
- members:
  - user:<YOUR USER ACCOUNT>
  role: roles/serviceusage.serviceUsageViewer

ผ่าน Cloud Console

หากต้องการเปิดใช้ API ให้ไปที่หน้า Cloud AI Companion API ในคอนโซล Google Cloud

เลือกโปรเจ็กต์ในตัวเลือกโปรเจ็กต์

คลิกเปิดใช้

หน้าเว็บจะอัปเดตและแสดงสถานะเปิดใช้ ตอนนี้ Duet AI พร้อมใช้งานแล้วในโปรเจ็กต์ Google Cloud ที่เลือกสำหรับผู้ใช้ทุกคนที่มีบทบาท IAM ที่จำเป็น

หากต้องการมอบบทบาท IAM ที่จำเป็นต่อการใช้ Duet AI โปรดไปที่หน้า IAM

ในคอลัมน์ผู้ใช้หลัก ให้ค้นหาผู้ใช้ที่ต้องการเปิดใช้การเข้าถึง Duet AI แล้วคลิกไอคอนดินสอ ✏️ แก้ไขผู้ใช้หลักในแถวนั้น

ในแผงการเข้าถึงแก้ไข ให้คลิกเพิ่มเพิ่มบทบาทอื่น

ในส่วน "เลือกบทบาท" ให้เลือก Cloud AI Companion User

คลิกเพิ่มบทบาทอื่น แล้วเลือกผู้ดูการใช้บริการ

คลิกบันทึก

การตั้งค่า IDE

นักพัฒนาแอปสามารถเลือก IDE ได้หลากหลายรายการซึ่งเหมาะกับความต้องการของตนเองมากที่สุด ความช่วยเหลือเกี่ยวกับโค้ด Duet AI จะอยู่ใน IDE หลายรายการ เช่น โค้ด Visual Studio, JetBrains IDE (IntelliJ, PyCharm, GoLand, WebStorm และอื่นๆ), Cloud Workstations และ Cloud Shell Editor

ในห้องทดลองนี้ คุณจะใช้เวิร์กสเตชันระบบคลาวด์หรือ Cloud Shell Editor

เวิร์กช็อปนี้ใช้ Cloud Shell Editor

โปรดทราบว่า Cloud Workstations อาจใช้เวลา 20-30 นาทีในการตั้งค่า

หากต้องการใช้ทันที ให้ใช้ Cloud Shell Editor

เปิด Cloud Shell Editor โดยคลิกที่ไอคอนดินสอ ✏️ ในแถบเมนูด้านบนของ Cloud Shell

Cloud Shell Editor มี UI และ UX ที่คล้ายกับ VSCode มาก

d6a6565f83576063.png

คลิก Ctrl (ใน Windows)/CMD (ใน Mac) + , (คอมมา) เพื่อเข้าสู่แผงการตั้งค่า

พิมพ์ "ดูเอ็ท" ในแถบค้นหา

ตรวจสอบหรือเปิดใช้ Cloudcode › Duet AI: เปิดใช้ และ Cloudcode › Duet AI › คำแนะนำในบรรทัด: เปิดใช้ Auto

111b8d587330ec74.png

ในแถบสถานะด้านล่าง ให้คลิก Cloud Code - Sign In แล้วทำตามขั้นตอนการลงชื่อเข้าใช้

หากลงชื่อเข้าใช้แล้ว แถบสถานะจะแสดงเป็น Cloud Code - ไม่มีโปรเจ็กต์

คลิก Cloud Code - "ไม่มีโปรเจ็กต์" แล้วแผงเมนูแบบเลื่อนลง "การดำเนินการ" จะปรากฏขึ้นที่ด้านบน คลิกเลือกโปรเจ็กต์ Google Cloud

3241a59811e3c84a.png

เริ่มพิมพ์รหัสโปรเจ็กต์ แล้วโปรเจ็กต์ควรปรากฏในรายการ

c5358fc837588fe.png

เลือก PROJECT_ID จากรายการโปรเจ็กต์

แถบสถานะด้านล่างจะอัปเดตเพื่อแสดงรหัสโปรเจ็กต์ หากไม่ คุณอาจต้องรีเฟรชแท็บ Cloud Shell Editor

คลิกไอคอน Duet AI d97fc4e7b594c3af.png ในแถบเมนูด้านซ้าย แล้วหน้าต่างแชท Duet AI จะปรากฏขึ้น หากได้รับข้อความที่ระบุว่า "เลือกโปรเจ็กต์ GCP" คลิกและเลือกโปรเจ็กต์อีกครั้ง

คุณจะเห็นหน้าต่างแชท Duet AI แล้ว

781f888360229ca6.png

3. การตั้งค่าโครงสร้างพื้นฐาน

d3234d237f00fdbb.png

หากต้องการเรียกใช้บริการจัดส่งใหม่ใน GCP คุณต้องมีทรัพยากร GCP ต่อไปนี้

  1. อินสแตนซ์ Cloud SQL ที่มีฐานข้อมูล
  2. คลัสเตอร์ GKE เพื่อเรียกใช้บริการที่สร้างโดยใช้คอนเทนเนอร์
  3. Artifact Registry เพื่อจัดเก็บอิมเมจ Docker
  4. Cloud Source Repository สำหรับโค้ด

โคลนที่เก็บต่อไปนี้ในเทอร์มินัล Cloud Shell และเรียกใช้คำสั่งต่อไปนี้เพื่อตั้งค่าโครงสร้างพื้นฐานในโปรเจ็กต์ GCP

# Set your project
export PROJECT_ID=<INSERT_YOUR_PROJECT_ID>
gcloud config set core/project ${PROJECT_ID}

# Enable Cloudbuild and grant Cloudbuild SA owner role 
export PROJECT_NUMBER=$(gcloud projects describe ${PROJECT_ID} --format 'value(projectNumber)')
gcloud services enable cloudbuild.googleapis.com
gcloud projects add-iam-policy-binding ${PROJECT_ID} --member serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com --role roles/owner

# Clone the repo
git clone https://github.com/duetailabs/dev.git ~/duetaidev
cd ~/duetaidev

# Run Cloudbuild to create the necessary resources
gcloud builds submit --substitutions=_PROJECT_ID=${PROJECT_ID}

# To destroy all GCP resources, run the following
# gcloud builds submit --substitutions=_PROJECT_ID=${PROJECT_ID} --config=cloudbuild_destroy.yaml

4. การพัฒนาบริการ Python Flask

9745ba5c70782e76.png

บริการที่เราจะสร้างจะประกอบด้วยไฟล์ต่อไปนี้ในท้ายที่สุด คุณไม่จำเป็นต้องสร้างไฟล์เหล่านี้ในขณะนี้ และสร้างไฟล์เหล่านี้ขึ้นมาทีละรายการตามคำแนะนำด้านล่าง:

  1. package-service.yaml - ข้อกำหนดของ Open API สำหรับบริการแพ็กเกจที่มีข้อมูล เช่น ความสูง ความกว้าง น้ำหนัก และวิธีการจัดการพิเศษ
  2. data_model.py - โมเดลข้อมูลสำหรับข้อกำหนดของ API บริการแพ็กเกจ และสร้างตาราง packages ในฐานข้อมูล product_details ด้วย
  3. connect_connector.py - การเชื่อมต่อ CloudSQL (กำหนดเครื่องมือ, เซสชัน และ Base ORM)
  4. db_init.py - สร้างข้อมูลตัวอย่างลงในตาราง packages
  5. main.py - บริการ Python Flask ที่มีปลายทาง GET เพื่อเรียกข้อมูลรายละเอียดแพ็กเกจจากข้อมูล packages ตาม product_id
  6. test.py - การทดสอบหน่วย
  7. requirement.txt - ข้อกำหนดของ Python
  8. Dockerfile - เพื่อสร้างคอนเทนเนอร์ของแอปพลิเคชันนี้

ถ้าคุณพบปัญหาติดหนึบระหว่างแบบฝึกหัด ไฟล์สุดท้ายทั้งหมดจะอยู่ในภาคผนวกของ Codelab นี้เพื่อเป็นข้อมูลอ้างอิง

ในขั้นตอนก่อนหน้า คุณได้สร้าง Cloud Source Repository โคลนที่เก็บ คุณจะสร้างไฟล์แอปพลิเคชันในโฟลเดอร์ที่เก็บที่โคลน

เรียกใช้คำสั่งต่อไปนี้เพื่อโคลนที่เก็บในเทอร์มินัล Cloud Shell

cd ~
gcloud source repos clone shipping shipping
cd ~/shipping 

เปิดแถบด้านข้างแชท Duet AI จากเมนูทางด้านซ้ายใน Cloud Shell Editor ไอคอนมีลักษณะคล้ายกับ 8b135a000b259175.png ตอนนี้คุณสามารถใช้ Duet AI เพื่อรับความช่วยเหลือด้านโค้ดได้แล้ว

package-service.yaml

เมื่อไม่ต้องเปิดไฟล์ใดๆ โปรดขอให้ Duet สร้างข้อกำหนดของ Open API สำหรับบริการจัดส่ง

พรอมต์ที่ 1: สร้างข้อกำหนด YAML ของ OpenAPI สำหรับบริการที่ให้ข้อมูลการจัดส่งและแพ็กเกจที่กำหนดรหัสผลิตภัณฑ์ที่เป็นตัวเลข บริการควรมีข้อมูลเกี่ยวกับความสูงของพัสดุ ความกว้าง ความลึก น้ำหนัก และคำแนะนำในการจัดการพิเศษ

ba12626f491a1204.png

จะมี 3 ตัวเลือกแสดงอยู่ที่ด้านขวาบนของหน้าต่างโค้ดที่สร้างขึ้น

คุณสามารถCOPY 71194556d8061dae.pngโค้ดแล้ววางลงในไฟล์

คุณADD df645de8c65607a.pngโค้ดไปยังไฟล์ที่เปิดอยู่ใน Editor ได้

หรือจะOPEN a4c7ed6d845df343.pngโค้ดในไฟล์ใหม่ก็ได้

คลิกรหัส OPEN a4c7ed6d845df343.png ในไฟล์ใหม่

คลิก CTRL/CMD + s เพื่อบันทึกไฟล์ แล้วเก็บไฟล์ไว้ในโฟลเดอร์แอปพลิเคชันด้วยชื่อไฟล์ว่า package-service.yaml คลิก ตกลง

f6ebd5b836949366.png

ไฟล์สุดท้ายอยู่ในส่วน APPENDIX ของ Codelab นี้ หากยังแก้ไขไม่ได้ ให้ทำการเปลี่ยนแปลงที่เหมาะสมด้วยตนเอง

นอกจากนี้ คุณยังลองใช้พรอมต์ต่างๆ เพื่อดูคำตอบของ Duet AI ได้ด้วย

รีเซ็ตประวัติการแชท Duet AI โดยคลิกไอคอนถังขยะ f574ca2c1e114856.png ที่ด้านบนของแถบด้านข้าง Duet AI

data_model.py

ถัดไป คุณจะต้องสร้างไฟล์ Python โมเดลข้อมูลสำหรับบริการตามข้อกำหนดของ OpenAPI

เมื่อไฟล์ package-service.yaml เปิดอยู่ ให้ป้อนข้อความแจ้งต่อไปนี้

พรอมต์ที่ 1: ใช้ ORM ของ Python Sqlalchemy เพื่อสร้างโมเดลข้อมูลสำหรับบริการ API นี้ รวมถึงมีฟังก์ชันแยกต่างหากและจุดแรกเข้าหลักสำหรับสร้างตารางฐานข้อมูล

b873a6a28bd28ca1.png

เราลองมาดูแต่ละส่วนที่สร้างขึ้นกัน Duet AI ยังคงเป็นผู้ช่วยอยู่ และแม้ว่าจะช่วยให้เขียนโค้ดได้อย่างรวดเร็ว แต่คุณก็ควรหมั่นตรวจสอบเนื้อหาที่ AI สร้างขึ้นและทำความเข้าใจไปเรื่อยๆ

ประเภทแรกคือคลาสที่มีชื่อว่า Package ของ kind Base ซึ่งกำหนดโมเดลข้อมูลสำหรับฐานข้อมูล packages ดังต่อไปนี้

class Package(Base):
    __tablename__ = 'packages'

    id = Column(Integer, primary_key=True)
    product_id = Column(String(255))
    height = Column(Float)
    width = Column(Float)
    depth = Column(Float)
    weight = Column(Float)
    special_handling_instructions = Column(String(255))

ถัดไป คุณต้องใช้ฟังก์ชันที่สร้างตารางในฐานข้อมูลดังตัวอย่างต่อไปนี้

def create_tables(engine):
    Base.metadata.create_all(engine)

สุดท้าย คุณต้องใช้ฟังก์ชันหลักที่เรียกใช้ฟังก์ชัน create_tables เพื่อสร้างตารางในฐานข้อมูล CloudSQL จริงๆ ดังเช่นตัวอย่างต่อไปนี้

if __name__ == '__main__':
    from sqlalchemy import create_engine

    engine = create_engine('sqlite:///shipping.db')
    create_tables(engine)

    print('Tables created successfully.')

โปรดทราบว่าฟังก์ชัน main จะสร้างเครื่องมือโดยใช้ฐานข้อมูล sqlite ในเครื่อง หากต้องการใช้ CloudSQL คุณจะต้องทำการเปลี่ยนแปลง เดี๋ยวค่อยทำทีหลังนะ

ใช้โค้ด OPEN a4c7ed6d845df343.png ในเวิร์กโฟลว์ของไฟล์ใหม่เหมือนก่อนหน้านี้ บันทึกโค้ดในไฟล์ชื่อ data_model.py (โปรดใส่เครื่องหมายขีดล่างในชื่อ ไม่ใช่เครื่องหมายขีดกลาง)

รีเซ็ตประวัติการแชท Duet AI โดยคลิกไอคอนถังขยะ f574ca2c1e114856.png ที่ด้านบนของแถบด้านข้าง Duet AI

connect-connector.py

สร้างเครื่องมือเชื่อมต่อ CloudSQL

เมื่อไฟล์ data_model.py เปิดอยู่ ให้ป้อนข้อความแจ้งต่อไปนี้

พรอมต์ที่ 1: สร้างฟังก์ชันที่เริ่มต้นพูลการเชื่อมต่อสำหรับอินสแตนซ์ Cloud SQL ของ Postgres โดยใช้ไลบรารีเครื่องมือเชื่อมต่อ cloud-sql-python

ed05cb6ff85d34c5.png

โปรดทราบว่าการตอบกลับไม่ได้ใช้ไลบรารี cloud-sql-python-connector คุณสามารถปรับแต่งพรอมต์เพื่อเพิ่มการกระตุ้นเตือนให้กับ Duet ได้โดยเพิ่มรายละเอียดต่างๆ ในชุดข้อความแชทเดียวกัน

ลองใช้พรอมต์อื่น

พรอมต์ที่ 2: ต้องใช้ไลบรารีเครื่องมือเชื่อมต่อ cloud-sql-python

d09095b44dde35bf.png

โปรดตรวจสอบว่ามีการใช้ไลบรารี cloud-sql-python-connector

ใช้โค้ด OPEN a4c7ed6d845df343.png ในเวิร์กโฟลว์ของไฟล์ใหม่เหมือนก่อนหน้านี้ บันทึกโค้ดในไฟล์ชื่อ connect_conector.py คุณอาจต้องนำเข้าไลบรารี pg8000 ด้วยตนเอง โปรดดูไฟล์ด้านล่าง

ล้างประวัติแชท Duet AI และเมื่อไฟล์ connect_connector.py เปิดอยู่ ให้สร้าง DB engine, sessionmaker และ base ORM ที่จะใช้ในแอปพลิเคชัน

พรอมต์ที่ 1: สร้างเครื่องมือ, คลาส sessionmaker และ ORM ฐานโดยใช้เมธอด Connect_with_connector

6E4214b72ab13a63.png

คำตอบอาจเพิ่ม engine, Session และ Base ต่อท้ายไฟล์ connect_connector.py

ไฟล์สุดท้ายอยู่ในส่วน APPENDIX ของ Codelab นี้ หากยังแก้ไขไม่ได้ ให้ทำการเปลี่ยนแปลงที่เหมาะสมด้วยตนเอง

นอกจากนี้ คุณยังลองใช้พรอมต์ต่างๆ เพื่อดูคำตอบของ Duet AI ในรูปแบบที่หลากหลายได้ด้วย

รีเซ็ตประวัติการแชท Duet AI โดยคลิกไอคอนถังขยะ f574ca2c1e114856.png ที่ด้านบนของแถบด้านข้าง Duet AI

กำลังอัปเดต data_model.py

คุณต้องใช้เครื่องมือที่สร้างในขั้นตอนก่อนหน้า (ในไฟล์ connect_connector.py) เพื่อสร้างตารางในฐานข้อมูล CloudSQL

ล้างประวัติแชท Duet AI เปิดไฟล์ data_model.py ลองใช้คำสั่งต่อไปนี้

พรอมต์ที่ 1: ในฟังก์ชันหลัก ให้นำเข้าและใช้เครื่องมือจาก Connect_connector.py

2e768c9b6c523b9a.png

คุณควรเห็นการตอบกลับการนำเข้า engine จาก connect_connector (สำหรับ CloudSQL) create_table จะใช้เครื่องมือนั้น (แทน DB ในเครื่องเริ่มต้น sqlite)

อัปเดตไฟล์ data_model.py รายการ

ไฟล์สุดท้ายอยู่ในส่วน APPENDIX ของ Codelab นี้ หากยังแก้ไขไม่ได้ ให้ทำการเปลี่ยนแปลงที่เหมาะสมด้วยตนเอง

นอกจากนี้ คุณยังลองใช้พรอมต์ต่างๆ เพื่อดูคำตอบของ Duet AI ได้ด้วย

รีเซ็ตประวัติการแชท Duet AI โดยคลิกไอคอนถังขยะ f574ca2c1e114856.png ที่ด้านบนของแถบด้านข้าง Duet AI

requirements.txt

สร้างไฟล์ requirements.txt สำหรับแอปพลิเคชัน

เปิดทั้งไฟล์ connect_connector.py และ data_model.py แล้วป้อนข้อความแจ้งต่อไปนี้

พรอมต์ที่ 1: สร้างไฟล์ข้อกำหนด PIP สำหรับโมเดลข้อมูลและบริการนี้

พรอมต์ที่ 2: สร้างไฟล์ข้อกำหนด PIP สำหรับโมเดลข้อมูลและบริการนี้โดยใช้เวอร์ชันล่าสุด

69fae373bc5c6a18.png

ยืนยันว่าชื่อและเวอร์ชันถูกต้อง ตัวอย่างเช่น คำตอบข้างต้นทั้งชื่อและเวอร์ชันของ google-cloud-sql-connecter ไม่ถูกต้อง แก้ไขเวอร์ชันด้วยตนเองและสร้างไฟล์ requirements.txt ที่มีลักษณะดังนี้

cloud-sql-python-connector==1.2.4
sqlalchemy==1.4.36
pg8000==1.22.0

ในเทอร์มินัลคำสั่ง ให้เรียกใช้ข้อมูลต่อไปนี้

pip3 install -r requirements.txt

รีเซ็ตประวัติการแชท Duet AI โดยคลิกไอคอนถังขยะ f574ca2c1e114856.png ที่ด้านบนของแถบด้านข้าง Duet AI

กำลังสร้างตารางแพ็กเกจใน CloudSQL

ตั้งค่าตัวแปรสภาพแวดล้อมสำหรับเครื่องมือเชื่อมต่อฐานข้อมูล CloudSQL

export INSTANCE_NAME=$(gcloud sql instances list --format='value(name)')
export INSTANCE_CONNECTION_NAME=$(gcloud sql instances describe ${INSTANCE_NAME} --format="value(connectionName)")
export DB_USER=evolution
export DB_PASS=evolution
export DB_NAME=product_details

เรียกใช้ data_model.py

python data_model.py

ผลลัพธ์จะมีลักษณะคล้ายกับตัวอย่างต่อไปนี้ (ตรวจสอบโค้ดเพื่อดูผลลัพธ์จริง):

Tables created successfully.

เชื่อมต่อกับอินสแตนซ์ CloudSQL และตรวจสอบว่าระบบสร้างฐานข้อมูลแล้วหรือไม่

gcloud sql connect ${INSTANCE_NAME} --user=evolution --database=product_details

หลังจากป้อนรหัสผ่าน (หรือ evolution ด้วย) ให้โหลดตาราง

product_details=> \dt

ผลลัพธ์ที่ได้จะมีลักษณะคล้ายกับด้านล่างนี้

           List of relations
 Schema |   Name   | Type  |   Owner   
--------+----------+-------+-----------
 public | packages | table | evolution
(1 row)

คุณยังตรวจสอบโมเดลข้อมูลและรายละเอียดตารางได้ด้วย

product_details=> \d+ packages

ผลลัพธ์ที่ได้จะมีลักษณะคล้ายกับด้านล่างนี้

                                                                        Table "public.packages"
            Column             |       Type        | Collation | Nullable |               Default                | Storage  | Compression | Stats target | Description 
-------------------------------+-------------------+-----------+----------+--------------------------------------+----------+-------------+--------------+-------------
 id                            | integer           |           | not null | nextval('packages_id_seq'::regclass) | plain    |             |              | 
 product_id                    | integer           |           | not null |                                      | plain    |             |              | 
 height                        | double precision  |           | not null |                                      | plain    |             |              | 
 width                         | double precision  |           | not null |                                      | plain    |             |              | 
 depth                         | double precision  |           | not null |                                      | plain    |             |              | 
 weight                        | double precision  |           | not null |                                      | plain    |             |              | 
 special_handling_instructions | character varying |           |          |                                      | extended |             |              | 
Indexes:
    "packages_pkey" PRIMARY KEY, btree (id)
Access method: heap

พิมพ์ \q เพื่อออกจาก CloudSQL

db_init.py

ต่อไป มาเพิ่มข้อมูลตัวอย่างลงในตาราง packages กัน

ล้างประวัติแชท Duet AI เมื่อไฟล์ data_model.py เปิดอยู่ ให้ลองทำตามข้อความแจ้งต่อไปนี้

พรอมต์ที่ 1: สร้างฟังก์ชันที่สร้างแถวแพ็กเกจตัวอย่าง 10 แถวแล้วส่งไปยังตารางแพ็กเกจ

พรอมต์ที่ 2: สร้างฟังก์ชันที่สร้างแถวแพ็กเกจตัวอย่าง 10 แถวและส่งไปยังตารางแพ็กเกจ

34a9afc5f04ba5.png

ใช้โค้ด OPEN a4c7ed6d845df343.png ในเวิร์กโฟลว์ของไฟล์ใหม่เหมือนก่อนหน้านี้ บันทึกโค้ดในไฟล์ชื่อ db_init.py

ไฟล์สุดท้ายอยู่ในส่วน APPENDIX ของ Codelab นี้ หากยังแก้ไขไม่ได้ ให้ทำการเปลี่ยนแปลงที่เหมาะสมด้วยตนเอง

นอกจากนี้ คุณยังลองใช้พรอมต์ต่างๆ เพื่อดูคำตอบของ Duet AI ได้ด้วย

รีเซ็ตประวัติการแชท Duet AI โดยคลิกไอคอนถังขยะ f574ca2c1e114856.png ที่ด้านบนของแถบด้านข้าง Duet AI

การสร้างข้อมูลแพ็กเกจตัวอย่าง

เรียกใช้ db_init.py จากบรรทัดคำสั่ง

python db_init.py

ผลลัพธ์ที่ได้จะมีลักษณะคล้ายกับด้านล่างนี้

Packages created successfully.

เชื่อมต่อกับอินสแตนซ์ CloudSQL อีกครั้งและตรวจสอบว่าได้เพิ่มข้อมูลตัวอย่างลงในตารางแพ็กเกจแล้ว

เชื่อมต่อกับอินสแตนซ์ CloudSQL และตรวจสอบว่าระบบสร้างฐานข้อมูลแล้วหรือไม่

gcloud sql connect ${INSTANCE_NAME} --user=evolution --database=product_details

หลังจากป้อนรหัสผ่าน (หรือ evolution ด้วย) ให้รับข้อมูลทั้งหมดจากตารางแพ็กเกจ

product_details=> SELECT * FROM packages;

ผลลัพธ์ที่ได้จะมีลักษณะคล้ายกับด้านล่างนี้

 id | product_id | height | width | depth | weight |   special_handling_instructions   
----+------------+--------+-------+-------+--------+-----------------------------------
  1 |          0 |     10 |    10 |    10 |     10 | No special handling instructions.
  2 |          1 |     10 |    10 |    10 |     10 | No special handling instructions.
  3 |          2 |     10 |    10 |    10 |     10 | No special handling instructions.
  4 |          3 |     10 |    10 |    10 |     10 | No special handling instructions.
  5 |          4 |     10 |    10 |    10 |     10 | No special handling instructions.
  6 |          5 |     10 |    10 |    10 |     10 | No special handling instructions.
  7 |          6 |     10 |    10 |    10 |     10 | No special handling instructions.
  8 |          7 |     10 |    10 |    10 |     10 | No special handling instructions.
  9 |          8 |     10 |    10 |    10 |     10 | No special handling instructions.
 10 |          9 |     10 |    10 |    10 |     10 | No special handling instructions.
(10 rows)

พิมพ์ \q เพื่อออกจาก CloudSQL

main.py

เมื่อเปิดไฟล์ data_model.py, package-service.yaml และ connect_connector.py แล้ว ให้สร้าง main.py สำหรับแอปพลิเคชัน

พรอมต์ที่ 1: ใช้ไลบรารีขวดแก้วทดลอง Python - สร้างการติดตั้งใช้งานที่ใช้ปลายทางส่วนที่เหลือ HTTP สำหรับบริการนี้

พรอมต์ที่ 2: ใช้ไลบรารีขวดแก้วทดลอง Python - สร้างการติดตั้งใช้งานที่ใช้ปลายทางส่วนที่เหลือ HTTP สำหรับบริการนี้ นำเข้าและใช้ SessionMaker จาก meet_conector.py ไปยังข้อมูลแพ็กเกจ

พรอมต์ที่ 3: ใช้ไลบรารีขวดแก้วทดลอง Python - สร้างการติดตั้งใช้งานที่ใช้ปลายทางส่วนที่เหลือ HTTP สำหรับบริการนี้ นำเข้าและใช้แพ็กเกจจาก data_model.py และ SessionMaker จาก Connect_conector.py ไปยังข้อมูลแพ็กเกจ

พรอมต์ที่ 4: ใช้ไลบรารีขวดแก้วทดลอง Python - สร้างการติดตั้งใช้งานที่ใช้ปลายทางส่วนที่เหลือ HTTP สำหรับบริการนี้ นำเข้าและใช้ Package จาก data_model.py และ SessionMaker จาก Connect_conector.py ไปยัง สำหรับข้อมูลแพ็กเกจ ใช้ IP โฮสต์ 0.0.0.0 สำหรับ app.run

6d794fc52a90e6ae.png

โปรดอัปเดตข้อกำหนดสำหรับmain.py

พรอมต์: สร้างไฟล์ข้อกำหนดสำหรับ main.py

1cc0b318d2d4ca2f.png

เพิ่มรายการนี้ต่อท้าย requirements.txt ไฟล์ ตรวจสอบว่าคุณใช้ Flask เวอร์ชัน 3.0.0

ใช้โค้ด OPEN a4c7ed6d845df343.png ในเวิร์กโฟลว์ของไฟล์ใหม่เหมือนก่อนหน้านี้ บันทึกโค้ดในไฟล์ชื่อ main.py

ไฟล์สุดท้ายอยู่ในส่วน APPENDIX ของ Codelab นี้ หากยังแก้ไขไม่ได้ ให้ทำการเปลี่ยนแปลงที่เหมาะสมด้วยตนเอง

รีเซ็ตประวัติการแชท Duet AI โดยคลิกไอคอนถังขยะ f574ca2c1e114856.png ที่ด้านบนของแถบด้านข้าง Duet AI

5. การทดสอบและเรียกใช้แอปพลิเคชัน

ติดตั้งข้อกำหนด

pip3 install -r requirements.txt

เรียกใช้ main.py

python main.py

ผลลัพธ์ที่ได้จะมีลักษณะคล้ายกับด้านล่างนี้

 * Serving Flask app 'main'
 * Debug mode: off
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:5000
 * Running on http://10.88.0.3:5000
Press CTRL+C to quit

จากเทอร์มินัลที่ 2 ให้ทดสอบปลายทาง /packages/<product_id>

curl localhost:5000/packages/1

ผลลัพธ์ที่ได้จะมีลักษณะคล้ายกับด้านล่างนี้

{"depth":10.0,"height":10.0,"special_handling_instructions":"No special handling instructions.","weight":10.0,"width":10.0}

นอกจากนี้ คุณยังทดสอบรหัสผลิตภัณฑ์อื่นๆ ในข้อมูลตัวอย่างได้ด้วย

ป้อน CTRL_C เพื่อออกจากคอนเทนเนอร์ Docker ที่ทำงานอยู่ในเทอร์มินัล

กำลังสร้างการทดสอบหน่วย

เมื่อเปิดไฟล์ main.py แล้ว ให้สร้างการทดสอบ 1 หน่วย

พรอมต์ 1: สร้างการทดสอบ 1 หน่วย

e861e5b63e1b2657.png

ใช้โค้ด OPEN a4c7ed6d845df343.png ในเวิร์กโฟลว์ของไฟล์ใหม่เหมือนก่อนหน้านี้ บันทึกโค้ดในไฟล์ชื่อ test.py

ต้องกำหนด product_id ในฟังก์ชัน test_get_package คุณสามารถเพิ่มด้วยตัวเอง

ไฟล์สุดท้ายอยู่ในส่วน APPENDIX ของ Codelab นี้ หากยังแก้ไขไม่ได้ ให้ทำการเปลี่ยนแปลงที่เหมาะสมด้วยตนเอง

รีเซ็ตประวัติการแชท Duet AI โดยคลิกไอคอนถังขยะ f574ca2c1e114856.png ที่ด้านบนของแถบด้านข้าง Duet AI

กำลังทดสอบ 1 หน่วย

เรียกใช้การทดสอบหน่วย

python test.py

ผลลัพธ์ที่ได้จะมีลักษณะคล้ายกับด้านล่างนี้

.
----------------------------------------------------------------------
Ran 1 test in 1.061s

OK

ปิดไฟล์ทั้งหมดใน Cloud Shell Editor และล้างประวัติแชทโดยคลิกไอคอนถังขยะ 1ecccfe10d6c540.png ในแถบสถานะด้านบน

Dockerfile

สร้าง Dockerfile สำหรับแอปพลิเคชันนี้

เปิด main.py แล้วลองทำตามข้อความแจ้งต่อไปนี้

พรอมต์ที่ 1: สร้าง Dockerfile สำหรับแอปพลิเคชันนี้

ข้อความแจ้งที่ 2: สร้าง Dockerfile สำหรับแอปพลิเคชันนี้ คัดลอกไฟล์ทั้งหมดไปยังคอนเทนเนอร์

9c473caea437a5c3.png

คุณต้องตั้งค่า ENVARS สำหรับ INSTANCE_CONNECTION_NAME, DB_USER, DB_PASS และ DB_NAME ด้วย คุณสามารถดำเนินการได้ด้วยตนเอง Dockerfile ควรมีลักษณะดังนี้

FROM python:3.10-slim

WORKDIR /app

COPY . ./

RUN pip install -r requirements.txt

# Add these manually for your project
ENV INSTANCE_CONNECTION_NAME=YOUR_INSTANCE_CONNECTION_NAME
ENV DB_USER=evolution
ENV DB_PASS=evolution
ENV DB_NAME=product_details

CMD ["python", "main.py"]

ใช้โค้ด OPEN a4c7ed6d845df343.png ในเวิร์กโฟลว์ของไฟล์ใหม่เหมือนก่อนหน้านี้ บันทึกโค้ดในไฟล์ชื่อ Dockerfile

ไฟล์สุดท้ายอยู่ในส่วน APPENDIX ของ Codelab นี้ หากยังแก้ไขไม่ได้ ให้ทำการเปลี่ยนแปลงที่เหมาะสมด้วยตนเอง

การเรียกใช้แอปพลิเคชันในเครื่อง

เมื่อ Dockerfile เปิดอยู่ ให้ลองทำตามข้อความแจ้งต่อไปนี้

พรอมต์ที่ 1: ฉันจะเรียกใช้คอนเทนเนอร์ในเครื่องโดยใช้ Dockerfile นี้ได้อย่างไร

570fd5c296ca8c83.png

ทำตามวิธีการ

# Build
docker build -t shipping .
# And run
docker run -p 5000:5000 -it shipping

ผลลัพธ์ที่ได้จะมีลักษณะคล้ายกับด้านล่างนี้

 * Serving Flask app 'main'
 * Debug mode: off
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:5000
 * Running on http://172.17.0.2:5000
Press CTRL+C to quit

เข้าถึงคอนเทนเนอร์จากหน้าต่างเทอร์มินัลที่ 2

curl localhost:5000/packages/1

ผลลัพธ์ที่ได้จะมีลักษณะคล้ายกับด้านล่างนี้

{"depth":10.0,"height":10.0,"special_handling_instructions":"No special handling instructions.","weight":10.0,"width":10.0}

แอปพลิเคชันที่สร้างโดยใช้คอนเทนเนอร์ทำงานอยู่

ป้อน CTRL_C เพื่อออกจากคอนเทนเนอร์ Docker ที่ทำงานอยู่ในเทอร์มินัล

การสร้างอิมเมจคอนเทนเนอร์ใน Artifact Registry

สร้างอิมเมจคอนเทนเนอร์และพุชไปยัง Artifact Registry

cd ~/shipping
gcloud auth configure-docker us-central1-docker.pkg.dev
docker build -t us-central1-docker.pkg.dev/${PROJECT_ID}/shipping/shipping .
docker push us-central1-docker.pkg.dev/${PROJECT_ID}/shipping/shipping

ขณะนี้คอนเทนเนอร์ของแอปพลิเคชันอยู่ที่ us-central1-docker.pkg.dev/${PROJECT_ID}/shipping/shipping ซึ่งทำให้ใช้งานได้กับ GKE

6. กำลังทำให้แอปพลิเคชันใช้งานได้กับคลัสเตอร์ GKE

ระบบได้สร้างคลัสเตอร์ GKE Autopilot แล้วเมื่อคุณสร้างทรัพยากร GCP สำหรับเวิร์กช็อปนี้ เชื่อมต่อกับคลัสเตอร์ GKE

gcloud container clusters get-credentials gke1 \
    --region=us-central1

ใส่คำอธิบายประกอบบัญชีบริการเริ่มต้นของ Kubernetes ด้วยบัญชีบริการของ Google

kubectl annotate serviceaccount default iam.gke.io/gcp-service-account=cloudsqlsa@${PROJECT_ID}.iam.gserviceaccount.com

ผลลัพธ์ที่ได้จะมีลักษณะคล้ายกับด้านล่างนี้

serviceaccount/default annotated

เตรียมและใช้ไฟล์ k8s.yaml

cp ~/duetaidev/k8s.yaml_tmpl ~/shipping/.
export INSTANCE_NAME=$(gcloud sql instances list --format='value(name)')
export INSTANCE_CONNECTION_NAME=$(gcloud sql instances describe ${INSTANCE_NAME} --format="value(connectionName)")
export IMAGE_REPO=us-central1-docker.pkg.dev/${PROJECT_ID}/shipping/shipping
envsubst < ~/shipping/k8s.yaml_tmpl > k8s.yaml
kubectl apply -f k8s.yaml

ผลลัพธ์ที่ได้จะมีลักษณะคล้ายกับด้านล่างนี้

deployment.apps/shipping created
service/shipping created

รอจนกว่าพ็อดจะทำงานและบริการมีการกำหนดที่อยู่ IP ของตัวจัดสรรภาระงานภายนอก

kubectl get pods
kubectl get service shipping

ผลลัพธ์ที่ได้จะมีลักษณะคล้ายกับด้านล่างนี้

# kubectl get pods
NAME                      READY   STATUS    RESTARTS   AGE
shipping-f5d6f8d5-56cvk   1/1     Running   0          4m47s
shipping-f5d6f8d5-cj4vv   1/1     Running   0          4m48s
shipping-f5d6f8d5-rrdj2   1/1     Running   0          4m47s

# kubectl get service shipping
NAME       TYPE           CLUSTER-IP       EXTERNAL-IP    PORT(S)        AGE
shipping   LoadBalancer   34.118.225.125   34.16.39.182   80:30076/TCP   5m41s

สำหรับคลัสเตอร์ Autopilot ของ GKE โปรดรอสักครู่จนกว่าทรัพยากรจะพร้อม

เข้าถึงบริการผ่านที่อยู่ EXTERNAL-IP

export EXTERNAL_IP=$(kubectl get svc shipping --output jsonpath='{.status.loadBalancer.ingress[0].ip}')
curl http://${EXTERNAL_IP}/packages/1

ผลลัพธ์ที่ได้จะมีลักษณะคล้ายกับด้านล่างนี้

{"depth":10.0,"height":10.0,"special_handling_instructions":"No special handling instructions.","weight":10.0,"width":10.0}

7. เครดิตพิเศษ: การแก้ปัญหาเกี่ยวกับการสมัคร

นำบทบาท IAM ของไคลเอ็นต์ CloudSQL ออกจากบัญชีบริการ cloudsqlsa ซึ่งจะทำให้เกิดข้อผิดพลาดในการเชื่อมต่อกับฐานข้อมูล CloudSQL

gcloud projects remove-iam-policy-binding ${PROJECT_ID} \
    --member="serviceAccount:cloudsqlsa@${PROJECT_ID}.iam.gserviceaccount.com" \
    --role="roles/cloudsql.client"

รีสตาร์ทพ็อดการจัดส่ง

kubectl rollout restart deployment shipping

หลังจากพ็อดรีสตาร์ท ให้ลองเข้าถึงบริการ shipping อีกครั้ง

export EXTERNAL_IP=$(kubectl get svc shipping --output jsonpath='{.status.loadBalancer.ingress[0].ip}')
curl http://${EXTERNAL_IP}/packages/1 

ผลลัพธ์ที่ได้จะมีลักษณะคล้ายกับด้านล่างนี้

...
<title>500 Internal Server Error</title>
<h1>Internal Server Error</h1>
<p>The server encountered an internal error and was unable to complete your request. Either the server is overloaded or there is an error in the application.</p>

ตรวจสอบบันทึกโดยไปที่ Kubernetes Engine > ภาระงาน

d225b1916c829167.png

คลิกการติดตั้งใช้งาน shipping แล้วคลิกแท็บบันทึก

1d0459141483d6a7.png

คลิกไอคอนดูในเครื่องมือสำรวจบันทึก df8b9d19a9fe4c73.png ทางด้านขวาของแถบสถานะ ระบบจะเปิดหน้าต่าง Log Explorer ใหม่

e86d1c265e176bc4.png

คลิกรายการข้อผิดพลาด Traceback รายการใดรายการหนึ่ง จากนั้นคลิกอธิบายรายการบันทึกนี้

d6af045cf03008bc.png

คุณสามารถอ่านคำอธิบายข้อผิดพลาด

ถัดไป เราจะใช้ Duet AI เพื่อช่วยแก้ไขข้อผิดพลาด

ลองใช้คำสั่งต่อไปนี้

พรอมต์ที่ 1: ช่วยฉันแก้ปัญหาข้อผิดพลาดนี้

9288dd6045369167.png

ป้อนข้อความแสดงข้อผิดพลาดในข้อความแจ้ง

พรอมต์ 2: ไม่ได้รับอนุญาต: ดูเหมือนว่าผู้ใช้หลักของ IAM ที่ตรวจสอบสิทธิ์แล้วจะไม่ได้รับอนุญาตให้ส่งคำขอ API ยืนยัน "Cloud SQL Admin API" เปิดใช้อยู่ในโปรเจ็กต์ GCP และ "ไคลเอ็นต์ Cloud SQL" มอบบทบาทหลัก IAM ให้กับคุณแล้ว

f1e64fbdc435d31c.png

แล้วไง

พรอมต์ที่ 3: ฉันจะกำหนดบทบาทไคลเอ็นต์ Cloud SQL ให้กับบัญชีบริการของ Google โดยใช้ gcloud ได้อย่างไร

bb8926b995a8875c.png

กำหนดบทบาทไคลเอ็นต์ Cloud SQL ให้กับ cloudsqlsa

gcloud projects add-iam-policy-binding ${PROJECT_ID} \
    --member="serviceAccount:cloudsqlsa@${PROJECT_ID}.iam.gserviceaccount.com" \
    --role="roles/cloudsql.client"

โปรดรอสักครู่แล้วลองเข้าถึงแอปพลิเคชันอีกครั้ง

export EXTERNAL_IP=$(kubectl get svc shipping --output jsonpath='{.status.loadBalancer.ingress[0].ip}')
curl http://${EXTERNAL_IP}/packages/1

ผลลัพธ์ที่ได้จะมีลักษณะคล้ายกับด้านล่างนี้

{"depth":10.0,"height":10.0,"special_handling_instructions":"No special handling instructions.","weight":10.0,"width":10.0}

คุณได้ใช้ Duet AI ใน Cloud Logging, Log Explorer และฟีเจอร์คำอธิบายบันทึกเพื่อแก้ปัญหาสำเร็จแล้ว

8. บทสรุป

ยินดีด้วย คุณทำ Codelab นี้เสร็จสมบูรณ์แล้ว

คุณได้เรียนรู้สิ่งต่อไปนี้ใน Codelab นี้แล้ว

  1. เปิดใช้งาน Duet AI ในโปรเจ็กต์ GCP แล้วกำหนดค่าเพื่อใช้ใน IDE และ Cloud Console
  2. ใช้ Duet AI ในการสร้าง ดำเนินการโค้ด และเขียนคำอธิบาย
  3. ใช้ Duet AI เพื่ออธิบายและแก้ปัญหาเกี่ยวกับแอปพลิเคชัน
  4. ฟีเจอร์ Duet AI เช่น แชท IDE และการแชทแบบมัลติเทิร์น การแชทเทียบกับการสร้างโค้ดในหน้า การดำเนินการอัจฉริยะ เช่น คำอธิบายโค้ด การรับทราบการบรรยาย และอีกมากมาย

9. ภาคผนวก

package-service.yaml

swagger: "2.0"
info:
 title: Shipping and Package Information API
 description: This API provides information about shipping and packages.
 version: 1.0.0
host: shipping.googleapis.com
schemes:
 - https
produces:
 - application/json
paths:
 /packages/{product_id}:
   get:
     summary: Get information about a package
     description: This method returns information about a package, including its height, width, depth, weight, and any special handling instructions.
     parameters:
       - name: product_id
         in: path
         required: true
         type: integer
         format: int64
     responses:
       "200":
         description: A successful response
         schema:
           type: object
           properties:
             height:
               type: integer
               format: int64
             width:
               type: integer
               format: int64
             depth:
               type: integer
               format: int64
             weight:
               type: integer
               format: int64
             special_handling_instructions:
               type: string
       "404":
         description: The product_id was not found

data_model.py

from sqlalchemy import Column, Integer, String, Float
from sqlalchemy.ext.declarative import declarative_base

from connect_connector import engine

Base = declarative_base()

class Package(Base):
    __tablename__ = 'packages'

    id = Column(Integer, primary_key=True)
    product_id = Column(Integer, nullable=False)
    height = Column(Float, nullable=False)
    width = Column(Float, nullable=False)
    depth = Column(Float, nullable=False)
    weight = Column(Float, nullable=False)
    special_handling_instructions = Column(String, nullable=True)

def create_tables():
    Base.metadata.create_all(engine)

if __name__ == '__main__':
    create_tables()

    print('Tables created successfully.')

connect_connector.py

import os

from google.cloud.sql.connector import Connector, IPTypes
import sqlalchemy

# You may need to manually import pg8000 and Base as follows
import pg8000
from sqlalchemy.ext.declarative import declarative_base


def connect_with_connector() -> sqlalchemy.engine.base.Engine:
   """Initializes a connection pool for a Cloud SQL instance of Postgres."""
   # Note: Saving credentials in environment variables is convenient, but not
   # secure - consider a more secure solution such as
   # Cloud Secret Manager (https://cloud.google.com/secret-manager) to help
   # keep secrets safe.
   instance_connection_name = os.environ[
       "INSTANCE_CONNECTION_NAME"
   ]  # e.g. 'project:region:instance'
   db_user = os.environ["DB_USER"]  # e.g. 'my-database-user'
   db_pass = os.environ["DB_PASS"]  # e.g. 'my-database-password'
   db_name = os.environ["DB_NAME"]  # e.g. 'my-database'

   ip_type = IPTypes.PRIVATE if os.environ.get("PRIVATE_IP") else IPTypes.PUBLIC

   connector = Connector()

   def getconn() -> sqlalchemy.engine.base.Engine:
       conn: sqlalchemy.engine.base.Engine = connector.connect(
           instance_connection_name,
           "pg8000",
           user=db_user,
           password=db_pass,
           db=db_name,
           ip_type=ip_type,
       )
       return conn

   pool = sqlalchemy.create_engine(
       "postgresql+pg8000://",
       creator=getconn,
       # ...
   )
   return pool

# Create a connection pool
engine = connect_with_connector()

# Create a sessionmaker class to create new sessions
SessionMaker = sqlalchemy.orm.sessionmaker(bind=engine)

# Create a Base class for ORM
# You may need to manually fix the following
Base = declarative_base()

db_init.py

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from connect_connector import engine

from data_model import Package

def create_packages():
    # Create a session
    session = sessionmaker(bind=engine)()

    # Create 10 sample packages
    for i in range(10):
        package = Package(
            product_id=i,
            height=10.0,
            width=10.0,
            depth=10.0,
            weight=10.0,
            special_handling_instructions="No special handling instructions."
        )

        # Add the package to the session
        session.add(package)

    # Commit the changes
    session.commit()

if __name__ == '__main__':
    create_packages()

    print('Packages created successfully.')

main.py

from flask import Flask, request, jsonify

from data_model import Package
from connect_connector import SessionMaker

app = Flask(__name__)

session_maker = SessionMaker()

@app.route("/packages/<int:product_id>", methods=["GET"])
def get_package(product_id):
  """Get information about a package."""

  session = session_maker

  package = session.query(Package).filter(Package.product_id == product_id).first()

  if package is None:
    return jsonify({"message": "Package not found."}), 404

  return jsonify(
      {
          "height": package.height,
          "width": package.width,
          "depth": package.depth,
          "weight": package.weight,
          "special_handling_instructions": package.special_handling_instructions,
      }
  ), 200

if __name__ == "__main__":
  app.run(host="0.0.0.0")

test.py

import unittest

from data_model import Package
from connect_connector import SessionMaker

from main import app

class TestPackage(unittest.TestCase):

    def setUp(self):
        self.session_maker = SessionMaker()

    def tearDown(self):
        self.session_maker.close()

    def test_get_package(self):
        """Test the `get_package()` function."""

        package = Package(
        product_id=11, # Ensure that the product_id different from the sample data
        height=10,
        width=10,
        depth=10,
        weight=10,
        special_handling_instructions="Fragile",
        )

        session = self.session_maker

        session.add(package)
        session.commit()

        response = app.test_client().get("/packages/11")

        self.assertEqual(response.status_code, 200)

        self.assertEqual(
            response.json,
            {
                "height": 10,
                "width": 10,
                "depth": 10,
                "weight": 10,
                "special_handling_instructions": "Fragile",
            },
        )

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

requirements.txt

cloud-sql-python-connector==1.2.4
sqlalchemy==1.4.36
pg8000==1.22.0
Flask==3.0.0
gunicorn==20.1.0
psycopg2-binary==2.9.3

Dockerfile

FROM python:3.10-slim

WORKDIR /app

COPY . ./

RUN pip install -r requirements.txt

# Add these manually for your project
ENV INSTANCE_CONNECTION_NAME=YOUR_INSTANCE_CONNECTION_NAME
ENV DB_USER=evolution
ENV DB_PASS=evolution
ENV DB_NAME=product_details

CMD ["python", "main.py"]