Java调用Midjourney进行AI画图原生版抓包实现支持中文

用途介绍

Midjourney是一个目前优秀的AI画图工具,不挂梯无法直接访问

本代码主要用于搭建镜像站使用

适合人群

本代码不适合新手,建议使用过okhttp、且具有二开能力的同学使用~

实现原理

通过调用发送信息接口发送请求,通过轮询房间消息接口判断是否作图完成

发送的时候带上我们存储好的cookie信息即可

轮询房间消息接口是为了避免模拟网页实际的websocket连接,那玩意解密没解出来...

准备

1. 开通Midjourney会员的Discord账号

2. 新建很多房间(因为房间消息接口默认就50条数据,也就是说每个房间最多并行50个图片生成任务)

功能预览

上代码

代码功能:

1. 调用Midjourney生成并将生成好的内容发送微信消息给用户(这个是在微信公众号平台做的,大家做网页版的话自己改下输出到网页就可以)

2. 进行合规性检测(生成点不得了的东西后果你懂得,这里用的是百度的文本审核服务,5万次以下免费)

3. 如果用户输入是中文,就翻译为英文再发送

midjourneyLog

midjourney_log表字段如下代码所示

需要使用通用mapper哦~

package com.example.midjourney.bean.pojo;

import lombok.Data;
import tk.mybatis.mapper.annotation.NameStyle;
import tk.mybatis.mapper.code.Style;

import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import java.util.Date;

@Data
@NameStyle(Style.camelhump)
@Table(name = "midjourney_log")
public class MidjourneyLog {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private Integer memberId;

    private String channel;

    private String prompt;

    private Integer type;

    private Integer status;

    private String imgFile;

    private Integer roomId;

    private String uuid;

    private Date createTime;

}

MidJourneyBiz

请求唯一id没啥规律,一段时间内不一致就行,试了没啥校验

另外请求头除了cookie需要保证和 authorization、x-super-properties对应上,三者对应上实测2个月都不会掉线!

package com.example.midjourney.biz;

import cn.hutool.core.img.ImgUtil;
import cn.hutool.core.io.FileUtil;
import com.alibaba.fastjson.JSON;
import com.example.midjourney.bean.BaiduTextCensor;
import com.example.midjourney.bean.BaiduTextCensorData;
import com.example.midjourney.bean.MidMsg;
import com.example.midjourney.bean.pojo.Discord;
import com.example.midjourney.bean.pojo.MidjourneyLog;
import com.example.midjourney.bean.pojo.RoomInfo;
import com.example.midjourney.contant.Constant;
import com.example.midjourney.enums.MedjourneyLogType;
import com.example.midjourney.service.DiscordService;
import com.example.midjourney.service.MidjourneyLogService;
import com.example.midjourney.service.MemberService;
import com.example.midjourney.service.RoomInfoService;
import com.example.midjourney.util.*;
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import com.google.common.collect.Lists;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.apache.logging.log4j.util.Strings;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;

import static com.example.midjourney.contant.Constant.*;

/**
 * 启动就运行,不停刷新消息列表
 */
@Slf4j
@Service
public class MidJourneyBiz {

    private static BigDecimal bigDecimal = new BigDecimal("1099765990370980513")
            .add(new BigDecimal(System.currentTimeMillis()));

    @Resource
    private WeChatBiz weChatBiz;

    @Resource
    private TranslateBiz translateBiz;

    @Resource
    private MidjourneyLogService midjourneyLogService;

    @Resource
    private MemberService memberService;

    @Resource
    private RoomInfoService roomInfoService;

    @Resource
    private DiscordService discordService;

