การสร้างระบบการแนะนำภาพยนตร์ Fullstack

1. ก่อนเริ่มต้น

เครื่องมือแนะนำเป็นแอปพลิเคชันที่สำคัญมากของแมชชีนเลิร์นนิง ไม่ว่าจะเป็นการแนะนำภาพยนตร์หรือร้านอาหารไปจนถึงการไฮไลต์วิดีโอที่ให้ความบันเทิง ผู้แนะนำจะช่วยให้คุณแสดงเนื้อหาที่น่าสนใจจากผู้ใช้จำนวนมากได้ ตัวอย่างเช่น Google Play Store มีแอปให้ติดตั้งหลายล้านรายการ ในขณะที่ YouTube มีวิดีโอหลายพันล้านรายการให้รับชม รวมถึงมีแอปและวิดีโอเพิ่มเข้ามามากขึ้นทุกวัน

ใน Codelab นี้ คุณจะได้เรียนรู้วิธีสร้างโปรแกรมแนะนำ Fullstack โดยใช้สิ่งต่อไปนี้

  • ผู้แนะนำ TensorFlow เพื่อฝึกการดึงข้อมูลและโมเดลการจัดอันดับสำหรับการแนะนำภาพยนตร์
  • การแสดง TensorFlow เพื่อให้บริการโมเดล
  • Flutter เพื่อสร้างแอปข้ามแพลตฟอร์มเพื่อแสดงภาพยนตร์แนะนำ

ข้อกำหนดเบื้องต้น

  • ความรู้พื้นฐานเกี่ยวกับการพัฒนา Flutter ด้วย Dart
  • ความรู้พื้นฐานเกี่ยวกับแมชชีนเลิร์นนิงด้วย TensorFlow เช่น การฝึกและการติดตั้งใช้งาน
  • ความคุ้นเคยกับระบบการแนะนำวิดีโอเบื้องต้น
  • ความรู้พื้นฐานเกี่ยวกับ Python, เทอร์มินัล และ Docker

สิ่งที่คุณจะได้เรียนรู้

  • วิธีฝึกการดึงข้อมูลและการจัดอันดับโมเดลโดยใช้ผู้แนะนำ TensorFlow
  • วิธีแสดงโมเดลคำแนะนำที่ผ่านการฝึกโดยใช้ TensorFlow ในปัจจุบัน
  • วิธีสร้างแอป Flutter ข้ามแพลตฟอร์มเพื่อแสดงรายการที่แนะนำ

สิ่งที่ต้องมี

2. ตั้งค่าสภาพแวดล้อมในการพัฒนาซอฟต์แวร์ Flutter

สำหรับการพัฒนาซอฟต์แวร์ Flutter คุณต้องมีซอฟต์แวร์ 2 ส่วนเพื่อดำเนินการ Codelab ให้เสร็จสมบูรณ์ ได้แก่ Flutter SDK และเครื่องมือแก้ไข

คุณเรียกใช้ฟรอนท์เอนด์ของ Codelab ได้โดยใช้อุปกรณ์ต่อไปนี้

  • เครื่องมือจำลอง iOS (ต้องติดตั้งเครื่องมือ Xcode)
  • โปรแกรมจำลอง Android (ต้องตั้งค่าใน Android Studio)
  • เบราว์เซอร์ (การแก้ไขข้อบกพร่องต้องใช้ Chrome)
  • เป็นแอปพลิเคชัน Windows, Linux หรือ macOS บนเดสก์ท็อป คุณต้องพัฒนาบนแพลตฟอร์มที่คุณวางแผนจะทำให้ใช้งานได้ ดังนั้นหากต้องการพัฒนาแอป Windows บนเดสก์ท็อป คุณต้องพัฒนาบน Windows เพื่อเข้าถึงเชนบิลด์ที่เหมาะสม มีข้อกำหนดเฉพาะระบบปฏิบัติการที่ครอบคลุมรายละเอียดใน docs.flutter.dev/desktop

คุณจะต้องมีสิ่งต่อไปนี้สำหรับแบ็กเอนด์

  • เครื่อง Linux หรือ Mac ที่ใช้ Intel

3. ตั้งค่า

วิธีดาวน์โหลดโค้ดสำหรับ Codelab นี้

  1. ไปที่ที่เก็บ GitHub สำหรับ Codelab นี้
  2. คลิกโค้ด > ดาวน์โหลดรหัสไปรษณีย์เพื่อดาวน์โหลดรหัสทั้งหมดสำหรับ Codelab นี้

