aaa
admin
2025-05-28 b0a1260a566f6c844dd55c67d9587d4753840b0c
aaa
3个文件已修改
13个文件已添加
581 ■■■■■ 已修改文件
aiflowy-commons/aiflowy-common-web/src/main/java/tech/aiflowy/common/web/controller/BaseCurdController.java 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
aiflowy-modules/aiflowy-module-ai/src/main/java/tech/aiflowy/ai/controller/AiMenuController.java 140 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
aiflowy-modules/aiflowy-module-ai/src/main/java/tech/aiflowy/ai/entity/AiFirstMenu.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
aiflowy-modules/aiflowy-module-ai/src/main/java/tech/aiflowy/ai/entity/AiSecondMenu.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
aiflowy-modules/aiflowy-module-ai/src/main/java/tech/aiflowy/ai/entity/base/AiBotBase.java 67 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
aiflowy-modules/aiflowy-module-ai/src/main/java/tech/aiflowy/ai/entity/base/AiFirstMenuBase.java 87 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
aiflowy-modules/aiflowy-module-ai/src/main/java/tech/aiflowy/ai/entity/base/AiSecondMenuBase.java 102 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
aiflowy-modules/aiflowy-module-ai/src/main/java/tech/aiflowy/ai/mapper/AiFirstMenuMapper.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
aiflowy-modules/aiflowy-module-ai/src/main/java/tech/aiflowy/ai/mapper/AiSecondMenuMapper.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
aiflowy-modules/aiflowy-module-ai/src/main/java/tech/aiflowy/ai/service/AiFirstMenuService.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
aiflowy-modules/aiflowy-module-ai/src/main/java/tech/aiflowy/ai/service/AiSecondMenuService.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
aiflowy-modules/aiflowy-module-ai/src/main/java/tech/aiflowy/ai/service/impl/AiFirstMenuServiceImpl.java 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
aiflowy-modules/aiflowy-module-ai/src/main/java/tech/aiflowy/ai/service/impl/AiSecondMenuServiceImpl.java 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
aiflowy-modules/aiflowy-module-ai/src/main/resources/tech/aiflowy/ai/entity/mapper/AiFirstMenuMapper.xml 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
aiflowy-modules/aiflowy-module-ai/src/main/resources/tech/aiflowy/ai/entity/mapper/AiSecondMenuMapper.xml 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
aiflowy-starter/src/main/resources/application.yml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
aiflowy-commons/aiflowy-common-web/src/main/java/tech/aiflowy/common/web/controller/BaseCurdController.java
@@ -1,5 +1,7 @@
package tech.aiflowy.common.web.controller;
import javafx.beans.DefaultProperty;
import org.springframework.web.bind.annotation.RequestParam;
import tech.aiflowy.common.ai.ChatManager;
import tech.aiflowy.common.ai.util.AiSqlUtil;
import tech.aiflowy.common.domain.Result;
@@ -168,6 +170,30 @@
     * @return 查询的结果集
     */
    @GetMapping("page")
    public Result page(HttpServletRequest request, String sortKey, String sortType, Long pageNumber, Long pageSize,
                       @RequestParam(defaultValue = "-1") Integer firstMenuId,
                       @RequestParam(defaultValue = "-1") Integer secondMenuId) {
        if (pageNumber == null || pageNumber < 1) {
            pageNumber = 1L;
        }
        if (pageSize == null || pageSize < 1) {
            pageSize = 10L;
        }
        QueryWrapper queryWrapper = buildQueryWrapper(request);
        queryWrapper.orderBy(buildOrderBy(sortKey, sortType, getDefaultOrderBy()));
        if(firstMenuId == -1 && secondMenuId == -1){
        }
        else if(secondMenuId == -1){
            if(firstMenuId != -1){
                queryWrapper.eq("first_menu_id", firstMenuId);
            }
        }else{
            queryWrapper.eq("second_menu_id", secondMenuId);
        }
        return Result.success(queryPage(new Page<>(pageNumber, pageSize), queryWrapper));
    }
    public Result page(HttpServletRequest request, String sortKey, String sortType, Long pageNumber, Long pageSize) {
        if (pageNumber == null || pageNumber < 1) {
            pageNumber = 1L;
@@ -180,7 +206,6 @@
        queryWrapper.orderBy(buildOrderBy(sortKey, sortType, getDefaultOrderBy()));
        return Result.success(queryPage(new Page<>(pageNumber, pageSize), queryWrapper));
    }
    protected QueryWrapper buildQueryWrapper(HttpServletRequest request) {
aiflowy-modules/aiflowy-module-ai/src/main/java/tech/aiflowy/ai/controller/AiMenuController.java
New file
@@ -0,0 +1,140 @@
package tech.aiflowy.ai.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.mybatisflex.core.paginate.Page;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import tech.aiflowy.ai.entity.AiFirstMenu;
import tech.aiflowy.ai.entity.AiSecondMenu;
import tech.aiflowy.ai.service.AiFirstMenuService;
import tech.aiflowy.ai.service.AiSecondMenuService;
import tech.aiflowy.common.domain.Result;
import java.util.List;
@RestController
@RequestMapping("/api/v1/aiMenu")
public class AiMenuController {
    @Autowired
    private AiFirstMenuService aiFirstMenuService;
    /**
     * 创建一级菜单
     */
    @PostMapping("FirstMenu")
    public Result create(@RequestBody AiFirstMenu menu) {
        boolean success = aiFirstMenuService.save(menu);
        return Result.success(success);
    }
    /**
     * 删除一级菜单
     */
    @DeleteMapping("/FirstMenu/{id}")
    public Result delete(@PathVariable Integer id) {
        boolean success = aiFirstMenuService.removeById(id);
        return Result.success(success);
    }
    /**
     * 更新一级菜单
     */
    @PutMapping("FirstMenu")
    public Result updateFirstMenu(@RequestBody AiFirstMenu menu) {
        boolean success = aiFirstMenuService.updateById(menu);
        return Result.success(success);
    }
    /**
     * 根据ID查询一级菜单
     */
    @GetMapping("/FirstMenu/{id}")
    public Result getByIdFirstMenu(@PathVariable Integer id) {
        AiFirstMenu menu = aiFirstMenuService.getById(id);
        return Result.success(menu);
    }
    /**
     * 分页查询一级菜单
     */
    @GetMapping("/FirstMenu/page")
    public Result pageFirstMenu(
            @RequestParam(defaultValue = "1") Integer pageNumber,
            @RequestParam(defaultValue = "10") Integer pageSize) {
        Page<AiFirstMenu> page = new Page<>(pageNumber, pageSize);
        page = aiFirstMenuService.page(page);
        return Result.success(page);
    }
    /**
     * 获取所有一级菜单
     */
    @GetMapping("FirstMenu/list")
    public Result listFirstMenu() {
        List<AiFirstMenu> list = aiFirstMenuService.list();
        return Result.success(list);
    }
    @Autowired
    private AiSecondMenuService aiSecondMenuService;
    /**
     * 创建二级菜单
     */
    @PostMapping("SecondMenu")
    public Result createSecondMenu(@RequestBody AiSecondMenu menu) {
        boolean success = aiSecondMenuService.save(menu);
        return Result.success(success);
    }
    /**
     * 删除二级菜单
     */
    @DeleteMapping("SecondMenu/{id}")
    public Result deleteSecondMenu(@PathVariable Integer id) {
        boolean success = aiSecondMenuService.removeById(id);
        return Result.success(success);
    }
    /**
     * 更新二级菜单
     */
    @PutMapping("SecondMenu/update")
    public Result updateSecondMenu(@RequestBody AiSecondMenu menu) {
        boolean success = aiSecondMenuService.updateById(menu);
        return Result.success(success);
    }
    /**
     * 根据ID查询二级菜单
     */
    @GetMapping("SecondMenu/{id}")
    public Result getByIdSecondMenu(@PathVariable Integer id) {
        AiSecondMenu menu = aiSecondMenuService.getById(id);
        return Result.success(menu);
    }
    /**
     * 分页查询二级菜单
     */
    @GetMapping("SecondMenu/page")
    public Result pageSecondMenu(
            @RequestParam(defaultValue = "1") Integer pageNumber,
            @RequestParam(defaultValue = "10") Integer pageSize) {
        Page<AiSecondMenu> page = new Page<>(pageNumber, pageSize);
        page = aiSecondMenuService.page(page);
        return Result.success(page);
    }
    /**
     * 获取所有一级菜单
     */
    @GetMapping("SecondMenu/list")
    public Result listSecondMenu() {
        List<AiSecondMenu> list = aiSecondMenuService.list();
        return Result.success(list);
    }
}
aiflowy-modules/aiflowy-module-ai/src/main/java/tech/aiflowy/ai/entity/AiFirstMenu.java
New file
@@ -0,0 +1,8 @@
package tech.aiflowy.ai.entity;
import com.mybatisflex.annotation.Table;
import tech.aiflowy.ai.entity.base.AiFirstMenuBase;
@Table(value ="ai_first_menu")
public class AiFirstMenu extends AiFirstMenuBase {
}
aiflowy-modules/aiflowy-module-ai/src/main/java/tech/aiflowy/ai/entity/AiSecondMenu.java
New file
@@ -0,0 +1,7 @@
package tech.aiflowy.ai.entity;
import com.mybatisflex.annotation.Table;
import tech.aiflowy.ai.entity.base.AiSecondMenuBase;
@Table(value ="ai_second_menu")
public class AiSecondMenu extends AiSecondMenuBase {
}
aiflowy-modules/aiflowy-module-ai/src/main/java/tech/aiflowy/ai/entity/base/AiBotBase.java
@@ -94,6 +94,73 @@
    @Column(comment = "修改者ID")
    private BigInteger modifiedBy;
    @Column(comment = "API品牌")
    private String apiProvider;
    @Column(comment = "API地址")
    private String apiEndpoint;
    @Column(comment = "API密钥")
    private String apiKey;
    @Column(comment = "API额外配置")
    private String apiVersion;
    @Column(comment = "一级菜单编号")
    private Integer firstMenuId;
    @Column(comment = "二级菜单编号")
    private Integer secondMenuId;
    public Integer getFirstMenuId() {
        return firstMenuId;
    }
    public void setFirstMenuId(Integer firstMenuId) {
        this.firstMenuId = firstMenuId;
    }
    public String getApiProvider() {
        return apiProvider;
    }
    public void setApiProvider(String apiProvider) {
        this.apiProvider = apiProvider;
    }
    public String getApiEndpoint() {
        return apiEndpoint;
    }
    public void setApiEndpoint(String apiEndpoint) {
        this.apiEndpoint = apiEndpoint;
    }
    public String getApiKey() {
        return apiKey;
    }
    public void setApiKey(String apiKey) {
        this.apiKey = apiKey;
    }
    public String getApiVersion() {
        return apiVersion;
    }
    public void setApiVersion(String apiVersion) {
        this.apiVersion = apiVersion;
    }
    public Integer getSecondMenuId() {
        return secondMenuId;
    }
    public void setSecondMenuId(Integer secondMenuId) {
        this.secondMenuId = secondMenuId;
    }
    public BigInteger getId() {
        return id;
    }
aiflowy-modules/aiflowy-module-ai/src/main/java/tech/aiflowy/ai/entity/base/AiFirstMenuBase.java
New file
@@ -0,0 +1,87 @@
package tech.aiflowy.ai.entity.base;
import com.mybatisflex.annotation.Column;
import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.KeyType;
import com.mybatisflex.annotation.Table;
import java.math.BigInteger;
/**
 * ai机器人一级菜单表
 * @TableName ai_first_menu
 */
public class AiFirstMenuBase {
    /**
     * 一级菜单编号
     */
    @Id(keyType = KeyType.Auto, value = "firstMenuId", comment = "一级菜单编号")
    private BigInteger firstMenuId;
    /**
     * 一级菜单名称
     */
    @Column(comment = "一级菜单名称")
    private String firstMenuName;
    public BigInteger getFirstMenuId() {
        return firstMenuId;
    }
    public void setFirstMenuId(BigInteger firstMenuId) {
        this.firstMenuId = firstMenuId;
    }
    /**
     * 一级菜单名称
     */
    public String getFirstMenuName() {
        return firstMenuName;
    }
    /**
     * 一级菜单名称
     */
    public void setFirstMenuName(String firstMenuName) {
        this.firstMenuName = firstMenuName;
    }
    @Override
    public boolean equals(Object that) {
        if (this == that) {
            return true;
        }
        if (that == null) {
            return false;
        }
        if (getClass() != that.getClass()) {
            return false;
        }
        AiFirstMenuBase other = (AiFirstMenuBase) that;
        return (this.getFirstMenuId() == null ? other.getFirstMenuId() == null : this.getFirstMenuId().equals(other.getFirstMenuId()))
            && (this.getFirstMenuName() == null ? other.getFirstMenuName() == null : this.getFirstMenuName().equals(other.getFirstMenuName()));
    }
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((getFirstMenuId() == null) ? 0 : getFirstMenuId().hashCode());
        result = prime * result + ((getFirstMenuName() == null) ? 0 : getFirstMenuName().hashCode());
        return result;
    }
    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append(getClass().getSimpleName());
        sb.append(" [");
        sb.append("Hash = ").append(hashCode());
        sb.append(", firstMenuId=").append(firstMenuId);
        sb.append(", firstMenuName=").append(firstMenuName);
        sb.append("]");
        return sb.toString();
    }
}
aiflowy-modules/aiflowy-module-ai/src/main/java/tech/aiflowy/ai/entity/base/AiSecondMenuBase.java
New file
@@ -0,0 +1,102 @@
package tech.aiflowy.ai.entity.base;
import com.mybatisflex.annotation.Column;
import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.KeyType;
import com.mybatisflex.annotation.Table;
import java.math.BigInteger;
/**
 * ai机器人二级菜单表
 * @TableName ai_second_menu
 */