    public void buildImg(Long id) {
        MidjourneyLog midjourneyLog = midjourneyLogService.findById(id);
        try {
            if (midjourneyLog.getStatus() != 0) {
                return;
            }
            if (isFailMsg(midjourneyLog.getChannel(), midjourneyLog)) {
                log.info("[失败提示] 消息校验不通过 log:{}", midjourneyLog);
                sendBuildFail(midjourneyLog);
                return;
            }
            String prompt = midjourneyLog.getPrompt();
            if (midjourneyLog.getType() == MedjourneyLogType.BIG_IMG.getCode()) {
                downImg(midjourneyLog);
                return;
            }
            BaiduTextCensor censor = null;
            if (TextUtil.isHaveChinese(prompt)) {
                censor = BaiduUtil.textCensor(prompt);
            }
            prompt = cleanMsg(prompt);
            if (isBlackWord(prompt)) {
                sendSensitive(midjourneyLog);
                return;
            }
            if (Objects.isNull(censor)) {
                censor = BaiduUtil.textCensor(prompt);
            }
            midjourneyLogService.updatePrompt(midjourneyLog, prompt);
            if (censor.getConclusionType() == 2 || censor.getConclusionType() == 3) {
                sendSensitive(midjourneyLog, censor);
                return;
            }
            if (midjourneyLog.getType() == MedjourneyLogType.ITERATIVE.getCode()) {
                //暂不支持
                sendBuildFail(midjourneyLog);
                return;
            }
            RoomInfo roomInfo = roomInfoService.findIdleRoom();
            if (Objects.isNull(roomInfo)) {
                log.error("[并发超出警报] 当前并发次数已经无法满足!!!");
                sendBuildFail(midjourneyLog);
                return;
            }
            if (sendMsg(prompt, roomInfo)) {
                midjourneyLogService.updateRoom(midjourneyLog, roomInfo);
            } else {
                log.error("[发送失败] 发送信息失败,请检查");
                sendBuildFail(midjourneyLog);
            }
        } catch (Throwable t) {
            sendBuildFail(midjourneyLog);
        }
    }

    @SneakyThrows
    private void downImg(MidjourneyLog midjourneyLog) {
        MidjourneyLog lastLog = midjourneyLogService.findLastNormalLog(midjourneyLog.getMemberId());
        log.info("[下载图片] {}", lastLog);
        if (Objects.isNull(lastLog)) {
            log.info("[失败提示] 找不到上一次的图片 log:{}", midjourneyLog);
            sendBuildFail(midjourneyLog);
            return;
        }
        String imgFile = lastLog.getImgFile();
        File file = new File(imgFile);
        if (!file.exists()) {
            log.info("[失败提示] 上一次图片不存在 log:{}", lastLog);
            sendBuildFail(midjourneyLog);
            return;
        }
        cutAndSendImg(midjourneyLog, file);
    }

    private void cutAndSendImg(MidjourneyLog midjourneyLog, File oldFile) throws IOException {
        BufferedImage bufferedImage = ImageIO.read(new FileInputStream(oldFile));
        int width = bufferedImage.getWidth();
        int height = bufferedImage.getHeight();
        String msg = midjourneyLog.getPrompt().trim();
        String newFileName;
        if (msg.equalsIgnoreCase("u1")) {
            newFileName = oldFile.getPath() + "_u1.png";
            ImgUtil.cut(oldFile, FileUtil.file(newFileName),
                    new Rectangle(0, 0, width / 2, height / 2)
            );
        } else if (msg.equalsIgnoreCase("u2")) {
            newFileName = oldFile.getPath() + "_u2.png";
            ImgUtil.cut(oldFile, FileUtil.file(newFileName),
                    new Rectangle(width / 2, 0, width / 2, height / 2)
            );
        } else if (msg.equalsIgnoreCase("u3")) {
            newFileName = oldFile.getPath() + "_u3.png";
            ImgUtil.cut(oldFile, FileUtil.file(newFileName),
                    new Rectangle(0, height / 2, width / 2, height / 2)
            );
        } else if (msg.equalsIgnoreCase("u4")) {
            newFileName = oldFile.getPath() + "_u4.png";
            ImgUtil.cut(oldFile, FileUtil.file(newFileName),
                    new Rectangle(width / 2, height / 2, width / 2, height / 2)
            );
        } else {
            sendBuildFail(midjourneyLog);
            return;
        }
        String mediaId = weChatBiz.sendImg(newFileName, midjourneyLog.getChannel());
        log.info("[mediaId] {}", mediaId);
        if (Strings.isNotEmpty(mediaId)) {
            String wxId = memberService.selectWxidById(midjourneyLog.getMemberId());
            if (Strings.isEmpty(wxId)) {
                sendBuildFail(midjourneyLog);
                return;
            }
            midjourneyLogService.updateFinish(midjourneyLog);
            weChatBiz.sendImgMsg(wxId, mediaId, midjourneyLog.getChannel());
        }
    }

    private boolean isFailMsg(String channel, MidjourneyLog midjourneyLog) {
        return Objects.isNull(midjourneyLog) || Strings.isEmpty(midjourneyLog.getPrompt()) || Strings.isEmpty(channel)
                || Objects.isNull(midjourneyLog.getMemberId()) || checkNotRunMsg(midjourneyLog);
    }

