<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Duc Anh Phung</title>
    <description>The latest articles on DEV Community by Duc Anh Phung (@pmda3010).</description>
    <link>https://dev.to/pmda3010</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4200591%2F92b1917f-3fd4-420f-af01-f6e462c73f0e.png</url>
      <title>DEV Community: Duc Anh Phung</title>
      <link>https://dev.to/pmda3010</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/pmda3010"/>
    <language>en</language>
    <item>
      <title>Ngày về nhà mới: trình tự lễ nhập trạch từ sáng đến tối cho gia đình làm lần đầu</title>
      <dc:creator>Duc Anh Phung</dc:creator>
      <pubDate>Tue, 10 Nov 2026 16:08:17 +0000</pubDate>
      <link>https://dev.to/pmda3010/ngay-ve-nha-moi-trinh-tu-le-nhap-trach-tu-sang-den-toi-cho-gia-dinh-lam-lan-dau-2ec0</link>
      <guid>https://dev.to/pmda3010/ngay-ve-nha-moi-trinh-tu-le-nhap-trach-tu-sang-den-toi-cho-gia-dinh-lam-lan-dau-2ec0</guid>
      <description>&lt;p&gt;Tuần trước, một người bạn nhắn cho mình lúc gần nửa đêm: "Mai nhà tao về nhà mới, giờ mới nhớ ra không biết phải mang cái gì vào trước". Bạn ấy đã chọn ngày rất kỹ, đã hỏi tuổi, hỏi hướng, nhưng lại quên mất phần quan trọng không kém: trong ngày hôm đó phải làm những gì, theo thứ tự nào. Bài này mình viết lại trình tự mà gia đình mình và vài người quen đã làm, theo kiểu checklist để bạn in ra hoặc lưu vào điện thoại.&lt;/p&gt;

&lt;p&gt;Lưu ý trước: phong tục mỗi vùng, mỗi nhà có khác nhau. Đây là trình tự phổ biến, đơn giản. Nếu nhà bạn có nếp riêng thì cứ giữ nếp nhà.&lt;/p&gt;

&lt;h2&gt;
  
  
  Phần 1: Việc cần xong trước ngày về nhà mới
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Chọn ngày và giờ.&lt;/strong&gt; Phần này nên làm trước vài tuần. Người ta thường xem ngày hợp tuổi gia chủ (người đứng tên hoặc trụ cột gia đình), tránh những ngày dân gian kiêng như Tam Nương, Nguyệt Kỵ, rồi chọn một giờ hoàng đạo để bước vào nhà. Nếu chưa biết bắt đầu từ đâu, bạn có thể đọc &lt;a href="https://amlichvietnam.vn/kien-thuc/lich-am/cach-chon-ngay-chuyen-nha" rel="noopener noreferrer"&gt;hướng dẫn chọn ngày chuyển nhà trên amlichvietnam.vn&lt;/a&gt; để hiểu các tiêu chí cơ bản trước khi tra ngày cụ thể.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lưu ý mùa cuối năm.&lt;/strong&gt; Nhiều người nhận nhà vào tháng Chạp. Năm nay, mùng 1 tháng Chạp là thứ Sáu 8/1/2027, ngày ông Táo 23 tháng Chạp là thứ Bảy 30/1/2027, và Tết Đinh Mùi là thứ Bảy 6/2/2027 (mình đã đổi các ngày này bằng thư viện lịch âm theo giờ Việt Nam). Một số gia đình muốn dọn vào trước 23 tháng Chạp để kịp cúng ông Táo ở nhà mới. Một số khác chờ ra Giêng cho thong thả. Cả hai cách đều có lý. Quan trọng là đừng chọn ngày quá sát Tết khi thợ, xe chuyển nhà đều kín lịch.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dọn dẹp và chuẩn bị sẵn:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Lau dọn sạch sẽ nhà mới, mở cửa cho thoáng ít nhất một ngày trước đó.&lt;/li&gt;
&lt;li&gt;Lắp xong điện, nước, bếp. Nhập trạch mà chưa có nước hay chưa đun được nước thì rất bất tiện.&lt;/li&gt;
&lt;li&gt;Chuẩn bị chỗ đặt bàn thờ, nếu có. Bát hương có thể chuyển sau theo nghi thức riêng, không nhất thiết đúng ngày nhập trạch.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Phần 2: Buổi sáng, đồ mang vào nhà theo thứ tự
&lt;/h2&gt;

&lt;p&gt;Theo nếp phổ biến, khi bước vào nhà lần đầu theo giờ đã chọn, gia chủ và các thành viên mang theo những đồ mang ý nghĩa "đầy đủ, ấm no":&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Gia chủ&lt;/strong&gt; cầm bát hương hoặc bếp (bếp than nhỏ, bếp gas mini, hoặc ấm đun nước). Lửa tượng trưng cho sự ấm áp và sinh khí của căn nhà.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vợ hoặc chồng của gia chủ&lt;/strong&gt; mang hũ gạo, hũ muối, bình nước đầy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Con cái&lt;/strong&gt; mang chổi mới, sách vở, đồ chơi, những vật tượng trưng cho việc học hành, nề nếp.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Người khác trong nhà&lt;/strong&gt; mang chiếu, chăn gối, bộ bát đũa.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Không phải nhà nào cũng có đủ người như vậy. Nếu chỉ có một hai người thì mang lần lượt, miễn là bếp lửa và gạo nước được đưa vào sớm.&lt;/p&gt;

&lt;h2&gt;
  
  
  Phần 3: Mâm cúng nhập trạch
&lt;/h2&gt;

&lt;p&gt;Sau khi vào nhà, gia đình bày một mâm lễ để trình báo với thần linh, thổ địa nơi ở mới và mời gia tiên về. Mâm cúng thường có:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hương, hoa tươi, đèn hoặc nến, trầu cau, rượu, nước.&lt;/li&gt;
&lt;li&gt;Một mâm mặn (xôi, gà luộc, giò) hoặc mâm chay, tùy gia đình.&lt;/li&gt;
&lt;li&gt;Hoa quả, bánh kẹo, gạo, muối.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Văn khấn nhập trạch nói rõ họ tên gia chủ, địa chỉ cũ, địa chỉ mới, ngày giờ chuyển đến và lời xin phép được ở. Nếu bạn không quen khấn dài, viết ra một bản ngắn bằng lời của mình cũng được, miễn là thành tâm và đủ thông tin.&lt;/p&gt;

&lt;h2&gt;
  
  
  Phần 4: Nhóm bếp và nồi nước đầu tiên
&lt;/h2&gt;

&lt;p&gt;Cúng xong, việc đầu tiên nhiều nhà làm là &lt;strong&gt;đun một ấm nước&lt;/strong&gt; để pha trà mời cả nhà và khách. Sau đó nấu nồi cơm đầu tiên. Ý nghĩa rất giản dị: nhà mới đã có lửa, có hơi ấm, có bữa ăn.&lt;/p&gt;

