啱啱開始自學日文順便學下寫Chrome Extension 幫手學生字

59 回覆
79 Like 3 Dislike
2023-02-01 18:45:42
啱啱去完日本心血來潮想學下
不過目的唔係考試
主要只係方便聽Youtube ,睇Twitter 同漫畫

所以諗住買d online course 學文法
再背好生字讀法就應該夠做

我有App Store 睇過下d 學生字app 好多都畀錢同埋都係考試取向
有chrome extension 係會拆平假名但我覺得咁依賴應該唔會令自己記到點讀
所以諗住整個chrome extension 係會save 低你睇過嘅字
再寫個簡單Flashcard App 等得閒嘅時候開黎記番個extension save 低/export嘅字

本身冇寫過chrome extension
開咗個101 睇下入面d tutorial
https://developer.chrome.com/docs/extensions/mv3/getstarted/
如果本身寫過下webapp 應該容易上手

之後隨手玩下ChatGPT 試下開咗個頭先
結果而言其實自己寫+copilot 少少輔助會好過慢慢寫requirement 落ChatGPT 叫佢gen

原因有幾個:
1. 應該training data 比較舊,manifest_version 成日出2,就算指明係要version 3,玩多兩玩都會係2嘅syntax 咁出比你
2. 佢好似會直接當nodejs 咁寫,會require/import module,就算係叫佢用webpack pack 做一個js 黎用,佢用嘅package 都未必用到落chrome extension,例如path 咁
3. Debug 基本上係冇咩用,都係要自己發現問題,再講埋希望點解決先會出到d 有用少少嘅野

所以玩咗2日放棄咗完全靠ChatGPT
不過用嚟起個頭其實都ok 嘅
只係再深入嘅嘢就唔好徙自己時間


暫時成果係咁:

Click 落去一段文字會自動show 假名


會save 低d 字落chrome storage


之後如果有字係之前記低過嘅話,會變橙色,變相可以test 自己係咪識讀個字再click 落去睇



之後應該會真係睇返d online course學咗d 基本日文知識
同埋搞咗Flashcard 先

怕爆字數
係Reply 再慢慢講同update 多d 點搞成舊野
同埋ChatGPT 過程
2023-02-01 18:55:42
2023-02-01 18:58:19
2023-02-01 19:16:30
個chrome extension想法好簡單
1. 搵個library 漢字轉假名 (https://github.com/hexenq/kuroshiro)
2. 用個translate API 做埋翻譯 (未搞)
3. Save 低漢字 假名 翻譯,可以export 做json 比Flashcard App import/睇下有冇其他方法

咁我一開頭就叫ChatGPT 用kuroshiro 幫我簡單將webpage 所有漢字加假名
然後佢就寫require kuroshiro 跟住做落去
然後就prompt error
之後搵解決方法
基本上都係2種
一係build 做kuroshiro.min.js
一係webpack 成個build

但因爲path 同埋有其他問題所以決定直接快手起個express API 做住先就算
反正之後翻譯都係要call API

然後順住呢個API 叫ChatGPT 簡單整個漢字轉假名功能試下先
Write a chrome plugin in manifest version 3 with following requirement:
1. Yellow highlight a text (p, li, h1, h2, h3 etc.) when hovering, no highlight when moved out
2. When clicking into the highlighted text, convert the Japanese text into Hiragana by fetching the rest api using fetch API http://localhost:3000/convert which with the request and response format:

Request
{
"text": ["日本語の文章", "日本語の文章”, "日本語の文章"]
}

Response
{
"hiragana": [
"日本語(にほんご)の文章(ぶんしょう)",
"日本語(にほんご)の文章(ぶんしょう)",
"日本語(にほんご)の文章(ぶんしょう)"
]
}
3. Revert back to no Hiragana when clicking it again


regen 咗幾次真係行到嘅result


基本上呢段code 係行到
但就真係凈係Revert back to no Hiragana when clicking it again
Click 多次都冇得revert
ChatGPT 真係好適合train 人寫requirement
2023-02-01 19:30:01
之後再同ChatGPT慢慢猜
反而d 加減listener 嘅code 仲多仲亂
所知都係睇返code 改返就算

但之後再慢慢試ChatGPT
如果係比一段本身嘅code 佢叫佢寫其他function 其實係ok

例如

given a saveToStorage function as:
const saveToStorage = async (kanji, hiragana) => {
const data = { hiragana, mastered: false, archived: false };
chrome.storage.local.set({ [kanji]: JSON.stringify(data) }, function () {
console.log("Data is stored for " + kanji);
});
};

create a function that takes an input as a japanese sentence like: 日本語(にほんご)の文章(ぶんしょう)
and get all the kanji and hiragana to pass to saveToStorage function


Result


但諗諗下其實copilot 本身已經可以做到咁
仲唔使解釋咁多野
所以凈低其他野都係自己黎 + copilot
2023-02-01 19:31:21
貼住暫時code

// Add yellow highlight on hover
const highlight = (event) => {
  event.target.style.backgroundColor = "yellow";
};

// Remove yellow highlight on hover out
const unhighlight = (event) => {
  event.target.style.backgroundColor = "";
};

// chrome.storage.local.clear(function() {
//   console.log("Chrome storage local has been cleared.");
// });

chrome.storage.local.get(function(items) { console.log(items) });
// Convert Japanese text to Hiragana
const convertToHiragana = async (text) => {
  const response = await fetch("http://localhost:3000/convert", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ text: [text] }),
  });
  const data = await response.json();
  await extractKanjiAndHiragana(data.hiragana[0]);
  return data.hiragana[0];
};


