聊聊Spring AI Alibaba的YuQueDocumentReader

本文主要研究一下Spring AI Alibaba的YuQueDocumentReader

YuQueDocumentReader

community/document-readers/spring-ai-alibaba-starter-document-reader-yuque/src/main/java/com/alibaba/cloud/ai/reader/yuque/YuQueDocumentReader.java

public class YuQueDocumentReader implements DocumentReader {private final DocumentParser parser;private final YuQueResource yuQueResource;public YuQueDocumentReader(YuQueResource yuQueResource, DocumentParser parser) {this.yuQueResource = yuQueResource;this.parser = parser;}@Overridepublic List<Document> get() {try {List<Document> documents = parser.parse(yuQueResource.getInputStream());String source = yuQueResource.getResourcePath();for (Document doc : documents) {doc.getMetadata().put(YuQueResource.SOURCE, source);}return documents;}catch (IOException ioException) {throw new RuntimeException("Failed to load document from yuque: {}", ioException);}}}

YuQueDocumentReader構造器要求輸入YuQueResource、DocumentParser,其get方法通過DocumentParser解析,最后在其metadata追加一個SOURCE

YuQueResource

community/document-readers/spring-ai-alibaba-starter-document-reader-yuque/src/main/java/com/alibaba/cloud/ai/reader/yuque/YuQueResource.java

