1. ก่อนเริ่มต้น
ตั้งแต่การแนะนำภาพยนตร์หรือร้านอาหารไปจนถึงการไฮไลต์วิดีโอที่สร้างความบันเทิง เครื่องมือแนะนำหรือที่เรียกว่าระบบแนะนำเป็นแอปพลิเคชันที่สำคัญมากของแมชชีนเลิร์นนิง ระบบแนะนำช่วยให้คุณแสดงเนื้อหาที่น่าสนใจจากกลุ่มผู้สมัครจำนวนมากต่อผู้ใช้ ตัวอย่างเช่น Google Play Store มีแอปหลายล้านรายการให้ติดตั้ง ส่วน YouTube มีวิดีโอหลายพันล้านรายการให้รับชม และเรายังเพิ่มแอปและวิดีโอใหม่ๆ ทุกวัน
ในโค้ดแล็บนี้ คุณจะได้เรียนรู้วิธีสร้างระบบแนะนำแบบฟูลสแต็กโดยใช้เครื่องมือต่อไปนี้
- TensorFlow Recommenders เพื่อฝึกโมเดลการดึงข้อมูลและการจัดอันดับสำหรับภาพยนตร์แนะนำ
- TensorFlow Serving เพื่อแสดงโมเดล
- Flutter เพื่อสร้างแอปข้ามแพลตฟอร์มเพื่อแสดงภาพยนตร์ที่แนะนำ
ข้อกำหนดเบื้องต้น
- ความรู้พื้นฐานเกี่ยวกับการพัฒนา Flutter ด้วย Dart
- ความรู้พื้นฐานเกี่ยวกับแมชชีนเลิร์นนิงด้วย TensorFlow เช่น การฝึกเทียบกับการติดตั้งใช้งาน
- มีความคุ้นเคยกับระบบการแนะนำในระดับพื้นฐาน
- มีความรู้พื้นฐานเกี่ยวกับ Python, เทอร์มินัล และ Docker
สิ่งที่คุณจะได้เรียนรู้
- วิธีฝึกโมเดลการดึงข้อมูลและการจัดอันดับโดยใช้ TensorFlow Recommenders
- วิธีแสดงโมเดลคำแนะนำที่ฝึกแล้วโดยใช้ TensorFlow Serving
- วิธีสร้างแอป Flutter แบบข้ามแพลตฟอร์มเพื่อแสดงสินค้าแนะนำ
สิ่งที่คุณต้องมี
- Flutter SDK
- การตั้งค่า Android และ iOS สำหรับ Flutter
- การตั้งค่า Desktop สำหรับ Flutter
- การตั้งค่า Web สำหรับ Flutter
- การตั้งค่า Visual Studio Code (VS Code) สำหรับ Flutter และ Dart
- Docker
- Bash
- Python 3.7 ขึ้นไป
- สิทธิ์เข้าถึง Colab
2. ตั้งค่าสภาพแวดล้อมในการพัฒนา Flutter
สำหรับการพัฒนาด้วย Flutter คุณต้องมีซอฟต์แวร์ 2 อย่างเพื่อทำ Codelab นี้ให้เสร็จสมบูรณ์ ได้แก่ Flutter SDK และโปรแกรมแก้ไข
คุณเรียกใช้ส่วนหน้าของโค้ดแล็บได้โดยใช้อุปกรณ์ต่อไปนี้
- โปรแกรมจำลอง iOS (ต้องติดตั้งเครื่องมือ Xcode)
- Android Emulator (ต้องตั้งค่าใน Android Studio)
- เบราว์เซอร์ (ต้องใช้ Chrome สำหรับการแก้ไขข้อบกพร่อง)
- ในรูปแบบแอปพลิเคชันเดสก์ท็อป Windows, Linux หรือ macOS คุณต้องพัฒนาบนแพลตฟอร์มที่วางแผนจะใช้งาน ดังนั้น หากต้องการพัฒนาแอปเดสก์ท็อป Windows คุณต้องพัฒนาบน Windows เพื่อเข้าถึงห่วงโซ่การสร้างที่เหมาะสม มีข้อกำหนดเฉพาะของระบบปฏิบัติการที่อธิบายไว้โดยละเอียดใน docs.flutter.dev/desktop
สำหรับแบ็กเอนด์ คุณจะต้องมีสิ่งต่อไปนี้
- เครื่อง Linux หรือ Mac ที่ใช้ Intel
3. ตั้งค่า
วิธีดาวน์โหลดโค้ดสำหรับ Codelab นี้
- ไปที่ที่เก็บ GitHub สำหรับ Codelab นี้
- คลิกโค้ด > ดาวน์โหลด ZIP เพื่อดาวน์โหลดโค้ดทั้งหมดสำหรับ Codelab นี้