    public boolean checkNotRunMsg(MidjourneyLog midjourneyLog) {
        String prompt = midjourneyLog.getPrompt();
        if (midjourneyLog.getType() == MedjourneyLogType.BIG_IMG.getCode()) {
            return !(prompt.equalsIgnoreCase("u1") || prompt.equalsIgnoreCase("u2")
                    || prompt.equalsIgnoreCase("u3") || prompt.equalsIgnoreCase("u4"));
        } else if (midjourneyLog.getType() == MedjourneyLogType.ITERATIVE.getCode()) {
            return !(prompt.equalsIgnoreCase("v1") || prompt.equalsIgnoreCase("v2")
                    || prompt.equalsIgnoreCase("v3") || prompt.equalsIgnoreCase("v4"));
        } else {
            return false;
        }
    }

    private String cleanMsg(String msg) {
        msg = msg.replace("—", "--")
                .replace("-- ", "--")
                .replace("-- ", "--")
                .replace("-- ", "--")
                .replace(",", ",")
                .replace("/", "")
                .replace("--v", " --v ")
                .replace("--niji", " --niji ")
                .replace("--ar", " --ar ")
                .replace("--aspect", " --ar ")
                .replace("--chaos", " --chaos ")
                .replace("--c", " --c ")
                .replace("--no", " --no ")
                .replace("--quality", " --quality ")
                .replace("--q", " --q ")
                .replace("--repeat", " --repeat ")
                .replace("--s", " --s ")
                .replace("--upbeta", " --upbeta ")
                .trim();
        if (TextUtil.isHaveChinese(msg)) {
            msg = translateBiz.translate(msg);
        }
        msg = msg.replace(",", ",")
                .replace("/", "")
                .replace("--v5", " --v 5 ")
                .replace("--niji5", " --niji 5 ")
                .trim();
        if (!msg.contains("--niji") && !msg.contains("--v") && msg.length() > 3) {
            msg = msg + " --v 5";
        }
        return msg;
    }

    public void sendBuildFail(MidjourneyLog midjourneyLog) {
        String wxId = memberService.selectWxidById(midjourneyLog.getMemberId());
        CallBackUtil.failCallBack(midjourneyLog.getChannel(), MIDJOURNEY, midjourneyLog.getId());
        midjourneyLogService.updateFail(midjourneyLog);
        weChatBiz.sendTextMsg(wxId, "抱歉,您的消息【" + midjourneyLog.getPrompt() + "】处理失败,已为您退换对应电量",
                midjourneyLog.getChannel());
    }

    @Scheduled(cron = "34 * * * * ? ")
    public void checkImg() {
        //房间号清理
        cleanRoomNumber();
        //查询所有进行中的任务
        List<MidjourneyLog> logs = midjourneyLogService.selectAllDoing().stream()
                .filter(log -> Objects.nonNull(log.getRoomId())).collect(Collectors.toList());
        //找到超时任务进行关闭
        List<MidjourneyLog> failLogs = logs.stream()
                .filter(log -> System.currentTimeMillis() - log.getCreateTime().getTime() > MAX_WAIT_TIME)
                .collect(Collectors.toList());
        failLogs.forEach(this::sendBuildFail);
        //剩余任务整理出来房间号
        logs.removeAll(failLogs);
        Set<Integer> roomSet = logs.stream().map(MidjourneyLog::getRoomId).collect(Collectors.toSet());
        //轮询当前进度
        for (Integer roomId : roomSet) {
            RoomInfo roomInfo = roomInfoService.findById(roomId);
            if (Objects.isNull(roomInfo)) {
                log.error("[room没找到] roomId:{} 没找到对应房间,看一下是不是挂了", roomId);
                continue;
            }
            Discord discord = discordService.findById(roomInfo.getDiscordId());
            List<MidMsg> midMsgs = readNowList(roomInfo, discord);
            log.info("[消息列表] {}", midMsgs);
            checkAndSendMsg(midMsgs, logs, roomInfo);
        }
    }

    private void cleanRoomNumber() {
        List<RoomInfo> roomInfos = roomInfoService.findAll();
        for (RoomInfo roomInfo : roomInfos) {
            int count = midjourneyLogService.selectRoomOnUse(roomInfo.getId());
            roomInfo.setNowNumber(count);
            roomInfoService.update(roomInfo);
        }
    }

