五分钟 实现chatgpt+Midjourney工具 出图ai 变现

文章详细介绍了如何在Laf云平台上部署和使用Midjourney的API接口,包括创建云函数来处理消息检索、生图任务、图片放大和变换功能。同时,提供了前端渲染示例代码,展示了一个用户交互界面,允许用户提交生成图片的请求并显示结果。
摘要由CSDN通过智能技术生成

首先感谢laf提供免费使用Midjourney API接口和云函数,需要详细了解的可以访问他们的官网论坛。
感谢论坛前面几位的分享,我做了参考。都有参考就不列啦哈!!!

直接开始:

第一步

复制MJ-SEND云函数到laf云平台,并发布获得云函数访问地址“https://xxx.laf.dev/mj-sent”

import cloud from '@lafjs/cloud'
import { Midjourney, MidjourneyMessage } from 'midjourney'
const SERVER_ID = '' // Midjourney 服务 ID
const CHANNEL_ID = '' // Midjourney 频道 ID
const SALAI_TOKEN = '' // Midjourney 服务 Token
 
const Limit = 100
const MaxWait = 3
 
const client = new Midjourney({
  ServerId: SERVER_ID,
  ChannelId: CHANNEL_ID,
  SalaiToken: SALAI_TOKEN,
  Debug: true,
  SessionId: SALAI_TOKEN,
  Limit: Limit,
  MaxWait: MaxWait
});
 
export default async function (ctx: FunctionContext) {
  const { type, param } = ctx.body
  switch (type) {
    case 'RetrieveMessages':
      return await RetrieveMessages(param)
    case 'imagine':
      return await imagine(param)
    case 'upscale':
      return await upscale(param)
    case 'variation':
      return await variation(param)
  }
 
}
 
// 查询最近消息
async function RetrieveMessages(param) {
  console.log("RetrieveMessages")
  const client = new MidjourneyMessage({
    ChannelId: CHANNEL_ID,
    SalaiToken: SALAI_TOKEN,
  });
  const msg = await client.RetrieveMessages();
  console.log("RetrieveMessages success ", msg)
  return msg
}
 
// 创建生图任务
async function imagine(param) {
  console.log("imagine", param)
  const { question, msg_Id } = param
  const msg = await client.Imagine(
    `[${msg_Id}] ${question}`,
    (uri: string, progress: string) => {
      console.log("loading", uri, "progress", progress);
    }
  );
  console.log("imagine success ", msg)
  return true
}
 
// upscale 放大图片
async function upscale(param) {
  console.log("upscale", param)
  const { question, index, id, url } = param
  const hash = url.split("_").pop()?.split(".")[0] ?? ""
  console.log(hash)
  const msg = await client.Upscale(
    question,
    index,
    id,
    hash,
    (uri: string, progress: string) => {
      console.log("loading", uri, "progress", progress);
    }
  );
  console.log("upscale success ", msg)
  return msg
}
 
// variation 变换图片
async function variation(param) {
  console.log("variation", param)
  const client = new Midjourney({
    ServerId: SERVER_ID,
    ChannelId: CHANNEL_ID,
    SalaiToken: SALAI_TOKEN,
    Debug: true,
    SessionId: SALAI_TOKEN,
    Limit: Limit,
    MaxWait: 100
  });
  const { question, index, id, url } = param
  const hash = url.split("_").pop()?.split(".")[0] ?? ""
  const msg = await client.Variation(
    question,
    index,
    id,
    hash,
    (uri: string, progress: string) => {
      console.log("loading", uri, "progress", progress);
    }
  );
  console.log("variation success ", msg)
  return msg
}