&lt;p&gt;Nếu nhà dùng bếp từ hoặc bếp điện, bạn vẫn có thể bật bếp đun nước như bình thường. Không cần bếp than nếu điều kiện không cho phép, nhất là ở chung cư có quy định phòng cháy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Phần 5: Buổi trưa và chiều, mời người thân
&lt;/h2&gt;

&lt;p&gt;Một bữa cơm nhỏ với người thân, hàng xóm mới là cách tốt để "làm quen" với khu ở. Nhiều nơi gọi đây là tiệc tân gia, nhưng không cần làm to. Năm sáu người ngồi quanh mâm cơm đầu tiên cũng đủ ấm cúng.&lt;/p&gt;

&lt;p&gt;Trong ngày đầu, cố gắng tránh cãi vã, tránh làm vỡ đồ. Không phải vì kiêng mà vì ai cũng mệt sau một ngày chuyển đồ, rất dễ căng thẳng.&lt;/p&gt;

&lt;h2&gt;
  
  
  Phần 6: Buổi tối và đêm đầu tiên
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Bật đèn sáng khắp nhà trong buổi tối đầu tiên. Nhiều nhà để một ngọn đèn nhỏ sáng cả đêm.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ngủ lại đêm đầu tiên&lt;/strong&gt; ở nhà mới. Nếu chuyển đồ chưa xong, cả nhà vẫn nên ngủ lại để "giữ nhà".&lt;/li&gt;
&lt;li&gt;Nếu vẫn còn đồ đạc ở nhà cũ, có thể chuyển dần trong các ngày sau mà không cần xem ngày lại.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Những câu hỏi thường gặp
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Nhà thuê có cần làm lễ nhập trạch không?&lt;/strong&gt; Không bắt buộc. Nhiều người ở thuê vẫn làm một mâm lễ đơn giản để tâm an. Đó là lựa chọn cá nhân.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nhận nhà rồi nhưng chưa ở ngay thì sao?&lt;/strong&gt; Có thể làm lễ vào ngày bắt đầu ở thật sự, không phải ngày nhận chìa khóa.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Chuyển nhà đúng tuần ông Táo đi vắng có kiêng không?&lt;/strong&gt; Một số gia đình tránh chuyển nhà từ 23 đến hết 29 tháng Chạp vì quan niệm Táo quân không có nhà để "nhận" gia chủ mới. Đây là quan niệm dân gian, không phải quy định. Nhưng nếu bố mẹ bạn để ý thì nên tôn trọng.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lời kết
&lt;/h2&gt;

&lt;p&gt;Về nhà mới là một trong những ngày đáng nhớ nhất của mỗi gia đình. Xem ngày giúp mình yên tâm, còn trình tự rõ ràng giúp ngày đó diễn ra nhẹ nhàng. Chúc bạn và gia đình an cư ở tổ ấm mới.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Duc Tran&lt;/em&gt;&lt;/p&gt;

</description>
      <category>vietnamese</category>
      <category>culture</category>
      <category>calendar</category>
    </item>
    <item>
      <title>How we generate ID-style photos with AI (and where AI must not be used)</title>
      <dc:creator>Duc Anh Phung</dc:creator>
      <pubDate>Mon, 09 Nov 2026 16:12:24 +0000</pubDate>
      <link>https://dev.to/pmda3010/how-we-generate-id-style-photos-with-ai-and-where-ai-must-not-be-used-5bb</link>
      <guid>https://dev.to/pmda3010/how-we-generate-id-style-photos-with-ai-and-where-ai-must-not-be-used-5bb</guid>
      <description>&lt;p&gt;An ID photo looks like the simplest image task there is: one face, plain background, fixed size. In practice it is one of the least forgiving. A portrait for social media can be stylised freely. An ID photo has to be &lt;em&gt;geometrically correct&lt;/em&gt;, &lt;em&gt;visually clean&lt;/em&gt; and, above all, &lt;em&gt;still the same person&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Our ID-photo tool at &lt;a href="https://www.coolme.vn/tao-anh-the-ai" rel="noopener noreferrer"&gt;CoolMe AI&lt;/a&gt; turns a phone selfie into a 3×4, 4×6, 2×3 or 1×1 photo with a clean background and an outfit template (suit, office shirt, áo dài and so on). Below is the general shape of an ID-photo pipeline like this one, with simplified Python to illustrate the deterministic parts, followed by the places where generative AI should be kept out.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The code and thresholds below are illustrative and simplified for the article. They are not production code; the point is the constraints they encode.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The pipeline at a glance
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;selfie ──► quality gate ──► face detection + landmarks ──► alignment &amp;amp; crop
                                                              │
                     export (print / web sizes) ◄── background ◄── light correction
                                                              │
                                              outfit template (generative, constrained)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two kinds of steps live in this pipeline:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Deterministic steps&lt;/strong&gt; – quality checks, alignment, cropping, sizing. These must give the same output for the same input, and they must be explainable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Generative steps&lt;/strong&gt; – background clean-up, light correction, outfit template. These are where models help most and where they can do the most damage.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Keeping the two separate is the main design decision. Generative models should never decide &lt;em&gt;where&lt;/em&gt; the face goes or &lt;em&gt;how big&lt;/em&gt; it is.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: a quality gate before any model runs
&lt;/h2&gt;

&lt;p&gt;Most bad ID photos are caused by bad input, not bad models. Rejecting early saves the user money and avoids "fixing" what should simply be retaken.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;cv2&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;numpy&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;quality_gate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;img_bgr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ndarray&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Return a list of human-readable problems; empty list means OK.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;problems&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="n"&gt;gray&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cv2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cvtColor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;img_bgr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cv2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;COLOR_BGR2GRAY&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Blur: variance of the Laplacian is a cheap sharpness proxy.
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cv2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Laplacian&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;gray&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cv2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CV_64F&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;var&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;problems&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Photo looks blurry. Hold the phone steady or use the rear camera.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Exposure: too dark or blown out.
&lt;/span&gt;    &lt;span class="n"&gt;mean&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;gray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mean&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;mean&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;70&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;problems&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Photo is too dark. Face a window or a light source.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;mean&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;problems&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Photo is overexposed. Move away from direct light.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Resolution: ID prints need real pixels.
&lt;/span&gt;    &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;gray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shape&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;600&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;problems&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Resolution is too low for printing.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;problems&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The thresholds are placeholders; you tune them on your own data. The important part is that the messages tell the user &lt;em&gt;what to do&lt;/em&gt;, not just that something failed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: alignment and crop are pure geometry
&lt;/h2&gt;

&lt;p&gt;Once you have facial landmarks (any decent landmark model works), the crop is arithmetic: level the eyes, then place the face so that the head occupies a fixed share of the frame height.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;math&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;align_and_crop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;img&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;left_eye&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;right_eye&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;chin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;crown&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ratio&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;head_share&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.62&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    left_eye, right_eye, chin, crown: (x, y) pixel coordinates.
    ratio: output aspect ratio (w, h), e.g. (3, 4) or (2, 3).
    head_share: crown-to-chin height as a fraction of output height.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="c1"&gt;# 1) Rotate so the eyes are level.