    private void checkAndSendMsg(List<MidMsg> midMsgs, List<MidjourneyLog> logs, RoomInfo roomInfo) {
        List<MidjourneyLog> roomLogs = logs.stream()
                .filter(log -> log.getRoomId().equals(roomInfo.getId()))
                .collect(Collectors.toList());
        midMsgs.stream()
                .filter(this::isPrintOk)
                .forEach(m -> roomLogs.forEach(midjourey -> {
                    if (m.getContent().startsWith(MID_JOURNEY_HEAD + filterHead(midjourey.getPrompt()))) {
                        log.info("[Midjourney 配对] msg:{}  key:{}", m, midjourey.getPrompt());
                        String wxid = memberService.selectWxidById(midjourey.getMemberId());
                        String url = m.getAttachments().get(0).getUrl();
                        String localPath = Constant.FILE_PATH + UUID.randomUUID() + "." + FileUtil.getSuffix(url);
                        ImgDownUtil.getImage(url.replace("https://", "http://"), localPath);
                        localPath = localPath.replace("\\", "/");
                        if ("webp".equals(FileUtil.getSuffix(localPath))) {
                            com.example.midjourney.util.ImgUtil.webpToPng(localPath, localPath + ".png");
                            localPath = localPath + ".png";
                        }
                        String mediaId = weChatBiz.sendImg(localPath, midjourey.getChannel());
                        log.info("[mediaId] {}", mediaId);
                        if (Strings.isNotEmpty(mediaId)) {
                            weChatBiz.sendImgMsg(wxid, mediaId, midjourey.getChannel());
                            weChatBiz.sendTextMsg(wxid, "下载高清大图口令:\n\n☆左上图回复:U1\n\n☆右上图回复:U2" +
                                    "\n\n☆左下图回复:U3\n\n☆右下图回复:U4\n\n下载大图也会扣电量哦~", midjourey.getChannel());
                            midjourey.setImgFile(localPath);
                            midjourneyLogService.updateFinish(midjourey);
                        }
                    }
                }));
    }

    private String filterHead(String prompt) {
        return Lists.newArrayList(Splitter.on("--").split(prompt)).stream().findFirst().orElse("").trim();
    }

    private boolean isPrintOk(MidMsg midMsg) {
        if (Objects.isNull(midMsg)
                || Strings.isEmpty(midMsg.getContent())
                || !midMsg.getContent().contains(MID_FIND_LEFT)) {
            return false;
        }
        String str = midMsg.getContent().substring(midMsg.getContent().indexOf(MID_FIND_LEFT));
        return !str.contains("%") && !str.contains("Waiting");
    }

    private boolean isBlackWord(String msg) {
        msg = msg.toLowerCase();
        for (String s : Constant.MidjourneyBlackWord) {
            if (msg.contains(s.toLowerCase())) {
                return true;
            }
        }
        return false;
    }

    private void sendSensitive(MidjourneyLog midjourneyLog) {
        String wxid = memberService.selectWxidById(midjourneyLog.getMemberId());
        midjourneyLogService.updateSensitive(midjourneyLog);
        weChatBiz.sendTextMsg(wxid, "【违规提示】输入内容包含违禁词,依法进行屏蔽。", midjourneyLog.getChannel());
    }

    /**
     * 审核不通过通知用户
     */
    private void sendSensitive(MidjourneyLog midjourneyLog, BaiduTextCensor censor) {
        String reason = Joiner.on("、")
                .join(Safes.of(censor.getData()).stream()
                        .map(BaiduTextCensorData::getMsg)
                        .collect(Collectors.toList()));
        reason = Strings.isEmpty(reason) ? "包含敏感信息" : reason;
        String fullText = "【违规提示】输入内容因 " + reason + " ,依法进行屏蔽。(百度提供审核能力)";
        String wxid = memberService.selectWxidById(midjourneyLog.getMemberId());
        midjourneyLogService.updateSensitive(midjourneyLog);
        weChatBiz.sendTextMsg(wxid, fullText, midjourneyLog.getChannel());
    }

    public List<MidMsg> readNowList(RoomInfo roomInfo, Discord discord) {
        OkHttpClient client = new OkHttpClient().newBuilder()
                .build();
        Request request = new Request.Builder()
                .url("https://discord.com/api/v9/channels/" + roomInfo.getDiscordChannelId() + "/messages?limit=50")
                .get()
                .addHeader("authority", "discord.com")
                .addHeader("accept", "*/*")
                .addHeader("accept-language", "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6")
                .addHeader("authorization", discord.getAuthorization())
                .addHeader("cache-control", "no-cache")
                .addHeader("cookie", discord.getCookie())
                .addHeader("pragma", "no-cache")
                .addHeader("referer", "https://discord.com/channels/" + roomInfo.getDiscordGuildId() +
                        "/" + roomInfo.getDiscordChannelId())
                .addHeader("sec-ch-ua", "\"Not_A Brand\";v=\"99\", \"Microsoft Edge\";v=\"109\", \"Chromium\";v=\"109\"")
                .addHeader("sec-ch-ua-mobile", "?0")
                .addHeader("sec-ch-ua-platform", "\"Windows\"")
                .addHeader("sec-fetch-dest", "empty")
                .addHeader("sec-fetch-mode", "cors")
                .addHeader("sec-fetch-site", "same-origin")
                .addHeader("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36 Edg/109.0.1518.70")
                .addHeader("x-debug-options", "bugReporterEnabled")
                .addHeader("x-discord-locale", "zh-CN")
                .addHeader("x-super-properties", discord.getSuperProperties())
                .build();
        try {
            Response response = client.newCall(request).execute();
            String string = Objects.requireNonNull(response.body()).string();
            response.close();
            return JSON.parseArray(string, MidMsg.class);
        } catch (Throwable t) {
            log.error("[发生意外 读取消息失败] room: {}", roomInfo);
        }
        return Lists.newArrayList();
    }

