From 30acaeca3497d31d17bb149bd8d362182c79ed2d Mon Sep 17 00:00:00 2001 From: Theo-Hafsaoui Date: Sun, 17 Nov 2024 09:44:47 +0100 Subject: [PATCH] WIP get page number and lowest section work --- Makefile | 2 - internal/adapters/output/compiler.go | 41 ++++-- internal/core/generate.go | 66 ++++++++- internal/core/generate_test.go | 196 ++++++++++++++++++++++++++- internal/core/ports.go | 2 +- 5 files changed, 288 insertions(+), 19 deletions(-) diff --git a/Makefile b/Makefile index f39e93e..f6b2f52 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,3 @@ - run: echo "Not yet complete" @@ -7,7 +6,6 @@ run-docker: clean: rm ./assets/latex/output/* - rm ./assets/latex/output/* build: go build diff --git a/internal/adapters/output/compiler.go b/internal/adapters/output/compiler.go index ff06e7b..d684b6c 100644 --- a/internal/adapters/output/compiler.go +++ b/internal/adapters/output/compiler.go @@ -5,37 +5,54 @@ import ( "log/slog" "os" "os/exec" + "regexp" + "strconv" "strings" "sync" ) const COMPILER = "pdflatex" +var REGEX = regexp.MustCompile(`(\d+) page`) type LatexCompiler struct{} -//Compile the template into PDF -func (*LatexCompiler) CompileTemplate(root string)error{ +//Compile the templates into PDFs and return the number of page of the longest one +func (*LatexCompiler) CompileTemplate(root string)(int,error){ templates,err := getListOfTemplate(root);if err != nil { - return err + return 0,err } + max_nb_of_page := 0 + page_nb := make(chan int, len(templates)) var wg sync.WaitGroup for _,template := range templates{ wg.Add(1) - go compile(template,root,&wg) + go compile(template,root,&wg, page_nb) + pdf_pages_nb := <-page_nb + max_nb_of_page = max(pdf_pages_nb,max_nb_of_page) } + close(page_nb) wg.Wait() - return nil + return max_nb_of_page,nil } //Compile the template into a pdf -func compile(template string, root string, wg* sync.WaitGroup){ - defer wg.Done() - cmd := exec.Command(COMPILER,"-interaction=nonstopmode", - "-output-directory="+root+"/assets/latex/output", template ) - log, err := cmd.Output(); if err != nil { - slog.Info("---FROM pdflatex ---\n"+string(log)) - slog.Error("failed to compile file:"+template) +func compile(template string, root string, wg* sync.WaitGroup, c_page_nb chan int){ + defer wg.Done() + cmd := exec.Command(COMPILER,"-interaction=nonstopmode", + "-output-directory="+root+"/assets/latex/output", template ) + log, err := cmd.Output(); if err != nil { + slog.Warn("error(s) to compile file:"+template) } + page_nb := -1 + log_page := REGEX.FindStringSubmatch(string(log)) + if len(log_page)<1{ + slog.Error("failed to compile file didnt get the number of pages:"+template) + fmt.Println(log_page) + }else{ + page_nb,err = strconv.Atoi(log_page[1]);if err != nil{ + slog.Error(err.Error())} + } + c_page_nb <- page_nb } //Return the path of latex file inside the template directory diff --git a/internal/core/generate.go b/internal/core/generate.go index 896a717..41264cf 100644 --- a/internal/core/generate.go +++ b/internal/core/generate.go @@ -68,15 +68,16 @@ func (s *CVService) GenerateTemplates()error{ generiqueTemplate,err := s.templateReader.ReadCVTemplate(s.root,params); if err != nil{ return err } - for _, cv := range cvs { err = generateCVFrom(cv,params,s.root,generiqueTemplate,s.templateProcessor) if err != nil{ return err } } - - err = s.compiler.CompileTemplate(s.root); if err != nil{ return err } + max_nb_page,err := s.compiler.CompileTemplate(s.root); if err != nil{ return err } + println("---") + println(max_nb_page) + println("---") return nil } @@ -91,6 +92,7 @@ func generateCVFrom(cv CV, params Params, root string, cvName := "CV-"+cv.Lang+"-"+vari+".tex" slog.Info("Generating for:"+cvName) cvTemplate := template + for _, section := range cv.Sections { for _, paragraph := range section.Paragraphes { headers := []string{ paragraph.H1, paragraph.H2, @@ -108,6 +110,64 @@ func generateCVFrom(cv CV, params Params, root string, return nil } +//Sort items and after remove the last items +func sortAndRemoveLast(items []string, keywords []string) []string { + if len(items) == 0 { + return items + } + sortByScore(items, keywords) + return items[:len(items)-1] +} + +//Return the index of the section from the CV with the lowest score +func getLowestSection(cv CV, keywords []string) int { + min_score := getScoreSection(cv.Sections[0],keywords) + min_idx := 0 + for idx, section := range cv.Sections[1:] { + current_score := getScoreSection(section,keywords) + if current_score <= min_score{ + min_idx = idx + min_score = current_score + } + } + return min_idx +} + +//Return the index of the section from the CV with the lowest score +func getLowestParagraphe(section Section, keywords []string) int { + min_score := getScoreParagraphe(section.Paragraphes[0],keywords) + min_idx := 0 + for idx, para := range section.Paragraphes[1:] { + current_score := getScoreParagraphe(para,keywords) + if current_score <= min_score{ + min_idx = idx + min_score = current_score + } + } + return min_idx +} + +//Get items of a section and sum they score to get global score of the items +func getScoreSection (section Section, keywords []string)int{ + res := 0 + for _, paragraph := range section.Paragraphes { + for _,item := range paragraph.Items{ + res += getScore(item,keywords) + } + } + return res +} + +//Get items of a single paragraph and sum they score to get global score of the items +func getScoreParagraphe (paragraph Paragraphe, keywords []string)int{ + res := 0 + for _,item := range paragraph.Items{ + res += getScore(item,keywords) + } + return res +} + + //Sorte a slice of items by the number of keyword // //The sort is done in ascending order as the section append work like a stack(Lifo) diff --git a/internal/core/generate_test.go b/internal/core/generate_test.go index a856311..4f52772 100644 --- a/internal/core/generate_test.go +++ b/internal/core/generate_test.go @@ -16,7 +16,7 @@ func (s *MockParamsSource) GetParamsFrom(root string) (Params, error) { } type MockCompiler struct {} -func (c *MockCompiler) CompileTemplate(root string) error { return nil } +func (c *MockCompiler) CompileTemplate(root string) (int,error) { return 0,nil } type MockSource struct { CVs []CV @@ -227,3 +227,197 @@ func TestSortByScore(t *testing.T) { } } } + + +func TestSortAndRemoveLast(t *testing.T) { + keywords := []string{"foo", "bar"} + tests := []struct { + items []string + expected []string + }{ + { + items: []string{" with foo", " with foo and bar", " with neither", " with bar"}, + expected: []string{" with foo and bar", " with foo", " with bar"}, + }, + { + items: []string{" with foo bar foo bar", " with foo", " with bar bar bar", " with foo bar"}, + expected: []string{" with foo bar foo bar", " with bar bar bar", " with foo bar"}, + }, + { + items: []string{" without keywords", " with bar", "Another without keywords"}, + expected: []string{" with bar", " without keywords"}, + }, + { + items: []string{"single item"}, + expected: []string{}, + }, + { + items: []string{}, + expected: []string{}, + }, + } + + for _, tt := range tests { + items := make([]string, len(tt.items)) + copy(items, tt.items) + result := sortAndRemoveLast(items, keywords) + + if len(result) != len(tt.expected) { + t.Errorf("expected length %v but got %v", len(tt.expected), len(result)) + continue + } + + for i := range result { + if result[i] != tt.expected[i] { + t.Errorf("expected %v but got %v", tt.expected, result) + break + } + } + } +} + +func TestGetLowestSection(t *testing.T) { + keywords := []string{"experience", "skills", "projects"} + tests := []struct { + cv CV + expected int + }{ + { + cv: CV{ + Lang: "en", + Sections: []Section{ + { + Title: "Work Experience", + Paragraphes: []Paragraphe{ + {H1: "Experience 1", Items: []string{"experience", "project"}}, + }, + }, + { + Title: "Education", + Paragraphes: []Paragraphe{ + {H1: "Education 1", Items: []string{"education", "degree"}}, + }, + }, + { + Title: "Skills", + Paragraphes: []Paragraphe{ + {H1: "Skills", Items: []string{"skills", "knowledge"}}, + }, + }, + }, + }, + expected: 0, + }, + { + cv: CV{ + Lang: "en", + Sections: []Section{ + { + Title: "Skills", + Paragraphes: []Paragraphe{ + {H1: "Technical Skills", Items: []string{"skills", "knowledge"}}, + }, + }, + { + Title: "Projects", + Paragraphes: []Paragraphe{ + {H1: "Project 1", Items: []string{"project", "skill"}}, + }, + }, + { + Title: "Summary", + Paragraphes: []Paragraphe{ + {H1: "Personal Summary", Items: []string{"summary"}}, + }, + }, + }, + }, + expected: 1, + }, + { + cv: CV{ + Lang: "en", + Sections: []Section{ + { + Title: "Summary", + Paragraphes: []Paragraphe{ + {H1: "Summary", Items: []string{"introduction"}}, + }, + }, + { + Title: "Skills", + Paragraphes: []Paragraphe{ + {H1: "Skills", Items: []string{"skills"}}, + }, + }, + }, + }, + expected: 0, + }, + } + + for _, tt := range tests { + result := getLowestSection(tt.cv, keywords) + if result != tt.expected { + t.Errorf("expected index %v but got %v", tt.expected, result) + } + } +} + +func TestGetLowestParagraphe(t *testing.T) { + keywords := []string{"skills", "experience", "project"} + tests := []struct { + section Section + expected int + }{ + { + section: Section{ + Title: "Work Experience", + Paragraphes: []Paragraphe{ + {H1: "Experience 1", Items: []string{"skills", "project"}}, + {H1: "Experience 2", Items: []string{"experience", "skills"}}, + {H1: "Experience 3", Items: []string{"project"}}, + }, + }, + expected: 1, + }, + { + section: Section{ + Title: "Projects", + Paragraphes: []Paragraphe{ + {H1: "Project A", Items: []string{"project", "skills"}}, + {H1: "Project B", Items: []string{"skills", "experience"}}, + {H1: "Project C", Items: []string{"project", "experience"}}, + }, + }, + expected: 1, + }, + { + section: Section{ + Title: "Skills", + Paragraphes: []Paragraphe{ + {H1: "Skillset 1", Items: []string{"skills", "tools", "project"}}, + {H1: "Skillset 2", Items: []string{"experience", "skills"}}, + }, + }, + expected: 0, + }, + { + section: Section{ + Title: "Summary", + Paragraphes: []Paragraphe{ + {H1: "Summary", Items: []string{}}, + {H1: "Overview", Items: []string{}}, + }, + }, + expected: 0, + }, + } + + for _, tt := range tests { + result := getLowestParagraphe(tt.section, keywords) + if result != tt.expected { + t.Errorf("expected index %v but got %v", tt.expected, result) + } + } +} diff --git a/internal/core/ports.go b/internal/core/ports.go index 8ceef1f..993eaeb 100644 --- a/internal/core/ports.go +++ b/internal/core/ports.go @@ -10,7 +10,7 @@ type ICVservice interface { } type Compiler interface { - CompileTemplate(root string) error + CompileTemplate(root string) (int,error) } type SourceParams interface {