&lt;/span&gt;    &lt;span class="n"&gt;dx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;right_eye&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;left_eye&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;right_eye&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;left_eye&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;angle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;degrees&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;atan2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dx&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;cx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;left_eye&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;right_eye&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;left_eye&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;right_eye&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
    &lt;span class="n"&gt;M&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cv2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getRotationMatrix2D&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;cx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;angle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;rotated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cv2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;warpAffine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;img&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;M&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;img&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shape&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;img&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shape&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt; &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;cv2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;INTER_CUBIC&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;rot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;
        &lt;span class="nf"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;M&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;M&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;M&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;M&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;M&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;M&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

    &lt;span class="n"&gt;chin_r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;crown_r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;rot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chin&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;rot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;crown&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# 2) Size the frame from the head height.
&lt;/span&gt;    &lt;span class="n"&gt;head_h&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;chin_r&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;crown_r&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;out_h&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;head_h&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;head_share&lt;/span&gt;
    &lt;span class="n"&gt;out_w&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;out_h&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;ratio&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;ratio&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="c1"&gt;# 3) Centre horizontally on the eyes, leave a small margin above the crown.
&lt;/span&gt;    &lt;span class="n"&gt;top&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;crown_r&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;out_h&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.10&lt;/span&gt;
    &lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cx&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;out_w&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
    &lt;span class="n"&gt;x0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;x1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;out_w&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;out_h&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;x0&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;y0&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;x1&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;rotated&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shape&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;y1&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;rotated&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shape&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Face is too close to the edge. Ask the user to step back.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;rotated&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;y0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;y1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;x1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice what this function refuses to do: it does not pad the image with generated content when the head is cut off. If the shoulders or the top of the head are missing, the honest answer is "retake the photo", not "let a model invent them".&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: generative steps, with a short leash
&lt;/h2&gt;

&lt;p&gt;Background clean-up, light balancing and outfit templates are where generative models earn their place. A selfie taken in a bedroom becomes a flat white or light-blue background; harsh shadows are softened; a T-shirt becomes the suit template the user picked.&lt;/p&gt;

&lt;p&gt;These steps need a short leash. Three constraints are worth building in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Face region is protected.&lt;/strong&gt; Generative edits are masked so they apply to background, clothing and lighting, not to facial geometry.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Identity check after generation.&lt;/strong&gt; Compare a face embedding of the output with the input. If similarity drops below a threshold, discard the result instead of showing it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mild by default.&lt;/strong&gt; Skin smoothing and light correction start at a low strength. The goal is "photographed on a good day", not "a different person".&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A minimal version of the identity check looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;same_person&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;emb_in&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ndarray&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;emb_out&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ndarray&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;threshold&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.6&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Cosine similarity between L2-normalised face embeddings.
&lt;/span&gt;    &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;emb_in&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;linalg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;norm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;emb_in&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;emb_out&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;linalg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;norm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;emb_out&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;threshold&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The threshold depends on the embedding model; calibrate it on pairs you know are the same person and pairs you know are not.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: export for paper and for screens
&lt;/h2&gt;

&lt;p&gt;Print sizes are physical (3×4 cm, 4×6 cm), while screens care about aspect ratio. Export by DPI for print and by pixels for the web:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;cm_to_px&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dpi&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cm&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mf"&gt;2.54&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;dpi&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;PRINT_SIZES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3x4&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;cm_to_px&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;cm_to_px&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;4x6&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;cm_to_px&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;cm_to_px&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;))}&lt;/span&gt;
&lt;span class="c1"&gt;# 3x4 at 300 dpi -&amp;gt; 354 x 472 px; 4x6 -&amp;gt; 472 x 709 px
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A common user mistake is printing with "fit to page" enabled, which silently rescales the photo. It is worth warning about this near the download step, because no amount of AI fixes a printer setting.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where AI must not be used
&lt;/h2&gt;

&lt;p&gt;This is the part that matters most, and it applies to anyone building in this space.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Do not change identity.&lt;/strong&gt; No face slimming, eye enlarging, nose reshaping or age changes on an ID photo. A recruiter or an officer has to recognise the person in front of them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Do not invent missing anatomy.&lt;/strong&gt; If the crown or shoulders are out of frame, ask for a retake instead of outpainting.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Do not promise official acceptance.&lt;/strong&gt; Passport and visa offices publish their own rules, and many forbid digitally altered photos. For those documents, the product should tell users to check the official guideline, and in doubt, to use a photo studio.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Do not add things that are not true.&lt;/strong&gt; Uniforms, badges or insignia of organisations the user does not belong to are off-limits.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Do not keep photos longer than needed.&lt;/strong&gt; Face images are sensitive personal data. Process for the user's request, let them download, and set a clear retention policy.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Split the pipeline into deterministic geometry and constrained generation.&lt;/li&gt;
&lt;li&gt;Reject bad input early with actionable messages.&lt;/li&gt;
&lt;li&gt;Protect the face region and verify identity after every generative step.&lt;/li&gt;
&lt;li&gt;Be explicit about which documents your tool is &lt;em&gt;not&lt;/em&gt; for.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you read Vietnamese, there is a longer overview of how the studio is organised and how its credit model works in &lt;a href="https://coolmevn.blogspot.com/2026/10/coolme-ai-studio-la-gi.html" rel="noopener noreferrer"&gt;this introduction to CoolMe AI Studio&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;How do you handle identity preservation in your own image pipelines? I would be glad to compare notes in the comments.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>computervision</category>
      <category>python</category>
      <category>product</category>
    </item>
    <item>
      <title>Người trẻ lễ Phật trên điện thoại: trào lưu đi chùa online lan nhanh</title>
      <dc:creator>Duc Anh Phung</dc:creator>
      <pubDate>Fri, 06 Nov 2026 05:39:21 +0000</pubDate>
      <link>https://dev.to/pmda3010/nguoi-tre-le-phat-tren-dien-thoai-trao-luu-di-chua-online-lan-nhanh-5ea3</link>
      <guid>https://dev.to/pmda3010/nguoi-tre-le-phat-tren-dien-thoai-trao-luu-di-chua-online-lan-nhanh-5ea3</guid>
      <description>&lt;p&gt;Không ít bạn trẻ đang biến việc lễ Phật trên trình duyệt thành một nhịp cuối tuần, nhất là khi ở xa chùa hoặc lịch làm việc dày.&lt;/p&gt;

&lt;p&gt;Trào lưu này không xuất hiện trong khoảng trống. Trước đó, các sản phẩm thiền và lễ chùa trên điện thoại đã gây chú ý ở một số thị trường châu Á. Khi lan sang Việt Nam, cùng một nhu cầu được giữ nhịp sống tâm linh giữa lịch làm việc dày, nhưng cách triển khai lại rất khác nhau. Có trang nghiêng về tương tác kiểu trò chơi. Có trang tập trung tái hiện không gian lễ với hương, chuông, mõ và lời khấn.&lt;/p&gt;