// Revert back to original text
const revertToOriginal = (event) => {
  event.target.removeEventListener("click", revertToOriginal);
  event.target.innerHTML = event.target.dataset.original;
  event.target.addEventListener("click", addHiragana);
};

// Add Hiragana
const addHiragana = async (event) => {
  if (!event.target.dataset.original) {
    event.target.dataset.original = event.target.innerHTML;
  }
  event.target.innerHTML = await convertToHiragana(event.target.innerHTML);
  event.target.removeEventListener("click", addHiragana);
  event.target.addEventListener("click", revertToOriginal);
};

async function updateElements() {
  const elements = document.querySelectorAll("p, li, h1, h2, h3");
  for (const element of elements) {
    element.innerHTML = await setTextColor(element.innerHTML);
    element.addEventListener("mouseover", highlight);
    element.addEventListener("mouseout", unhighlight);
    element.addEventListener("click", addHiragana);
  }
}

updateElements();

async function setTextColor(text) {
  return new Promise((resolve) => {
    let coloredText = text;

    chrome.storage.local.get(null, function(result) {
      let keys = Object.keys(result);
      keys.sort((a, b) => b.length - a.length);
      let foundKeys = [];
    
      for (let i = 0; i < keys.length; i++) {
        let key = keys[i];
        let index = coloredText.indexOf(key);
        if (key === "") {
          continue;
        }
        
        let skip = false;
        foundKeys.forEach(fKey => {
          if (fKey.includes(key)) {
            skip = true;
          }
        });
        
        if (skip) {
          continue;
        }
    
        if (index !== -1) {
          foundKeys.push(key);
          let data = result[key];
          let color = data.mastered ? "green" : "orange";
          let beforeText = coloredText.substring(0, index);
          let afterText = coloredText.substring(index + key.length);
          coloredText = beforeText + "<span style='color:" + color + "'>" + key + "</span>" + afterText;
        }
      }
      console.log(coloredText)
    
      resolve(coloredText);
    });
    
  });
}


const saveToStorage = async (kanji, hiragana) => {
  const data = { hiragana, mastered: false, archived: false };
  if (kanji === "") return;
  chrome.storage.local.set({ [kanji]: JSON.stringify(data) }, function () {
    console.log("Data is stored for " + kanji + " as " + hiragana);
  });
};

const extractKanjiAndHiragana = async (sentence) => {
  const kanjiRegex = /[\u4e00-\u9faf]/;
  const hiraganaRegex = /[\u3040-\u309f]/;
  
  let kanji = "";
  let hiragana = "";
  
  for (const char of sentence) {
    if (char === "(") {
      hiragana = "";
    } else if (char === ")") {
      await saveToStorage(kanji, hiragana);
      kanji = "";
      hiragana = "";
    } else if (kanjiRegex.test(char)) {
      kanji += char;
    } else if (hiraganaRegex.test(char)) {
      hiragana += char;
    }
  }
  
  await saveToStorage(kanji, hiragana);
};
2023-02-01 19:49:35
2023-02-01 20:02:57
Lm
2023-02-01 20:11:30
不錯
2023-02-01 21:30:42
Lm
2023-02-01 21:46:32
已追蹤會員
2023-02-01 21:51:31
lm
2023-02-01 23:07:21
留名
2023-02-02 03:48:49
2023-02-02 03:50:23
2023-02-02 04:41:00
連狗d fd黎?好撚勁
2023-02-02 12:26:58
勁呀!
2023-02-02 18:15:42
今日快手加埋Translate 呢part:


得Azure 有credit 用所以用咗Azure Translator
費事擺access key 落個extension 個source code 度
所以都係用express 包埋個Translator 嘅API call


再細執返少少就ok
const translate = async (text) => {
  const response = await fetch("http://localhost:3000/translate", {
  method: "POST",
  headers: {
  "Content-Type": "application/json",
  },
  body: JSON.stringify({ text }),
  });
  const data = await response.json();
  return data.chinese.join("\n").replace(/<\/?span.*?>/g, "");
};
   
// Add Hiragana
const addHiragana = async (event) => {
  if (!event.target.dataset.original) {
    event.target.dataset.original = event.target.innerHTML;
  }
  event.target.innerHTML = await convertToHiragana(event.target.innerHTML);
  event.target.innerHTML += '<br/>'
  event.target.innerHTML += await translate(event.target.dataset.original);
  event.target.removeEventListener("click", addHiragana);
  event.target.addEventListener("click", revertToOriginal);
};
2023-02-02 18:17:13
2023-02-02 18:19:05
弱弱一問
香港點用chatGPT
用vpn定咩?
2023-02-02 18:19:14
唔係啦
整呢個工具仔個個都做到
同整咁大scale 嘅forum 完全兩回事黎
2023-02-02 18:20:14
申請用外國number
用就開住VPN 用
2023-02-02 18:22:40
2023-02-03 13:47:54
ching有冇諗住open source?
2023-02-03 13:53:10
1. 會唔會放上store
2. 會唔會open source
3. 識唔識將 表れる 當係一個字 而唔係 おもて れる
吹水台自選台熱 門最 新手機台時事台政事台World體育台娛樂台動漫台Apps台遊戲台影視台講故台健康台感情台家庭台潮流台美容台上班台財經台房屋台飲食台旅遊台學術台校園台汽車台音樂台創意台硬件台電器台攝影台玩具台寵物台軟件台活動台電訊台直播台站務台黑 洞