- แตกไฟล์ ZIP ที่ดาวน์โหลดเพื่อคลายโฟลเดอร์รูท
codelabs-mainที่มีทรัพยากรทั้งหมดที่คุณต้องการ
สำหรับ Codelab นี้ คุณจะต้องใช้ไฟล์ในไดเรกทอรีย่อย tfrs-flutter/ ในที่เก็บเท่านั้น ซึ่งมีโฟลเดอร์หลายโฟลเดอร์ดังนี้
- โฟลเดอร์
step0ถึงstep5มีโค้ดเริ่มต้นที่คุณจะใช้ต่อในแต่ละขั้นตอนของ Codelab นี้ - โฟลเดอร์
finishedมีโค้ดที่เสร็จสมบูรณ์สำหรับแอปตัวอย่างที่เสร็จแล้ว - แต่ละโฟลเดอร์จะมีโฟลเดอร์ย่อย
backendซึ่งมีโค้ดแบ็กเอนด์ของเครื่องมือแนะนำ และโฟลเดอร์ย่อยfrontendซึ่งมีโค้ดฟรอนต์เอนด์ Flutter
4. ดาวน์โหลดทรัพยากร Dependency สำหรับโปรเจ็กต์
แบ็กเอนด์
เราจะใช้ Flask เพื่อสร้างแบ็กเอนด์ เปิดเทอร์มินัลแล้วเรียกใช้คำสั่งต่อไปนี้
pip install Flask flask-cors requests numpy
ฟรอนท์เอนด์
- ใน VS Code ให้คลิกไฟล์ > เปิดโฟลเดอร์ แล้วเลือกโฟลเดอร์
step0จากซอร์สโค้ดที่คุณดาวน์โหลดไว้ก่อนหน้านี้ - เปิดไฟล์
step0/frontend/lib/main.dartหากเห็นกล่องโต้ตอบ VS Code ปรากฏขึ้นซึ่งแจ้งให้คุณดาวน์โหลดแพ็กเกจที่จำเป็นสำหรับแอปเริ่มต้น ให้คลิกรับแพ็กเกจ - หากไม่เห็นกล่องโต้ตอบนี้ ให้เปิดเทอร์มินัล แล้วเรียกใช้
flutter pub getคำสั่งในโฟลเดอร์step0/frontend

5. ขั้นตอนที่ 0: เรียกใช้แอปเริ่มต้น
- เปิด
step0/frontend/lib/main.dartใน VS Code ตรวจสอบว่าได้ตั้งค่า Android Emulator หรือ iOS Simulator อย่างถูกต้องและปรากฏในแถบสถานะ
ตัวอย่างเช่น สิ่งที่คุณเห็นเมื่อใช้ Pixel 5 กับ Android Emulator มีดังนี้

ต่อไปนี้คือสิ่งที่คุณจะเห็นเมื่อใช้ iPhone 13 กับ iOS Simulator

- คลิก
เริ่มแก้ไขข้อบกพร่อง
เรียกใช้และสำรวจแอป
แอปควรเปิดตัวใน Android Emulator หรือ iOS Simulator UI นั้นใช้งานง่าย มีช่องข้อความที่ให้ผู้ใช้พิมพ์ข้อความเป็นรหัสผู้ใช้ แอป Flutter จะส่งคำขอค้นหาไปยังแบ็กเอนด์ ซึ่งเรียกใช้โมเดลคำแนะนำ 2 รายการและแสดงรายการคำแนะนำภาพยนตร์ที่จัดอันดับแล้ว ส่วนหน้าจะแสดงผลลัพธ์ใน UI หลังจากได้รับคำตอบ