    @SneakyThrows
    public boolean sendMsg(String msg, RoomInfo roomInfo) {
        Discord discord = discordService.findById(roomInfo.getDiscordId());
        bigDecimal = bigDecimal.add(new BigDecimal(1000));
        OkHttpClient client = new OkHttpClient().newBuilder()
                .build();
        RequestBody body = new MultipartBody.Builder().setType(MultipartBody.FORM)
                .addFormDataPart("payload_json", "{\"type\":2,\"application_id\":\"936929561302675456\"," +
                        "\"guild_id\":\"" + roomInfo.getDiscordGuildId() + "\"," +
                        "\"channel_id\":\"" + roomInfo.getDiscordChannelId() + "\"," +
                        "\"session_id\":\"" + discord.getSessionId() + "\"," +
                        "\"data\":{\"version\":\"1077969938624553050\"," +
                        "\"id\":\"938956540159881230\"," +
                        "\"name\":\"imagine\"," +
                        "\"type\":1,\"options\":[" +
                        "{\"type\":3,\"name\":\"prompt\"," +
                        "\"value\":\"" + TextUtil.cleanString(msg) + "\"}]," +
                        "\"application_command\":" +
                        "{\"id\":\"938956540159881230\",\"application_id\":\"936929561302675456\",\"version\":" +
                        "\"1077969938624553050\",\"default_member_permissions\":null,\"type\":1,\"nsfw\":false," +
                        "\"name\":\"imagine\",\"description\":\"Create images with Midjourney\",\"dm_permission\":true," +
                        "\"contexts\":null,\"options\":[{\"type\":3,\"name\":\"prompt\"," +
                        "\"description\":\"The prompt to imagine\",\"required\":true}]}," +
                        "\"attachments\":[]},\"nonce\":\"" + bigDecimal.toString() + "\"} ")
                .build();
        Request request = new Request.Builder()
                .url("https://discord.com/api/v9/interactions")
                .method("POST", body)
                .addHeader("authority", "discord.com")
                .addHeader("accept", "*/*")
                .addHeader("accept-language", "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6")
                .addHeader("authorization", discord.getAuthorization())
                .addHeader("cache-control", "no-cache")
                .addHeader("cookie", discord.getCookie())
                .addHeader("origin", "https://discord.com")
                .addHeader("pragma", "no-cache")
                .addHeader("referer", "https://discord.com/channels/" + roomInfo.getDiscordGuildId() +
                        "/" + roomInfo.getDiscordChannelId())
                .addHeader("sec-ch-ua", "\"Not_A Brand\";v=\"99\", \"Microsoft Edge\";v=\"109\", \"Chromium\";v=\"109\"")
                .addHeader("sec-ch-ua-mobile", "?0")
                .addHeader("sec-ch-ua-platform", "\"Windows\"")
                .addHeader("sec-fetch-dest", "empty")
                .addHeader("sec-fetch-mode", "cors")
                .addHeader("sec-fetch-site", "same-origin")
                .addHeader("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36 Edg/109.0.1518.70")
                .addHeader("x-debug-options", "bugReporterEnabled")
                .addHeader("x-discord-locale", "zh-CN")
                .addHeader("x-super-properties", discord.getSuperProperties())
                .build();
        Response response = client.newCall(request).execute();
        if (response.code() == 204) {
            roomInfoService.addOnce(roomInfo);
            response.close();
            return true;
        }
        response.close();
        log.info("[midjourney发消息失败] {}", response.code());
        return false;
    }
}

MidjourneyLogService

package com.example.midjourney.service;

import com.example.midjourney.bean.pojo.MidjourneyLog;
import com.example.midjourney.bean.pojo.RoomInfo;

import java.util.List;