public class AiSecondMenuBase {
    /**
     * 二级菜单编号
     */
    @Id(keyType = KeyType.Auto, value = "secondMenuId", comment = "二级菜单编号")
    private BigInteger secondMenuId;
    /**
     * 一级菜单编号
     */
    @Column(comment = "一级菜单编号")
    private BigInteger firstMenuId;
    /**
     * 二级菜单名称
     */
    @Column(comment = "二级菜单名称")
    private String secondMenuName;
    public BigInteger getFirstMenuId() {
        return firstMenuId;
    }
    public void setFirstMenuId(BigInteger firstMenuId) {
        this.firstMenuId = firstMenuId;
    }
    public BigInteger getSecondMenuId() {
        return secondMenuId;
    }
    public void setSecondMenuId(BigInteger secondMenuId) {
        this.secondMenuId = secondMenuId;
    }
    /**
     * 二级菜单名称
     */
    public String getSecondMenuName() {
        return secondMenuName;
    }
    /**
     * 二级菜单名称
     */
    public void setSecondMenuName(String secondMenuName) {
        this.secondMenuName = secondMenuName;
    }
    @Override
    public boolean equals(Object that) {
        if (this == that) {
            return true;
        }
        if (that == null) {
            return false;
        }
        if (getClass() != that.getClass()) {
            return false;
        }
        AiSecondMenuBase other = (AiSecondMenuBase) that;
        return (this.getSecondMenuId() == null ? other.getSecondMenuId() == null : this.getSecondMenuId().equals(other.getSecondMenuId()))
            && (this.getFirstMenuId() == null ? other.getFirstMenuId() == null : this.getFirstMenuId().equals(other.getFirstMenuId()))
            && (this.getSecondMenuName() == null ? other.getSecondMenuName() == null : this.getSecondMenuName().equals(other.getSecondMenuName()));
    }
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((getSecondMenuId() == null) ? 0 : getSecondMenuId().hashCode());
        result = prime * result + ((getFirstMenuId() == null) ? 0 : getFirstMenuId().hashCode());
        result = prime * result + ((getSecondMenuName() == null) ? 0 : getSecondMenuName().hashCode());
        return result;
    }
    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append(getClass().getSimpleName());
        sb.append(" [");
        sb.append("Hash = ").append(hashCode());
        sb.append(", secondMenuId=").append(secondMenuId);
        sb.append(", firstMenuId=").append(firstMenuId);
        sb.append(", secondMenuName=").append(secondMenuName);
        sb.append("]");
        return sb.toString();
    }
}
aiflowy-modules/aiflowy-module-ai/src/main/java/tech/aiflowy/ai/mapper/AiFirstMenuMapper.java
New file
@@ -0,0 +1,19 @@
package tech.aiflowy.ai.mapper;
import com.mybatisflex.core.BaseMapper;
import tech.aiflowy.ai.entity.AiFirstMenu;
import tech.aiflowy.ai.entity.base.AiFirstMenuBase;
/**
* @author admin
* @description 针对表【ai_first_menu(ai机器人一级菜单表)】的数据库操作Mapper
* @createDate 2025-05-28 15:26:35
* @Entity tech.aiflowy.ai.entity.base.AiFirstMenu
*/
public interface AiFirstMenuMapper extends BaseMapper<AiFirstMenu> {
}
aiflowy-modules/aiflowy-module-ai/src/main/java/tech/aiflowy/ai/mapper/AiSecondMenuMapper.java
New file
@@ -0,0 +1,19 @@
package tech.aiflowy.ai.mapper;
import com.mybatisflex.core.BaseMapper;
import tech.aiflowy.ai.entity.AiSecondMenu;
import tech.aiflowy.ai.entity.base.AiSecondMenuBase;
/**
* @author admin
* @description 针对表【ai_second_menu(ai机器人二级菜单表)】的数据库操作Mapper
* @createDate 2025-05-28 15:26:35
* @Entity tech.aiflowy.ai.entity.base.AiSecondMenu
*/
public interface AiSecondMenuMapper extends BaseMapper<AiSecondMenu> {
}
aiflowy-modules/aiflowy-module-ai/src/main/java/tech/aiflowy/ai/service/AiFirstMenuService.java
New file
@@ -0,0 +1,14 @@
package tech.aiflowy.ai.service;
import com.mybatisflex.core.service.IService;
import tech.aiflowy.ai.entity.AiFirstMenu;
import tech.aiflowy.ai.entity.base.AiFirstMenuBase;
/**
* @author admin
* @description 针对表【ai_first_menu(ai机器人一级菜单表)】的数据库操作Service
* @createDate 2025-05-28 15:26:35
*/
public interface AiFirstMenuService extends IService<AiFirstMenu> {
}
aiflowy-modules/aiflowy-module-ai/src/main/java/tech/aiflowy/ai/service/AiSecondMenuService.java
New file
@@ -0,0 +1,14 @@
package tech.aiflowy.ai.service;
import com.mybatisflex.core.service.IService;
import tech.aiflowy.ai.entity.AiSecondMenu;
import tech.aiflowy.ai.entity.base.AiSecondMenuBase;
/**
* @author admin
* @description 针对表【ai_second_menu(ai机器人二级菜单表)】的数据库操作Service
* @createDate 2025-05-28 15:26:35
*/
public interface AiSecondMenuService extends IService<AiSecondMenu> {
}
aiflowy-modules/aiflowy-module-ai/src/main/java/tech/aiflowy/ai/service/impl/AiFirstMenuServiceImpl.java
New file
@@ -0,0 +1,23 @@
package tech.aiflowy.ai.service.impl;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import tech.aiflowy.ai.entity.AiFirstMenu;
import tech.aiflowy.ai.entity.base.AiFirstMenuBase;
import tech.aiflowy.ai.service.AiFirstMenuService;
import tech.aiflowy.ai.mapper.AiFirstMenuMapper;
import org.springframework.stereotype.Service;
/**
* @author admin
* @description 针对表【ai_first_menu(ai机器人一级菜单表)】的数据库操作Service实现
* @createDate 2025-05-28 15:26:35
*/
@Service
public class AiFirstMenuServiceImpl extends ServiceImpl<AiFirstMenuMapper, AiFirstMenu>
    implements AiFirstMenuService{
}
aiflowy-modules/aiflowy-module-ai/src/main/java/tech/aiflowy/ai/service/impl/AiSecondMenuServiceImpl.java
New file
@@ -0,0 +1,21 @@
package tech.aiflowy.ai.service.impl;
import org.springframework.stereotype.Service;
import tech.aiflowy.ai.entity.AiSecondMenu;
import tech.aiflowy.ai.mapper.AiSecondMenuMapper;
import tech.aiflowy.ai.service.AiSecondMenuService;
import com.mybatisflex.spring.service.impl.ServiceImpl;
/**
* @author admin
* @description 针对表【ai_second_menu(ai机器人二级菜单表)】的数据库操作Service实现
* @createDate 2025-05-28 15:26:35
*/
@Service
public class AiSecondMenuServiceImpl extends ServiceImpl<AiSecondMenuMapper, AiSecondMenu>
    implements AiSecondMenuService {
}
aiflowy-modules/aiflowy-module-ai/src/main/resources/tech/aiflowy/ai/entity/mapper/AiFirstMenuMapper.xml
New file
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="tech.aiflowy.ai.mapper.AiFirstMenuMapper">
    <resultMap id="BaseResultMap" type="tech.aiflowy.ai.entity.base.AiFirstMenuBase">
            <id property="firstMenuId" column="first_menu_id" />
            <result property="firstMenuName" column="first_menu_name" />
    </resultMap>
    <sql id="Base_Column_List">
        first_menu_id,first_menu_name
    </sql>
</mapper>
aiflowy-modules/aiflowy-module-ai/src/main/resources/tech/aiflowy/ai/entity/mapper/AiSecondMenuMapper.xml
New file
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="tech.aiflowy.ai.mapper.AiSecondMenuMapper">
    <resultMap id="BaseResultMap" type="tech.aiflowy.ai.entity.base.AiSecondMenuBase">
            <id property="secondMenuId" column="second_menu_id" />
            <result property="firstMenuId" column="first_menu_id" />
            <result property="secondMenuName" column="second_menu_name" />
    </resultMap>
    <sql id="Base_Column_List">
        second_menu_id,first_menu_id,second_menu_name
    </sql>
</mapper>
aiflowy-starter/src/main/resources/application.yml
@@ -7,7 +7,7 @@
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/aiflowy?useInformationSchema=true&characterEncoding=utf-8
    username: root
    password: 123456
    password: win2020
  servlet:
    multipart:
      max-file-size: 100MB