&lt;p&gt;AmLichVietnam.vn chọn hướng thứ hai. Trang &lt;a href="https://amlichvietnam.vn/chua-online" rel="noopener noreferrer"&gt;Chùa Online&lt;/a&gt; chạy ngay trên trình duyệt, không cần tải ứng dụng, không bắt buộc tạo tài khoản và không thu tiền công đức. Người dùng nên đeo tai nghe: tiếng chuông và tiếng mõ được thiết kế để tạo không khí lễ, khác với thao tác bấm cho có trên một giao diện tĩnh.&lt;/p&gt;

&lt;h2&gt;
  
  
  Từ trào lưu đến thao tác thực tế
&lt;/h2&gt;

&lt;p&gt;Hiện trang đã mở bốn không gian: Chùa Một Cột (Ba Đình, Hà Nội), Chùa Trấn Quốc (Tây Hồ, Hà Nội), Chùa Bái Đính (Gia Viễn, Ninh Bình) và Chùa Thiên Mụ (TP. Huế). Các điểm Chùa Hương, Yên Tử, Miếu Bà Chúa Xứ Núi Sam và Chùa Vĩnh Nghiêm được ghi là sắp mở.&lt;/p&gt;

&lt;p&gt;Cách tham gia tương đối thẳng: mở &lt;a href="https://amlichvietnam.vn/chua-online" rel="noopener noreferrer"&gt;https://amlichvietnam.vn/chua-online&lt;/a&gt;, bấm “Vào chùa” rồi chọn nơi lễ. Tại lư hương, người dùng thắp ba nén hương, sau đó thỉnh chuông và gõ mõ. Tiếp theo có thể lần tràng hạt 108 hạt, viết lời khấn rồi hồi hướng công đức. Ai muốn lễ cùng người khác thì vào Phòng chung để ngồi thiền, lạy Phật theo thời gian thực; trang còn có khóa thiền chung 15 phút và bảng công đức theo tuần.&lt;/p&gt;

&lt;p&gt;Một chi tiết gắn với lịch Việt Nam là trang hiển thị âm lịch từng ngày và cho phép bật thông báo nhắc Rằm, Mùng 1 cùng các ngày lễ Phật. Đây là điểm nhiều người đi làm văn phòng thường bỏ sót: không phải ai cũng nhớ rằm rơi vào thứ mấy trong tuần, nhất là những tháng âm lịch lệch khá xa so với lịch dương.&lt;/p&gt;

&lt;p&gt;Đơn vị vận hành cũng lưu ý đây là không gian 3D cách điệu, lấy cảm hứng từ kiến trúc di tích, không thay cho việc đến chùa thật. Cách dùng phù hợp là giữ sự trang nghiêm tối thiểu, coi đây là nhịp lễ khi chưa đến được hiện trường, chứ không biến nơi khấn nguyện thành trò đùa trên mạng.&lt;/p&gt;

&lt;h2&gt;
  
  
  Khi người dùng “đi chùa xong” thường xem tiếp vận hạn và duyên số
&lt;/h2&gt;

&lt;p&gt;Quan sát các cuộc thảo luận quanh trào lưu này cho thấy một mạch khá quen thuộc của người Việt: sau lúc muốn tĩnh lại, nhiều người lại mở tiếp tử vi, tình duyên hoặc lịch ngày tốt. AmLichVietnam.vn vốn xuất phát từ lịch âm và các công cụ tra cứu, nên nhóm tính năng này được làm khá bài bản, khác với những trang chỉ trả về một đoạn văn chung cho mọi người.&lt;/p&gt;

&lt;p&gt;Tại &lt;a href="https://amlichvietnam.vn/tu-vi" rel="noopener noreferrer"&gt;https://amlichvietnam.vn/tu-vi&lt;/a&gt;, người dùng nhập ngày sinh dương lịch, giới tính và giờ sinh để lập lá số. Không nhớ giờ vẫn chọn một khung giờ tham khảo; hệ thống ghi chú đây chưa phải giờ xác nhận. Kết quả miễn phí đã gồm địa bàn 12 cung theo cách an sao Nam phái, với cung Mệnh, cung Thân, chính tinh, phụ tinh và tứ hóa hiện trên web. Người xem còn có bảng lưu niên, đại hạn, luận các cung ở mức rút gọn và tải được ảnh địa bàn dạng PNG để lưu hoặc gửi người nhà.&lt;/p&gt;

&lt;p&gt;Nếu cần đọc sâu hơn, trang mở thêm gói luận Premium: kể mạch đời theo lá số, luận theo hướng nghề nghiệp, tài lộc, tình duyên, học hành và vận năm, kèm sách luận đọc liền mạch. Phần hỏi đáp AI được gắn với đúng lá vừa lập, thay vì trả lời chung chung theo prompt trống. Kết quả vẫn được nêu rõ là tham khảo văn hóa, không thay tư vấn chuyên môn. Điểm khác nằm ở độ phủ của địa bàn và cách trình bày có lớp, thay vì một đoạn “lời khuyên năm nay” giống nhau cho hàng loạt người dùng.&lt;/p&gt;

&lt;p&gt;Công cụ &lt;a href="https://amlichvietnam.vn/tinh-duyen" rel="noopener noreferrer"&gt;tình duyên&lt;/a&gt; cũng đi theo hướng đối chiếu chứ không kết luận bằng một chữ “hợp” hoặc “không hợp”. Người dùng nhập họ tên và ngày sinh của hai người; có giờ sinh thì hệ thống đọc thêm cung Phu Thê, chưa rõ giờ vẫn xem được phần lớn kết quả. Bản miễn phí cho điểm hợp đôi, một kết luận ngắn, ba điểm nổi bật và biểu đồ radar theo từng chiều. Nền tảng đối chiếu cùng lúc can chi, Tử Vi và thần số Pythagorean. Bản đầy đủ hơn còn mở luận hai lá số, Bát Tự của cả hai người, tương hợp theo tính cách, giao tiếp, tài chính, gia đình, sự nghiệp lẫn mức gần gũi, cùng gợi ý năm thuận cưới. Trang nhấn mạnh đây là dữ liệu tham khảo, không thay lời trao đổi trực tiếp giữa hai người.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lịch âm và ngày tốt: phần ít “viral” nhưng được xem kỹ hơn
&lt;/h2&gt;

&lt;p&gt;Nếu chùa online đang hút tương tác vì hình ảnh đẹp và dễ chia sẻ, thì lịch âm và ngày tốt mới là phần người Việt tra đi tra lại quanh việc cưới hỏi, xuất hành, khai trương hay nhập trạch. &lt;a href="https://amlichvietnam.vn/lich-am" rel="noopener noreferrer"&gt;Lịch âm&lt;/a&gt; trên cùng hệ thống đối chiếu ngày âm – dương, rằm, mùng 1 và tiết khí theo năm. &lt;a href="https://amlichvietnam.vn/ngay-tot" rel="noopener noreferrer"&gt;Ngày tốt&lt;/a&gt; cho phép xem theo việc cụ thể, thay vì gộp mọi nhu cầu thành một dòng “hôm nay đại cát”.&lt;/p&gt;