public interface MidjourneyLogService {

    MidjourneyLog findById(Long id);

    MidjourneyLog findLastNormalLog(Integer memberId);

    MidjourneyLog findLastNormalOrIterative(Integer memberId);

    void updateRoom(MidjourneyLog midjourneyLog, RoomInfo roomInfo);

    List<MidjourneyLog> selectAllDoing();

    void updateFail(MidjourneyLog midjourneyLog);

    void updateSensitive(MidjourneyLog midjourneyLog);

    void updatePrompt(MidjourneyLog midjourneyLog, String prompt);

    void updateFinish(MidjourneyLog midjourey);

    int selectRoomOnUse(Integer id);

}

MidjourneyLogServiceImpl

package com.example.midjourney.service.impl;

import com.example.midjourney.bean.pojo.MidjourneyLog;
import com.example.midjourney.bean.pojo.RoomInfo;
import com.example.midjourney.mapper.MidjourneyLogMapper;
import com.example.midjourney.service.MidjourneyLogService;
import com.example.midjourney.util.Safes;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;

@Service
public class MidjourneyLogServiceImpl implements MidjourneyLogService {

    @Resource
    private MidjourneyLogMapper midjourneyLogMapper;

    @Override
    public MidjourneyLog findById(Long id) {
        return midjourneyLogMapper.selectByPrimaryKey(id);
    }

    @Override
    public MidjourneyLog findLastNormalLog(Integer memberId) {
        return midjourneyLogMapper.findLastNormalLog(memberId);
    }

    @Override
    public MidjourneyLog findLastNormalOrIterative(Integer memberId) {
        return midjourneyLogMapper.findLastNormalOrIterative(memberId);
    }

    @Override
    public void updateRoom(MidjourneyLog midjourneyLog, RoomInfo roomInfo) {
        midjourneyLog.setRoomId(roomInfo.getId());
        midjourneyLogMapper.updateByPrimaryKeySelective(midjourneyLog);
    }

    @Override
    public List<MidjourneyLog> selectAllDoing() {
        MidjourneyLog midjourneyLog = new MidjourneyLog();
        midjourneyLog.setStatus(0);
        return Safes.of(midjourneyLogMapper.select(midjourneyLog));
    }

    @Override
    public void updateFail(MidjourneyLog midjourneyLog) {
        midjourneyLog.setStatus(500);
        midjourneyLogMapper.updateByPrimaryKeySelective(midjourneyLog);
    }

    @Override
    public void updateSensitive(MidjourneyLog midjourneyLog) {
        midjourneyLog.setStatus(-1);
        midjourneyLogMapper.updateByPrimaryKeySelective(midjourneyLog);
    }

    @Override
    public void updatePrompt(MidjourneyLog midjourneyLog, String prompt) {
        midjourneyLog.setPrompt(prompt);
        midjourneyLogMapper.updateByPrimaryKeySelective(midjourneyLog);
    }

    @Override
    public void updateFinish(MidjourneyLog midjourey) {
        midjourey.setStatus(1);
        midjourneyLogMapper.updateByPrimaryKeySelective(midjourey);
    }

    @Override
    public int selectRoomOnUse(Integer id) {
        return midjourneyLogMapper.selectRoomOnUse(id);
    }
}

MidjourneyLogMapper 

这里用了通用mapper插件

package com.example.midjourney.mapper;

import com.example.midjourney.bean.pojo.MidjourneyLog;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import tk.mybatis.mapper.common.Mapper;

public interface MidjourneyLogMapper extends Mapper<MidjourneyLog> {

    String COLUMN = " id, member_id AS memberId, prompt, channel, type, " +
            "status, img_file AS imgFile, room_id AS roomId ";

    @Select("SELECT " + COLUMN + " FROM midjourney_log WHERE member_id = #{memberId} AND type = 0 ORDER BY id DESC LIMIT 1")
    MidjourneyLog findLastNormalLog(@Param("memberId") Integer memberId);

    @Select("SELECT " + COLUMN + " FROM midjourney_log WHERE member_id = #{memberId} AND (type = 0 OR type = 2)" +
            " ORDER BY id DESC LIMIT 1")
    MidjourneyLog findLastNormalOrIterative(Integer memberId);

    @Select("SELECT COUNT(*) AS count FROM midjourney_log WHERE room_id = #{id} AND status = 0")
    Integer selectRoomOnUse(@Param("id") Integer id);

}

Constant

常量类可以根据需要自定调整敏感词

敏感词写上审核不过,大家自己想想脑补下吧,各种不好的词都往那个敏感词List里面自己加吧!

 

