2026-06-26 08:37:04 +00:00
|
|
|
|
package matrix
|
|
|
|
|
|
|
2026-07-09 03:45:28 +00:00
|
|
|
|
import "strings"
|
2026-06-26 08:37:04 +00:00
|
|
|
|
|
2026-07-09 03:45:28 +00:00
|
|
|
|
// SelectKnowledgeItems prefers explicit selections, otherwise falls back to all items.
|
2026-06-28 08:28:42 +00:00
|
|
|
|
func SelectKnowledgeItems(selected, all []string) []string {
|
|
|
|
|
|
source := selected
|
|
|
|
|
|
if len(source) == 0 {
|
|
|
|
|
|
source = all
|
|
|
|
|
|
}
|
|
|
|
|
|
return dedupeKnowledgeLines(source)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// MergeKnowledgeItems combines explicit user selections without falling back to unselected items.
|
|
|
|
|
|
func MergeKnowledgeItems(parts ...[]string) []string {
|
|
|
|
|
|
merged := make([]string, 0)
|
|
|
|
|
|
for _, part := range parts {
|
|
|
|
|
|
merged = append(merged, part...)
|
|
|
|
|
|
}
|
|
|
|
|
|
return dedupeKnowledgeLines(merged)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func dedupeKnowledgeLines(lines []string) []string {
|
|
|
|
|
|
out := make([]string, 0, len(lines))
|
|
|
|
|
|
seen := map[string]struct{}{}
|
|
|
|
|
|
for _, item := range lines {
|
|
|
|
|
|
item = strings.TrimSpace(item)
|
|
|
|
|
|
if item == "" {
|
|
|
|
|
|
continue
|
|
|
|
|
|
}
|
|
|
|
|
|
key := strings.ToLower(item)
|
|
|
|
|
|
if _, ok := seen[key]; ok {
|
|
|
|
|
|
continue
|
|
|
|
|
|
}
|
|
|
|
|
|
seen[key] = struct{}{}
|
|
|
|
|
|
out = append(out, item)
|
|
|
|
|
|
}
|
|
|
|
|
|
return out
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-07-09 03:45:28 +00:00
|
|
|
|
// FormatCopyResearchMapBlock renders a compact research-map block for LLM prompts.
|
2026-06-28 08:28:42 +00:00
|
|
|
|
func FormatCopyResearchMapBlock(audience, goal string, questions, pillars, exclusions []string, knowledgeItems ...[]string) string {
|
2026-06-26 08:37:04 +00:00
|
|
|
|
var b strings.Builder
|
|
|
|
|
|
if audience = strings.TrimSpace(audience); audience != "" {
|
|
|
|
|
|
b.WriteString("受眾:")
|
|
|
|
|
|
b.WriteString(audience)
|
|
|
|
|
|
b.WriteString("\n")
|
|
|
|
|
|
}
|
|
|
|
|
|
if goal = strings.TrimSpace(goal); goal != "" {
|
|
|
|
|
|
b.WriteString("內容目標:")
|
|
|
|
|
|
b.WriteString(goal)
|
|
|
|
|
|
b.WriteString("\n")
|
|
|
|
|
|
}
|
|
|
|
|
|
if len(pillars) > 0 {
|
|
|
|
|
|
b.WriteString("支柱:")
|
|
|
|
|
|
b.WriteString(strings.Join(pillars, "、"))
|
|
|
|
|
|
b.WriteString("\n")
|
|
|
|
|
|
}
|
|
|
|
|
|
if len(questions) > 0 {
|
|
|
|
|
|
b.WriteString("受眾問題:")
|
|
|
|
|
|
b.WriteString(strings.Join(questions, ";"))
|
|
|
|
|
|
b.WriteString("\n")
|
|
|
|
|
|
}
|
2026-06-28 08:28:42 +00:00
|
|
|
|
if len(knowledgeItems) > 0 && len(knowledgeItems[0]) > 0 {
|
|
|
|
|
|
b.WriteString("勾選延伸知識:")
|
|
|
|
|
|
b.WriteString(strings.Join(knowledgeItems[0], ";"))
|
|
|
|
|
|
b.WriteString("\n")
|
|
|
|
|
|
}
|
2026-06-26 08:37:04 +00:00
|
|
|
|
if len(exclusions) > 0 {
|
|
|
|
|
|
b.WriteString("排除:")
|
|
|
|
|
|
b.WriteString(strings.Join(exclusions, ";"))
|
|
|
|
|
|
}
|
|
|
|
|
|
return strings.TrimSpace(b.String())
|
|
|
|
|
|
}
|