正在显示
13 个修改的文件
包含
663 行增加
和
6 行删除
| 1 | +package org.jeecg.modules.airag.app.config; | ||
| 2 | + | ||
| 3 | +import org.springframework.boot.context.properties.ConfigurationProperties; | ||
| 4 | +import org.springframework.boot.jdbc.DataSourceBuilder; | ||
| 5 | +import org.springframework.context.annotation.Bean; | ||
| 6 | +import org.springframework.context.annotation.Configuration; | ||
| 7 | +import org.springframework.context.annotation.Primary; | ||
| 8 | + | ||
| 9 | +import javax.sql.DataSource; | ||
| 10 | + | ||
| 11 | +@Configuration | ||
| 12 | +public class DataSourceConfig { | ||
| 13 | + | ||
| 14 | +// @Bean(name = "mysqlDataSource") | ||
| 15 | +// @Primary | ||
| 16 | +// @ConfigurationProperties(prefix = "spring.datasource.mysql") | ||
| 17 | +// public DataSource mysqlDataSource() { | ||
| 18 | +// return DataSourceBuilder.create().build(); | ||
| 19 | +// } | ||
| 20 | +// | ||
| 21 | +// @Bean(name = "postgresDataSource") | ||
| 22 | +// @ConfigurationProperties(prefix = "spring.datasource.postgres") | ||
| 23 | +// public DataSource postgresDataSource() { | ||
| 24 | +// return DataSourceBuilder.create().build(); | ||
| 25 | +// } | ||
| 26 | +} |
| 1 | +package org.jeecg.modules.airag.app.controller; | ||
| 2 | + | ||
| 3 | +import java.lang.reflect.Field; | ||
| 4 | +import java.util.Arrays; | ||
| 5 | +import java.util.List; | ||
| 6 | +import javax.servlet.http.HttpServletRequest; | ||
| 7 | +import javax.servlet.http.HttpServletResponse; | ||
| 8 | +import javax.sql.DataSource; | ||
| 9 | +import java.sql.Connection; // PostgreSQL JDBC 连接 | ||
| 10 | +import java.sql.PreparedStatement; | ||
| 11 | +import java.sql.ResultSet; | ||
| 12 | +import java.sql.ResultSetMetaData; | ||
| 13 | +import java.sql.SQLException; | ||
| 14 | +import java.util.ArrayList; | ||
| 15 | +import java.util.HashMap; | ||
| 16 | +import java.util.List; | ||
| 17 | +import java.util.Map; | ||
| 18 | + | ||
| 19 | +import dev.langchain4j.store.embedding.EmbeddingStore; // LangChain4j 的 EmbeddingStore 接口 | ||
| 20 | +import dev.langchain4j.store.embedding.pgvector.PgVectorEmbeddingStore; | ||
| 21 | +import dev.langchain4j.data.embedding.Embedding; | ||
| 22 | +import dev.langchain4j.data.segment.TextSegment; | ||
| 23 | +import dev.langchain4j.model.embedding.EmbeddingModel; | ||
| 24 | +import dev.langchain4j.model.output.Response; | ||
| 25 | +import dev.langchain4j.store.embedding.EmbeddingMatch; | ||
| 26 | +import dev.langchain4j.store.embedding.EmbeddingSearchRequest; | ||
| 27 | +import dev.langchain4j.store.embedding.EmbeddingSearchResult; | ||
| 28 | +import dev.langchain4j.store.embedding.EmbeddingStore; | ||
| 29 | +import dev.langchain4j.store.embedding.pgvector.PgVectorEmbeddingStore; | ||
| 30 | +import org.jeecg.common.api.vo.Result; | ||
| 31 | +import org.jeecg.common.system.query.QueryGenerator; | ||
| 32 | + | ||
| 33 | +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; | ||
| 34 | +import com.baomidou.mybatisplus.core.metadata.IPage; | ||
| 35 | +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | ||
| 36 | +import lombok.extern.slf4j.Slf4j; | ||
| 37 | + | ||
| 38 | +//import org.jeecg.modules.airag.app.config.PostgreEmbeddingStore; | ||
| 39 | +import org.jeecg.modules.airag.app.entity.Embeddings; | ||
| 40 | +import org.jeecg.modules.airag.app.entity.Embeddings; | ||
| 41 | +import org.jeecg.modules.airag.app.service.IEmbeddingsService; | ||
| 42 | +import org.jeecg.common.system.base.controller.JeecgController; | ||
| 43 | +import org.jeecg.modules.airag.app.utils.AiModelUtils; | ||
| 44 | +import org.jeecg.modules.airag.llm.entity.AiragModel; | ||
| 45 | +import org.springframework.beans.factory.annotation.Autowired; | ||
| 46 | +import org.springframework.beans.factory.annotation.Qualifier; | ||
| 47 | +import org.springframework.boot.jdbc.DataSourceBuilder; | ||
| 48 | +import org.springframework.web.bind.annotation.*; | ||
| 49 | +import org.springframework.web.servlet.ModelAndView; | ||
| 50 | +import io.swagger.v3.oas.annotations.tags.Tag; | ||
| 51 | +import io.swagger.v3.oas.annotations.Operation; | ||
| 52 | +import org.jeecg.common.aspect.annotation.AutoLog; | ||
| 53 | +import org.apache.shiro.authz.annotation.RequiresPermissions; | ||
| 54 | + | ||
| 55 | + /** | ||
| 56 | + * @Description: Embeddings | ||
| 57 | + * @Author: jeecg-boot | ||
| 58 | + * @Date: 2025-05-26 | ||
| 59 | + * @Version: V1.0 | ||
| 60 | + */ | ||
| 61 | +@Tag(name="Embeddings") | ||
| 62 | +@RestController | ||
| 63 | +@RequestMapping("/embeddings/embeddings") | ||
| 64 | +@Slf4j | ||
| 65 | +public class EmbeddingsController { | ||
| 66 | + @Autowired | ||
| 67 | + private IEmbeddingsService embeddingsService; | ||
| 68 | + | ||
| 69 | + @Autowired | ||
| 70 | + private AiModelUtils aiModelUtils; | ||
| 71 | + | ||
| 72 | + | ||
| 73 | + /** | ||
| 74 | + * 分页列表查询 | ||
| 75 | + * | ||
| 76 | + * @param Embeddings | ||
| 77 | + * @param pageNo | ||
| 78 | + * @param pageSize | ||
| 79 | + * @param req | ||
| 80 | + * @return | ||
| 81 | + */ | ||
| 82 | + //@AutoLog(value = "Embeddings-分页列表查询") | ||
| 83 | + @Operation(summary="Embeddings-分页列表查询") | ||
| 84 | + @GetMapping(value = "/list") | ||
| 85 | + public Result<IPage<Embeddings>> queryPageList(Embeddings Embeddings, | ||
| 86 | + @RequestParam(name="pageNo", defaultValue="1") Integer pageNo, | ||
| 87 | + @RequestParam(name="pageSize", defaultValue="10") Integer pageSize, | ||
| 88 | + HttpServletRequest req) throws NoSuchFieldException, IllegalAccessException, SQLException { | ||
| 89 | + Response<Embedding> embedding = aiModelUtils.getEmbedding("1925730210204721154", "33333"); | ||
| 90 | + | ||
| 91 | + List<Embeddings> records = embeddingsService.findAll(); | ||
| 92 | + for (Embeddings record : records) { | ||
| 93 | + System.out.println("record = " + record); | ||
| 94 | + } | ||
| 95 | + Page<Embeddings> page = new Page<Embeddings>(pageNo, pageSize); | ||
| 96 | + page.setRecords(records); | ||
| 97 | + return Result.OK(page); | ||
| 98 | + } | ||
| 99 | + | ||
| 100 | + /** | ||
| 101 | + * 添加 | ||
| 102 | + * | ||
| 103 | + * @param Embeddings | ||
| 104 | + * @return | ||
| 105 | + */ | ||
| 106 | + @AutoLog(value = "Embeddings-添加") | ||
| 107 | + @Operation(summary="Embeddings-添加") | ||
| 108 | + @RequiresPermissions("Embeddings:Embeddings:add") | ||
| 109 | + @PostMapping(value = "/add") | ||
| 110 | + public Result<String> add(@RequestBody Embeddings Embeddings) { | ||
| 111 | +// embeddingsService.save(Embeddings); | ||
| 112 | + return Result.OK("添加成功!"); | ||
| 113 | + } | ||
| 114 | + | ||
| 115 | + /** | ||
| 116 | + * 编辑 | ||
| 117 | + * | ||
| 118 | + * @param Embeddings | ||
| 119 | + * @return | ||
| 120 | + */ | ||
| 121 | + @AutoLog(value = "Embeddings-编辑") | ||
| 122 | + @Operation(summary="Embeddings-编辑") | ||
| 123 | + @RequiresPermissions("Embeddings:Embeddings:edit") | ||
| 124 | + @RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST}) | ||
| 125 | + public Result<String> edit(@RequestBody Embeddings Embeddings) { | ||
| 126 | +// embeddingsService.updateById(Embeddings); | ||
| 127 | + return Result.OK("编辑成功!"); | ||
| 128 | + } | ||
| 129 | + | ||
| 130 | + /** | ||
| 131 | + * 通过id删除 | ||
| 132 | + * | ||
| 133 | + * @param id | ||
| 134 | + * @return | ||
| 135 | + */ | ||
| 136 | + @AutoLog(value = "Embeddings-通过id删除") | ||
| 137 | + @Operation(summary="Embeddings-通过id删除") | ||
| 138 | + @RequiresPermissions("Embeddings:Embeddings:delete") | ||
| 139 | + @DeleteMapping(value = "/delete") | ||
| 140 | + public Result<String> delete(@RequestParam(name="id",required=true) String id) { | ||
| 141 | +// embeddingsService.removeById(id); | ||
| 142 | + return Result.OK("删除成功!"); | ||
| 143 | + } | ||
| 144 | + | ||
| 145 | + /** | ||
| 146 | + * 批量删除 | ||
| 147 | + * | ||
| 148 | + * @param ids | ||
| 149 | + * @return | ||
| 150 | + */ | ||
| 151 | + @AutoLog(value = "Embeddings-批量删除") | ||
| 152 | + @Operation(summary="Embeddings-批量删除") | ||
| 153 | + @RequiresPermissions("Embeddings:Embeddings:deleteBatch") | ||
| 154 | + @DeleteMapping(value = "/deleteBatch") | ||
| 155 | + public Result<String> deleteBatch(@RequestParam(name="ids",required=true) String ids) { | ||
| 156 | +// this.embeddingsService.removeByIds(Arrays.asList(ids.split(","))); | ||
| 157 | + return Result.OK("批量删除成功!"); | ||
| 158 | + } | ||
| 159 | + | ||
| 160 | + /** | ||
| 161 | + * 通过id查询 | ||
| 162 | + * | ||
| 163 | + * @param id | ||
| 164 | + * @return | ||
| 165 | + */ | ||
| 166 | + //@AutoLog(value = "Embeddings-通过id查询") | ||
| 167 | + @Operation(summary="Embeddings-通过id查询") | ||
| 168 | + @GetMapping(value = "/queryById") | ||
| 169 | + public Result<Embeddings> queryById(@RequestParam(name="id",required=true) String id) { | ||
| 170 | +// Embeddings Embeddings = embeddingsService.getById(id); | ||
| 171 | +// if(Embeddings==null) { | ||
| 172 | +// return Result.error("未找到对应数据"); | ||
| 173 | +// } | ||
| 174 | + return Result.OK(); | ||
| 175 | + } | ||
| 176 | + | ||
| 177 | + /** | ||
| 178 | + * 导出excel | ||
| 179 | + * | ||
| 180 | + * @param request | ||
| 181 | + * @param Embeddings | ||
| 182 | + */ | ||
| 183 | + @RequiresPermissions("Embeddings:Embeddings:exportXls") | ||
| 184 | + @RequestMapping(value = "/exportXls") | ||
| 185 | + public ModelAndView exportXls(HttpServletRequest request, Embeddings Embeddings) { | ||
| 186 | + return null; | ||
| 187 | + } | ||
| 188 | + | ||
| 189 | + /** | ||
| 190 | + * 通过excel导入数据 | ||
| 191 | + * | ||
| 192 | + * @param request | ||
| 193 | + * @param response | ||
| 194 | + * @return | ||
| 195 | + */ | ||
| 196 | + @RequiresPermissions("Embeddings:Embeddings:importExcel") | ||
| 197 | + @RequestMapping(value = "/importExcel", method = RequestMethod.POST) | ||
| 198 | + public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response) { | ||
| 199 | + return null; | ||
| 200 | + } | ||
| 201 | + | ||
| 202 | +} |
| 1 | +package org.jeecg.modules.airag.app.entity; | ||
| 2 | + | ||
| 3 | +import lombok.AllArgsConstructor; | ||
| 4 | +import lombok.Data; | ||
| 5 | +import lombok.NoArgsConstructor; | ||
| 6 | + | ||
| 7 | +import java.util.Map; | ||
| 8 | + | ||
| 9 | +@Data | ||
| 10 | +@AllArgsConstructor | ||
| 11 | +@NoArgsConstructor | ||
| 12 | +public class Embeddings { | ||
| 13 | + private String id; | ||
| 14 | + | ||
| 15 | + private String text; | ||
| 16 | + | ||
| 17 | + private float[] embedding; | ||
| 18 | + | ||
| 19 | + private Map<String, Object> metadata; | ||
| 20 | + | ||
| 21 | + private Double similarity; | ||
| 22 | +} |
jeecg-boot-module/jeecg-boot-module-airag/src/main/java/org/jeecg/modules/airag/app/entity/Test.java
0 → 100644
| 1 | +package org.jeecg.modules.airag.app.entity; | ||
| 2 | + | ||
| 3 | +import java.io.Serializable; | ||
| 4 | +import java.io.UnsupportedEncodingException; | ||
| 5 | +import java.util.Date; | ||
| 6 | +import java.math.BigDecimal; | ||
| 7 | +import com.baomidou.mybatisplus.annotation.IdType; | ||
| 8 | +import com.baomidou.mybatisplus.annotation.TableId; | ||
| 9 | +import com.baomidou.mybatisplus.annotation.TableName; | ||
| 10 | +import com.baomidou.mybatisplus.annotation.TableLogic; | ||
| 11 | +import org.jeecg.common.constant.ProvinceCityArea; | ||
| 12 | +import org.jeecg.common.util.SpringContextUtils; | ||
| 13 | +import lombok.Data; | ||
| 14 | +import com.fasterxml.jackson.annotation.JsonFormat; | ||
| 15 | +import org.springframework.format.annotation.DateTimeFormat; | ||
| 16 | +import org.jeecgframework.poi.excel.annotation.Excel; | ||
| 17 | +import org.jeecg.common.aspect.annotation.Dict; | ||
| 18 | +import io.swagger.v3.oas.annotations.media.Schema; | ||
| 19 | +import lombok.EqualsAndHashCode; | ||
| 20 | +import lombok.experimental.Accessors; | ||
| 21 | + | ||
| 22 | +/** | ||
| 23 | + * @Description: test | ||
| 24 | + * @Author: jeecg-boot | ||
| 25 | + * @Date: 2025-05-26 | ||
| 26 | + * @Version: V1.0 | ||
| 27 | + */ | ||
| 28 | +@Data | ||
| 29 | +@TableName("test") | ||
| 30 | +@Accessors(chain = true) | ||
| 31 | +@EqualsAndHashCode(callSuper = false) | ||
| 32 | +@Schema(description="test") | ||
| 33 | +public class Test implements Serializable { | ||
| 34 | + private static final long serialVersionUID = 1L; | ||
| 35 | + | ||
| 36 | + /**id*/ | ||
| 37 | + @TableId(type = IdType.ASSIGN_ID) | ||
| 38 | + @Schema(description = "id") | ||
| 39 | + private Integer id; | ||
| 40 | + /**name*/ | ||
| 41 | + @Excel(name = "name", width = 15) | ||
| 42 | + @Schema(description = "name") | ||
| 43 | + private String name; | ||
| 44 | +} |
| 1 | +package org.jeecg.modules.airag.app.mapper; | ||
| 2 | + | ||
| 3 | +import java.util.List; | ||
| 4 | + | ||
| 5 | +import org.apache.ibatis.annotations.Param; | ||
| 6 | +import com.baomidou.mybatisplus.core.mapper.BaseMapper; | ||
| 7 | +import org.jeecg.modules.airag.app.entity.Embeddings; | ||
| 8 | +import org.jeecg.modules.airag.app.entity.Test; | ||
| 9 | + | ||
| 10 | +/** | ||
| 11 | + * @Description: test | ||
| 12 | + * @Author: jeecg-boot | ||
| 13 | + * @Date: 2025-05-26 | ||
| 14 | + * @Version: V1.0 | ||
| 15 | + */ | ||
| 16 | +public interface EmbeddingsMapper { | ||
| 17 | + | ||
| 18 | +} |
| 1 | +package org.jeecg.modules.airag.app.mapper; | ||
| 2 | + | ||
| 3 | +import com.fasterxml.jackson.core.JsonProcessingException; | ||
| 4 | +import com.fasterxml.jackson.core.type.TypeReference; | ||
| 5 | +import com.fasterxml.jackson.databind.ObjectMapper; | ||
| 6 | +import com.pgvector.PGvector; | ||
| 7 | +import lombok.extern.slf4j.Slf4j; | ||
| 8 | +import org.apache.commons.lang3.StringUtils; | ||
| 9 | +import org.apache.shiro.dao.DataAccessException; | ||
| 10 | +import org.jeecg.modules.airag.app.entity.Embeddings; | ||
| 11 | +import org.springframework.stereotype.Component; | ||
| 12 | + | ||
| 13 | +import java.sql.*; | ||
| 14 | +import java.util.ArrayList; | ||
| 15 | +import java.util.Collections; | ||
| 16 | +import java.util.List; | ||
| 17 | +import java.util.Map; | ||
| 18 | + | ||
| 19 | +@Component | ||
| 20 | +@Slf4j | ||
| 21 | +public class PgVectorMapper { | ||
| 22 | + | ||
| 23 | + // PostgreSQL连接参数(实际项目中应从配置读取) | ||
| 24 | + private static final String URL = "jdbc:postgresql://192.168.100.103:5432/postgres"; | ||
| 25 | + private static final String USER = "postgres"; | ||
| 26 | + private static final String PASSWORD = "postgres"; | ||
| 27 | + | ||
| 28 | + // 获取数据库连接 | ||
| 29 | + private Connection getConnection() throws SQLException { | ||
| 30 | + return DriverManager.getConnection(URL, USER, PASSWORD); | ||
| 31 | + } | ||
| 32 | + | ||
| 33 | + // 查询所有向量记录 | ||
| 34 | + public List<Embeddings> findAll() { | ||
| 35 | + List<Embeddings> results = new ArrayList<>(); | ||
| 36 | + String sql = "SELECT * FROM embeddings"; | ||
| 37 | + | ||
| 38 | + try (Connection conn = getConnection(); | ||
| 39 | + PreparedStatement stmt = conn.prepareStatement(sql); | ||
| 40 | + ResultSet rs = stmt.executeQuery()) { | ||
| 41 | + | ||
| 42 | + while (rs.next()) { | ||
| 43 | + results.add(mapRowToEmbeddings(rs)); | ||
| 44 | + } | ||
| 45 | + } catch (SQLException e) { | ||
| 46 | + log.error("查询所有向量记录失败", e); | ||
| 47 | + throw new RuntimeException("查询向量数据时发生数据库错误", e); | ||
| 48 | + } | ||
| 49 | + return results; | ||
| 50 | + } | ||
| 51 | + | ||
| 52 | + // 根据ID查询单个向量记录 | ||
| 53 | + public Embeddings findById(Long id) { | ||
| 54 | + String sql = "SELECT * FROM embeddings WHERE id = ?"; | ||
| 55 | + | ||
| 56 | + try (Connection conn = getConnection(); | ||
| 57 | + PreparedStatement stmt = conn.prepareStatement(sql)) { | ||
| 58 | + | ||
| 59 | + stmt.setLong(1, id); | ||
| 60 | + try (ResultSet rs = stmt.executeQuery()) { | ||
| 61 | + if (rs.next()) { | ||
| 62 | + return mapRowToEmbeddings(rs); | ||
| 63 | + } | ||
| 64 | + } | ||
| 65 | + } catch (SQLException e) { | ||
| 66 | + log.error("根据ID查询向量记录失败, ID: {}", id, e); | ||
| 67 | + throw new RuntimeException("根据ID查询向量时发生数据库错误", e); | ||
| 68 | + } | ||
| 69 | + return null; | ||
| 70 | + } | ||
| 71 | + | ||
| 72 | + // 插入新向量记录 | ||
| 73 | + public int insert(Embeddings record) { | ||
| 74 | + String sql = "INSERT INTO embeddings (id, embedding, metadata) VALUES (?, ?, ?::jsonb)"; | ||
| 75 | + | ||
| 76 | + try (Connection conn = getConnection(); | ||
| 77 | + PreparedStatement stmt = conn.prepareStatement(sql)) { | ||
| 78 | + | ||
| 79 | + stmt.setString(1, record.getId()); | ||
| 80 | + stmt.setObject(2, new PGvector(record.getEmbedding())); | ||
| 81 | + stmt.setString(3, toJson(record.getMetadata())); | ||
| 82 | + | ||
| 83 | + return stmt.executeUpdate(); | ||
| 84 | + } catch (SQLException e) { | ||
| 85 | + log.error("插入向量记录失败: {}", record, e); | ||
| 86 | + throw new RuntimeException("插入向量数据时发生数据库错误", e); | ||
| 87 | + } | ||
| 88 | + } | ||
| 89 | + | ||
| 90 | + // 更新向量记录 | ||
| 91 | + public int update(Embeddings record) { | ||
| 92 | + String sql = "UPDATE embeddings SET embedding = ?, metadata = ?::jsonb WHERE id = ?"; | ||
| 93 | + | ||
| 94 | + try (Connection conn = getConnection(); | ||
| 95 | + PreparedStatement stmt = conn.prepareStatement(sql)) { | ||
| 96 | + | ||
| 97 | + stmt.setObject(1, new PGvector(record.getEmbedding())); | ||
| 98 | + stmt.setString(2, toJson(record.getMetadata())); | ||
| 99 | + stmt.setString(3, record.getId()); | ||
| 100 | + | ||
| 101 | + return stmt.executeUpdate(); | ||
| 102 | + } catch (SQLException e) { | ||
| 103 | + log.error("更新向量记录失败: {}", record, e); | ||
| 104 | + throw new RuntimeException("更新向量数据时发生数据库错误", e); | ||
| 105 | + } | ||
| 106 | + } | ||
| 107 | + | ||
| 108 | + // 根据ID删除向量记录 | ||
| 109 | + public int deleteById(Long id) { | ||
| 110 | + String sql = "DELETE FROM embeddings WHERE id = ?"; | ||
| 111 | + | ||
| 112 | + try (Connection conn = getConnection(); | ||
| 113 | + PreparedStatement stmt = conn.prepareStatement(sql)) { | ||
| 114 | + | ||
| 115 | + stmt.setLong(1, id); | ||
| 116 | + return stmt.executeUpdate(); | ||
| 117 | + } catch (SQLException e) { | ||
| 118 | + log.error("删除向量记录失败, ID: {}", id, e); | ||
| 119 | + throw new RuntimeException("删除向量数据时发生数据库错误", e); | ||
| 120 | + } | ||
| 121 | + } | ||
| 122 | + | ||
| 123 | + // 向量相似度搜索 | ||
| 124 | + public List<Embeddings> similaritySearch(float[] vector, int limit) { | ||
| 125 | + String sql = "SELECT * FROM embeddings ORDER BY embedding <-> ? LIMIT ?"; | ||
| 126 | + List<Embeddings> results = new ArrayList<>(); | ||
| 127 | + | ||
| 128 | + try (Connection conn = getConnection(); | ||
| 129 | + PreparedStatement stmt = conn.prepareStatement(sql)) { | ||
| 130 | + | ||
| 131 | + stmt.setObject(1, new PGvector(vector)); | ||
| 132 | + stmt.setInt(2, limit); | ||
| 133 | + | ||
| 134 | + try (ResultSet rs = stmt.executeQuery()) { | ||
| 135 | + while (rs.next()) { | ||
| 136 | + results.add(mapRowToEmbeddings(rs)); | ||
| 137 | + } | ||
| 138 | + } | ||
| 139 | + } catch (SQLException e) { | ||
| 140 | + log.error("向量相似度搜索失败", e); | ||
| 141 | + throw new RuntimeException("执行向量相似度搜索时发生数据库错误", e); | ||
| 142 | + } | ||
| 143 | + return results; | ||
| 144 | + } | ||
| 145 | + | ||
| 146 | + // 将ResultSet行映射为VectorRecord对象 | ||
| 147 | + private Embeddings mapRowToEmbeddings(ResultSet rs) throws SQLException { | ||
| 148 | + Embeddings record = new Embeddings(); | ||
| 149 | + record.setId(rs.getString("embedding_id")); | ||
| 150 | + record.setText(rs.getString("text")); | ||
| 151 | + | ||
| 152 | + String metadataJson = rs.getString("metadata"); | ||
| 153 | + if (StringUtils.isNotBlank(metadataJson)) { | ||
| 154 | + record.setMetadata(fromJson(metadataJson)); | ||
| 155 | + } | ||
| 156 | + | ||
| 157 | + return record; | ||
| 158 | + } | ||
| 159 | + | ||
| 160 | + // 将Map转换为JSON字符串 | ||
| 161 | + private String toJson(Map<String, Object> map) { | ||
| 162 | + try { | ||
| 163 | + return new ObjectMapper().writeValueAsString(map); | ||
| 164 | + } catch (JsonProcessingException e) { | ||
| 165 | + log.error("元数据转换为JSON失败", e); | ||
| 166 | + return "{}"; | ||
| 167 | + } | ||
| 168 | + } | ||
| 169 | + | ||
| 170 | + // 将JSON字符串转换为Map | ||
| 171 | + private Map<String, Object> fromJson(String json) { | ||
| 172 | + try { | ||
| 173 | + return new ObjectMapper().readValue(json, new TypeReference<Map<String, Object>>() {}); | ||
| 174 | + } catch (JsonProcessingException e) { | ||
| 175 | + log.error("JSON转换为元数据失败", e); | ||
| 176 | + return Collections.emptyMap(); | ||
| 177 | + } | ||
| 178 | + } | ||
| 179 | +} |
| 1 | +package org.jeecg.modules.airag.app.service; | ||
| 2 | + | ||
| 3 | +//import org.jeecg.modules.demo.test.entity.Test; | ||
| 4 | +import org.jeecg.modules.airag.app.entity.Test; | ||
| 5 | + | ||
| 6 | +import com.baomidou.mybatisplus.extension.service.IService; | ||
| 7 | +import org.jeecg.modules.airag.app.entity.Embeddings; | ||
| 8 | + | ||
| 9 | +import java.util.List; | ||
| 10 | + | ||
| 11 | +/** | ||
| 12 | + * @Description: test | ||
| 13 | + * @Author: jeecg-boot | ||
| 14 | + * @Date: 2025-05-26 | ||
| 15 | + * @Version: V1.0 | ||
| 16 | + */ | ||
| 17 | +public interface IEmbeddingsService { | ||
| 18 | + | ||
| 19 | + List<Embeddings> findAll(); | ||
| 20 | +} |
| 1 | +package org.jeecg.modules.airag.app.service.impl; | ||
| 2 | + | ||
| 3 | +import org.jeecg.modules.airag.app.entity.Test; | ||
| 4 | +import org.jeecg.modules.airag.app.entity.Embeddings; | ||
| 5 | +import org.jeecg.modules.airag.app.mapper.EmbeddingsMapper; | ||
| 6 | +import org.jeecg.modules.airag.app.mapper.PgVectorMapper; | ||
| 7 | +import org.jeecg.modules.airag.app.service.IEmbeddingsService; | ||
| 8 | +import org.springframework.beans.factory.annotation.Autowired; | ||
| 9 | +import org.springframework.stereotype.Service; | ||
| 10 | + | ||
| 11 | +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; | ||
| 12 | + | ||
| 13 | +import java.util.List; | ||
| 14 | + | ||
| 15 | +/** | ||
| 16 | + * @Description: test | ||
| 17 | + * @Author: jeecg-boot | ||
| 18 | + * @Date: 2025-05-26 | ||
| 19 | + * @Version: V1.0 | ||
| 20 | + */ | ||
| 21 | +@Service | ||
| 22 | +public class IEmbeddingsServiceImpl implements IEmbeddingsService { | ||
| 23 | + @Autowired | ||
| 24 | + private PgVectorMapper pgVectorMapper; | ||
| 25 | + @Override | ||
| 26 | + public List<Embeddings> findAll() { | ||
| 27 | + return pgVectorMapper.findAll(); | ||
| 28 | + } | ||
| 29 | +} |
| 1 | +package org.jeecg.modules.airag.app.utils; | ||
| 2 | + | ||
| 3 | +import dev.langchain4j.data.embedding.Embedding; | ||
| 4 | +import dev.langchain4j.model.embedding.EmbeddingModel; | ||
| 5 | +import dev.langchain4j.model.output.Response; | ||
| 6 | +import org.jeecg.ai.factory.AiModelFactory; | ||
| 7 | +import org.jeecg.ai.factory.AiModelOptions; | ||
| 8 | +import org.jeecg.common.util.AssertUtils; | ||
| 9 | +import org.jeecg.modules.airag.llm.consts.LLMConsts; | ||
| 10 | +import org.jeecg.modules.airag.llm.entity.AiragModel; | ||
| 11 | +import org.jeecg.modules.airag.llm.service.IAiragModelService; | ||
| 12 | +import org.springframework.beans.factory.annotation.Autowired; | ||
| 13 | +import org.springframework.context.annotation.Lazy; | ||
| 14 | +import org.springframework.stereotype.Component; | ||
| 15 | + | ||
| 16 | +import static org.jeecg.modules.airag.llm.handler.EmbeddingHandler.buildModelOptions; | ||
| 17 | + | ||
| 18 | +@Component | ||
| 19 | +public class AiModelUtils { | ||
| 20 | + | ||
| 21 | + @Autowired | ||
| 22 | + @Lazy | ||
| 23 | + private IAiragModelService airagModelService; | ||
| 24 | + | ||
| 25 | + private AiragModel getEmbedModelData(String modelId) { | ||
| 26 | + AssertUtils.assertNotEmpty("向量模型不能为空", modelId); | ||
| 27 | + AiragModel model = airagModelService.getById(modelId); | ||
| 28 | + AssertUtils.assertNotEmpty("向量模型不存在", model); | ||
| 29 | + AssertUtils.assertEquals("仅支持向量模型", LLMConsts.MODEL_TYPE_EMBED, model.getModelType()); | ||
| 30 | + return model; | ||
| 31 | + } | ||
| 32 | + | ||
| 33 | + /** | ||
| 34 | + * 获取向量模型 | ||
| 35 | + * @param modelId 模型id | ||
| 36 | + * @return 向量模型 | ||
| 37 | + */ | ||
| 38 | + public EmbeddingModel getEmbeddingModel(String modelId) { | ||
| 39 | + AiModelOptions modelOp = buildModelOptions(getEmbedModelData(modelId)); | ||
| 40 | + return AiModelFactory.createEmbeddingModel(modelOp); | ||
| 41 | + } | ||
| 42 | + | ||
| 43 | + /** | ||
| 44 | + * 根据模型id选择向量模型,将文本向量化 | ||
| 45 | + * @param modelId 模型id | ||
| 46 | + * text 文本 | ||
| 47 | + * @return Embedding | ||
| 48 | + */ | ||
| 49 | + public Response<Embedding> getEmbedding(String modelId, String text) { | ||
| 50 | + return getEmbeddingModel(modelId).embed(text); | ||
| 51 | + } | ||
| 52 | + | ||
| 53 | + | ||
| 54 | + | ||
| 55 | + | ||
| 56 | +} |
| 1 | +package org.jeecg.modules.airag.app.utils; | ||
| 2 | + | ||
| 3 | +import java.sql.*; | ||
| 4 | +import java.util.ArrayList; | ||
| 5 | +import java.util.HashMap; | ||
| 6 | +import java.util.List; | ||
| 7 | +import java.util.Map; | ||
| 8 | + | ||
| 9 | +public class PureJdbcVectorQuery { | ||
| 10 | + | ||
| 11 | + // PostgreSQL连接参数 | ||
| 12 | + private static final String URL = "jdbc:postgresql://192.168.100.103:5432/postgres"; | ||
| 13 | + private static final String USER = "postgres"; | ||
| 14 | + private static final String PASSWORD = "postgres"; | ||
| 15 | + | ||
| 16 | + public static List<Map<String, Object>> queryVectors() { | ||
| 17 | + List<Map<String, Object>> results = new ArrayList<>(); | ||
| 18 | + | ||
| 19 | + try (Connection conn = DriverManager.getConnection(URL, USER, PASSWORD); | ||
| 20 | + PreparedStatement stmt = conn.prepareStatement("SELECT * FROM embeddings"); | ||
| 21 | + ResultSet rs = stmt.executeQuery()) { | ||
| 22 | + | ||
| 23 | + ResultSetMetaData metaData = rs.getMetaData(); | ||
| 24 | + int columnCount = metaData.getColumnCount(); | ||
| 25 | + | ||
| 26 | + while (rs.next()) { | ||
| 27 | + Map<String, Object> row = new HashMap<>(); | ||
| 28 | + for (int i = 1; i <= columnCount; i++) { | ||
| 29 | + String columnName = metaData.getColumnName(i); | ||
| 30 | + Object value = "embedding".equals(columnName) | ||
| 31 | + ? rs.getBytes(i) // 向量字段特殊处理 | ||
| 32 | + : rs.getObject(i); | ||
| 33 | + row.put(columnName, value); | ||
| 34 | + } | ||
| 35 | + results.add(row); | ||
| 36 | + } | ||
| 37 | + } catch (SQLException e) { | ||
| 38 | + e.printStackTrace(); | ||
| 39 | + } | ||
| 40 | + return results; | ||
| 41 | + } | ||
| 42 | + | ||
| 43 | + | ||
| 44 | + public static void main(String[] args) { | ||
| 45 | + List<Map<String, Object>> maps = queryVectors(); | ||
| 46 | + for (Map<String, Object> map : maps) { | ||
| 47 | + System.out.println(map); | ||
| 48 | + } | ||
| 49 | + } | ||
| 50 | +} |
| @@ -6,6 +6,7 @@ import org.flywaydb.core.Flyway; | @@ -6,6 +6,7 @@ import org.flywaydb.core.Flyway; | ||
| 6 | import org.flywaydb.core.api.FlywayException; | 6 | import org.flywaydb.core.api.FlywayException; |
| 7 | import org.springframework.beans.factory.annotation.Autowired; | 7 | import org.springframework.beans.factory.annotation.Autowired; |
| 8 | 8 | ||
| 9 | +import org.springframework.beans.factory.annotation.Qualifier; | ||
| 9 | import org.springframework.beans.factory.annotation.Value; | 10 | import org.springframework.beans.factory.annotation.Value; |
| 10 | import org.springframework.context.annotation.Bean; | 11 | import org.springframework.context.annotation.Bean; |
| 11 | import org.springframework.context.annotation.Configuration; | 12 | import org.springframework.context.annotation.Configuration; |
| @@ -26,6 +27,7 @@ import java.util.Map; | @@ -26,6 +27,7 @@ import java.util.Map; | ||
| 26 | public class FlywayConfig { | 27 | public class FlywayConfig { |
| 27 | 28 | ||
| 28 | @Autowired | 29 | @Autowired |
| 30 | +// @Qualifier("mysqlDataSource") | ||
| 29 | private DataSource dataSource; | 31 | private DataSource dataSource; |
| 30 | 32 | ||
| 31 | @Autowired | 33 | @Autowired |
| @@ -26,7 +26,7 @@ management: | @@ -26,7 +26,7 @@ management: | ||
| 26 | spring: | 26 | spring: |
| 27 | flyway: | 27 | flyway: |
| 28 | # 是否启用flyway | 28 | # 是否启用flyway |
| 29 | - enabled: true | 29 | + enabled: false |
| 30 | # 是否关闭要清除已有库下的表功能,生产环境必须为true,否则会删库,非常重要!!! | 30 | # 是否关闭要清除已有库下的表功能,生产环境必须为true,否则会删库,非常重要!!! |
| 31 | clean-disabled: true | 31 | clean-disabled: true |
| 32 | servlet: | 32 | servlet: |
| @@ -50,6 +50,8 @@ spring: | @@ -50,6 +50,8 @@ spring: | ||
| 50 | quartz: | 50 | quartz: |
| 51 | job-store-type: jdbc | 51 | job-store-type: jdbc |
| 52 | initialize-schema: embedded | 52 | initialize-schema: embedded |
| 53 | + jdbc: | ||
| 54 | + initialize-schema: always | ||
| 53 | #定时任务启动开关,true-开 false-关 | 55 | #定时任务启动开关,true-开 false-关 |
| 54 | auto-startup: true | 56 | auto-startup: true |
| 55 | #延迟1秒启动定时任务 | 57 | #延迟1秒启动定时任务 |
| @@ -119,6 +121,7 @@ spring: | @@ -119,6 +121,7 @@ spring: | ||
| 119 | web-stat-filter: | 121 | web-stat-filter: |
| 120 | enabled: true | 122 | enabled: true |
| 121 | dynamic: | 123 | dynamic: |
| 124 | + primary: master | ||
| 122 | druid: # 全局druid参数,绝大部分值和默认保持一致。(现已支持的参数如下,不清楚含义不要乱设置) | 125 | druid: # 全局druid参数,绝大部分值和默认保持一致。(现已支持的参数如下,不清楚含义不要乱设置) |
| 123 | # 连接池的配置信息 | 126 | # 连接池的配置信息 |
| 124 | # 初始化大小,最小,最大 | 127 | # 初始化大小,最小,最大 |
| @@ -154,11 +157,11 @@ spring: | @@ -154,11 +157,11 @@ spring: | ||
| 154 | password: 1234 | 157 | password: 1234 |
| 155 | driver-class-name: com.mysql.cj.jdbc.Driver | 158 | driver-class-name: com.mysql.cj.jdbc.Driver |
| 156 | # 多数据源配置 | 159 | # 多数据源配置 |
| 157 | - #multi-datasource1: | ||
| 158 | - #url: jdbc:mysql://localhost:3306/jeecg-boot2?useUnicode=true&characterEncoding=utf8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai | ||
| 159 | - #username: root | ||
| 160 | - #password: root | ||
| 161 | - #driver-class-name: com.mysql.cj.jdbc.Driver | 160 | +# pgvector: |
| 161 | +# jdbc-url: jdbc:postgresql://192.168.100.103:5432/postgres | ||
| 162 | +# username: postgres | ||
| 163 | +# password: postgres | ||
| 164 | +# driver-class-name: org.postgresql.Driver | ||
| 162 | #redis 配置 | 165 | #redis 配置 |
| 163 | redis: | 166 | redis: |
| 164 | database: 0 | 167 | database: 0 |
| @@ -432,6 +432,12 @@ | @@ -432,6 +432,12 @@ | ||
| 432 | </exclusion> | 432 | </exclusion> |
| 433 | </exclusions> | 433 | </exclusions> |
| 434 | </dependency> | 434 | </dependency> |
| 435 | + <!-- HikariCP连接池 --> | ||
| 436 | +<!-- <dependency>--> | ||
| 437 | +<!-- <groupId>com.zaxxer</groupId>--> | ||
| 438 | +<!-- <artifactId>HikariCP</artifactId>--> | ||
| 439 | +<!-- <version>5.0.1</version>--> | ||
| 440 | +<!-- </dependency>--> | ||
| 435 | <dependency> | 441 | <dependency> |
| 436 | <groupId>org.jeecgframework.jimureport</groupId> | 442 | <groupId>org.jeecgframework.jimureport</groupId> |
| 437 | <artifactId>jimureport-nosql-starter</artifactId> | 443 | <artifactId>jimureport-nosql-starter</artifactId> |
-
请 注册 或 登录 后发表评论