package com.example.midjourney.contant;

import com.example.midjourney.bean.UserInfo;
import com.example.midjourney.biz.WeChatBiz;
import com.example.midjourney.util.BaiduUtil;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Constant {

    public static ExecutorService threadPool = Executors.newFixedThreadPool(20);

    public static Map<String, UserInfo> imgWordUserMap = Maps.newConcurrentMap();

    public static String MID_JOURNEY_HEAD = "**";

    public static String MID_FIND_LEFT = "** - <";

    public static String FILE_PATH = "D:\\000img\\";

    public static String CHATGPT = "chatgpt";
    public static String MIDJOURNEY = "midjourney";

    public static final String INSUFFICIENT = "insufficient_quota";

    public static Map<String, String> WX_TOKEN_CHANNEL = Maps.newHashMap();

    public static Map<String, String> WX_TOKEN_MAP = Maps.newHashMap();

    public static String BAIDU_TOKEN = BaiduUtil.queryBaiduToken();

    public static Map<String, String> CHANNEL_CALL_BACK = Maps.newHashMap();

    /**
     * 最大等待时间15分钟
     */
    public static long MAX_WAIT_TIME = 1000 * 60 * 15;

    public static List<String> MidjourneyBlackWord = Lists.newArrayList("写了审核不过,大家自己发挥想象吧...");


}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/28622.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

一、PyTorch基础

一、PyTorch基本操作 1&#xff0c;导包 import torch2&#xff0c;查看版本号 torch.__version__ """ 2.0.1cpu """3&#xff0c;初始化(全零)矩阵 x torch.empty(3,2) x """ tensor([[7.2868e-44, 8.1275e-44],[6.7262e-4…

AST使用(二)

//在此之前&#xff0c;先了解下path和node/*path指的是路径 其常用的方法当前路径所对应的源代码 : path.toString判断path是什么type&#xff0c;使用path.isXXX 这个方法 : if(path.isStringLiteral()){}获取path的上一级路径 : let parent path.parentPath;获取path的子…

ARM基础(3):MPU内存保护单元详解及例子

MPU(Memory Protection Unit)是ARM处理器中的一个特性&#xff0c;它提供了内存保护和访问控制的功能&#xff0c;通常用于实现操作系统的内存隔离和保护。比如我们可以设置所有的RAM为不可执行&#xff0c;这样就可以避免代码注入攻击。最近做项目过程中&#xff0c;使用的几个…

中空百叶玻璃隔断怎么组装

以下是中空百叶玻璃隔断的组装步骤&#xff1a; 1. 准备材料&#xff1a;中空百叶玻璃、接头、U型槽、挂件、固定螺钉等。 2. 根据实际需要&#xff0c;将中空百叶玻璃按照尺寸进行切割。 3. 在地面上铺上一张软垫&#xff0c;将切好的玻璃放置在垫子上&#xff0c;然后在两侧标…

管理类联考——逻辑——真题篇——阅读新题型真题

阅读新题型真题 Part B-2010- Part B Directions: Read the following text and decide whether each of the statements is true or false. Choose T if the statement is true or F if the statement is not true. Mark your answers on ANSWER SHEET. (10 points) Copying…

之江实验室: 如何基于 JuiceFS 为超异构算力集群构建存储层 ?

今天&#xff0c;高性能计算结合人工智能技术正在推动科研创新。例如通过破解水稻基因密码推动作物育种从“试验选优”向“计算选优”发展&#xff0c;在医药领域快速分析分子与蛋白之间的相互作用&#xff0c;发现潜在的能够有效干预疾病发生的药物分子。 之江实验室就是上述科…

大学生实习周记总结

大学生实习周记总结1 经过两个月的实习&#xff0c;我收获了很多&#xff0c;也懂得了许多&#xff0c;同时也成熟了不少。下面我将把我两个月的实习生活分成五个部分进行总结&#xff1a;教学经验、班主任工作、做事态度、学生友谊、感恩的心。 教学经验&#xff1a;如何上好一…

4.4网络模型 4.5协议 4.6网络通信的过程

4.4网络模型 OSI七层参考模型 七层模型&#xff0c;亦称 OSI&#xff08;Open System Interconnection&#xff09;参考模型&#xff0c;即开放式系统互联。参考模型是国际标准化组织&#xff08;ISO&#xff09;制定的一个用于计算机或通信系统间互联的标准体系&#xff0c;…

【三维视觉】空间点集的最小包围盒计算