&lt;p&gt;Đây là điểm khá khác biệt so với nhiều trang đón trend chỉ gắn một lịch nhỏ cho có. Việc chọn ngày lớn trong đời vốn đòi hỏi tra đúng việc, thấy được cả ngày nên làm và ngày nên tránh. Một công cụ nêu rõ từng việc sẽ hữu ích hơn một câu chúc may mắn đi kèm hình ảnh lan tỏa trên mạng.&lt;/p&gt;

&lt;h2&gt;
  
  
  Một lượt xem cho cả trào lưu lẫn nhu cầu tra cứu thường ngày
&lt;/h2&gt;

&lt;p&gt;Người đang tò mò về trào lưu có thể đi một mạch trên cùng website:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Lễ chùa trên điện thoại: &lt;a href="https://amlichvietnam.vn/chua-online" rel="noopener noreferrer"&gt;https://amlichvietnam.vn/chua-online&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Lập lá số tử vi: &lt;a href="https://amlichvietnam.vn/tu-vi" rel="noopener noreferrer"&gt;https://amlichvietnam.vn/tu-vi&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Xem tình duyên đôi: &lt;a href="https://amlichvietnam.vn/tinh-duyen" rel="noopener noreferrer"&gt;https://amlichvietnam.vn/tinh-duyen&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Xem lịch âm: &lt;a href="https://amlichvietnam.vn/lich-am" rel="noopener noreferrer"&gt;https://amlichvietnam.vn/lich-am&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Xem ngày tốt theo việc: &lt;a href="https://amlichvietnam.vn/ngay-tot" rel="noopener noreferrer"&gt;https://amlichvietnam.vn/ngay-tot&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Trào lưu “đi chùa online” có thể hạ nhiệt khi mạng xã hội chuyển sang chủ đề khác. Nhưng nhu cầu lễ khi chưa đến được chùa, nhu cầu đọc lá số có địa bàn rõ và nhu cầu tra ngày tốt theo đúng việc thì không phụ thuộc hashtag. Đó cũng là lý do một trang gắn được không gian lễ với lịch âm, tử vi và tình duyên sẽ được dùng lâu hơn một sản phẩm chỉ tồn tại trong vòng vài tuần sốt mạng.&lt;/p&gt;

</description>
      <category>vietnam</category>
      <category>culture</category>
      <category>webdev</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Batch video editing with Adobe Premiere scripting: lessons learned</title>
      <dc:creator>Duc Anh Phung</dc:creator>
      <pubDate>Fri, 30 Oct 2026 22:27:22 +0000</pubDate>
      <link>https://dev.to/pmda3010/batch-video-editing-with-adobe-premiere-scripting-lessons-learned-2458</link>
      <guid>https://dev.to/pmda3010/batch-video-editing-with-adobe-premiere-scripting-lessons-learned-2458</guid>
      <description>&lt;p&gt;Scripting a single Premiere Pro edit is a fun weekend project. Running the same script over fifty folders of footage overnight, and finding fifty usable exports in the morning, is a different problem. Most of the difficulty is not in the editing logic. It is in everything around it: timing, file paths, partial failures and the render queue.&lt;/p&gt;

&lt;p&gt;This post collects the lessons that apply to any batch pipeline built on Premiere's scripting layer (ExtendScript, usually reached from a CEP panel). The examples are simplified and illustrative, not production code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lesson 1: separate the plan from the timeline
&lt;/h2&gt;

&lt;p&gt;The most useful design decision is to never let analysis code touch the timeline directly. Instead, each job produces a plain JSON &lt;em&gt;edit plan&lt;/em&gt;, and a separate, boring step applies that plan to Premiere.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"job_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"C017"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"D:/footage/C017/main.mp4"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"sequence_preset"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1080p25"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"segments"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"in"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;3.20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"out"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;18.75&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"in"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;21.10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"out"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;47.40&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"captions_srt"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"D:/footage/C017/C017.srt"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"exports"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"16x9"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"9x16"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This gives you three things for free. You can inspect and diff a plan before anything is cut. You can re-apply a plan after Premiere crashes without re-running analysis. And you can generate plans with whatever tool you like, whether that is a rule-based script or an AI agent, while the apply step stays deterministic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lesson 2: measure silence on the source file, not on the timeline
&lt;/h2&gt;

&lt;p&gt;Cutting dead air is the first thing most people automate. It is tempting to inspect audio levels inside Premiere, but it is slower and harder to test than running &lt;code&gt;ffmpeg&lt;/code&gt; on the source once:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-hide_banner&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; main.mp4 &lt;span class="nt"&gt;-af&lt;/span&gt; &lt;span class="nv"&gt;silencedetect&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;noise&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nt"&gt;-35dB&lt;/span&gt;:d&lt;span class="o"&gt;=&lt;/span&gt;0.6 &lt;span class="nt"&gt;-f&lt;/span&gt; null - 2&amp;gt; silence.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;silencedetect&lt;/code&gt; writes &lt;code&gt;silence_start&lt;/code&gt; and &lt;code&gt;silence_end&lt;/code&gt; lines to stderr. Turning them into keep-segments is a few lines of Python:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;keep_segments&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;log_text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pad&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.15&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;starts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;silence_start: ([\d.]+)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;log_text&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="n"&gt;ends&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;silence_end: ([\d.]+)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;log_text&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="n"&gt;segments&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cursor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;starts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ends&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;cursor&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mf"&gt;0.3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="c1"&gt;# ignore tiny islands of sound
&lt;/span&gt;            &lt;span class="n"&gt;segments&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;in&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cursor&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;pad&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;out&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;pad&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="n"&gt;cursor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;duration&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;cursor&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mf"&gt;0.3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;segments&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;in&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cursor&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;pad&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;out&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;segments&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The threshold (&lt;code&gt;-35dB&lt;/code&gt;) and minimum duration (&lt;code&gt;0.6s&lt;/code&gt;) depend on the microphone and the room. Tune them per series, store them in the plan, and keep the padding so words are not clipped.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lesson 3: Premiere counts time in ticks
&lt;/h2&gt;

&lt;p&gt;When you apply a plan, remember that Premiere's scripting API represents time in &lt;em&gt;ticks&lt;/em&gt;, with 254,016,000,000 ticks per second. Floating-point seconds are fine in your plan, but convert once, at the boundary, and round consistently:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ExtendScript (ES3-era JavaScript)&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;TICKS_PER_SECOND&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;254016000000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;secondsToTicks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sec&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sec&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;TICKS_PER_SECOND&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;insertSegment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;seq&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;projectItem&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;seg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;atSeconds&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Time&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ticks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;secondsToTicks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;atSeconds&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// In real code, set the in/out on a subclip or trim the track item after inserting.&lt;/span&gt;
  &lt;span class="nx"&gt;seq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;videoTracks&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;insertClip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;projectItem&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Many "off by one frame" bugs in batch pipelines come from converting seconds to frames in one place and seconds to ticks in another. Pick one direction and stick to it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lesson 4: make every job resumable