public class YuQueResource implements Resource {private static final String BASE_URL = "https://www.yuque.com";private static final String INFO_PATH = "/api/v2/hello";private static final String DOC_DETAIL_PATH = "/api/v2/repos/%s/%s/docs/%s";public static final String SOURCE = "source";public static final String SUPPORT_TYPE = "Doc";private final HttpClient httpClient;private final InputStream inputStream;private final URI uri;private final String resourcePath;private String groupLogin;private String bookSlug;private String id;public YuQueResource(String yuQueToken, String resourcePath) {this.resourcePath = resourcePath;this.httpClient = HttpClient.newBuilder().version(HttpClient.Version.HTTP_2).build();judgePathRule(resourcePath);judgeToken(yuQueToken);URI baseUri = URI.create(BASE_URL + DOC_DETAIL_PATH.formatted(groupLogin, bookSlug, id));HttpRequest httpRequest = HttpRequest.newBuilder().header("X-Auth-Token", yuQueToken).uri(baseUri).GET().build();try {HttpResponse<String> response = this.httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString());String body = response.body();// Parse the JSON response using JacksonObjectMapper objectMapper = new ObjectMapper();JsonNode jsonObject = objectMapper.readTree(body);JsonNode dataObject = jsonObject.get("data");if (dataObject == null || !dataObject.isObject()) {throw new RuntimeException("Invalid response format: 'data' is not an object");}if (!Objects.equals(dataObject.get("type").asText(), SUPPORT_TYPE)) {throw new RuntimeException("Unsupported resource type, only support " + SUPPORT_TYPE);}inputStream = new ByteArrayInputStream(dataObject.get("body_html").asText().getBytes());uri = URI.create(resourcePath);}catch (Exception e) {throw new RuntimeException(e);}}/*** Judge resource path rule Official online doc* https://www.yuque.com/yuque/developer/openapi* @param resourcePath*/private void judgePathRule(String resourcePath) {// Determine if the path conforms to this format: https://xx.xxx.com/aa/bb/ccString regex = "^https://[a-zA-Z0-9.-]+/([a-zA-Z0-9.-]+)/([a-zA-Z0-9.-]+)/([a-zA-Z0-9.-]+)$";Pattern pattern = Pattern.compile(regex);Matcher matcher = pattern.matcher(resourcePath);Assert.isTrue(matcher.matches(), "Invalid resource path");// Extract the captured groupsthis.groupLogin = matcher.group(1);this.bookSlug = matcher.group(2);this.id = matcher.group(3);Assert.isTrue(StringUtils.hasText(this.groupLogin), "Invalid resource path");Assert.isTrue(StringUtils.hasText(this.bookSlug), "Invalid resource path");Assert.isTrue(StringUtils.hasText(this.id), "Invalid resource path");}/*** judge yuQue token* @param yuQueToken User/Team token*/private void judgeToken(String yuQueToken) {URI uri = URI.create(BASE_URL + INFO_PATH);HttpRequest httpRequest = HttpRequest.newBuilder().header("X-Auth-Token", yuQueToken).uri(uri).GET().build();try {HttpResponse<String> response = this.httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString());int statusCode = response.statusCode();Assert.isTrue(statusCode == 200, "Failed to auth YuQueToken");}catch (Exception e) {throw new RuntimeException(e);}}//......
}  

YuQueResource的構造器要求輸入yuQueToken和resourcePath,它通過httpClient請求https://www.yuque.com/api/v2/repos/{groupLogin}/{bookSlug}/docs/{id},之后解析body_html到inputStream;其中groupLogin、bookSlug、id是judgePathRule通過解析resourcePath提取出來

示例

community/document-readers/spring-ai-alibaba-starter-document-reader-yuque/src/test/java/com/alibaba/cloud/ai/reader/yuque/YuQueDocumentLoaderIT.java

@EnabledIfEnvironmentVariable(named = "YUQUE_TOKEN", matches = ".+")
@EnabledIfEnvironmentVariable(named = "YUQUE_RESOURCE_PATH", matches = ".+")
class YuQueDocumentLoaderIT {private static final String YU_QUE_TOKEN = System.getenv("YUQUE_TOKEN");private static final String RESOURCE_PATH = System.getenv("YUQUE_RESOURCE_PATH");YuQueDocumentReader reader;YuQueResource source;static {if (YU_QUE_TOKEN == null || RESOURCE_PATH == null) {System.out.println("YUQUE_TOKEN or YUQUE_RESOURCE_PATH environment variable is not set. Tests will be skipped.");}}@BeforeEachpublic void beforeEach() {// Skip test if environment variables are not setAssumptions.assumeTrue(YU_QUE_TOKEN != null && !YU_QUE_TOKEN.isEmpty(),"Skipping test because YUQUE_TOKEN is not set");Assumptions.assumeTrue(RESOURCE_PATH != null && !RESOURCE_PATH.isEmpty(),"Skipping test because YUQUE_RESOURCE_PATH is not set");source = YuQueResource.builder().yuQueToken(YU_QUE_TOKEN).resourcePath(RESOURCE_PATH).build();reader = new YuQueDocumentReader(source, new TikaDocumentParser());}@Testpublic void should_load_file() {// Skip test if reader is not initializedAssumptions.assumeTrue(reader != null, "Skipping test because reader is not initialized");List<Document> document = reader.get();String content = document.get(0).getText();System.out.println(content);}}

小結

spring-ai-alibaba-starter-document-reader-yuque提供了YuQueDocumentReader,它通過YuQueResource去請求資源,再通過DocumentParser解析(比如TikaDocumentParser)為Document,最后追加一個SOURCE的metadata。

doc