2cd45599f51fb8a2.png

  1. แตกไฟล์ ZIP ที่ดาวน์โหลดมาเพื่อคลายแพ็กโฟลเดอร์รูท codelabs-main ที่มีทรัพยากรทั้งหมดที่คุณต้องการ

สำหรับ Codelab นี้ คุณต้องการเฉพาะไฟล์ในไดเรกทอรีย่อย tfrs-flutter/ ในที่เก็บซึ่งมีหลายโฟลเดอร์ดังนี้

  • โฟลเดอร์ step0 ถึง step5 มีโค้ดเริ่มต้นที่คุณสร้างสำหรับแต่ละขั้นตอนใน Codelab นี้
  • โฟลเดอร์ finished มีโค้ดที่สมบูรณ์สำหรับแอปตัวอย่างที่สมบูรณ์แล้ว
  • แต่ละโฟลเดอร์จะมีโฟลเดอร์ย่อย backend ซึ่งมีโค้ดแบ็กเอนด์ของเครื่องมือแนะนำ และโฟลเดอร์ย่อย frontend ซึ่งมีโค้ดฟรอนท์เอนด์ Flutter

4. ดาวน์โหลดทรัพยากร Dependency สำหรับโปรเจ็กต์

แบ็กเอนด์

เราจะใช้ Flask ในการสร้างแบ็กเอนด์ เปิดเทอร์มินัลและเรียกใช้ดังนี้

pip install Flask flask-cors requests numpy

ฟรอนท์เอนด์

  1. ใน VS Code ให้คลิก File > เปิดโฟลเดอร์ แล้วเลือกโฟลเดอร์ step0 จากซอร์สโค้ดที่คุณดาวน์โหลดไว้ก่อนหน้านี้
  2. เปิดไฟล์ step0/frontend/lib/main.dart หากเห็นกล่องโต้ตอบ "VS Code" ปรากฏขึ้นซึ่งแจ้งให้คุณดาวน์โหลดแพ็กเกจที่จำเป็นสำหรับแอปเริ่มต้น ให้คลิกรับแพ็กเกจ
  3. หากไม่เห็นกล่องโต้ตอบนี้ ให้เปิดเทอร์มินัลแล้วเรียกใช้คำสั่ง flutter pub get ในโฟลเดอร์ step0/frontend

7ada07c300f1665.png

5. ขั้นตอนที่ 0: เรียกใช้แอปเริ่มต้น

  1. เปิดไฟล์ step0/frontend/lib/main.dart ใน VS Code ตรวจสอบว่าได้ตั้งค่าโปรแกรมจำลอง Android หรือ iOS Simulator ไว้อย่างถูกต้องและปรากฏในแถบสถานะ

เช่นสิ่งที่คุณเห็นเมื่อใช้ Pixel 5 กับโปรแกรมจำลอง Android มีดังนี้

9767649231898791.png

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

95529e3a682268b2.png

  1. คลิก a19a0c68bc4046e6.png เริ่มแก้ไขข้อบกพร่อง

เรียกใช้และสำรวจแอป

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

d21427db9587560f.png 73e8272a5ce8dfbc.png

หากคลิกแนะนำตอนนี้ จะไม่มีอะไรเกิดขึ้นเนื่องจากแอปยังสื่อสารกับแบ็กเอนด์ไม่ได้

6. ขั้นตอนที่ 1: สร้างโมเดลการดึงข้อมูลและการจัดอันดับสำหรับเครื่องมือแนะนำ

เครื่องมือแนะนำในสถานการณ์จริงมักประกอบด้วยหลายขั้นตอน ดังนี้

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

70dfc0d7e989164f.png

สำหรับ Codelab นี้ คุณจะได้ฝึกโมเดลการดึงข้อมูลและโมเดลการจัดอันดับโดยใช้ชุดข้อมูล MovieLens ยอดนิยม คุณสามารถเปิดโค้ดการฝึกอบรมด้านล่างผ่านทาง Colab และทำตามวิธีการต่อไปนี้ได้

7. ขั้นตอนที่ 2: สร้างแบ็กเอนด์ของเครื่องมือแนะนำ

ตอนนี้คุณก็ได้ฝึกโมเดลการดึงข้อมูลและการจัดอันดับแล้ว คุณก็ทำให้โมเดลเหล่านั้นใช้งานได้และสร้างแบ็กเอนด์ได้