&lt;/h2&gt;

&lt;p&gt;A batch of fifty jobs will fail somewhere: a corrupt clip, a missing font, a full disk. The pipeline should treat each job as a small state machine and write its state to disk after each step:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;planned -&amp;gt; imported -&amp;gt; assembled -&amp;gt; captioned -&amp;gt; queued -&amp;gt; exported
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On restart, the runner skips finished steps and continues from the last good one. Two rules make this reliable:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Idempotent steps.&lt;/strong&gt; Running "import" twice must not create duplicate bins. Check before you create.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One project per job, or one clearly named sequence per job.&lt;/strong&gt; Sharing a sequence across jobs makes partial failures very hard to clean up.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Lesson 5: let Adobe Media Encoder own the render queue
&lt;/h2&gt;

&lt;p&gt;Rendering inside Premiere blocks the scripting thread. Queueing exports to Adobe Media Encoder lets the next job start assembling while the previous one renders:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;queueExport&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;seq&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;outPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;presetPath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;encoder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;launchEncoder&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="c1"&gt;// workAreaType 0 = entire sequence; last arg: remove from queue when done&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;jobId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;encoder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encodeSequence&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;seq&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;outPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;presetPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;jobId&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// After all jobs are queued:&lt;/span&gt;
&lt;span class="c1"&gt;// app.encoder.startBatch();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keep one &lt;code&gt;.epr&lt;/code&gt; preset per output format (16:9 for YouTube, 9:16 for Shorts and Reels) under version control, so a colleague's local preset change does not silently alter your exports.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lesson 6: validate before you export
&lt;/h2&gt;

&lt;p&gt;Before queueing a render, check what you can check cheaply: every segment has &lt;code&gt;out &amp;gt; in&lt;/code&gt;, the caption file exists and its last cue ends before the sequence does, the expected tracks are present, and the output folder is writable. A failed validation should mark the job as &lt;code&gt;needs_review&lt;/code&gt; instead of exporting something broken that someone might publish by accident.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lesson 7: keep a human approval step
&lt;/h2&gt;

&lt;p&gt;Automation is good at the repetitive 80%: trimming silence, placing captions, reframing to vertical, rendering. Judgement calls such as whether a joke lands, whether a product claim is accurate, or whether a clip is safe to publish still belong to a person. A simple review folder with the export and its plan side by side works better than any dashboard.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this is going
&lt;/h2&gt;

&lt;p&gt;Tools are starting to wrap this whole loop behind a chat interface. One example is &lt;a href="https://www.coolme.vn/coolme-ai-premiere-automation" rel="noopener noreferrer"&gt;Premiere Pro automation&lt;/a&gt; from CoolMe (the page is in Vietnamese), a Windows tool where an AI agent such as Grok or Claude reads the footage, builds an edit plan, applies cuts and captions in Premiere and queues renders, reporting back when jobs finish or fail. Whatever tool you use, the lessons above still apply: plans you can read, steps you can resume and renders you can trust.&lt;/p&gt;

&lt;p&gt;What has broken most often in your own batch editing pipelines? I would like to hear about it in the comments.&lt;/p&gt;

</description>
      <category>automation</category>
      <category>video</category>
      <category>javascript</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Hai nhà bàn chuyện cưới năm 2027: những câu hỏi về tuổi nên thống nhất trước khi chọn ngày</title>
      <dc:creator>Duc Anh Phung</dc:creator>
      <pubDate>Fri, 30 Oct 2026 14:40:04 +0000</pubDate>
      <link>https://dev.to/pmda3010/hai-nha-ban-chuyen-cuoi-nam-2027-nhung-cau-hoi-ve-tuoi-nen-thong-nhat-truoc-khi-chon-ngay-1inm</link>
      <guid>https://dev.to/pmda3010/hai-nha-ban-chuyen-cuoi-nam-2027-nhung-cau-hoi-ve-tuoi-nen-thong-nhat-truoc-khi-chon-ngay-1inm</guid>
      <description>&lt;p&gt;Có một kịch bản rất hay gặp: hai bạn trẻ đã yêu nhau vài năm, quyết định cưới sau Tết. Bố mẹ hai bên gặp nhau, không khí vui vẻ, rồi đến đoạn "để nhà tôi đi xem tuổi đã". Một tuần sau, một bên báo "năm sau cô dâu phạm Kim Lâu", bên kia lại nói "thầy nhà tôi bảo không sao". Thế là chuyện vui thành chuyện khó xử.&lt;/p&gt;

&lt;p&gt;Phần lớn những va chạm kiểu này không đến từ việc ai tin hay không tin, mà đến từ việc hai bên dùng hai cách tính khác nhau mà không ai nói ra. Bài này gợi ý những câu hỏi nên thống nhất từ đầu, để khi chọn ngày, mọi người cùng nhìn vào một bộ tiêu chí.&lt;/p&gt;

&lt;h2&gt;
  
  
  Câu hỏi 1: Tính tuổi theo tuổi mụ hay tuổi thật?
&lt;/h2&gt;

&lt;p&gt;Trong cách xem tuổi cưới truyền thống, người ta thường dùng &lt;strong&gt;tuổi mụ&lt;/strong&gt; (tuổi âm), tức lấy năm xem trừ năm sinh âm lịch rồi cộng thêm 1. Ví dụ cô dâu sinh năm 2000, đến năm 2027 thì tuổi mụ là 28.&lt;/p&gt;

&lt;p&gt;Nghe thì đơn giản, nhưng có một cái bẫy: người sinh vào tháng 1 hoặc đầu tháng 2 dương lịch có thể vẫn thuộc năm âm lịch trước. Ví dụ một người sinh đầu năm 2000 dương lịch nhưng trước Tết Canh Thìn thì năm sinh âm lịch là Kỷ Mão 1999. Chỉ một chi tiết này thôi đã có thể khiến hai thầy cho hai kết quả khác nhau. Vì vậy, việc đầu tiên là đổi ngày sinh của cả hai sang âm lịch cho chắc.&lt;/p&gt;

&lt;h2&gt;
  
  
  Câu hỏi 2: Hai nhà có xét Kim Lâu không, và xét theo cách nào?
&lt;/h2&gt;

&lt;p&gt;Kim Lâu là một quan niệm dân gian xét tuổi người phụ nữ khi cưới. Cách tính phổ biến: lấy tuổi mụ chia cho 9, nếu số dư là 1, 3, 6 hoặc 8 thì năm đó được coi là phạm Kim Lâu.&lt;/p&gt;