0 问题描述 假设有一个空间点集&#xff0c;不重合的点数有N个。 N1时&#xff0c;最小包围盒是一个点&#xff1a;中心为其本身&#xff0c;半径无穷小 N2时&#xff0c;最小包围盒是一个圆&#xff1a;中心为连线中点&#xff0c;半径为边长一半 N3时&#xff0c;不共线的三…

番茄工作法图解——简单易行的时间管理方法

ISBN: 978-7-115-24669-1 作者&#xff1a;【瑞典】诺特伯格&#xff08;Staffan Noteberg&#xff09; 页数&#xff1a;136页 阅读时间&#xff1a;2023-06-10 推荐指数&#xff1a;★★★★★ 番茄工作法&#xff08;意大利语&#xff1a;Pomodoro Technique&#xff09;是一…

如何选择到最合适的DDoS缓解服务?

DDoS缓解服务提供商的数量可能很多&#xff0c;但只有一些提供商提供高效服务的所有必要功能&#xff0c;因此如果要选择正确的 DDoS保护解决方案&#xff0c;必须考虑以下因素&#xff1a; 1.缩小风险范围 选择DDoS缓解服务的第一步&#xff0c;确定您组织的特定需求&#…

使用SQL语句创建存储过程

前言: 本篇文章是记录学校学习SQL server中知识,可用于复习资料. 目录 前言:一、存储过程的创建1、创建简单存储过程2、创建带参数的存储过程3、创建带输出参数的存储过程 二 、使用T一SQL语句管理和维护存储过程2.1 使用sp_helptext查看存储过程student_sc的定义脚本2.2 使用…

AI 绘画(1):生成一个图片的标准流程

文章目录 文章回顾感谢人员生成一个图片的标准流程前期准备&#xff0c;以文生图为例去C站下载你需要的绘画模型导入参数导入生成结果&#xff1f;可能是BUG事后处理 图生图如何高度贴合原图火柴人转角色 涂鸦局部重绘 Ai绘画公约 文章回顾 AI 绘画&#xff08;0&#xff09;&…

在Django项目中的各个应用中分别编写路由配置文件urls.py

目录 01-通过命令建立三个应用02-配置路由 /index/、/app1/index/、/app2/index/02-1-配置路由 /index/ 并将各个应用的urls.py文件包含进主路由目录中02-02-配置路由/app1/index/02-03-配置路由/app2/index/ 03-编写各个应用的视图views.py 文件04-注册模板文件所在目录05 创建…

一文吃透低代码平台的衍生历程、优势及未来趋势

一、低代码概念 低代码开发平台是一种无需编码或者只需要少量代码即可快速生成应用程序的开发平台&#xff0c;通过可视化进行应用程序开发的方法&#xff0c;让不同经验水平的开发人员可以通过图形化的用户界面&#xff0c;使用拖拽组件和模型驱动的逻辑来创建网页和移动应用程…

【统计模型】缺失数据处理方法

目录 一、缺失数据定义 二、缺失数据原因 三、缺失数据处理步骤 四、数据缺失机制 1.完全随机缺失&#xff08;MCAR&#xff09; 2.随机缺失&#xff08;MAR&#xff09; 3.非随机、不可忽略缺失&#xff08;NMAR&#xff09; 五、缺失数据处理方法 1.直接删除 2.缺失值…

从零开始理解Linux中断架构(2)-朴素的中断管理设计理念

既然是从零开始,我们先从最为简单的中断逻辑处理架构开始,这个逻辑结构跟CPU架构没有关系,纯逻辑上的。纯逻辑是跨越系统和应用的,不管对于应用程序员还是系统程序员,逻辑推导是基本的工具,设计原型是基本的出发点。 中断发起的时候,PC指针被设置为中断向量表中相对应的…

SpringBoot 中使用 JWT 案例分享详解

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…

Qt6.5.1+WebRTC学习笔记(十二)环境搭建流媒体服务器(ubuntu22.04+SRS)

前言 若只是实现一对一通信&#xff0c;仅使用webrtc就足够了。但有时间需要进行多个人的直播会议&#xff0c;当人比较多时&#xff0c;建议使用一个流媒体服务器&#xff0c;笔者使用的是SRS。 这个开源项目资料比较全&#xff0c;笔者仅在此记录下搭建过程 一、准备 1.操…

这些方法可以手写扫描识别

小伙伴们知道有一项技术是可以将我们手写的东西识别出来吗&#xff1f;这一项创新的技术就是手写识别功能&#xff0c;它能够将手写内容快速转换为数字或文本格式&#xff0c;并提高信息处理和管理的效率。而且相比传统的手工记录方式&#xff0c;手写识别功能具有较高的准确性…