หากคุณคลิกแนะนำตอนนี้ จะไม่มีอะไรเกิดขึ้นเนื่องจากแอปยังสื่อสารกับแบ็กเอนด์ไม่ได้
6. ขั้นตอนที่ 1: สร้างโมเดลการดึงข้อมูลและการจัดอันดับสำหรับเครื่องมือแนะนำ
เครื่องมือแนะนำในโลกแห่งความเป็นจริงมักประกอบด้วยหลายขั้นตอน ดังนี้
- ขั้นตอนการดึงข้อมูลมีหน้าที่เลือกชุดผู้สมัครรับเลือกเบื้องต้นหลายร้อยคนจากผู้สมัครรับเลือกที่เป็นไปได้ทั้งหมด เป้าหมายหลักของโมเดลนี้คือการคัดกรองผู้สมัครทั้งหมดที่ผู้ใช้ไม่สนใจอย่างมีประสิทธิภาพ เนื่องจากโมเดลการดึงข้อมูลอาจต้องจัดการกับตัวเลือกหลายล้านรายการ จึงต้องมีประสิทธิภาพในการคำนวณ
- ขั้นตอนการจัดอันดับจะนำเอาเอาต์พุตของโมเดลการดึงข้อมูลมาปรับแต่งเพื่อเลือกคำแนะนำที่ดีที่สุด โดยมีหน้าที่จำกัดชุดสินค้าที่ผู้ใช้อาจสนใจให้เหลือเพียงรายการสินค้าที่น่าสนใจในลำดับหลักร้อย
- ขั้นตอนหลังการจัดอันดับช่วยให้มั่นใจได้ถึงความหลากหลาย ความสดใหม่ และความเป็นธรรม รวมถึงจัดระเบียบรายการที่ได้รับการพิจารณาใหม่ให้เป็นชุดคำแนะนำที่เป็นประโยชน์ในลำดับหลายสิบรายการ