เริ่มแสดงผล TensorFlow

เนื่องจากคุณจำเป็นต้องใช้ทั้งโมเดลการดึงข้อมูลและการจัดอันดับเพื่อสร้างรายการภาพยนตร์ที่แนะนำ คุณจึงนำทั้ง 2 โมเดลนี้ไปใช้พร้อมกันโดยใช้ TensorFlow Serve ได้

  • ในเทอร์มินัล ให้ไปที่โฟลเดอร์ step2/backend ในคอมพิวเตอร์แล้วเริ่ม TensorFlow Serve ด้วย Docker โดยใช้คำสั่งต่อไปนี้
docker run -t --rm -p 8501:8501 -p 8500:8500 -v "$(pwd)/:/models/" tensorflow/serving --model_config_file=/models/models.config

Docker จะดาวน์โหลดอิมเมจการแสดงของ TensorFlow โดยอัตโนมัติก่อน ซึ่งจะใช้เวลา 1 นาที หลังจากนั้น การแสดง TensorFlow ควรเริ่มทำงาน บันทึกควรมีลักษณะดังนี้

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 ไม่รองรับ "การเชน" โมเดลตามลำดับหลายโมเดล คุณต้องสร้างบริการใหม่ที่เชื่อมต่อโมเดลการดึงข้อมูลและการจัดอันดับ

  • เพิ่มโค้ดนี้ลงในฟังก์ชัน 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');
}

เรียกใช้

  1. คลิก a19a0c68bc4046e6.png เริ่มแก้ไขข้อบกพร่อง แล้วรอให้แอปโหลด
  2. ป้อนรหัสผู้ใช้ (เช่น 42) จากนั้นเลือกแนะนำ

badb59d8b96959ae.png a0d2d4020aebfb0a.png

9. ขั้นตอนที่ 4: เรียกใช้แอป Flutter ในแพลตฟอร์มเดสก์ท็อป

นอกเหนือจาก Android และ iOS แล้ว Flutter ยังรองรับแพลตฟอร์มเดสก์ท็อปอย่าง Linux, Mac และ Windows ด้วย

Linux

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

2665514231033f1.png

Mac

  1. สำหรับ Mac คุณต้องตั้งค่าการให้สิทธิ์ที่เหมาะสมเนื่องจากแอปจะส่งคำขอ HTTP ไปยังแบ็กเอนด์ โปรดดูรายละเอียดเพิ่มเติมที่การให้สิทธิ์และ App Sandbox

เพิ่มโค้ดนี้ลงใน step4/frontend/macOS/Runner/DebugProfile.entitlements และ step4/frontend/macOS/Runner/Release.entitlements ตามลำดับ

<key>com.apple.security.network.client</key>
<true/>
  1. ตรวจสอบว่าอุปกรณ์เป้าหมายตั้งค่าเป็น eb4b0b5563824138.png ในแถบสถานะของ VSCode
  2. คลิก a19a0c68bc4046e6.png เริ่มแก้ไขข้อบกพร่อง แล้วรอให้แอปโหลด
  3. ป้อนรหัสผู้ใช้ (เช่น 42) จากนั้นเลือกแนะนำ

860d523a7ac537e0.png

Windows

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

7d77c1e52a5927fc.png

10. ขั้นตอนที่ 5: เรียกใช้แอป Flutter บนแพลตฟอร์มเว็บ

อีกสิ่งหนึ่งที่ทำได้คือการเพิ่มการสนับสนุนผ่านเว็บลงในแอป Flutter โดยค่าเริ่มต้น แพลตฟอร์มเว็บจะเปิดใช้โดยอัตโนมัติสำหรับแอป Flutter ดังนั้นคุณเพียงแค่ต้องเปิดใช้งาน

  1. ตรวจสอบว่าอุปกรณ์เป้าหมายตั้งค่าเป็น 71db93efa928d15d.png ในแถบสถานะของ VSCode
  2. คลิก a19a0c68bc4046e6.png เริ่มแก้ไขข้อบกพร่อง จากนั้นรอให้แอปโหลดในเบราว์เซอร์ Chrome
  3. ป้อนรหัสผู้ใช้ (เช่น 42) จากนั้นเลือกแนะนำ

9376e1e432c18bef.png

11. ขอแสดงความยินดี

คุณสร้างแอป Fullstack เพื่อแนะนำภาพยนตร์ให้แก่ผู้ใช้!

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

ดูข้อมูลเพิ่มเติม