feat: harden support, localize knowledge and add operator availability [skip ci]
Source-only publication of reviewed commit 64e96a7f423673dc29ad56485be9fc79bce8af1c.
Passed in isolation: focused frontend/backend tests, race checks, TypeScript typecheck, lint, Go compilation, Flowgram build, and deterministic SDK build/tests.
Not accepted as a production release: Next.js export/native assembly remains blocked by environment memory limits; browser interaction and MySQL staging acceptance remain unverified. No production server, database/schema, runtime configuration, deployment, release tag, or workflow execution was performed.
Expected source tree: 0a4a7528e9.
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
// Modified in the independent AgentDesk fork: localized knowledge workflows and safe display errors.
|
||||
package services
|
||||
|
||||
import (
|
||||
@@ -43,27 +44,27 @@ type knowledgeFAQImportRow struct {
|
||||
Remark string
|
||||
}
|
||||
|
||||
func (s *knowledgeFAQService) BuildKnowledgeFAQImportTemplate() (*response.KnowledgeFAQExportedFile, error) {
|
||||
func (s *knowledgeFAQService) BuildKnowledgeFAQImportTemplate(locales ...string) (*response.KnowledgeFAQExportedFile, error) {
|
||||
workbook := excelize.NewFile()
|
||||
defer workbook.Close()
|
||||
if err := writeKnowledgeFAQWorkbookHeader(workbook); err != nil {
|
||||
if err := writeKnowledgeFAQWorkbookHeader(workbook, locales...); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_ = workbook.SetCellValue(knowledgeFAQExcelSheetName, "A2", "如何重置密码?")
|
||||
_ = workbook.SetCellValue(knowledgeFAQExcelSheetName, "B2", "进入个人设置后点击重置密码。")
|
||||
_ = workbook.SetCellValue(knowledgeFAQExcelSheetName, "C2", "忘记密码怎么办\n重置密码在哪里")
|
||||
_ = workbook.SetCellValue(knowledgeFAQExcelSheetName, "D2", "账号")
|
||||
_ = workbook.SetCellValue(knowledgeFAQExcelSheetName, "A2", i18nx.Getf(knowledgeFAQExcelLocale(locales), "knowledge.excel.exampleQuestion"))
|
||||
_ = workbook.SetCellValue(knowledgeFAQExcelSheetName, "B2", i18nx.Getf(knowledgeFAQExcelLocale(locales), "knowledge.excel.exampleAnswer"))
|
||||
_ = workbook.SetCellValue(knowledgeFAQExcelSheetName, "C2", i18nx.Getf(knowledgeFAQExcelLocale(locales), "knowledge.excel.exampleSimilar"))
|
||||
_ = workbook.SetCellValue(knowledgeFAQExcelSheetName, "D2", i18nx.Getf(knowledgeFAQExcelLocale(locales), "knowledge.excel.exampleRemark"))
|
||||
return buildKnowledgeFAQExcelFile("knowledge-faq-import-template.xlsx", workbook)
|
||||
}
|
||||
|
||||
func (s *knowledgeFAQService) ExportKnowledgeFAQs(knowledgeBaseID int64) (*response.KnowledgeFAQExportedFile, error) {
|
||||
func (s *knowledgeFAQService) ExportKnowledgeFAQs(knowledgeBaseID int64, locales ...string) (*response.KnowledgeFAQExportedFile, error) {
|
||||
if _, err := s.requireFAQKnowledgeBase(knowledgeBaseID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
list := repositories.KnowledgeFAQRepository.FindAllByKnowledgeBaseID(sqls.DB(), knowledgeBaseID)
|
||||
workbook := excelize.NewFile()
|
||||
defer workbook.Close()
|
||||
if err := writeKnowledgeFAQWorkbookHeader(workbook); err != nil {
|
||||
if err := writeKnowledgeFAQWorkbookHeader(workbook, locales...); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for index, item := range list {
|
||||
@@ -182,7 +183,7 @@ func (s *knowledgeFAQService) ImportKnowledgeFAQs(req request.ImportKnowledgeFAQ
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func writeKnowledgeFAQWorkbookHeader(workbook *excelize.File) error {
|
||||
func writeKnowledgeFAQWorkbookHeader(workbook *excelize.File, locales ...string) error {
|
||||
sheet := workbook.GetSheetName(0)
|
||||
if sheet == "" {
|
||||
sheet = knowledgeFAQExcelSheetName
|
||||
@@ -192,7 +193,13 @@ func writeKnowledgeFAQWorkbookHeader(workbook *excelize.File) error {
|
||||
return err
|
||||
}
|
||||
}
|
||||
headers := []string{"标准问题", "答案", "相似问", "备注"}
|
||||
locale := knowledgeFAQExcelLocale(locales)
|
||||
headers := []string{
|
||||
i18nx.Getf(locale, "knowledge.excel.question"),
|
||||
i18nx.Getf(locale, "knowledge.excel.answer"),
|
||||
i18nx.Getf(locale, "knowledge.excel.similarQuestions"),
|
||||
i18nx.Getf(locale, "knowledge.excel.remark"),
|
||||
}
|
||||
for index, header := range headers {
|
||||
cell, err := excelize.CoordinatesToCellName(index+1, 1)
|
||||
if err != nil {
|
||||
@@ -274,7 +281,7 @@ func parseKnowledgeFAQImportRows(reader io.Reader, locale string) ([]knowledgeFA
|
||||
SimilarQuestions: parseKnowledgeFAQSimilarQuestions(getKnowledgeFAQExcelCell(current, headerMap["similarQuestions"])),
|
||||
Remark: getKnowledgeFAQExcelCell(current, headerMap["remark"]),
|
||||
}
|
||||
if row.Question == "" {
|
||||
if strings.TrimSpace(row.Question) == "" {
|
||||
result.Failed++
|
||||
result.Errors = append(result.Errors, response.KnowledgeFAQImportError{Row: rowNo, Message: i18nx.Getf(locale, "error.e0340")})
|
||||
continue
|
||||
@@ -284,7 +291,7 @@ func parseKnowledgeFAQImportRows(reader io.Reader, locale string) ([]knowledgeFA
|
||||
result.Errors = append(result.Errors, response.KnowledgeFAQImportError{Row: rowNo, Message: i18nx.Getf(locale, "error.e0341")})
|
||||
continue
|
||||
}
|
||||
if row.Answer == "" {
|
||||
if strings.TrimSpace(row.Answer) == "" {
|
||||
result.Failed++
|
||||
result.Errors = append(result.Errors, response.KnowledgeFAQImportError{Row: rowNo, Message: i18nx.Getf(locale, "error.e0292")})
|
||||
continue
|
||||
@@ -302,22 +309,37 @@ func parseKnowledgeFAQImportRows(reader io.Reader, locale string) ([]knowledgeFA
|
||||
|
||||
func buildKnowledgeFAQHeaderMap(headerRow []string) map[string]int {
|
||||
accepted := map[string]string{
|
||||
"标准问题": "question",
|
||||
"问题": "question",
|
||||
"question": "question",
|
||||
"答案": "answer",
|
||||
"answer": "answer",
|
||||
"相似问": "similarQuestions",
|
||||
"相似问题": "similarQuestions",
|
||||
"similarquestions": "similarQuestions",
|
||||
"备注": "remark",
|
||||
"remark": "remark",
|
||||
"标准问题": "question",
|
||||
"问题": "question",
|
||||
"question": "question",
|
||||
"primary question": "question",
|
||||
"standard question": "question",
|
||||
"основной вопрос": "question",
|
||||
"стандартный вопрос": "question",
|
||||
"вопрос": "question",
|
||||
"答案": "answer",
|
||||
"answer": "answer",
|
||||
"ответ": "answer",
|
||||
"相似问": "similarQuestions",
|
||||
"相似问题": "similarQuestions",
|
||||
"similarquestions": "similarQuestions",
|
||||
"similar questions": "similarQuestions",
|
||||
"similar_questions": "similarQuestions",
|
||||
"похожие вопросы": "similarQuestions",
|
||||
"похожие вопрос": "similarQuestions",
|
||||
"схожие вопросы": "similarQuestions",
|
||||
"备注": "remark",
|
||||
"remark": "remark",
|
||||
"remarks": "remark",
|
||||
"notes": "remark",
|
||||
"примечание": "remark",
|
||||
"примечания": "remark",
|
||||
}
|
||||
result := make(map[string]int)
|
||||
result := map[string]int{"similarQuestions": -1, "remark": -1}
|
||||
for index, header := range headerRow {
|
||||
key := strings.ToLower(strings.TrimSpace(strings.TrimPrefix(header, "\uFEFF")))
|
||||
if field, ok := accepted[key]; ok {
|
||||
if _, exists := result[field]; !exists {
|
||||
if existing, exists := result[field]; !exists || existing < 0 {
|
||||
result[field] = index
|
||||
}
|
||||
}
|
||||
@@ -329,7 +351,8 @@ func getKnowledgeFAQExcelCell(row []string, index int) string {
|
||||
if index < 0 || index >= len(row) {
|
||||
return ""
|
||||
}
|
||||
return strings.TrimSpace(row[index])
|
||||
// Keep authored Q/A and notes verbatim; trim only for validation and headers.
|
||||
return row[index]
|
||||
}
|
||||
|
||||
func isKnowledgeFAQExcelRowEmpty(row []string) bool {
|
||||
@@ -346,8 +369,8 @@ func parseKnowledgeFAQSimilarQuestions(value string) []string {
|
||||
items := make([]string, 0, len(lines))
|
||||
seen := make(map[string]struct{}, len(lines))
|
||||
for _, line := range lines {
|
||||
item := strings.TrimSpace(strings.ReplaceAll(line, "\r", ""))
|
||||
if item == "" {
|
||||
item := strings.TrimSuffix(line, "\r")
|
||||
if strings.TrimSpace(item) == "" {
|
||||
continue
|
||||
}
|
||||
if _, ok := seen[item]; ok {
|
||||
@@ -369,3 +392,10 @@ func decodeKnowledgeFAQSimilarQuestions(value string) []string {
|
||||
}
|
||||
return items
|
||||
}
|
||||
|
||||
func knowledgeFAQExcelLocale(locales []string) string {
|
||||
if len(locales) > 0 {
|
||||
return i18nx.NormalizeLocale(locales[0])
|
||||
}
|
||||
return i18nx.DefaultLocale
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user