สำหรับ Codelab นี้ คุณจะฝึกโมเดลการดึงข้อมูลและโมเดลการจัดอันดับโดยใช้ชุดข้อมูล MovieLens ที่ได้รับความนิยม คุณเปิดโค้ดการฝึกด้านล่างผ่าน Colab และทำตามวิธีการได้
7. ขั้นตอนที่ 2: สร้างแบ็กเอนด์ของเครื่องมือแนะนำ
ตอนนี้คุณได้ฝึกโมเดลการดึงข้อมูลและการจัดอันดับแล้ว คุณสามารถนําไปใช้งานและสร้างแบ็กเอนด์ได้
เริ่ม TensorFlow Serving
เนื่องจากคุณต้องใช้ทั้งโมเดลการดึงข้อมูลและโมเดลการจัดอันดับเพื่อสร้างรายการภาพยนตร์ที่แนะนำ คุณจึงต้องติดตั้งใช้งานทั้ง 2 โมเดลพร้อมกันโดยใช้ TensorFlow Serving
- ในเทอร์มินัล ให้ไปที่โฟลเดอร์
step2/backendในคอมพิวเตอร์ แล้วเริ่ม TensorFlow Serving ด้วย Docker
docker run -t --rm -p 8501:8501 -p 8500:8500 -v "$(pwd)/:/models/" tensorflow/serving --model_config_file=/models/models.config
Docker จะดาวน์โหลดอิมเมจ TensorFlow Serving โดยอัตโนมัติก่อน ซึ่งจะใช้เวลา 1 นาที หลังจากนั้น TensorFlow Serving ควรจะเริ่มทำงาน โดยบันทึกควรมีลักษณะดังข้อมูลโค้ดต่อไปนี้
2022-04-24 09:32:06.461702: I tensorflow_serving/model_servers/server_core.cc:465] Adding/updating models.
2022-04-24 09:32:06.461843: I tensorflow_serving/model_servers/server_core.cc:591] (Re-)adding model: retrieval
2022-04-24 09:32:06.461907: I tensorflow_serving/model_servers/server_core.cc:591] (Re-)adding model: ranking
2022-04-24 09:32:06.576920: I tensorflow_serving/core/basic_manager.cc:740] Successfully reserved resources to load servable {name: retrieval version: 123}
2022-04-24 09:32:06.576993: I tensorflow_serving/core/loader_harness.cc:66] Approving load for servable version {name: retrieval version: 123}
2022-04-24 09:32:06.577011: I tensorflow_serving/core/loader_harness.cc:74] Loading servable version {name: retrieval version: 123}
2022-04-24 09:32:06.577848: I external/org_tensorflow/tensorflow/cc/saved_model/reader.cc:38] Reading SavedModel from: /models/retrieval/exported-retrieval/123
2022-04-24 09:32:06.583809: I external/org_tensorflow/tensorflow/cc/saved_model/reader.cc:90] Reading meta graph with tags { serve }
2022-04-24 09:32:06.583879: I external/org_tensorflow/tensorflow/cc/saved_model/reader.cc:132] Reading SavedModel debug info (if present) from: /models/retrieval/exported-retrieval/123
2022-04-24 09:32:06.584970: I external/org_tensorflow/tensorflow/core/platform/cpu_feature_guard.cc:142] This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN) to use the following CPU instructions in performance-critical operations: AVX2 FMA
To enable them in other operations, rebuild TensorFlow with the appropriate compiler flags.
2022-04-24 09:32:06.629900: I external/org_tensorflow/tensorflow/cc/saved_model/loader.cc:206] Restoring SavedModel bundle.
2022-04-24 09:32:06.634662: I external/org_tensorflow/tensorflow/core/platform/profile_utils/cpu_utils.cc:114] CPU Frequency: 2800000000 Hz
2022-04-24 09:32:06.672534: I external/org_tensorflow/tensorflow/cc/saved_model/loader.cc:190] Running initialization op on SavedModel bundle at path: /models/retrieval/exported-retrieval/123
2022-04-24 09:32:06.673629: I tensorflow_serving/core/basic_manager.cc:740] Successfully reserved resources to load servable {name: ranking version: 123}
2022-04-24 09:32:06.673765: I tensorflow_serving/core/loader_harness.cc:66] Approving load for servable version {name: ranking version: 123}
2022-04-24 09:32:06.673786: I tensorflow_serving/core/loader_harness.cc:74] Loading servable version {name: ranking version: 123}
2022-04-24 09:32:06.674731: I external/org_tensorflow/tensorflow/cc/saved_model/reader.cc:38] Reading SavedModel from: /models/ranking/exported-ranking/123
2022-04-24 09:32:06.683557: I external/org_tensorflow/tensorflow/cc/saved_model/reader.cc:90] Reading meta graph with tags { serve }
2022-04-24 09:32:06.683601: I external/org_tensorflow/tensorflow/cc/saved_model/reader.cc:132] Reading SavedModel debug info (if present) from: /models/ranking/exported-ranking/123
2022-04-24 09:32:06.688665: I external/org_tensorflow/tensorflow/cc/saved_model/loader.cc:277] SavedModel load for tags { serve }; Status: success: OK. Took 110815 microseconds.
2022-04-24 09:32:06.690019: I tensorflow_serving/servables/tensorflow/saved_model_warmup_util.cc:59] No warmup data file found at /models/retrieval/exported-retrieval/123/assets.extra/tf_serving_warmup_requests
2022-04-24 09:32:06.693025: I tensorflow_serving/core/loader_harness.cc:87] Successfully loaded servable version {name: retrieval version: 123}
2022-04-24 09:32:06.702594: I external/org_tensorflow/tensorflow/cc/saved_model/loader.cc:206] Restoring SavedModel bundle.
2022-04-24 09:32:06.745361: I external/org_tensorflow/tensorflow/cc/saved_model/loader.cc:190] Running initialization op on SavedModel bundle at path: /models/ranking/exported-ranking/123
2022-04-24 09:32:06.772363: I external/org_tensorflow/tensorflow/cc/saved_model/loader.cc:277] SavedModel load for tags { serve }; Status: success: OK. Took 97633 microseconds.
2022-04-24 09:32:06.774853: I tensorflow_serving/servables/tensorflow/saved_model_warmup_util.cc:59] No warmup data file found at /models/ranking/exported-ranking/123/assets.extra/tf_serving_warmup_requests
2022-04-24 09:32:06.777706: I tensorflow_serving/core/loader_harness.cc:87] Successfully loaded servable version {name: ranking version: 123}
2022-04-24 09:32:06.778969: I tensorflow_serving/model_servers/server_core.cc:486] Finished adding/updating models
2022-04-24 09:32:06.779030: I tensorflow_serving/model_servers/server.cc:367] Profiler service is enabled
2022-04-24 09:32:06.784217: I tensorflow_serving/model_servers/server.cc:393] Running gRPC ModelServer at 0.0.0.0:8500 ...
[warn] getaddrinfo: address family for nodename not supported
2022-04-24 09:32:06.785748: I tensorflow_serving/model_servers/server.cc:414] Exporting HTTP/REST API at:localhost:8501 ...
[evhttp_server.cc : 245] NET_LOG: Entering the event loop ...
สร้างปลายทางใหม่
เนื่องจาก TensorFlow Serving ไม่รองรับการ "เชื่อมโยง" โมเดลแบบลำดับหลายรายการ คุณจึงต้องสร้างบริการใหม่ที่เชื่อมต่อโมเดลการดึงข้อมูลและการจัดอันดับ
- เพิ่มโค้ดนี้ลงในฟังก์ชัน
get_recommendations()ในไฟล์step2/backend/recommendations.py
user_id = request.get_json()["user_id"]
retrieval_request = json.dumps({"instances": [user_id]})
retrieval_response = requests.post(RETRIEVAL_URL, data=retrieval_request)
movie_candidates = retrieval_response.json()["predictions"][0]["output_2"]
ranking_queries = [
{"user_id": u, "movie_title": m}
for (u, m) in zip([user_id] * NUM_OF_CANDIDATES, movie_candidates)
]
ranking_request = json.dumps({"instances": ranking_queries})
ranking_response = requests.post(RANKING_URL, data=ranking_request)
movies_scores = list(np.squeeze(ranking_response.json()["predictions"]))
ranked_movies = [
m[1] for m in sorted(list(zip(movies_scores, movie_candidates)), reverse=True)
]
return make_response(jsonify({"movies": ranked_movies}), 200)
เริ่มบริการ Flask
ตอนนี้คุณก็เริ่มบริการ Flask ได้แล้ว
- ในเทอร์มินัล ให้ไปที่โฟลเดอร์
step2/backend/แล้วเรียกใช้คำสั่งต่อไปนี้
FLASK_APP=recommender.py FLASK_ENV=development flask run
Flask จะสร้างปลายทางใหม่ที่ http://localhost:5000/recommend คุณควรเห็นบันทึกดังนี้
* Serving Flask app 'recommender.py' (lazy loading) * Environment: development * Debug mode: on * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit) * Restarting with stat * Debugger is active! * Debugger PIN: 705-382-264 127.0.0.1 - - [25/Apr/2022 19:44:47] "POST /recommend HTTP/1.1" 200 -
คุณส่งคำขอตัวอย่างไปยังปลายทางได้เพื่อให้แน่ใจว่าทำงานได้ตามที่คาดไว้
curl -X POST -H "Content-Type: application/json" -d '{"user_id":"42"}' http://localhost:5000/recommend
ปลายทางจะแสดงรายการภาพยนตร์ที่แนะนำสำหรับผู้ใช้ 42 ดังนี้
{
"movies": [
"While You Were Sleeping (1995)",
"Preacher's Wife, The (1996)",
"Michael (1996)",
"Lion King, The (1994)",
"Father of the Bride Part II (1995)",
"Sleepless in Seattle (1993)",
"101 Dalmatians (1996)",
"Bridges of Madison County, The (1995)",
"Rudy (1993)",
"Jack (1996)"
]
}
เท่านี้ก็เรียบร้อย คุณสร้างแบ็กเอนด์เพื่อแนะนำภาพยนตร์ตามรหัสผู้ใช้ได้สำเร็จแล้ว
8. ขั้นตอนที่ 3: สร้างแอป Flutter สำหรับ Android และ iOS
แบ็กเอนด์พร้อมแล้ว คุณเริ่มส่งคำขอไปยังโมเดลเพื่อค้นหาคำแนะนำภาพยนตร์จากแอป Flutter ได้
แอปฟรอนท์เอนด์ค่อนข้างเรียบง่าย โดยมีเพียง TextField ที่รับรหัสผู้ใช้และส่งคำขอ (ในฟังก์ชัน recommend()) ไปยังแบ็กเอนด์ที่คุณเพิ่งสร้าง หลังจากได้รับคำตอบแล้ว UI ของแอปจะแสดงภาพยนตร์ที่แนะนำใน ListView
- เพิ่มโค้ดนี้ลงในฟังก์ชัน
recommend()ในไฟล์step3/frontend/lib/main.dart
final response = await http.post(
Uri.parse('http://' + _server + ':5000/recommend'),
headers: <String, String>{
'Content-Type': 'application/json',
},
body: jsonEncode(<String, String>{
'user_id': _userIDController.text,
}),
);
เมื่อแอปได้รับการตอบกลับจากแบ็กเอนด์แล้ว ให้อัปเดต UI เพื่อแสดงรายการภาพยนตร์แนะนำสำหรับผู้ใช้ที่ระบุ
- เพิ่มโค้ดนี้ใต้โค้ดด้านบน
if (response.statusCode == 200) {
return List<String>.from(jsonDecode(response.body)['movies']);
} else {
throw Exception('Error response');
}
เรียกใช้
- คลิก
เริ่มการแก้ไขข้อบกพร่อง แล้วรอให้แอปโหลด - ป้อนรหัสผู้ใช้ (เช่น 42) แล้วเลือกแนะนำ