&lt;p&gt;Áp vào năm 2027, theo cách tính này thì những cô dâu sinh năm âm lịch 1995, 1998, 2000 và 2002 rơi vào tuổi mụ có số dư thuộc nhóm trên. Còn sinh năm 1996, 1997, 1999, 2001 thì không. (Mình tự tính lại bằng phép chia, bạn có thể kiểm lại dễ dàng.)&lt;/p&gt;

&lt;p&gt;Nhưng điều quan trọng hơn con số là thái độ của hai nhà:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Có nhà coi Kim Lâu là điều kiện bắt buộc, phạm là dời năm.&lt;/li&gt;
&lt;li&gt;Có nhà chỉ coi là tham khảo, và chọn cách "xin dâu" hoặc tổ chức sau một mốc nhất định như qua Lập Xuân.&lt;/li&gt;
&lt;li&gt;Có nhà không xét.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hãy nói thẳng nhau từ đầu nhà mình thuộc nhóm nào. Nếu một bên xét kỹ còn bên kia không, thì thường bên không xét sẽ nhường, vì nhường cũng chẳng mất gì mà giữ được hòa khí.&lt;/p&gt;

&lt;h2&gt;
  
  
  Câu hỏi 3: Năm 2027 có ai trong nhà gặp Tam Tai không?
&lt;/h2&gt;

&lt;p&gt;Năm Đinh Mùi 2027 là năm thứ ba (năm cuối) của chu kỳ Tam Tai đối với ba tuổi &lt;strong&gt;Hợi, Mão, Mùi&lt;/strong&gt;. Trong dân gian, có nhà kiêng làm việc lớn trong năm Tam Tai của người chủ hôn, có nhà không.&lt;/p&gt;

&lt;p&gt;Nên hỏi trước: nhà mình xét Tam Tai theo tuổi cô dâu chú rể, hay theo tuổi bố mẹ đứng ra tổ chức? Mỗi nơi một lệ, và đây là chỗ hay gây hiểu lầm nhất.&lt;/p&gt;

&lt;h2&gt;
  
  
  Câu hỏi 4: Xét hợp tuổi đến mức nào?
&lt;/h2&gt;

&lt;p&gt;Ngoài chuyện năm cưới, nhiều gia đình còn xem hai tuổi có hợp nhau không: theo địa chi (tam hợp, lục hợp, xung, hại), theo ngũ hành nạp âm của năm sinh, hoặc theo cung phi. Mỗi hệ có một kết luận, và hiếm có cặp nào "đẹp" ở tất cả các hệ.&lt;/p&gt;

&lt;p&gt;Gợi ý của mình là chọn một hệ chính mà cả hai nhà đều chấp nhận, rồi coi các hệ khác là tham khảo. Nếu muốn hiểu các hệ này khác nhau thế nào và đọc kết quả sao cho tỉnh táo, bạn có thể xem &lt;a href="https://amlichvietnam.vn/kien-thuc/lich-am/xem-tuoi-ket-hon" rel="noopener noreferrer"&gt;bài xem tuổi kết hôn theo can chi của Âm Lịch Việt Nam&lt;/a&gt;. Bài viết giải thích rõ từng yếu tố, đọc xong sẽ dễ nói chuyện với người lớn hơn.&lt;/p&gt;

&lt;h2&gt;
  
  
  Câu hỏi 5: Ai là người "chốt" cuối cùng?
&lt;/h2&gt;

&lt;p&gt;Nghe có vẻ thừa, nhưng rất nhiều cuộc bàn bạc kéo dài vì không ai được giao quyền quyết. Có thể là ông bà nội, có thể là bố mẹ cô dâu, có thể là chính hai bạn trẻ. Thống nhất người chốt từ đầu giúp tránh tình trạng mỗi tuần một ý kiến mới.&lt;/p&gt;

&lt;h2&gt;
  
  
  Một quy trình gọn cho hai nhà
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Hai bạn trẻ đổi ngày sinh sang âm lịch, gửi cho cả hai nhà cùng một bản.&lt;/li&gt;
&lt;li&gt;Mỗi bên nói rõ nhà mình có xét Kim Lâu, Tam Tai, hợp tuổi hay không.&lt;/li&gt;
&lt;li&gt;Chọn khoảng thời gian cưới dự kiến (ví dụ sau rằm tháng Giêng 2027, tức sau thứ Bảy 20/2/2027).&lt;/li&gt;
&lt;li&gt;Mới bắt đầu chọn ngày cụ thể trong khoảng đó: ngày hoàng đạo, tránh ngày gia đình kiêng, hợp lịch làm việc của khách.&lt;/li&gt;
&lt;li&gt;Ghi lại kết quả bằng văn bản, gửi vào nhóm chung để không ai nhớ nhầm.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Khi kết quả không như ý
&lt;/h2&gt;

&lt;p&gt;Nếu sau tất cả mà năm 2027 vẫn bị coi là chưa đẹp, đừng vội nghĩ là "không hợp nên không cưới được". Các gia đình vẫn có nhiều cách: dời ngày sang cuối năm, làm lễ ăn hỏi trước rồi cưới sau, hoặc tổ chức đăng ký kết hôn trước và làm tiệc sau. Điều cốt lõi của một đám cưới là hai người và hai gia đình về chung một nhà, còn ngày tháng chỉ là cách người lớn gửi gắm mong muốn bình an.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lời kết
&lt;/h2&gt;

&lt;p&gt;Xem tuổi cưới là phong tục đẹp khi nó giúp hai nhà cẩn trọng và tôn trọng nhau. Nó chỉ trở thành gánh nặng khi mỗi bên dùng một thước đo mà không nói ra. Chịu khó thống nhất năm câu hỏi ở trên trước khi chọn ngày, bạn sẽ thấy cả quá trình nhẹ nhàng hơn rất nhiều.&lt;/p&gt;

</description>
      <category>vietnamese</category>
      <category>culture</category>
      <category>calendar</category>
    </item>
    <item>
      <title>Tháng nhuận trong âm lịch Việt Nam: quy tắc 'không trung khí' và những năm dễ tính sai</title>
      <dc:creator>Duc Anh Phung</dc:creator>
      <pubDate>Fri, 23 Oct 2026 14:14:04 +0000</pubDate>
      <link>https://dev.to/pmda3010/thang-nhuan-trong-am-lich-viet-nam-quy-tac-khong-trung-khi-va-nhung-nam-de-tinh-sai-1fj6</link>
      <guid>https://dev.to/pmda3010/thang-nhuan-trong-am-lich-viet-nam-quy-tac-khong-trung-khi-va-nhung-nam-de-tinh-sai-1fj6</guid>
      <description>&lt;h1&gt;
  
  
  Tháng nhuận trong âm lịch Việt Nam: quy tắc "không trung khí" và những năm dễ tính sai
&lt;/h1&gt;

