From b590091c9ea80d8a8a8629ef3ebb6ee27fc99758 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B4=AE=E7=94=9F?= Date: Sat, 15 Jun 2024 17:51:48 +0800 Subject: [PATCH 1/3] :art: Remove the check for !TesseractEnabled when saving OCR recognition results (#11708) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 去除保存ocr识别结果时对 !TesseractEnabled 的检测 * :bug: https://github.com/siyuan-note/siyuan/issues/11709 * https://github.com/siyuan-note/siyuan/pull/11708 修改ocr相关接口 * https://github.com/siyuan-note/siyuan/pull/11708 修改前端相关代码 * Update router.go * Update router.go --------- Co-authored-by: Vanessa --- app/src/menus/protyle.ts | 17 +++++++---------- kernel/api/asset.go | 26 +++++++++++++++++++++----- kernel/api/router.go | 1 + kernel/sql/block.go | 2 +- kernel/util/ocr.go | 10 ++++++++-- 5 files changed, 38 insertions(+), 18 deletions(-) diff --git a/app/src/menus/protyle.ts b/app/src/menus/protyle.ts index 1819e0bf5..1e59bb119 100644 --- a/app/src/menus/protyle.ts +++ b/app/src/menus/protyle.ts @@ -1017,8 +1017,7 @@ export const imgMenu = (protyle: IProtyle, range: Range, assetElement: HTMLEleme bind(element) { element.style.maxWidth = "none"; fetchPost("/api/asset/getImageOCRText", { - path: imgElement.getAttribute("src"), - force: false + path: imgElement.getAttribute("src") }, (response) => { element.querySelector("textarea").value = response.data.text; }); @@ -1029,9 +1028,14 @@ export const imgMenu = (protyle: IProtyle, range: Range, assetElement: HTMLEleme iconHTML: "", label: window.siyuan.languages.reOCR, click() { - fetchPost("/api/asset/getImageOCRText", { + fetchPost("/api/asset/ocr", { path: imgElement.getAttribute("src"), force: true + }, (response) => { + fetchPost("/api/asset/setImageOCRText", { + path: imgElement.getAttribute("src"), + text: response.data.text + }); }); } }], @@ -1115,13 +1119,6 @@ export const imgMenu = (protyle: IProtyle, range: Range, assetElement: HTMLEleme const textElements = window.siyuan.menus.menu.element.querySelectorAll("textarea"); textElements[0].focus(); window.siyuan.menus.menu.removeCB = () => { - const ocrElemennt = window.siyuan.menus.menu.element.querySelector('[data-type="ocr"]') as HTMLTextAreaElement; - if (ocrElemennt) { - fetchPost("/api/asset/setImageOCRText", { - path: imgElement.getAttribute("src"), - text: ocrElemennt.value - }); - } imgElement.setAttribute("alt", textElements[2].value.replace(/\n|\r\n|\r|\u2028|\u2029/g, "")); nodeElement.setAttribute("updated", dayjs().format("YYYYMMDDHHmmss")); updateTransaction(protyle, id, nodeElement.outerHTML, html); diff --git a/kernel/api/asset.go b/kernel/api/asset.go index ba7ef3599..2b3ad7223 100644 --- a/kernel/api/asset.go +++ b/kernel/api/asset.go @@ -107,13 +107,9 @@ func getImageOCRText(c *gin.Context) { } path := arg["path"].(string) - force := false - if forceArg := arg["force"]; nil != forceArg { - force = forceArg.(bool) - } ret.Data = map[string]interface{}{ - "text": util.GetAssetText(path, force), + "text": util.GetAssetText(path), } } @@ -131,6 +127,26 @@ func setImageOCRText(c *gin.Context) { util.SetAssetText(path, text) } +func ocr(c *gin.Context) { + ret := gulu.Ret.NewResult() + defer c.JSON(http.StatusOK, ret) + + arg, ok := util.JsonArg(c, ret) + if !ok { + return + } + + path := arg["path"].(string) + force := false + if forceArg := arg["force"]; nil != forceArg { + force = forceArg.(bool) + } + + ret.Data = map[string]interface{}{ + "text": util.OcrAsset(path, force), + } +} + func renameAsset(c *gin.Context) { ret := gulu.Ret.NewResult() defer c.JSON(http.StatusOK, ret) diff --git a/kernel/api/router.go b/kernel/api/router.go index 567cb37ad..2290ee016 100644 --- a/kernel/api/router.go +++ b/kernel/api/router.go @@ -266,6 +266,7 @@ func ServeAPI(ginServer *gin.Engine) { ginServer.Handle("POST", "/api/asset/renameAsset", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, renameAsset) ginServer.Handle("POST", "/api/asset/getImageOCRText", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, getImageOCRText) ginServer.Handle("POST", "/api/asset/setImageOCRText", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, setImageOCRText) + ginServer.Handle("POST", "/api/asset/ocr", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, ocr) ginServer.Handle("POST", "/api/asset/fullReindexAssetContent", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, fullReindexAssetContent) ginServer.Handle("POST", "/api/asset/statAsset", model.CheckAuth, model.CheckAdminRole, statAsset) diff --git a/kernel/sql/block.go b/kernel/sql/block.go index 0c98a22a7..f6efa0152 100644 --- a/kernel/sql/block.go +++ b/kernel/sql/block.go @@ -198,7 +198,7 @@ func nodeStaticContent(node *ast.Node, excludeTypes []string, includeTextMarkATi var linkDestStr, ocrText string if nil != linkDest { linkDestStr = linkDest.TokensStr() - ocrText = util.GetAssetText(linkDestStr, false) + ocrText = util.OcrAsset(linkDestStr, false) } linkText := n.ChildByType(ast.NodeLinkText) diff --git a/kernel/util/ocr.go b/kernel/util/ocr.go index 8d280cc4e..3f2e8c3b6 100644 --- a/kernel/util/ocr.go +++ b/kernel/util/ocr.go @@ -102,7 +102,7 @@ func LoadAssetsTexts() { } func SaveAssetsTexts() { - if !assetsTextsChanged.Load() || !TesseractEnabled { + if !assetsTextsChanged.Load() { return } @@ -149,7 +149,7 @@ func ExistsAssetText(asset string) (ret bool) { return } -func GetAssetText(asset string, force bool) (ret string) { +func OcrAsset(asset string, force bool) (ret string) { if !force { assetsTextsLock.Lock() ret = assetsTexts[asset] @@ -170,6 +170,12 @@ func GetAssetText(asset string, force bool) (ret string) { return } +// https://github.com/siyuan-note/siyuan/pull/11708 +func GetAssetText(asset string) (ret string) { + ret = assetsTexts[asset] + return +} + func IsTesseractExtractable(p string) bool { lowerName := strings.ToLower(p) return strings.HasSuffix(lowerName, ".png") || strings.HasSuffix(lowerName, ".jpg") || strings.HasSuffix(lowerName, ".jpeg") From e99852f0675e7998a7260d55ce44bde596532b2f Mon Sep 17 00:00:00 2001 From: Daniel <845765@qq.com> Date: Sat, 15 Jun 2024 21:41:04 +0800 Subject: [PATCH 2/3] :art: Improve database block remove https://github.com/siyuan-note/siyuan/issues/11731 --- kernel/model/file.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/kernel/model/file.go b/kernel/model/file.go index 56ff36346..ffb20a41a 100644 --- a/kernel/model/file.go +++ b/kernel/model/file.go @@ -1640,6 +1640,15 @@ func removeDoc(box *Box, p string, luteEngine *lute.Lute) { } indexHistoryDir(filepath.Base(historyDir), util.NewLute()) + // 刷新文档关联的数据库 https://github.com/siyuan-note/siyuan/issues/11731 + allRemoveRootIDs := []string{tree.ID} + allRemoveRootIDs = append(allRemoveRootIDs, removeIDs...) + for _, rootID := range allRemoveRootIDs { + if removeTree, _ := LoadTreeByBlockID(rootID); nil != removeTree { + syncDelete2AttributeView(removeTree.Root) + } + } + if existChildren { if err = box.Remove(childrenDir); nil != err { logging.LogErrorf("remove children dir [%s%s] failed: %s", box.ID, childrenDir, err) From ba8b07f64ccbdb9dec1b57e24c0be0e6b5d2757f Mon Sep 17 00:00:00 2001 From: Daniel <845765@qq.com> Date: Sat, 15 Jun 2024 21:47:49 +0800 Subject: [PATCH 3/3] :art: Supports creating different docs when the database primary key content is the same https://github.com/siyuan-note/siyuan/issues/11713 --- kernel/api/search.go | 7 ++++++- kernel/model/search.go | 12 ++++++++---- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/kernel/api/search.go b/kernel/api/search.go index e16e47beb..bb4f16a43 100644 --- a/kernel/api/search.go +++ b/kernel/api/search.go @@ -341,11 +341,16 @@ func searchRefBlock(c *gin.Context) { isSquareBrackets = isSquareBracketsArg.(bool) } + isDatabase := false + if isDatabaseArg := arg["isDatabase"]; nil != isDatabaseArg { + isDatabase = isDatabaseArg.(bool) + } + rootID := arg["rootID"].(string) id := arg["id"].(string) keyword := arg["k"].(string) beforeLen := int(arg["beforeLen"].(float64)) - blocks, newDoc := model.SearchRefBlock(id, rootID, keyword, beforeLen, isSquareBrackets) + blocks, newDoc := model.SearchRefBlock(id, rootID, keyword, beforeLen, isSquareBrackets, isDatabase) ret.Data = map[string]interface{}{ "blocks": blocks, "newDoc": newDoc, diff --git a/kernel/model/search.go b/kernel/model/search.go index 3faf632ef..b6e228108 100644 --- a/kernel/model/search.go +++ b/kernel/model/search.go @@ -311,7 +311,7 @@ func buildEmbedBlock(embedBlockID string, excludeIDs []string, headingMode int, return } -func SearchRefBlock(id, rootID, keyword string, beforeLen int, isSquareBrackets bool) (ret []*Block, newDoc bool) { +func SearchRefBlock(id, rootID, keyword string, beforeLen int, isSquareBrackets, isDatabase bool) (ret []*Block, newDoc bool) { cachedTrees := map[string]*parse.Tree{} onlyDoc := false @@ -398,9 +398,13 @@ func SearchRefBlock(id, rootID, keyword string, beforeLen int, isSquareBrackets } ret = tmp - if block := treenode.GetBlockTree(id); nil != block { - p := path.Join(block.HPath, keyword) - newDoc = nil == treenode.GetBlockTreeRootByHPath(block.BoxID, p) + if !isDatabase { + // 如果非数据库中搜索块引,则不允许新建重名文档 + // 如果是数据库中搜索绑定块,则允许新建重名文档 https://github.com/siyuan-note/siyuan/issues/11713 + if block := treenode.GetBlockTree(id); nil != block { + p := path.Join(block.HPath, keyword) + newDoc = nil == treenode.GetBlockTreeRootByHPath(block.BoxID, p) + } } // 在 hPath 中加入笔记本名 Show notebooks in hpath of block ref search list results https://github.com/siyuan-note/siyuan/issues/9378