diff --git a/internal/dictionary/dictionary.go b/internal/dictionary/dictionary.go new file mode 100644 index 0000000..5a37a42 --- /dev/null +++ b/internal/dictionary/dictionary.go @@ -0,0 +1,182 @@ +package dictionary + +import ( + "encoding/json" + "os" + "strings" + + "nihongo-search/internal/models" +) + +type Dictionary struct { + KanjiDetails []models.KanjiData + JMDictWords []models.JMDictWord +} + +func New() *Dictionary { + return &Dictionary{ + KanjiDetails: []models.KanjiData{}, + JMDictWords: []models.JMDictWord{}, + } +} + +func toStringSlice(data interface{}) []string { + var result []string + for _, v := range data.([]interface{}) { + result = append(result, v.(string)) + } + return result +} + +func toStringMap(data interface{}) map[string]string { + result := make(map[string]string) + for k, v := range data.(map[string]interface{}) { + result[k] = v.(string) + } + return result +} + +func (d *Dictionary) LoadKanji(filename string) error { + data, err := os.ReadFile(filename) + if err != nil { + return err + } + + var kanji [][]interface{} + err = json.Unmarshal(data, &kanji) + if err != nil { + return err + } + + for _, k := range kanji { + onyomi := k[1].(string) + kunyomi := k[2].(string) + kanjiData := models.KanjiData{ + Kanji: k[0].(string), + Onyomi: strings.Fields(onyomi), + Kunyomi: strings.Fields(kunyomi), + Type: k[3].(string), + Meanings: toStringSlice(k[4]), + AdditionalInfo: toStringMap(k[5]), + } + d.KanjiDetails = append(d.KanjiDetails, kanjiData) + } + return nil +} + +func (d *Dictionary) LoadJMDict(filename string) error { + data, err := os.ReadFile(filename) + if err != nil { + return err + } + + var iwords [][]interface{} + err = json.Unmarshal(data, &iwords) + if err != nil { + return err + } + + for _, iw := range iwords { + d.JMDictWords = append(d.JMDictWords, models.JMDictWord{ + Word: iw[0].(string), + Reading: iw[1].(string), + Category: iw[2].(string), + Meanings: toStringSlice(iw[5]), + Identifier: int(iw[6].(float64)), + }) + } + return nil +} + +func (d *Dictionary) GetKanji(kanji string) []models.KanjiData { + var results []models.KanjiData + for _, kanjiData := range d.KanjiDetails { + if kanjiData.Kanji == kanji { + results = append(results, kanjiData) + } + } + return results +} + +func (d *Dictionary) SearchKanjiByMeaning(meaning string) []models.KanjiData { + var results []models.KanjiData + for _, kanjiData := range d.KanjiDetails { + for _, m := range kanjiData.Meanings { + if m == meaning { + results = append(results, kanjiData) + } + } + } + return results +} + +func (d *Dictionary) SearchKanjiByReading(reading string, type_ string) []models.KanjiData { + var results []models.KanjiData + if type_ == "onyomi" { + for _, kanjiData := range d.KanjiDetails { + for _, onyomi := range kanjiData.Onyomi { + if strings.Replace(onyomi, ".", "", -1) == reading { + results = append(results, kanjiData) + } + } + } + } else if type_ == "kunyomi" { + for _, kanjiData := range d.KanjiDetails { + for _, kunyomi := range kanjiData.Kunyomi { + if strings.Replace(kunyomi, ".", "", -1) == reading { + results = append(results, kanjiData) + } + } + } + } + return results +} + +func (d *Dictionary) SearchJMDictByMeaning(meaning string) []models.JMDictWord { + var results []models.JMDictWord + for _, word := range d.JMDictWords { + for _, m := range word.Meanings { + if strings.ToLower(m) == meaning { + results = append(results, word) + } + } + } + return results +} + +func (d *Dictionary) SearchJMDictByReading(reading string) []models.JMDictWord { + var results []models.JMDictWord + // Check if reading has no dots. Wait, why check? The original code did: + // if strings.Replace(reading, ".", "", -1) == reading { ... } + // This implies that if `reading` has a dot, we don't search. + // But `reading` passed here is usually RomajiToKana result, which shouldn't have dots. + // The original code was: + /* + if strings.Replace(reading, ".", "", -1) == reading { + for _, word := range words { + if word.Reading == reading { + results = append(results, word) + } + } + } + */ + // I'll keep the logic same. + if strings.Replace(reading, ".", "", -1) == reading { + for _, word := range d.JMDictWords { + if word.Reading == reading { + results = append(results, word) + } + } + } + return results +} + +func (d *Dictionary) GetJMDictWord(word string) []models.JMDictWord { + var results []models.JMDictWord + for _, w := range d.JMDictWords { + if w.Word == word { + results = append(results, w) + } + } + return results +} diff --git a/internal/models/models.go b/internal/models/models.go new file mode 100644 index 0000000..48b8d03 --- /dev/null +++ b/internal/models/models.go @@ -0,0 +1,18 @@ +package models + +type KanjiData struct { + Kanji string + Onyomi []string + Kunyomi []string + Type string + Meanings []string + AdditionalInfo map[string]string +} + +type JMDictWord struct { + Word string + Reading string + Category string + Meanings []string + Identifier int +} diff --git a/internal/search/search.go b/internal/search/search.go new file mode 100644 index 0000000..aa3efc5 --- /dev/null +++ b/internal/search/search.go @@ -0,0 +1,67 @@ +package search + +import ( + "sort" + "strconv" + "strings" + + "nihongo-search/internal/dictionary" + "nihongo-search/internal/models" + "nihongo-search/lang/ja" +) + +type SearchData struct { + KanjiDataList []models.KanjiData + WordDataList []models.JMDictWord +} + +type Service struct { + dict *dictionary.Dictionary +} + +func NewService(dict *dictionary.Dictionary) *Service { + return &Service{ + dict: dict, + } +} + +func (s *Service) Search(query string) *SearchData { + query = strings.TrimSpace(query) + data := &SearchData{ + KanjiDataList: []models.KanjiData{}, + WordDataList: []models.JMDictWord{}, + } + if query == "" { + return data + } + + // Search Kanji + data.KanjiDataList = append(data.KanjiDataList, s.dict.GetKanji(query)...) + data.KanjiDataList = append(data.KanjiDataList, s.dict.SearchKanjiByMeaning(query)...) + + kunyomi := ja.RomajiToKana(query, "hiragana") + data.KanjiDataList = append(data.KanjiDataList, s.dict.SearchKanjiByReading(kunyomi, "kunyomi")...) + + onyomi := ja.RomajiToKana(query, "katakana") + data.KanjiDataList = append(data.KanjiDataList, s.dict.SearchKanjiByReading(onyomi, "onyomi")...) + + // Sort Kanji + sort.Slice(data.KanjiDataList, func(i, j int) bool { + iFreq, err := strconv.Atoi(data.KanjiDataList[i].AdditionalInfo["freq"]) + if err != nil { + iFreq = 99999 + } + jFreq, err := strconv.Atoi(data.KanjiDataList[j].AdditionalInfo["freq"]) + if err != nil { + jFreq = 99999 + } + return iFreq < jFreq + }) + + // Search Words + data.WordDataList = append(data.WordDataList, s.dict.GetJMDictWord(query)...) + data.WordDataList = append(data.WordDataList, s.dict.SearchJMDictByMeaning(query)...) + data.WordDataList = append(data.WordDataList, s.dict.SearchJMDictByReading(ja.RomajiToKana(query, "hiragana"))...) + + return data +} diff --git a/internal/search/search_test.go b/internal/search/search_test.go new file mode 100644 index 0000000..243180c --- /dev/null +++ b/internal/search/search_test.go @@ -0,0 +1,24 @@ +package search + +import ( + "testing" + "nihongo-search/internal/dictionary" + "nihongo-search/internal/models" +) + +func TestSearch(t *testing.T) { + dict := dictionary.New() + // Add some dummy data + dict.KanjiDetails = append(dict.KanjiDetails, models.KanjiData{ + Kanji: "日", + Meanings: []string{"day", "sun"}, + AdditionalInfo: map[string]string{"freq": "1"}, + }) + + srv := NewService(dict) + results := srv.Search("day") + + if len(results.KanjiDataList) == 0 { + t.Errorf("Expected results, got 0") + } +} diff --git a/internal/server/server.go b/internal/server/server.go new file mode 100644 index 0000000..27b0bbd --- /dev/null +++ b/internal/server/server.go @@ -0,0 +1,95 @@ +package server + +import ( + "fmt" + "html/template" + "net/http" + "nihongo-search/internal/search" +) + +type PageData struct { + Title string +} + +type Server struct { + searchService *search.Service + templates map[string]*template.Template +} + +func NewServer(searchService *search.Service) *Server { + s := &Server{ + searchService: searchService, + templates: make(map[string]*template.Template), + } + s.loadTemplates() + return s +} + +func (s *Server) loadTemplates() { + s.templates["home"] = template.Must(template.ParseFiles("templates/index.html")) + s.templates["search"] = template.Must(template.ParseFiles("partials/search.html")) + s.templates["pango"] = template.Must(template.ParseFiles("partials/pango/search.html")) + s.templates["text"] = template.Must(template.ParseFiles("partials/text/search.html")) +} + +func (s *Server) Start(port string) error { + http.HandleFunc("GET /", s.handleHome) + http.HandleFunc("GET /healthcheck", s.handleHealthCheck) + http.HandleFunc("GET /partial/search", s.handlePartialSearch) + http.HandleFunc("GET /partial/pango/search", s.handlePangoPartialSearch) + http.HandleFunc("GET /partial/text/search", s.handleTextPartialSearch) + + fmt.Printf("Server running on port %s\n", port) + return http.ListenAndServe(":"+port, nil) +} + +func (s *Server) handleHome(w http.ResponseWriter, r *http.Request) { + data := PageData{ + Title: "Nihongo search!", + } + s.templates["home"].Execute(w, data) +} + +func (s *Server) handleHealthCheck(w http.ResponseWriter, _ *http.Request) { + w.Write([]byte("OK")) +} + +func (s *Server) handlePartialSearch(w http.ResponseWriter, r *http.Request) { + query := r.URL.Query().Get("query") + fmt.Println("Query:", query) + + data := s.searchService.Search(query) + s.templates["search"].Execute(w, data) +} + +func (s *Server) handlePangoPartialSearch(w http.ResponseWriter, r *http.Request) { + query := r.URL.Query().Get("query") + fmt.Println("Query:", query) + + data := s.searchService.Search(query) + + if len(data.KanjiDataList) > 3 { + data.KanjiDataList = data.KanjiDataList[:3] + } + if len(data.WordDataList) > 3 { + data.WordDataList = data.WordDataList[:3] + } + + s.templates["pango"].Execute(w, data) +} + +func (s *Server) handleTextPartialSearch(w http.ResponseWriter, r *http.Request) { + query := r.URL.Query().Get("query") + fmt.Println("Query:", query) + + data := s.searchService.Search(query) + + if len(data.KanjiDataList) > 3 { + data.KanjiDataList = data.KanjiDataList[:3] + } + if len(data.WordDataList) > 3 { + data.WordDataList = data.WordDataList[:3] + } + + s.templates["text"].Execute(w, data) +} diff --git a/lang/ja/ja.go b/lang/ja/ja.go index 8e36041..46ac1c4 100644 --- a/lang/ja/ja.go +++ b/lang/ja/ja.go @@ -1,13 +1,5 @@ package ja -import ( - "encoding/json" - "fmt" - "log" - "os" - "strings" -) - // Romaji to Hiragana mappings var romajiToHiragana = map[string]string{ // Basic syllables @@ -138,228 +130,3 @@ func RomajiToKana(romaji string, to string) string { return kana } - -func PrintPWD() { - fmt.Println("PWD:", os.Getenv("PWD")) -} - -/* - * Sample code for loading kanji data from a JSON file - [ - [ - "亜", - "ア", - "つ.ぐ", - "jouyou", - [ - "Asia", - "rank next", - "come after", - "-ous" - ], - { - "deroo": "3273", - "four_corner": "1010.6", - "freq": "1509", - "gakken": "1331", - "grade": "8", - "halpern_kkd": "4354", - "halpern_kkld": "2204", - "halpern_kkld_2ed": "2966", - "halpern_njecd": "3540", - "heisig": "1809", - "heisig6": "1950", - "henshall": "997", - "jf_cards": "1032", - "jis208": "1-16-01", - "jlpt": "1", - "kanji_in_context": "1818", - "kodansha_compact": "35", - "maniette": "1827", - "moro": "272", - "nelson_c": "43", - "nelson_n": "81", - "oneill_kk": "1788", - "oneill_names": "525", - "sh_desc": "0a7.14", - "sh_kk": "1616", - "sh_kk2": "1724", - "skip": "4-7-1", - "strokes": "7", - "tutt_cards": "1092", - "ucs": "4e9c" - } - ] - ] - -*/ - -type KanjiData struct { - Kanji string - Onyomi []string - Kunyomi []string - Type string - Meanings []string - AdditionalInfo map[string]string -} - -type JMDictWord struct { - Word string - Reading string - Category string - Meanings []string - Identifier int -} - -func toStringSlice(data interface{}) []string { - var result []string - for _, v := range data.([]interface{}) { - result = append(result, v.(string)) - } - return result -} - -func toStringMap(data interface{}) map[string]string { - result := make(map[string]string) - for k, v := range data.(map[string]interface{}) { - result[k] = v.(string) - } - return result -} - -func LoadKanjiFromJsonFile(filename string) ([]KanjiData, error) { - // Load kanji from JSON file - data, err := os.ReadFile(filename) - if err != nil { - return nil, err - } - - var kanji [][]interface{} - var kanjiDataList []KanjiData - - err = json.Unmarshal(data, &kanji) - if err != nil { - log.Fatal(err) - } - - for _, k := range kanji { - onyomi := k[1].(string) - kunyomi := k[2].(string) - kanjiData := KanjiData{ - Kanji: k[0].(string), - Onyomi: strings.Fields(onyomi), - Kunyomi: strings.Fields(kunyomi), - Type: k[3].(string), - Meanings: toStringSlice(k[4]), - AdditionalInfo: toStringMap(k[5]), - } - kanjiDataList = append(kanjiDataList, kanjiData) - } - return kanjiDataList, nil -} - -func LoadJMDictFromJsonFile(filename string) ([]JMDictWord, error) { - // Load kanji from JSON file - data, err := os.ReadFile(filename) - if err != nil { - return nil, err - } - - var iwords [][]interface{} - var words []JMDictWord - - err = json.Unmarshal(data, &iwords) - if err != nil { - log.Fatal(err) - } - - for _, iw := range iwords { - words = append(words, JMDictWord{ - Word: iw[0].(string), - Reading: iw[1].(string), - Category: iw[2].(string), - Meanings: toStringSlice(iw[5]), - Identifier: int(iw[6].(float64)), - }) - } - - return words, nil -} - -func GetKanji(kanjiDataList []KanjiData, kanji string) []KanjiData { - var results []KanjiData - for _, kanjiData := range kanjiDataList { - if kanjiData.Kanji == kanji { - results = append(results, kanjiData) - } - } - return results -} - -func SearchKanjiByMeaning(kanjiDataList []KanjiData, meaning string) []KanjiData { - var results []KanjiData - for _, kanjiData := range kanjiDataList { - for _, m := range kanjiData.Meanings { - if m == meaning { - results = append(results, kanjiData) - } - } - } - return results -} - -func SearchKanjiByReading(kanjiDataList []KanjiData, reading string, type_ string) []KanjiData { - var results []KanjiData - if type_ == "onyomi" { - for _, kanjiData := range kanjiDataList { - for _, onyomi := range kanjiData.Onyomi { - if strings.Replace(onyomi, ".", "", -1) == reading { - results = append(results, kanjiData) - } - } - } - } else if type_ == "kunyomi" { - for _, kanjiData := range kanjiDataList { - for _, kunyomi := range kanjiData.Kunyomi { - if strings.Replace(kunyomi, ".", "", -1) == reading { - results = append(results, kanjiData) - } - } - } - } - return results -} - -func SearchJMDictByMeaning(words []JMDictWord, meaning string) []JMDictWord { - var results []JMDictWord - for _, word := range words { - for _, m := range word.Meanings { - if strings.ToLower(m) == meaning { - results = append(results, word) - } - } - } - return results -} - -func SearchJMDictByReading(words []JMDictWord, reading string) []JMDictWord { - var results []JMDictWord - if strings.Replace(reading, ".", "", -1) == reading { - for _, word := range words { - if word.Reading == reading { - results = append(results, word) - } - } - } - return results -} - -func GetJMDictyWord(words []JMDictWord, word string) []JMDictWord { - var results []JMDictWord - for _, w := range words { - if w.Word == word { - results = append(results, w) - } - } - return results -} diff --git a/main.go b/main.go index 86a5bdf..47c042c 100644 --- a/main.go +++ b/main.go @@ -2,228 +2,38 @@ package main import ( "fmt" - "html/template" - "net/http" - "nihongo-search/lang/ja" - "sort" + "log" "strconv" - "strings" -) - -var counter int -var kanjiDetails []ja.KanjiData -var JMDictWords []ja.JMDictWord - -type PageData struct { - Title string -} - -type SearchData struct { - KanjiDataList []ja.KanjiData - WordDataList []ja.JMDictWord -} - -func handleHome(w http.ResponseWriter, r *http.Request) { - tmpl := template.Must(template.ParseFiles("templates/index.html")) - data := PageData{ - Title: "Nihongo search!", - } - tmpl.Execute(w, data) - -} - -// TODO: Refactor this function to use a single search function -func handlePartialSearch(w http.ResponseWriter, r *http.Request) { - query := r.URL.Query().Get("query") - query = strings.TrimSpace(query) - fmt.Println("Query:", query) - - tmpl := template.Must(template.ParseFiles("partials/search.html")) - data := SearchData{ - KanjiDataList: []ja.KanjiData{}, - WordDataList: []ja.JMDictWord{}, - } - counter++ - if query == "" { - tmpl.Execute(w, data) - return - } - - data.KanjiDataList = append(data.KanjiDataList, ja.GetKanji(kanjiDetails, query)...) - data.KanjiDataList = append(data.KanjiDataList, ja.SearchKanjiByMeaning(kanjiDetails, query)...) - - kunyomi := ja.RomajiToKana(query, "hiragana") - data.KanjiDataList = append(data.KanjiDataList, ja.SearchKanjiByReading(kanjiDetails, kunyomi, "kunyomi")...) - onyomi := ja.RomajiToKana(query, "katakana") - data.KanjiDataList = append(data.KanjiDataList, ja.SearchKanjiByReading(kanjiDetails, onyomi, "onyomi")...) - - sort.Slice(data.KanjiDataList, func(i, j int) bool { - iFreq, err := strconv.Atoi(data.KanjiDataList[i].AdditionalInfo["freq"]) - if err != nil { - iFreq = 99999 - } - jFreq, err := strconv.Atoi(data.KanjiDataList[j].AdditionalInfo["freq"]) - if err != nil { - jFreq = 99999 - } - return iFreq < jFreq - }) - - data.WordDataList = append(data.WordDataList, ja.GetJMDictyWord(JMDictWords, query)...) - data.WordDataList = append(data.WordDataList, ja.SearchJMDictByMeaning(JMDictWords, query)...) - data.WordDataList = append(data.WordDataList, ja.SearchJMDictByReading(JMDictWords, ja.RomajiToKana(query, "hiragana"))...) - fmt.Println("Word data list:", data.WordDataList) - - tmpl.Execute(w, data) -} - -func handlePangoPartialSearch(w http.ResponseWriter, r *http.Request) { - query := r.URL.Query().Get("query") - query = strings.TrimSpace(query) - fmt.Println("Query:", query) - - tmpl := template.Must(template.ParseFiles("partials/pango/search.html")) - data := SearchData{ - KanjiDataList: []ja.KanjiData{}, - WordDataList: []ja.JMDictWord{}, - } - counter++ - if query == "" { - tmpl.Execute(w, data) - return - } - - data.KanjiDataList = append(data.KanjiDataList, ja.GetKanji(kanjiDetails, query)...) - data.KanjiDataList = append(data.KanjiDataList, ja.SearchKanjiByMeaning(kanjiDetails, query)...) - - kunyomi := ja.RomajiToKana(query, "hiragana") - data.KanjiDataList = append(data.KanjiDataList, ja.SearchKanjiByReading(kanjiDetails, kunyomi, "kunyomi")...) - - onyomi := ja.RomajiToKana(query, "katakana") - data.KanjiDataList = append(data.KanjiDataList, ja.SearchKanjiByReading(kanjiDetails, onyomi, "onyomi")...) - - sort.Slice(data.KanjiDataList, func(i, j int) bool { - iFreq, err := strconv.Atoi(data.KanjiDataList[i].AdditionalInfo["freq"]) - if err != nil { - iFreq = 99999 - } - jFreq, err := strconv.Atoi(data.KanjiDataList[j].AdditionalInfo["freq"]) - if err != nil { - jFreq = 99999 - } - return iFreq < jFreq - }) - - if len(data.KanjiDataList) > 3 { - data.KanjiDataList = data.KanjiDataList[:3] - } - - data.WordDataList = append(data.WordDataList, ja.GetJMDictyWord(JMDictWords, query)...) - data.WordDataList = append(data.WordDataList, ja.SearchJMDictByMeaning(JMDictWords, query)...) - data.WordDataList = append(data.WordDataList, ja.SearchJMDictByReading(JMDictWords, ja.RomajiToKana(query, "hiragana"))...) - fmt.Println("Word data list:", data.WordDataList) - - if len(data.WordDataList) > 3 { - data.WordDataList = data.WordDataList[:3] - } - - tmpl.Execute(w, data) -} - -func handleTextPartialSearch(w http.ResponseWriter, r *http.Request) { - query := r.URL.Query().Get("query") - query = strings.TrimSpace(query) - fmt.Println("Query:", query) - - tmpl := template.Must(template.ParseFiles("partials/text/search.html")) - data := SearchData{ - KanjiDataList: []ja.KanjiData{}, - WordDataList: []ja.JMDictWord{}, - } - counter++ - if query == "" { - tmpl.Execute(w, data) - return - } - - data.KanjiDataList = append(data.KanjiDataList, ja.GetKanji(kanjiDetails, query)...) - data.KanjiDataList = append(data.KanjiDataList, ja.SearchKanjiByMeaning(kanjiDetails, query)...) - - kunyomi := ja.RomajiToKana(query, "hiragana") - data.KanjiDataList = append(data.KanjiDataList, ja.SearchKanjiByReading(kanjiDetails, kunyomi, "kunyomi")...) - - onyomi := ja.RomajiToKana(query, "katakana") - data.KanjiDataList = append(data.KanjiDataList, ja.SearchKanjiByReading(kanjiDetails, onyomi, "onyomi")...) - - sort.Slice(data.KanjiDataList, func(i, j int) bool { - iFreq, err := strconv.Atoi(data.KanjiDataList[i].AdditionalInfo["freq"]) - if err != nil { - iFreq = 99999 - } - jFreq, err := strconv.Atoi(data.KanjiDataList[j].AdditionalInfo["freq"]) - if err != nil { - jFreq = 99999 - } - return iFreq < jFreq - }) - - if len(data.KanjiDataList) > 3 { - data.KanjiDataList = data.KanjiDataList[:3] - } - - data.WordDataList = append(data.WordDataList, ja.GetJMDictyWord(JMDictWords, query)...) - data.WordDataList = append(data.WordDataList, ja.SearchJMDictByMeaning(JMDictWords, query)...) - data.WordDataList = append(data.WordDataList, ja.SearchJMDictByReading(JMDictWords, ja.RomajiToKana(query, "hiragana"))...) - fmt.Println("Word data list:", data.WordDataList) - - if len(data.WordDataList) > 3 { - data.WordDataList = data.WordDataList[:3] - } - - tmpl.Execute(w, data) -} - -func handleHealthCheck(w http.ResponseWriter, _ *http.Request) { - w.Write([]byte("OK")) -} + "nihongo-search/internal/dictionary" + "nihongo-search/internal/search" + "nihongo-search/internal/server" +) func main() { - var err error - var kanjiDetailsList []ja.KanjiData + dict := dictionary.New() + + // Load Kanji Data for i := 1; i <= 2; i++ { filename := "./data/ja/kanji_bank_" + strconv.Itoa(i) + ".json" - kanjiDetailsList, err = ja.LoadKanjiFromJsonFile(filename) - if err != nil { - fmt.Println("Error loading kanji data:", err) - return + if err := dict.LoadKanji(filename); err != nil { + log.Fatalf("Error loading kanji data from %s: %v", filename, err) } - kanjiDetails = append(kanjiDetails, kanjiDetailsList...) } - var JMDictWordsData []ja.JMDictWord + // Load JMDict Data for i := 1; i <= 75; i++ { filename := "./data/ja/term_bank_" + strconv.Itoa(i) + ".json" - JMDictWordsData, err = ja.LoadJMDictFromJsonFile(filename) - if err != nil { - fmt.Println("Error loading JMDict data:", err) - return + if err := dict.LoadJMDict(filename); err != nil { + log.Fatalf("Error loading JMDict data from %s: %v", filename, err) } - JMDictWords = append(JMDictWords, JMDictWordsData...) - } fmt.Println("JMDict words loaded") - // Route handlers - http.HandleFunc("GET /", handleHome) - http.HandleFunc("GET /healthcheck", handleHealthCheck) - http.HandleFunc("GET /partial/search", handlePartialSearch) - http.HandleFunc("GET /partial/pango/search", handlePangoPartialSearch) - http.HandleFunc("GET /partial/text/search", handleTextPartialSearch) + searchService := search.NewService(dict) + srv := server.NewServer(searchService) - // Start server - fmt.Println("Server running on port 8080") - if err = http.ListenAndServe(":8080", nil); err != nil { - fmt.Println(err) + if err := srv.Start("8080"); err != nil { + log.Fatal(err) } }