&lt;p&gt;Nếu bạn từng phải hiển thị ngày âm trong một ứng dụng cho người Việt, có lẽ bạn đã gặp câu hỏi: năm nay có tháng nhuận không, nhuận tháng mấy? Đây là phần khó nhất của bài toán âm lịch, và cũng là chỗ mà copy một hàm trên mạng dễ cho ra kết quả sai nhất. Bài này tóm tắt quy tắc, cách cài đặt và vài năm nên đưa vào bộ test.&lt;/p&gt;

&lt;h2&gt;
  
  
  Âm lịch Việt Nam là âm dương lịch
&lt;/h2&gt;

&lt;p&gt;Tháng âm bắt đầu vào ngày có điểm Sóc (trăng mới). Một tháng dài 29 hoặc 30 ngày, tùy khoảng cách giữa hai điểm Sóc liên tiếp. 12 tháng âm chỉ khoảng 354 ngày, ngắn hơn năm Mặt Trời chừng 11 ngày. Cứ khoảng 2–3 năm lại phải chèn thêm một tháng để lịch không trôi khỏi mùa. Tháng chèn thêm đó là tháng nhuận.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quy tắc xác định tháng nhuận
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Tìm tháng 11 âm của năm trước và tháng 11 âm của năm cần tính. Tháng 11 âm là tháng chứa Đông chí.&lt;/li&gt;
&lt;li&gt;Đếm số lần Sóc nằm giữa hai mốc đó. Nếu có 13 tháng âm thay vì 12, năm đó có tháng nhuận.&lt;/li&gt;
&lt;li&gt;Tháng nhuận là &lt;strong&gt;tháng đầu tiên sau tháng 11 không chứa trung khí nào&lt;/strong&gt;. Trung khí là 12 tiết khí ứng với kinh độ Mặt Trời 0°, 30°, 60°… như Xuân phân, Cốc vũ, Hạ chí.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Viết dạng giả mã:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;a11 = ngay_bat_dau_thang_11(nam - 1)
b11 = ngay_bat_dau_thang_11(nam)
if (b11 - a11) &amp;gt; 365:            # có 13 tháng âm
    k = 1
    while trung_khi(soc(a11, k)) == trung_khi(soc(a11, k + 1)):
        k += 1                   # tháng k không có trung khí mới
    thang_nhuan = k - 1          # đổi về số thứ tự tháng âm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Chìa khóa là hai hàm &lt;code&gt;soc()&lt;/code&gt; (thời điểm trăng mới) và &lt;code&gt;trung_khi()&lt;/code&gt; (kinh độ Mặt Trời tại đầu ngày). Cả hai đều phải tính &lt;strong&gt;theo giờ Việt Nam, UTC+7&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Vì sao múi giờ lại quan trọng đến vậy
&lt;/h2&gt;

&lt;p&gt;Điểm Sóc là một khoảnh khắc thiên văn. Nếu Sóc rơi vào 23h30 theo giờ Hà Nội thì đó đã là 0h30 ngày hôm sau theo giờ Bắc Kinh. Một tháng âm có thể bắt đầu lệch một ngày. Khi cái lệch đó rơi đúng vào tháng Giêng, Tết cũng lệch theo. Ví dụ năm 2007, Tết Nguyên Đán ở Việt Nam là 17/2/2007, còn Tết theo lịch Trung Quốc là 18/2/2007.&lt;/p&gt;

&lt;p&gt;Vì vậy dùng nguyên một thư viện âm lịch Trung Quốc (tính theo UTC+8) cho người dùng Việt là một lỗi kinh điển. Phần lớn ngày vẫn khớp, nên lỗi này hay lọt qua khâu test.&lt;/p&gt;

&lt;h2&gt;
  
  
  Các năm nên đưa vào test
&lt;/h2&gt;

&lt;p&gt;Mình kiểm các giá trị dưới đây bằng thư viện &lt;code&gt;vnlunar&lt;/code&gt; (thuật toán Hồ Ngọc Đức, múi giờ 7.0):&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Năm âm&lt;/th&gt;
&lt;th&gt;Tháng nhuận&lt;/th&gt;
&lt;th&gt;Mùng 1 tháng nhuận (dương lịch)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;2025 (Ất Tỵ)&lt;/td&gt;
&lt;td&gt;tháng 6&lt;/td&gt;
&lt;td&gt;25/7/2025&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2028 (Mậu Thân)&lt;/td&gt;
&lt;td&gt;tháng 5&lt;/td&gt;
&lt;td&gt;23/6/2028&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2031 (Tân Hợi)&lt;/td&gt;
&lt;td&gt;tháng 3&lt;/td&gt;
&lt;td&gt;21/4/2031&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2033 (Quý Sửu)&lt;/td&gt;
&lt;td&gt;tháng 11&lt;/td&gt;
&lt;td&gt;22/12/2033&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Năm 2033 rất đáng test. Tháng nhuận rơi vào cuối năm, sát tháng 11, nên các cài đặt chỉ "đếm tháng" thay vì kiểm trung khí rất dễ sai.&lt;/p&gt;

&lt;p&gt;Thêm vài ca biên khác:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Năm 2026 (Bính Ngọ) có 12 tháng, và tháng Chạp chỉ có 29 ngày. Ngày cuối năm là 29 tháng Chạp (5/2/2027), mùng 1 Tết Đinh Mùi là 6/2/2027.&lt;/li&gt;
&lt;li&gt;Chuyển đổi ngược từ âm sang dương phải nhận thêm cờ &lt;code&gt;leap&lt;/code&gt;. Nếu không, "ngày 10 tháng 6 âm năm 2025" sẽ mơ hồ vì năm đó có hai tháng 6.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Gợi ý cài đặt
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Lưu ngày âm dưới dạng &lt;code&gt;(ngày, tháng, năm, nhuận)&lt;/code&gt;, đừng ghép thành chuỗi.&lt;/li&gt;
&lt;li&gt;Tính sẵn bảng tháng cho khoảng năm cần dùng (ví dụ 1900–2100) rồi tra bảng, thay vì tính thiên văn mỗi lần render.&lt;/li&gt;
&lt;li&gt;Viết test so sánh với một nguồn lịch Việt đáng tin cho ít nhất 1 ngày/tháng trong vài chục năm.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Nếu muốn đối chiếu kết quả của mình với một lịch Việt đang chạy thật, trang phương pháp của &lt;a href="https://amlichvietnam.vn/phuong-phap-tinh-lich" rel="noopener noreferrer"&gt;Âm Lịch Việt Nam&lt;/a&gt; mô tả rõ thuật toán và múi giờ họ dùng. Lưới tháng trên đó cũng đánh dấu tháng nhuận, nên tiện để kiểm tra chéo.&lt;/p&gt;

&lt;p&gt;Bạn từng gặp bug lịch âm nào kỳ lạ? Kể ở phần bình luận nhé.&lt;/p&gt;

&lt;p&gt;— Duc Tran&lt;/p&gt;

</description>
      <category>algorithms</category>
      <category>calendar</category>
      <category>python</category>
      <category>vietnam</category>
    </item>
  </channel>
</rss>