9. ขั้นตอนที่ 4: เรียกใช้แอป Flutter บนแพลตฟอร์มเดสก์ท็อป
นอกจาก Android และ iOS แล้ว Flutter ยังรองรับแพลตฟอร์มเดสก์ท็อปด้วย ซึ่งรวมถึง Linux, Mac และ Windows
Linux
- ตรวจสอบว่าได้ตั้งค่าอุปกรณ์เป้าหมายเป็น
ในแถบสถานะของ VSCode - คลิก
เริ่มการแก้ไขข้อบกพร่อง แล้วรอให้แอปโหลด - ป้อนรหัสผู้ใช้ (เช่น 42) แล้วเลือกแนะนำ

Mac
- สำหรับ Mac คุณต้องตั้งค่าสิทธิ์ที่เหมาะสมเนื่องจากแอปจะส่งคำขอ HTTP ไปยังแบ็กเอนด์ โปรดดูรายละเอียดเพิ่มเติมในสิทธิ์และแซนด์บ็อกซ์ของแอป
เพิ่มโค้ดนี้ลงใน step4/frontend/macOS/Runner/DebugProfile.entitlements และ step4/frontend/macOS/Runner/Release.entitlements ตามลำดับ
<key>com.apple.security.network.client</key>
<true/>
- ตรวจสอบว่าได้ตั้งค่าอุปกรณ์เป้าหมายเป็น
ในแถบสถานะของ VSCode - คลิก
เริ่มการแก้ไขข้อบกพร่อง แล้วรอให้แอปโหลด - ป้อนรหัสผู้ใช้ (เช่น 42) แล้วเลือกแนะนำ