第二步 写一个前端渲染效果

 <html>
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width,initial-scale=1.0" />
    <script type="module" src="https://gradio.s3-us-west-2.amazonaws.com/3.19.1/gradio.js"></script>
    <!-- import vue -->
    <script src="https://unpkg.com/vue@next"></script>
    <!-- import Elm CSS -->
    <link rel="stylesheet" href="https://unpkg.com/element-plus/dist/index.css">
    <!-- import Elm JavaScript -->
    <script src="https://unpkg.com/element-plus"></script>
    <!-- import axios -->
    <script src="https://unpkg.com/axios@1.1.2/dist/axios.min.js"></script>
    <title>mj</title>
    <style>
      body {
        display: flex;
        justify-content: center;
        background-color: #f5f5f5;
      }
      #app {
        width: 1000px;
      }
      .task {
        border: 1px solid #ddd;
        background-color: #fff;
        border-radius: 10px;
        margin-bottom: 20px;
        padding: 20px;
      }
      image {
        border-radius: 10px;
      }
    </style>
  </head>
  <body>
 
    <div id="app">
      <el-form>
        <el-form-item>
          <el-input type="textarea" v-model="question" placeholder="请输入要生成的图片内容,尽量使用英文"></el-input>
          <el-button style="margin-top: 10px;" type="primary" @click="submit" :loading="loading">提交</el-button>
        </el-form-item>
      </el-form>
      <div class="result" style="margin-top: 10px;">
        <h1>我的作品</h1>
        <div v-for="(item, index) in tasks" class="task" :key="item.msg_Id">
          <p>任务id: <el-button link type="primary">{{item.msg_Id}}</el-button> </p>
          <p>{{item.question}}</p>
          <p>
            <el-button type="primary" @click="getResult(item.msg_Id)">刷新</el-button>
          </p>
          <template v-if="item.result">
            <el-image fit="scale-down" lazy :src="item.result.url" :alt="item.question"></el-image>
            <p>
              <el-button type="primary" plain @click="variation(item, 1)">V1</el-button>
              <el-button type="primary" plain @click="variation(item, 2)">V2</el-button>
              <el-button type="primary" plain @click="variation(item, 3)">V3</el-button>
              <el-button type="primary" plain @click="variation(item, 4)">V4</el-button>
            </p>
            <p>
              <el-button type="primary" plain @click="upscale(item, 1)">U1</el-button>
              <el-button type="primary" plain @click="upscale(item, 2)">U2</el-button>
              <el-button type="primary" plain @click="upscale(item, 3)">U3</el-button>
              <el-button type="primary" plain @click="upscale(item, 4)">U4</el-button>
            </p>
            <template v-if="item.result.upscaleUrl">
              <h5>大图</h5>
              <el-image fit="scale-down" lazy :src="item.result.upscaleUrl" :alt="item.question"></el-image>
            </template>
          </template>
        </div>
        <h2>其他人的作品</h2>
        <div v-for="item in otherCase" :key="item.id" class="task">
          <h3>prompt:{{ formatPrompt(item.content) }}</h3>
          <h3>time:{{ formatDate(item.timestamp) }}</h3>
          <div v-for="attachment in item.attachments" :key="attachment.id">
            <el-image fit="scale-down" lazy :src="attachment.url" :alt="formatPrompt(item.content)"></el-image>
          </div>
        </div>
      </div>
    </div>
    <script>
      const App = {
        data() {
          return {
            question: "",
            msg_Id: "",
            loading: false,
            tasks: [],
            otherCase: []
          };
        },
        mounted() {
          this.initTask()
          this.getOtherCase()
        },
        methods: {
          initTask() {
            this.tasks = JSON.parse(window.localStorage.getItem('task') || JSON.stringify([]))
          },
          submit() {
            this.msg_Id = grs()
            this.loading = true
            axios({
              method: 'post',
              url: 'https://rpcqmo.laf.dev/mj-service',
              data: {
                type: 'imagine',
                param: {
                  msg_Id: this.msg_Id,
                  question: this.question
                }
              }
            }).then(res => {
              console.log('[ res ] >', res)
              this.$message.success("上传成功,正在画图,请稍后...")
              window.localStorage.setItem('task', JSON.stringify([
                { msg_Id: this.msg_Id, question: this.question, result: null },
                ...this.tasks
              ]))
              this.initTask()
              this.getResult(this.msg_Id)
            }).catch(err => {
              console.log('[ err ] >', err)
            }).finally(() => {
              this.loading = false
            })
          },
          getResult(msg_Id) {
            axios({
              method: 'post',
              url: 'https://rpcqmo.laf.dev/mj-service',
              data: {
                type: 'RetrieveMessages'
              }
            }).then(res => {
              console.log('[ res ] >', res)
              const { data } = res
              const resIndex = data.findIndex(item => item.content.includes(msg_Id))
              if (resIndex < 0) {
                this.$message.success('正在努力生成,请耐心等待')
                return
              }
              const { id, attachments } = data[resIndex]
              if (!attachments.length) {
                this.$message.success('正在努力生成,请耐心等待')
                return
              }
              const { url, width } = attachments[0]
              if (width >= 2048) {
                const myIndex = this.tasks.findIndex(item => item.msg_Id == msg_Id)
                this.tasks[myIndex].result = {
                  id,
                  url
                }
                window.localStorage.setItem('task', JSON.stringify(this.tasks))
              } else {
                this.$message.success('正在努力生成,请耐心等待')
                return
              }
            }).catch(err => {
              console.log('[ err ] >', err)
            }).finally(() => {
            })
          },
          variation({ result, question, msg_Id }, index) {
            console.log(result, question, index);
            this.$message.warning('努力开发中')
            return
            axios({
              method: 'post',
              url: 'https://rpcqmo.laf.dev/mj-service',
              data: {
                type: 'variation',
                param: {
                  id: result.id,
                  url: result.url,
                  question,
                  index
                }
              }
            }).then(res => {
            }).catch(err => {
              console.log('[ err ] >', err)
            }).finally(() => {
            })
          },
          upscale({ result, question, msg_Id }, index) {
            console.log(result, question, index);
            // this.$loading('正在生成大图')
            const loadingInstance = this.$loading({
              lock: true,
              text: '正在生成大图...',
              spinner: 'el-icon-loading',
              background: 'rgba(0, 0, 0, 0.7)'
            });
            axios({
              method: 'post',
              url: 'https://rpcqmo.laf.dev/mj-service',
              data: {
                type: 'upscale',
                param: {
                  id: result.id,
                  url: result.url,
                  question,
                  index
                }
              }
            }).then(res => {
              const { data } = res
              console.log('[ upscale data ] >', data)
              const taskIndex = this.tasks.findIndex(item => item.msg_Id == msg_Id)
              this.tasks[taskIndex].result.upscaleUrl = data.uri
              window.localStorage.setItem('task', JSON.stringify(this.tasks))
            }).catch(err => {
              console.log('[ err ] >', err)
            }).finally(() => {
              loadingInstance.close();
            })
          },
          getOtherCase() {
            axios({
              method: 'post',
              url: 'https://rpcqmo.laf.dev/mj-service',
              data: {
                type: 'RetrieveMessages'
              }
            }).then(res => {
              const { data } = res
              this.otherCase = data.filter(item => item.attachments.length)
            })
          },
          formatPrompt(str) {
            return str.substring(str.indexOf(']') + 1, str.indexOf('--seed')) + `(${str.substring(str.indexOf('[') + 1, str.indexOf(']'))})`
          },
          // 格式化日期时间
          padLeftZero(str) {
            return ('00' + str).substr(str.length);
          },
          formatDate(date, fmt = "yyyy-MM-dd hh:mm:ss") {
            if (/(y+)/.test(fmt)) {
              fmt = fmt.replace(RegExp.$1, (new Date(date).getFullYear() + '').substr(4 - RegExp.$1.length));
            }
            const o = {
              'M+': new Date(date).getMonth() + 1,
              'd+': new Date(date).getDate(),
              'h+': new Date(date).getHours(),
              'm+': new Date(date).getMinutes(),
              's+': new Date(date).getSeconds()
            }
            for (const k in o) {
              if (new RegExp(`(${k})`).test(fmt)) {
                const str = o[k] + '';
                fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? str : this.padLeftZero(str));
              }
            }
            return fmt;
          },
        }
      };
      const app = Vue.createApp(App);
      app.use(ElementPlus);
      app.mount("#app");
      function grs() {
        return 'Charlie-' + 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
          var r = Math.random() * 16 | 0,
              v = c == 'x' ? r : (r & 0x3 | 0x8);
          return v.toString(16);
        });
      }
    </script>
  </body>
</html>

第三步 上传服务器或者找个空间也可以本地访问

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值