{"promptTemplate":"Bạn là một nhạc sĩ sáng tác lời bài hát parody (nhạc chế) tiếng Việt chuyên nghiệp, mượt mà, giàu hình ảnh và tự nhiên như văn nói.\r\n\r\nHãy chế lời cho BÀI HÁT GỐC dưới đây theo CHỦ ĐỀ và BỐI CẢNH được yêu cầu.\r\n\r\n---\r\n### 1. THÔNG TIN BÀI HÁT & CHỦ ĐỀ\r\n- Bài hát gốc: {songName}\r\n- Chủ đề chế: {theme}{tuKhoaInfo}{extraContentRule}\r\n- Phong cách: {styleInstruction}\r\n- Hãy tự nghĩ ra bối cảnh sao cho phù hợp với chủ đề và phong cách\r\n\r\n---\r\n### 2. YÊU CẦU BẮT BUỘC VỀ SÁNG TÁC & NHẠC LÝ\r\n\r\n1. **TUYỆT ĐỐI KHÔNG SAO CHÉP LỜI GỐC (CHỐNG TRÙNG LẶP 100%):**\r\n   - BẮT BUỘC VIẾT MỚI TOÀN BỘ 100% TẤT CẢ CÁC CÂU TỪ ĐẦU ĐẾN CUỐI BÀI.\r\n   - TUYỆT ĐỐI KHÔNG ĐƯỢC chỉ chế vài câu đầu rồi các đoạn sau copy nguyên lời bài hát gốc hoặc bỏ dở giữa chừng.\r\n   - TUYỆT ĐỐI KHÔNG GIỮ LẠI bất kỳ câu hát gốc nào (kể cả điệp khúc, đoạn chuyển hay câu kết). Mọi câu trong bài mới phải mang nội dung mới hoàn toàn theo đúng chủ đề và phong cách.\r\n   - Tỷ lệ từ ngữ trùng lặp với bài gốc phải dưới 10% (chỉ chấp nhận trùng một vài hư từ ngữ pháp như: thì, là, mà, ở, cho, về... tuyệt đối không giữ nguyên cụm từ hay câu gốc).\r\n\r\n2. **ĐỦ 100% SỐ DÒNG (KHÔNG ĐƯỢC THIẾU CÂU):**\r\n   - Bài hát gốc được cung cấp có bao nhiêu dòng thì bản parody BẮT BUỘC phải có ĐỦ ĐÚNG BẤY NHIÊU DÒNG tương ứng (mỗi dòng tương ứng 1 dòng bài gốc). Tuyệt đối không được bỏ sót dòng nào.\r\n\r\n3. **CHÍNH XÁC SỐ TIẾNG (ÂM TIẾT):**\r\n   - Số tiếng của từng dòng trong bài mới BẮT BUỘC phải khớp chuẩn 100% với số tiếng của dòng tương ứng trong bài gốc.\r\n\r\n4. **DỄ HÁT & KHỚP THANH ĐIỆU THEO TỪNG TIẾNG:**\r\n   - Ưu tiên giữ đúng thanh điệu ở **từ cuối mỗi câu (vần chân)**.\r\n   - Khi so sánh tương ứng giữa **từng tiếng ở câu gốc** và **tiếng ở vị trí tương đương tại câu chế**:\r\n     + Tiếng gốc mang dấu **SẮC**: Tiếng mới BẮT BUỘC phải mang dấu **SẮC, HỎI, NGÃ** hoặc **KHÔNG DẤU** (Tuyệt đối KHÔNG dùng dấu NẶNG hoặc HUYỀN).\r\n     + Tiếng gốc mang dấu **NẶNG / HUYỀN**: Tiếng mới BẮT BUỘC phải mang dấu **NẶNG hoặc HUYỀN** (Tuyệt đối KHÔNG dùng dấu SẮC, NGÃ, HỎI).\r\n     + Tiếng gốc **KHÔNG DẤU**: Ưu tiên dùng tiếng **KHÔNG DẤU** hoặc **HUYỀN**.\r\n\r\n5. **CHỐNG LẶP TỪ & KHÔNG ÉP CÂU:**\r\n   - KHÔNG ĐƯỢC lặp lại các từ khóa chính (từ chỉ cảm xúc/chủ đề) quá 3 lần trong toàn bài.\r\n   - Dùng vốn từ phong phú, sinh động mô tả hình ảnh/hành động thực tế theo Bối cảnh đã tự tạo.\r\n   - Mỗi câu phải có nghĩa hoàn chỉnh, tự nhiên, tuyệt đối không ghép từ ngô nghê/vô nghĩa chỉ để cho đủ tiếng hay đúng dấu.\r\n\r\n---\r\n### 3. QUY TRÌNH TỰ KIỂM TRA TRƯỚC KHI XUẤT KẾT QUẢ (CỰC KỲ QUAN TRỌNG)\r\nTrước khi xuất ra kết quả, hãy âm thầm kiểm tra:\r\n1. Đã chế đủ 100% số câu của bài gốc chưa? (Đếm số dòng phải bằng đúng số dòng bài gốc).\r\n2. Có câu nào bị trùng với bài hát gốc không? ĐẶC BIỆT TỪ NỬA BÀI ĐẾN HẾT BÀI: Nếu có câu nào giống bài hát gốc, BẮT BUỘC phải viết lại câu đó ngay!\r\n3. Hát nhẩm theo nhịp bài gốc: Đã đủ/đúng số tiếng, không bị gượng miệng, méo tiếng chưa?\r\n*(Nếu câu nào chưa đạt, BẮT BUỘC phải viết lại câu đó trước khi xuất).*\r\n\r\n---\r\n### 4. ĐỊNH DẠNG ĐẦU RA BẮT BUỘC\r\n- TUYỆT ĐỐI KHÔNG xuất quá trình nháp suy luận, KHÔNG phân tích thanh điệu (Tones, ->, syllables, L1, L2, Check tones...).\r\n- BÊN TRONG CẶP THẺ ### CHỈ ĐƯỢC CHỨA DUY NHẤT CÁC CÂU LỜI HÁT PARODY HOÀN CHỈNH, MỖI CÂU TRÊN MỘT DÒNG.\r\nChỉ xuất duy nhất cấu trúc:\r\n\r\n$$$[Tên bài parody]$$$\r\n\r\n###[Toàn bộ lời parody]###\r\n\r\nKhông giải thích, không nhắc lại bài gốc, không phân tích.\r\n\r\n---\r\nBÀI HÁT GỐC:\r\n{originalExcerpt}","geminiAndroidSendJs":"\r\n(async () => {\r\n  const text = {promptJson};\r\n  const delay = (ms) => new Promise(r => setTimeout(r, ms));\r\n\r\n  const isDisabled = (el) =>\r\n    !el ||\r\n    el.disabled === true ||\r\n    el.getAttribute('disabled') !== null ||\r\n    el.getAttribute('aria-disabled') === 'true';\r\n\r\n  const clickLikeUser = (el) => {\r\n    el.dispatchEvent(new MouseEvent('mousedown', { bubbles: true, cancelable: true, view: window }));\r\n    el.dispatchEvent(new MouseEvent('mouseup',   { bubbles: true, cancelable: true, view: window }));\r\n    el.dispatchEvent(new MouseEvent('click',     { bubbles: true, cancelable: true, view: window }));\r\n  };\r\n\r\n  const inputRoot =\r\n    document.querySelector('input-area-v2') ||\r\n    document.querySelector('input-container') ||\r\n    document.querySelector('.input-area') ||\r\n    document.querySelector('.input-area-container') ||\r\n    document.querySelector('.text-input-field') ||\r\n    document;\r\n\r\n  const editor =\r\n    document.querySelector('div[contenteditable=\"true\"]') ||\r\n    inputRoot.querySelector('.ql-editor[contenteditable=\"true\"]') ||\r\n    document.querySelector('.ql-editor[contenteditable=\"true\"]');\r\n\r\n  if (!editor) return 'ERR: editor not found';\r\n\r\n  editor.focus();\r\n  var success = false;\r\n  try {\r\n    document.execCommand('selectAll', false, null);\r\n    success = document.execCommand('insertText', false, text);\r\n  } catch(e) {}\r\n  if (!success || editor.innerText.trim() !== text.trim()) {\r\n    editor.innerText = text;\r\n  }\r\n\r\n  const events = ['beforeinput', 'input', 'change', 'textInput', 'keydown', 'keyup'];\r\n  events.forEach(function(name) {\r\n    try {\r\n      var ev = new Event(name, { bubbles: true, cancelable: true });\r\n      editor.dispatchEvent(ev);\r\n    } catch(e) {}\r\n  });\r\n\r\n  await delay(100);\r\n\r\n  const findSendButtonNearInput = () => {\r\n    let btn =\r\n      document.querySelector('button.send-button') ||\r\n      document.querySelector('.send-button-container button') ||\r\n      document.querySelector('button[aria-label*=\"Send\" i]') ||\r\n      document.querySelector('button[aria-label*=\"Gửi\" i]') ||\r\n      document.querySelector('button[class*=\"send\" i]') ||\r\n      document.querySelector('button[id*=\"send\" i]') ||\r\n      document.querySelector('button[type=\"submit\"]');\r\n\r\n    if (btn) return btn;\r\n\r\n    const scope = editor.closest('input-area-v2, input-container, .input-area, .input-area-container, .text-input-field') || inputRoot;\r\n\r\n    btn = scope.querySelector('button.send-button.submit') ||\r\n          scope.querySelector('button.send-button') ||\r\n          scope.querySelector('.send-button');\r\n\r\n    if (btn) return btn;\r\n\r\n    btn = Array.from(scope.querySelectorAll('button'))\r\n      .find(b => b.querySelector('mat-icon[fonticon=\"send\"], mat-icon[data-mat-icon-name=\"send\"]') || b.querySelector('svg'));\r\n    if (btn) return btn;\r\n\r\n    if (editor) {\r\n      let parent = editor.parentElement;\r\n      while (parent && parent.tagName.toLowerCase() !== 'body') {\r\n        const buttons = parent.querySelectorAll('button');\r\n        if (buttons && buttons.length > 0) {\r\n          for (let j = 0; j < buttons.length; j++) {\r\n            const b = buttons[j];\r\n            const label = b.getAttribute('aria-label') || '';\r\n            const className = b.className || '';\r\n            if (label.toLowerCase().includes('send') ||\r\n                label.toLowerCase().includes('gửi') ||\r\n                className.toLowerCase().includes('send') ||\r\n                b.querySelector('svg') ||\r\n                b.querySelector('mat-icon')) {\r\n              btn = b;\r\n              break;\r\n            }\r\n          }\r\n          if (btn) break;\r\n          btn = buttons[0];\r\n          break;\r\n        }\r\n        parent = parent.parentElement;\r\n      }\r\n    }\r\n\r\n    return btn || null;\r\n  };\r\n\r\n  const sendBtn = findSendButtonNearInput();\r\n  if (!sendBtn) return 'ERR: send button not found (fallback failed)';\r\n\r\n  if (isDisabled(sendBtn)) {\r\n    events.forEach(function(name) {\r\n      try {\r\n        var ev = new Event(name, { bubbles: true, cancelable: true });\r\n        editor.dispatchEvent(ev);\r\n      } catch(e) {}\r\n    });\r\n    await delay(200);\r\n  }\r\n\r\n  try { sendBtn.click(); } catch(e) {}\r\n  clickLikeUser(sendBtn);\r\n  return 'OK: sent';\r\n})();","geminiAndroidExtractJs":"\r\n(() => {\r\n  try {\r\n    const query = 'message-content, .model-response-text, [data-message-author-role=\"assistant\"], model-response, .markdown[id^=\"model-response-message-content\"], .markdown';\r\n    const allNodes = Array.from(document.querySelectorAll(query));\r\n    const uniqueNodes = allNodes.filter(function(node) {\r\n      return !allNodes.some(function(otherNode) {\r\n        return otherNode !== node && otherNode.contains(node);\r\n      });\r\n    });\r\n\r\n    if (!uniqueNodes.length) {\r\n      const fallback = document.querySelectorAll('[data-message-author-role=\"assistant\"], .model-response-text, message-content');\r\n      if (fallback.length) {\r\n        const lastFb = fallback[fallback.length - 1];\r\n        return JSON.stringify((lastFb.innerText || lastFb.textContent || '').trim());\r\n      }\r\n      return JSON.stringify('');\r\n    }\r\n\r\n    const last = uniqueNodes[uniqueNodes.length - 1];\r\n    const text = last ? (last.innerText || last.textContent || '').trim() : '';\r\n    return JSON.stringify(text);\r\n  } catch(e) {\r\n    return JSON.stringify('');\r\n  }\r\n})();","updatedAt":"2026-10-27T09:45:43.3542074Z"}