Windows
- ตรวจสอบว่าได้ตั้งค่าอุปกรณ์เป้าหมายเป็น
ในแถบสถานะของ VSCode - คลิก
เริ่มการแก้ไขข้อบกพร่อง แล้วรอให้แอปโหลด - ป้อนรหัสผู้ใช้ (เช่น 42) แล้วเลือกแนะนำ

10. ขั้นตอนที่ 5: เรียกใช้แอป Flutter บนแพลตฟอร์มเว็บ
อีกสิ่งหนึ่งที่คุณทำได้คือการเพิ่มการรองรับเว็บลงในแอป Flutter โดยค่าเริ่มต้น แพลตฟอร์มเว็บจะเปิดใช้โดยอัตโนมัติสำหรับแอป Flutter ดังนั้นสิ่งที่คุณต้องทำก็คือเปิดใช้
- ตรวจสอบว่าได้ตั้งค่าอุปกรณ์เป้าหมายเป็น
ในแถบสถานะของ VSCode - คลิก
Start debugging แล้วรอให้แอปโหลดในเบราว์เซอร์ Chrome - ป้อนรหัสผู้ใช้ (เช่น 42) แล้วเลือกแนะนำ

11. ขอแสดงความยินดี
คุณสร้างแอปฟูลสแต็กเพื่อแนะนำภาพยนตร์ให้แก่ผู้ใช้แล้ว
แม้ว่าแอปจะแนะนำเฉพาะภาพยนตร์ แต่คุณก็ได้เรียนรู้เวิร์กโฟลว์โดยรวมของการสร้างเครื่องมือแนะนำที่มีประสิทธิภาพ และเชี่ยวชาญทักษะในการใช้คำแนะนำในแอป Flutter คุณสามารถนำสิ่งที่ได้เรียนรู้ไปใช้กับสถานการณ์อื่นๆ ได้อย่างง่ายดาย (เช่น อีคอมเมิร์ซ อาหาร และวิดีโอสั้น)