最近AI生成图片(AIGC)很火,大家玩NovelAI和Midjourney都非常开心。 不过,AIGC还是处于一个很早期的阶段,大家还不太清楚它到底可以用在什么地方,为用户提供什么帮助,带来什么实际价值。对于广大程序员来说,哪怕大家有很多很好的想法,但是碍于AI大模型的高门槛,加上GPU计算高昂的价格,其实也很难实践。
那么我想,作为智源人工智能研究院的一名优秀的前端工程师,是时候站出来帮大家一把,为中国的AIGC事业的发展贡献出自己一点微薄的力量了!
其实说起来很简单,就是,我们可以薅一下智源的羊毛。智源开放了文生图大模型接口可以随便调用(https://github.com/FlagAI-Open/FlagAI/tree/master/examples/AltDiffusion),我们搞个前后端调用一下,就可以做一个简单的APP。在这个基础上加上点自己的创意,也许可以弄出个新的现象级应用呢!
下面我给大家介绍一下具体的步骤。其实很简单,就算是0基础的工程师,2个小时也可以搞定了。我先放个最后的APP效果视频:
一、准备阶段
1 环境要求
Node版本大于14 Java Development Kit [JDK] 11
2 开发环境搭建
本部分基于
ReactNative中文文档,如遇到困难请阅读官方以获取更详细的指导。
本文以Windows作为开发平台,Android作为目标平台。
安装 Node 与 JDK
首先直接使用搜索引擎搜索下载 Node 和 Java SE Development Kit (JDK) [11]
,注意 Node 的版本应大于等于 14。
在Node安装完成后打开cmd或PowerShell(以windows为例)并输入命令 node -v,此时若Node已经安装成功,则会显示当前node的版本,若版本小于14则需要重新安装14以上版本的Node。
在 Java Development Kit 安装完成后。你可以在命令行中输入 javac -version(请注意是 javac,不是 java)来查看你当前安装的 JDK 版本。
安装 Yarn
Yarn
是 Facebook 提供的替代 npm 的工具,可以加速 Node 模块的下载。请在确保 Node 已经安装完成后,打开cmd或PowerShell(以windows为例)并输入以下命令:npm install -g yarn。
安装完 yarn 之后就可以用 yarn 代替 npm 了,例如用yarn代替npm install命令,用yarn add 某第三方库名代替npm install 某第三方库名。
安装 Android 开发环境
安装 Android Studio
首先下载和安装 Android Studio 安装界面中选择"Custom"选项,确保选中了以下几项:
Android SDK Android SDK Platform Android Virtual Device
安装 Android SDK
你可以在 Android Studio 的欢迎界面中找到 SDK Manager。点击"Configure",然后就能看到"SDK Manager"。
在 SDK Manager 中选择"SDK Platforms"选项卡,然后在右下角勾选"Show Package Details"。展开Android 12 (S)选项,确保勾选了下面这些组件(重申你必须使用稳定的代理软件,否则可能都看不到这个界面):
Android SDK Platform 31Intel x86 Atom_64 System Image(官方模拟器镜像文件,使用非官方模拟器不需要安装此组件)
然后点击"SDK Tools"选项卡,同样勾中右下角的"Show Package Details"。展开"Android SDK Build-Tools"选项,确保选中了 React Native 所必须的31.0.0版本。你可以同时安装多个其他版本。
最后点击"Apply"来下载和安装这些组件。
配置 ANDROID_SDK_ROOT 环境变量
打开控制面板 -> 系统和安全 -> 系统 -> 高级系统设置 -> 高级 -> 环境变量 -> 新建,创建一个名为ANDROID_SDK_ROOT的环境变量(系统或用户变量均可),指向你的 Android SDK 所在的目录(具体的路径可能和下图不一致,请自行确认):
SDK 默认是安装在下面的目录:
C:\Users\你的用户名\AppData\Local\Android\Sdk
把一些工具目录添加到环境变量 Path
打开控制面板 -> 系统和安全 -> 系统 -> 高级系统设置 -> 高级 -> 环境变量,选中Path变量,然后点击编辑。点击新建然后把这些工具目录路径添加进去:platform-tools、emulator、tools、tools/bin
%ANDROID_SDK_ROOT%\platform-tools
%ANDROID_SDK_ROOT%\emulator
%ANDROID_SDK_ROOT%\tools
%ANDROID_SDK_ROOT%\tools\bin
3 安装代码编辑工具
推荐使用 Visual Studio Code(免费)或者 WebStorm 作为开发工具。如果在使用 WebStorm 时遇到需要License的情况,可以先选择免费体验30天跳过此步。。
4 准备 Android 设备
使用 Android 真机
需用 usb 数据线连接到电脑,然后遵照在设备上运行这篇文档的说明操作。
使用 Android 模拟器
打开 Android Studio 创建一个虚拟设备。点击"Create Virtual Device",然后选择所需的设备类型并点击"Next",然后选择S API Level 31 image。
5 创建带 TypeScript 的新项目
注意事项
如果你之前全局安装过旧的react-native-cli命令行工具,请使用npm uninstall -g react-native-cli卸载掉它以避免一些冲突请不要在目录、文件名中使用中文、空格等特殊符号。请不要单独使用常见的关键字作为项目名(如 class, native, new, package 等等)。请不要使用与核心模块同名的项目名(如 react, react-native 等)。请不要在某些权限敏感的目录例如 System32 目录中 init 项目!会有各种权限限制导致不能运行!请不要使用一些移植的终端环境,例如git bash或mingw等等,这些在 windows 下可能导致找不到环境变量。请使用系统自带的命令行(CMD 或 powershell)运行。
初始化项目
TypeScript 是 JavaScript 的超集,扩展了 JavaScript 的语法,同时 TypeScript 通过类型注解提供编译时的静态类型检查,更好的保证了代码的类型安全。
我们使用 React Native 内建的命令行工具来创建一个名为"TextToImgAPP"的新项目。这个命令行工具不需要安装,可以直接用 node 自带的npx命令来使用。我们可以通过--template来使用一些社区提供的模板,例如带有TypeScript配置。
npx react-native init TextToImgAPP --template react-native-template-typescript
如果出现以下提示,输入 y 继续
Need to install the following packages:
react-native
Ok to proceed? (y)
等待项目初始化完成后,进入TextToImgAPP文件夹就可以看到初始化后的项目源代码了。此时请确保已经运行了模拟器或者连接了Android真机,在项目目录中输入以下命令:
yarn android
// 或者
yarn react-native run-android
此命令会对项目的原生部分进行编译,如果配置没有问题,你应该可以看到应用自动安装到设备上并开始运行。注意第一次运行时需要下载大量编译依赖,耗时可能数十分钟。如果项目成功运行,你将在模拟器或者真机中看到如下画面。
二、开发阶段
在项目初始化并成功启动后,我们便可以开始我们的开发工作了。我们将搭建一个非常简单的文生图APP,功能包含用户输入文字,选择图片生成数量与图片长宽。并向后端发送请求后接收生成的图片并进行展示。
首先我们在项目根目录下创建一个文件夹src,我们将在这个目录下编写我们的代码。在src文件夹中创建三个文件夹Components、Style、Utils分别存放我们编写的组件、样式和工具函数
开发前准备(可选)
本部分主要为代码风格与格式化设置
进入根目录/.eslintrc.js,在rules中添加以下两行代码:
react-native/no-inline-styles: off,
semi: 0,
进入根目录/.prettierrc.js,在文件中添加以下代码:
printWidth: 120,
semi: false,
useTabs: false,
tabWidth: 4,
1 编写按钮组件
在src/Components下创建两个文件BatchSizeButtonGroup.tsx和GenerateButton.tsx,我们将在这里编写设置图片数量按钮组件和生成图片按钮组件。
在BatchSizeButtonGroup.tsx中填入以下代码:
import React from react
import {Text, TextStyle, TouchableHighlight, View} from react-native
import {componentsStyleSheet} from ../Style/ComponentsStyleSheet
type BatchSizeButtonGroupPropsType = {
batchSize: number
setBatchSize: React.Dispatch<React.SetStateAction<number>>
}
export const BatchSizeButtonGroup: React.FC<BatchSizeButtonGroupPropsType> = ({batchSize, setBatchSize}) => {
return (
<View style={{display: flex, flexDirection: row, alignItems: center, marginBottom: 16}}>
<Text style={{fontSize: 16, marginRight: 16}}>生成数量</Text>
{[1, 2, 3, 4].map(value => (
<BatchSizeButton
key={value}
isCurSelected={value === batchSize}
label={value.toString()}
style={{marginRight: 16, borderRadius: 4}}
onPress={() => {
setBatchSize(value)
}}
/>
))}
</View>
)
}
type StyledButtonPropsType = {
label: string
isCurSelected: boolean
onPress: () => void
style?: TextStyle
}
const BatchSizeButton: React.FC<StyledButtonPropsType> = ({label, isCurSelected, onPress, style}) => {
return (
<TouchableHighlight onPress={onPress} underlayColor="#5E3A9E" style={{...style}}>
<View
style={[
componentsStyleSheet.batchSizeButton,
{backgroundColor: isCurSelected ? #925FF0 : #E9DFFC},
]}>
<Text
style={[componentsStyleSheet.batchSizeButtonText, {color: isCurSelected ? #FFFFFF : #784DC7}]}>
{label}
</Text>
</View>
</TouchableHighlight>
)
}
在GenerateButton.tsx中填入以下代码:
import React from react
import {Text, TouchableHighlight, View} from react-native
import {componentsStyleSheet} from ../Style/ComponentsStyleSheet
type GenerateButtonPropsType = {
onPress: () => void
disabled: boolean
}
export const GenerateButton: React.FC<GenerateButtonPropsType> = ({onPress, disabled}) => {
return (
<TouchableHighlight
onPress={onPress}
style={{borderRadius: 40}}
underlayColor={disabled ? #F4EFFE : #5E3A9E}>
<View style={[componentsStyleSheet.generateButton, {backgroundColor: disabled ? #F4EFFE : #925FF0}]}>
<Text style={[componentsStyleSheet.generateButtonText, {color: disabled ? #737373 : #FFFFFF}]}>
生成图片
</Text>
</View>
</TouchableHighlight>
)
}
在src/Style下创建一个文件ComponentsStyleSheet.ts,并填入以下代码:
import {StyleSheet} from react-native
export const componentsStyleSheet = StyleSheet.create({
styleTypeButton:{
display: flex,
alignItems: center,
justifyContent: center,
height: 30,
width: 50,
borderRadius: 4,
},
styleTypeButtonText: {
fontSize: 16,
fontWeight: 400,
},
batchSizeButton: {
display: flex,
alignItems: center,
justifyContent: center,
height: 40,
width: 40,
borderRadius: 4,
},
batchSizeButtonText: {
fontSize: 20,
fontWeight: 400,
},
generateButton: {
display: flex,
flexDirection: row,
alignItems: center,
justifyContent: center,
height: 40,
width: 130,
borderRadius: 40,
},
generateButtonText:{
fontSize: 20,
fontWeight: 300,
}
})
在src/Utils目录下创建文件StyleType.ts并填入以下代码:
export enum styleType {
general = 通用,
traditional = 国画,
}
在src/Components目录下创建StyleTypeButtonGroup.tsx文件,并填入以下代码:
import React from react
import {Text, TextStyle, TouchableHighlight, View} from react-native
import {componentsStyleSheet} from ../Style/ComponentsStyleSheet
import {styleType} from ../Utils/StyleType
type styleButtonGroupPropsType = {
imageStyle: styleType
setImageStyle: React.Dispatch<React.SetStateAction<styleType>>
}
export const StyleTypeButtonGroup: React.FC<styleButtonGroupPropsType> = ({imageStyle, setImageStyle}) => {
return (
<View
style={{
display: flex,
flexDirection: row,
alignItems: center,
marginTop: 16,
marginBottom: 16,
}}>
<Text style={{fontSize: 16, marginRight: 16}}>生成数量</Text>
<StyleTypeButton
label={styleType.general}
style={{marginRight: 16}}
onPress={() => setImageStyle(styleType.general)}
isCurSelected={imageStyle === styleType.general}
/>
<StyleTypeButton
label={styleType.traditional}
onPress={() => setImageStyle(styleType.traditional)}
isCurSelected={imageStyle === styleType.traditional}
/>
</View>
)
}
type StyleTypeButtonPropsType = {
label: styleType
isCurSelected: boolean
onPress: () => void
style?: TextStyle
}
const StyleTypeButton: React.FC<StyleTypeButtonPropsType> = ({label, isCurSelected, onPress, style}) => {
return (
<TouchableHighlight onPress={onPress} underlayColor="#5E3A9E" style={{...style}}>
<View
style={[
componentsStyleSheet.styleTypeButton,
{backgroundColor: isCurSelected ? #925FF0 : #E9DFFC},
]}>
<Text
style={[componentsStyleSheet.styleTypeButtonText, {color: isCurSelected ? #FFFFFF : #784DC7}]}>
{label}
</Text>
</View>
</TouchableHighlight>
)
}
2 编写滑块组件
在这一部分我们需要引入@react-native-community/slider,切换到项目根目录,并在命令行输入以下指令yarn add @react-native-community/slider。等待依赖下载完成后,我们在src/Components目录下创建文件SizeSlider.tsx并填入以下代码
import React from react
import {Text, View} from react-native
import Slider from @react-native-community/slider
type sizeSliderPropsType = {
label: string
size: number
setSize: (payload: number) => void
}
export const SizeSlider: React.FC<sizeSliderPropsType> = ({label, size, setSize}) => {
return (
<View style={{display: flex, flexDirection: row, alignItems: center, height: 40}}>
<Text>{label}</Text>
<Slider
style={{width: 200, height: 40}}
value={size}
onValueChange={value => setSize(value)}
minimumValue={512}
maximumValue={1024}
minimumTrackTintColor="#925FF0"
maximumTrackTintColor="#000000"
/>
<Text style={{color: #925FF0}}>{size}</Text>
</View>
)
}
3 编写图片展示组件
在src/Components下创建ImageDisplay.tsx文件并填入以下代码:
import React from react
import {ActivityIndicator, Image, View} from react-native
type ImageDisplayPropsType={
isLoading:boolean
imageData:Array<string>
}
export const ImageDisplay: React.FC<ImageDisplayPropsType> = ({isLoading,imageData}) => {
return (
<View style={{display: flex, alignItems: center, paddingTop: 16, paddingBottom: 16}}>
{isLoading ? <ActivityIndicator size="large" /> : null}
{imageData.length > 0 && !isLoading
? imageData.map((imgData, idx) => (
<View key={idx} style={{marginTop: 8, marginBottom: 8}}>
<Image
resizeMethod="scale"
resizeMode="contain"
style={{height: 300, width: 300}}
source={{
uri: imgData,
}}
/>
</View>
))
: null}
</View>
)
}
4 编写请求函数
在src/Utils目录下创建MessageData.ts文件并填入以下代码:
export type MessageData= {
data: Array<Array<string>>
is_generating: boolean
duration: number
average_duration: number
}
在src/Utils目录下创建SendMessage.ts文件并填入以下代码:
export function sendMessage(body: any) {
return new Promise((resolve, reject) => {
fetch(http://81.70.134.89:8086/api/getmappedimagemessage/, {
method: POST,
headers: {
Content-Type: application/json,
},
body: JSON.stringify(body),
})
.then(response => {
if (response.ok) {
const res = response.json()
resolve(res)
} else {
return reject(error)
}
})
.catch(error => reject(error))
})
}
5 修改 AndroidManifest
进入根目录/android/app/src/main/AndroidManifest.xml,找到以下代码:
android:windowSoftInputMode="adjustResize"
并将其替换为:
android:windowSoftInputMode="stateAlwaysHidden|adjustPan"
之后请确保在manifest标签内包含以下代码:
在application标签内包含属性:
android:usesCleartextTraffic="true"
6 编写主界面
在src/目录下创建文件HomeScreen.tsx,我们将在这里编写APP主界面的代码,文件创建完成后我们在文件中填入以下代码:
import React, {useState} from react
import {ScrollView, Text, TextInput, View} from react-native
import {sendMessage} from ./Utils/SendMessage
import {mainStyleSheet} from ./Style/MainStyleSheet
import {BatchSizeButtonGroup} from ./Components/BatchSizeButtonGroup
import {GenerateButton} from ./Components/GenerateButton
import {SizeSlider} from ./Components/SizeSlider
import {StyleTypeButtonGroup} from ./Components/StyleTypeButtonGroup
import {styleType} from ./Utils/StyleType
import {ImageDisplay} from ./Components/ImageDisplay
import {MessageData} from ./Utils/MessageData
export function HomeScreen() {
const [content, setContent] = useState<string>()
const [imageStyle, setImageStyle] = useState<styleType>(styleType.general)
const [imageHeight, setImageHeight] = useState<number>(512)
const [imageWidth, setImageWidth] = useState<number>(512)
const [batchSize, setBatchSize] = useState<number>(1)
const [imageData, setImageData] = useState<Array<string>>([])
const [isLoading, setIsLoading] = useState<boolean>(false)
const onPressGenerate = () => {
if (isLoading) {
return
}
setIsLoading(true)
sendMessage({
text: content,
styleType: imageStyle,
num: batchSize,
w: imageWidth,
h: imageHeight,
})
.then((response: any) => {
const res = JSON.parse(response) as MessageData
setIsLoading(false)
setImageData(res.data[0])
})
.catch(err => {
console.log(err)
setIsLoading(false)
})
}
return (
<View style={{height: 100%, width: 100%, display: flex}}>
<Text style={{width: 100%, fontSize: 32, textAlign: center}}>Text2Image</Text>
<ScrollView style={{flex: 1, paddingLeft: 10%, paddingRight: 10%}}>
<Text style={{fontSize: 16}}>请输入文字内容</Text>
<ScrollView>
<TextInput
multiline
numberOfLines={5}
style={mainStyleSheet.textInput}
onChangeText={text => setContent(text)}
value={content}
/>
</ScrollView>
<StyleTypeButtonGroup imageStyle={imageStyle} setImageStyle={setImageStyle} />
<BatchSizeButtonGroup batchSize={batchSize} setBatchSize={setBatchSize} />
<SizeSlider label={图片高度} size={imageHeight} setSize={setImageHeight} />
<SizeSlider label={图片宽度} size={imageWidth} setSize={setImageWidth} />
<ImageDisplay isLoading={isLoading} imageData={imageData} />
</ScrollView>
<View style={mainStyleSheet.generateButton}>
<GenerateButton onPress={onPressGenerate} disabled={isLoading} />
</View>
</View>
)
}
然后在src/Style目录下创建文件MainStyleSheet.ts,在其中填入以下代码
import {StyleSheet} from react-native
export const mainStyleSheet = StyleSheet.create({
textInput: {
width: 100%,
textAlignVertical: top,
marginTop: 16,
background: #FFFFFF,
borderColor: #DECFFB,
borderWidth: 1,
boxShadow: 0 4 8 rgba(151, 71, 255, 0.08),
borderRadius: 8,
},
generateButton: {
marginTop: auto,
marginBottom: 16,
display: flex,
alignItems: center,
width: 100%,
},
})
打开根目录/App.tsx文件,将文件中的代码替换为以下代码:
import React from react
import {SafeAreaView, StatusBar, StyleSheet} from react-native
import {HomeScreen} from ./src/HomeScreen
const App = () => {
return (
<SafeAreaView style={styles.mainContainer}>
<StatusBar barStyle="light-content" />
<HomeScreen />
</SafeAreaView>
)
}
const styles = StyleSheet.create({
mainContainer: {width: 100%, height: 100%},
})
export default App
7 本地测试
在完成上述代码的编写后保存文件,按下 R 键,或是在开发者菜单中选择 Reload,将会在模拟器或真机中看到以下画面:
在文本输入框中输入对图片的描述,选择生成类型、数量与长宽后点击生成图片,等待一段时间后便可以看到生成的图片。
三、打包发布
本部分基于
ReactNative官方文档,如遇到困难请阅读官方文档寻求进一步帮助。
1 生成签名密钥
Android 要求所有应用都有一个数字签名才会被允许安装在用户手机上,我们需要首先生成一个新的签名密钥,首先找到 jdk 的安装目录,在 Windows 上keytool命令放在 JDK 的 bin 目录中(比如C:\Program Files\Java\jdkx.x.x_x\bin)。打开 CMD 或者 powershell 进入该目录,然后输入以下指令:
keytool -genkeypair -v -storetype PKCS12 -keystore my-release-key.keystore -alias my-key-alias -keyalg RSA -keysize 2048 -validity 10000
该条命令会要求你设置一段密码与相关发行信息,请妥善保存你设置的密码。在运行完上述指令后,会在目录下生成一个文件my-release-key.keystore
2 设置 gradle 变量
把my-release-key.keystore文件放到你工程中的android/app文件夹下,打开项目目录/android/gradle.properties并添加如下代码:
MYAPP_RELEASE_STORE_FILE=my-release-key.keystore
MYAPP_RELEASE_KEY_ALIAS=my-key-alias
MYAPP_RELEASE_STORE_PASSWORD=*****
MYAPP_RELEASE_KEY_PASSWORD=*****
其中*****是第一步时设置的密码
进入项目目录/android/app/build.gradle添加如下配置
...
android {
...
defaultConfig { ... }
signingConfigs {
release {
if (project.hasProperty(MYAPP_RELEASE_STORE_FILE)) {
storeFile file(MYAPP_RELEASE_STORE_FILE)
storePassword MYAPP_RELEASE_STORE_PASSWORD
keyAlias MYAPP_RELEASE_KEY_ALIAS
keyPassword MYAPP_RELEASE_KEY_PASSWORD
}
}
}
buildTypes {
release {
...
signingConfig signingConfigs.release
}
}
}
...
3 生成APK包
在项目根目录的终端中输入以下指令:
cd android
./gradlew assembleRelease
生成的 APK 文件位于android/app/build/outputs/apk/release/app-release.apk,它已经可以用来发布了。
4 测试发行版本
输入以下命令可以在设备上安装发行版本:
npx react-native run-android --variant=release
注意:你可能需要先将真机或虚拟机中安装的测试版APP删除,否则可能出现无法安装的情况
5 其他需要注意的问题
如果出现发行版APP安装成功但点击生成图片按钮时无法发送请求的情况,请检查项目根目录/android/app/src/main/AndroidManifest.xml文件,并确保manifest标签内包含以下代码:<uses-permission android:name="android.permission.INTERNET" />,以及在application标签内包含属性:android:usesCleartextTraffic="true",以保证APP有权限发起网络请求。
项目完整代码 :https://github.com/MX0723/TextToImageAPP
本文由某某资讯网发布,不代表某某资讯网立场,转载联系作者并注明出处:http://www.nxfun.com/index.php?m=home&c=View&a=index&aid=966