fix: cross-section search and CSS loading for chat widget
- agent.go: add section="search" that queries experience, projects, skills, and courses simultaneously — fixes missing results when a technology spans multiple CV sections (e.g. Java at Insa) - head-styles.html: use modular CSS in development mode and load chat CSS separately — fixes unstyled page when bundle is stale
This commit is contained in:
+34
-6
@@ -33,6 +33,7 @@ You answer questions about the CV owner's experience, projects, skills, educatio
|
|||||||
|
|
||||||
RULES:
|
RULES:
|
||||||
- Use the query_cv tool to look up CV data before answering. Never make up information.
|
- Use the query_cv tool to look up CV data before answering. Never make up information.
|
||||||
|
- For technology questions (e.g. "Java", "Go", "React"), ALWAYS use section="search" — this searches across experience, projects, courses, and skills simultaneously. Do NOT search only projects or only experience.
|
||||||
- Answer in the SAME LANGUAGE the user writes in. If they ask in Spanish, answer in Spanish.
|
- Answer in the SAME LANGUAGE the user writes in. If they ask in Spanish, answer in Spanish.
|
||||||
- Be concise and direct — visitors want quick answers, not essays.
|
- Be concise and direct — visitors want quick answers, not essays.
|
||||||
- When listing items (projects, technologies, companies), use bullet points.
|
- When listing items (projects, technologies, companies), use bullet points.
|
||||||
@@ -42,18 +43,19 @@ RULES:
|
|||||||
- You represent the CV owner professionally — be friendly but not overly casual.
|
- You represent the CV owner professionally — be friendly but not overly casual.
|
||||||
|
|
||||||
EXAMPLES of questions you might receive:
|
EXAMPLES of questions you might receive:
|
||||||
- "How many years of experience does Juan have?"
|
- "How many years of experience does Juan have?" → section="summary"
|
||||||
- "What Go projects has he built?"
|
- "What Java experience does he have?" → section="search", query="java"
|
||||||
- "Has he worked with React?"
|
- "Has he worked with React?" → section="search", query="react"
|
||||||
- "Tell me about his time at Olympic Broadcasting"
|
- "Tell me about his time at Olympic Broadcasting" → section="search", query="olympic"
|
||||||
- "What certifications does he have?"`,
|
- "What certifications does he have?" → section="certifications"
|
||||||
|
- "List all his projects" → section="projects"`,
|
||||||
Tools: []tool.Tool{queryTool},
|
Tools: []tool.Tool{queryTool},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// QueryCVArgs is the input for the CV query tool.
|
// QueryCVArgs is the input for the CV query tool.
|
||||||
type QueryCVArgs struct {
|
type QueryCVArgs struct {
|
||||||
Section string `json:"section" jsonschema:"CV section to query: 'experience', 'projects', 'skills', 'education', 'languages', 'certifications', 'courses', 'awards', 'summary', 'all'"`
|
Section string `json:"section" jsonschema:"CV section to query: 'search' (cross-section keyword search — recommended for technology queries), 'experience', 'projects', 'skills', 'education', 'languages', 'certifications', 'courses', 'awards', 'summary', 'all'"`
|
||||||
Query string `json:"query" jsonschema:"Search term to filter results (e.g. 'Go', 'React', '2019', 'Olympic'). Empty returns all items in the section."`
|
Query string `json:"query" jsonschema:"Search term to filter results (e.g. 'Go', 'React', '2019', 'Olympic'). Empty returns all items in the section."`
|
||||||
Language string `json:"language" jsonschema:"Language for CV data: 'en' or 'es'. Default: 'en'."`
|
Language string `json:"language" jsonschema:"Language for CV data: 'en' or 'es'. Default: 'en'."`
|
||||||
}
|
}
|
||||||
@@ -71,6 +73,7 @@ func newQueryCVTool(dataCache *cache.DataCache) (tool.Tool, error) {
|
|||||||
Name: "query_cv",
|
Name: "query_cv",
|
||||||
Description: `Query the CV data to answer questions about experience, projects, skills, education, certifications, and more.
|
Description: `Query the CV data to answer questions about experience, projects, skills, education, certifications, and more.
|
||||||
Use the 'section' parameter to target a specific area, and 'query' to filter by keyword.
|
Use the 'section' parameter to target a specific area, and 'query' to filter by keyword.
|
||||||
|
For technology or keyword queries (e.g. "Java", "Go", "React", "Olympic"), use section="search" to search across experience, projects, skills, and courses simultaneously. This avoids missing results that appear in multiple sections.
|
||||||
Always call this tool before answering CV-related questions.`,
|
Always call this tool before answering CV-related questions.`,
|
||||||
}, func(ctx tool.Context, args QueryCVArgs) (QueryCVResult, error) {
|
}, func(ctx tool.Context, args QueryCVArgs) (QueryCVResult, error) {
|
||||||
lang := args.Language
|
lang := args.Language
|
||||||
@@ -128,6 +131,31 @@ Always call this tool before answering CV-related questions.`,
|
|||||||
result.TotalFound = len(cv.Awards)
|
result.TotalFound = len(cv.Awards)
|
||||||
result.Data = mustJSON(cv.Awards)
|
result.Data = mustJSON(cv.Awards)
|
||||||
|
|
||||||
|
case "search":
|
||||||
|
// Cross-section search: search across experience, projects, skills, and courses simultaneously.
|
||||||
|
crossResult := make(map[string]any)
|
||||||
|
total := 0
|
||||||
|
|
||||||
|
if expMatches := filterExperience(cv.Experience, q); len(expMatches) > 0 {
|
||||||
|
crossResult["experience"] = expMatches
|
||||||
|
total += len(expMatches)
|
||||||
|
}
|
||||||
|
if projMatches := filterProjects(cv.Projects, q); len(projMatches) > 0 {
|
||||||
|
crossResult["projects"] = projMatches
|
||||||
|
total += len(projMatches)
|
||||||
|
}
|
||||||
|
if skillMatches := filterSkills(cv.Skills, q); len(skillMatches) > 0 {
|
||||||
|
crossResult["skills"] = skillMatches
|
||||||
|
total += len(skillMatches)
|
||||||
|
}
|
||||||
|
if courseMatches := filterCourses(cv.Courses, q); len(courseMatches) > 0 {
|
||||||
|
crossResult["courses"] = courseMatches
|
||||||
|
total += len(courseMatches)
|
||||||
|
}
|
||||||
|
|
||||||
|
result.TotalFound = total
|
||||||
|
result.Data = mustJSON(crossResult)
|
||||||
|
|
||||||
case "all":
|
case "all":
|
||||||
// Return a high-level overview
|
// Return a high-level overview
|
||||||
overview := map[string]int{
|
overview := map[string]int{
|
||||||
|
|||||||
@@ -1,7 +1,14 @@
|
|||||||
{{define "head-styles"}}
|
{{define "head-styles"}}
|
||||||
<!-- CSS - Always use bundled CSS (built via 'make css-prod') -->
|
{{if .IsProduction}}
|
||||||
<!-- Individual CSS files are merged into one bundle to reduce HTTP requests -->
|
<!-- CSS - Bundled CSS (built via 'make css-prod') -->
|
||||||
<link rel="stylesheet" href="/static/dist/bundle.min.css?v=20251206b">
|
<link rel="stylesheet" href="/static/dist/bundle.min.css?v=20251206b">
|
||||||
|
{{else}}
|
||||||
|
<!-- CSS - Modular (development) -->
|
||||||
|
<link rel="stylesheet" href="/static/css/main.css">
|
||||||
|
{{end}}
|
||||||
|
{{if .ChatEnabled}}
|
||||||
|
<link rel="stylesheet" href="/static/css/04-interactive/_chat.css">
|
||||||
|
{{end}}
|
||||||
<!-- Print styles - loaded separately, only applied when printing -->
|
<!-- Print styles - loaded separately, only applied when printing -->
|
||||||
<link rel="stylesheet" href="/static/css/print.css" media="print">
|
<link rel="stylesheet" href="/static/css/print.css" media="print">
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|||||||
Reference in New Issue
Block a user