  • java2ai

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/80666.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/80666.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/80666.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

OCR定制識別:解鎖文字識別的無限可能

OCR 定制識別是什么&#xff1f; OCR&#xff0c;即光學字符識別&#xff08;Optical Character Recognition&#xff09; &#xff0c;它就像是一個神奇的 “文字翻譯器”&#xff0c;能把圖片里的文字轉化成計算機可編輯的文本。比如&#xff0c;你掃描一份紙質文檔成圖片&am…

麒麟系統(基于Ubuntu)上使用Qt編譯時遇到“type_traits文件未找到”的錯誤

在麒麟系統&#xff08;基于Ubuntu&#xff09;上使用Qt編譯時遇到“type_traits文件未找到”的錯誤&#xff0c;通常是由于C標準庫頭文件缺失或項目配置問題導致的。以下是逐步解決方案&#xff1a; 1. 安裝C標準庫和開發工具 確保系統已安裝完整的開發工具鏈和標準庫&#…

服務器上安裝node

1.安裝 下載安裝包 https://nodejs.org/en/download 解壓安裝包 將安裝包上傳到/opt/software目錄下 cd /opt/software tar -xzvf node-v16.14.2-linux-x64.tar.gz 將解壓的文件夾移動到安裝目錄(/opt/nodejs)下 mv /opt/software/node-v16.14.2-linux-x64 /opt/nodejs …

Vue3 + Vite + TS,使用 ExcelJS導出excel文檔,生成水印,添加背景水印,dom轉圖片,插入圖片,全部代碼

Vue3 Vite TS,使用 ExcelJS導出excel文檔&#xff0c;生成水印&#xff0c;添加背景水印&#xff0c;dom轉圖片&#xff0c;插入圖片&#xff0c;全部代碼 ExcelJS生成文檔并導出導出表頭其他函數 生成水印設置文檔的背景水印dom 轉圖片插入圖片全部代碼 ExcelJS 讀取&#…

devops自動化容器化部署

devops 一、簡單案例體驗gitlabrunner部署靜態文件二、devops企業級部署方案1、流程圖2、依賴工具3、流程圖4、主機規劃5、安裝工具軟件1、安裝git2、安裝gitlab3、安裝jenkins-server4、安裝harbor5、安裝web-server&#xff0c;也就是部署服務的機子&#xff0c;需要安裝dock…

高級 SQL 技巧:提升數據處理能力的實用方法

在數據驅動的時代,SQL 作為操作和管理關系型數據庫的標準語言,其重要性不言而喻。基礎的 SQL 語句能滿足日常的數據查詢需求,但在處理復雜業務邏輯、進行數據分析和優化數據庫性能時,就需要掌握一些高級 SQL 技巧。這些技巧不僅能提高查詢效率,還能實現復雜的數據處理任務…

21.disql命令登錄達夢數據庫,查詢并操作數據庫

目錄 1.連接達夢數據庫 1.1 windows或linux系統 步驟&#xff08;1&#xff09;&#xff1a;打開終端窗口 步驟&#xff08;2&#xff09;&#xff1a;進入夢數據庫安裝目錄下的 bin 文件夾 步驟&#xff08;3&#xff09;&#xff1a;用disql命令進行登錄 1.2 docker部署…

N8N MACOS本地部署流程避坑指南

最近n8n很火&#xff0c;就想在本地部署一個&#xff0c;嘗嘗鮮&#xff0c;看說明n8n是開源軟件&#xff0c;可以在本地部署&#xff0c;于是就嘗試部署了下&#xff0c;大概用了1個多小時&#xff0c;把相關的過程記錄一下&#xff1a; 1、基礎軟件包 abcXu-MacBook-m2-Air…

qt之開發大恒usb3.0相機一

1.在大恒相機給的sample里沒有看見qt開發的demo. 第一步先運行c sdk中中的demo&#xff0c;看了下代碼&#xff0c;大恒使用的UI框架是MFC.然后 vs2022編譯。運行結果 第一步&#xff0c;先用qt進行坐下頁面布局&#xff0c;如下圖&#xff08;保存圖片的地方做了些更改&#…

leetcode-枚舉

枚舉 3200. 三角形的最大高度 題目 給你兩個整數 red 和 blue&#xff0c;分別表示紅色球和藍色球的數量。你需要使用這些球來組成一個三角形&#xff0c;滿足第 1 行有 1 個球&#xff0c;第 2 行有 2 個球&#xff0c;第 3 行有 3 個球&#xff0c;依此類推。 每一行的球必…

DeepSeek智能時空數據分析(三):專業級地理數據可視化賞析-《杭州市國土空間總體規劃(2021-2035年)》

序言&#xff1a;時空數據分析很有用&#xff0c;但是GIS/時空數據庫技術門檻太高 時空數據分析在優化業務運營中至關重要&#xff0c;然而&#xff0c;三大挑戰仍制約其發展&#xff1a;技術門檻高&#xff0c;需融合GIS理論、SQL開發與時空數據庫等多領域知識&#xff1b;空…

如何用WordPress AI插件自動生成SEO文章,提升網站流量?

1. 為什么你需要一個WordPress AI文章生成插件&#xff1f; 每天手動寫文章太耗時&#xff1f;SEO優化總是不達標&#xff1f;WordPress AI插件能幫你24小時自動生成原創內容&#xff0c;從關鍵詞挖掘到智能排版&#xff0c;全程無需人工干預。 痛點&#xff1a;手動寫作效率低…

鼠標指定范圍內隨機點擊

鼠標指定范圍內隨機點擊 點贊神器 將鼠標移動到相應位置后按F5 F6鍵&#xff0c;設置點擊范圍&#xff0c; F8開始&#xff0c;ESC中止。 有些直播有點贊限制&#xff0c;例如某音&#xff0c;每小時限制3千次&#xff0c;可以設置1200毫秒&#xff0c;3000次。 軟件截圖&#…

數據庫設置外鍵的作用

數據庫外鍵&#xff08;Foreign Key&#xff09;是關系型數據庫中用于建立表與表之間關聯關系的重要約束&#xff0c;其核心作用是確保數據的一致性、完整性和關聯性。以下是外鍵的主要作用及相關說明&#xff1a; 1. 建立表間關聯關系 外鍵通過引用另一張表的主鍵&#xff0…

發幣流程是什么,需要多少成本?

這是一個專注于Web3相關開發的賬號&#xff0c;具體會講解步驟以及開發方案 偶爾會有科普&#xff0c;有興趣的可以點右上角關注一下 發幣&#xff08;發行數字貨幣&#xff09;的流程通常涉及技術實現、法律合規、經濟模型設計等多個環節&#xff0c;以下是關鍵步驟的簡要說明…

測試常用的Linux系統指令詳解

為什么測試工程師需要掌握Linux命令&#xff1f; 在現代軟件測試領域&#xff0c;約75%的服務端應用運行在Linux環境中&#xff0c;能夠熟練使用Linux命令的測試工程師&#xff0c;其工作效率比僅依賴GUI工具的測試人員高出40%以上。本文將系統介紹測試工作中最實用的Linux命令…

Java學習手冊:Web 安全基礎

一、常見 Web 安全威脅 在 Web 開發中&#xff0c;安全問題至關重要。以下是一些常見的 Web 安全威脅&#xff1a; 1. SQL 注入 SQL 注入是一種攻擊方式&#xff0c;攻擊者通過在輸入字段中插入惡意的 SQL 代碼&#xff0c;從而操縱數據庫。例如&#xff0c;假設有一個登錄表…

游戲引擎學習第246天:將 Worker 上下文移到主線程創建

回顧并為今天的工作做準備 關于GPU驅動bug的問題&#xff0c;目前本地機器上沒有復現。如果有問題&#xff0c;昨天的測試就應該已經暴露出來了。當前演示的是游戲的過場動畫&#xff0c;運行正常&#xff0c;使用的是硬件渲染。 之前使用軟件渲染時沒有遇到太多問題&#xff…

2025.4.26總結

今天把馬良老師的《職場十二法則》看完后&#xff0c;感觸極大&#xff0c;這們課程就是一場職場啟蒙課。 雖然看過不少關于職場的書籍&#xff0c;但大多數是關于職場進階&#xff0c;方法方面的。并沒有解答“面對未來二三十年的職場生涯&#xff0c;我該怎么去看待自己的工…

路由器轉發規則設置方法步驟,內網服務器端口怎么讓異地連接訪問的實現

在路由器上設置端口轉發&#xff08;Port Forwarding&#xff09;可以將外部網絡流量引導到特定的局域網設備&#xff0c;這對于需要遠程訪問服務器、攝像頭、游戲主機等設備非常有用。 登錄路由器管理界面&#xff0c;添加端口轉發規則讓外網訪問內網的實現教程分享。以下是設…