Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 16 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,18 @@
This project is deployed here: https://outfitanyone.site
# 算法妈妈虚拟试衣服务
## 简介
通过选定(模特,上装,下装)这个三元组,以达到搭配试衣效果。

## TODOs
* 修复此虚拟试衣服务
* 完整搭配而非两件套

## 线上服务
[免费使用](https://tryon.suanfamama.com)

## 附加信息
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).

## Getting Started
### Getting Started

First, run the development server:

Expand All @@ -16,17 +26,17 @@ pnpm dev
bun dev
```

Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
Open [http://localhost:3001](http://localhost:3001) with your browser to see the result.

You can start editing the page by modifying `pages/index.tsx`. The page auto-updates as you edit the file.

[API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.ts`.
[API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3001/api/hello](http://localhost:3001/api/hello). This endpoint can be edited in `pages/api/hello.ts`.

The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages.

This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.

## Learn More
### Learn More

To learn more about Next.js, take a look at the following resources:

Expand All @@ -35,7 +45,7 @@ To learn more about Next.js, take a look at the following resources:

You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!

## Deploy on Vercel
### Deploy on Vercel

The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.

Expand Down
11 changes: 7 additions & 4 deletions components/ImagePipeline/ImageUploader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export default function ImageUploader({ imageList = [], onUpload, onPick }) {
const randomString = generateRandomString();

const response = await fetch(
`https://humanaigc-outfitanyone.hf.space/--replicas/o90fr/upload?upload_id=${randomString}`,
`https://humanaigc-outfitanyone.hf.space/upload?upload_id=${randomString}`,
{
method: "POST",
body: formData,
Expand Down Expand Up @@ -54,7 +54,10 @@ export default function ImageUploader({ imageList = [], onUpload, onPick }) {
return (
<div className="flex flex-col h-full self-stretch">
{/* Image preview section */}
<div className="mb-4 relative flex h-full self-stretch items-center justify-center" ref={wrapperRef}>
<div
className="mb-4 relative flex h-full self-stretch items-center justify-center"
ref={wrapperRef}
>
{selectedImage ? (
<>
<img
Expand All @@ -66,7 +69,7 @@ export default function ImageUploader({ imageList = [], onUpload, onPick }) {
className="absolute top-0 right-0 m-2 bg-red-500 text-white px-2 py-1 text-sm rounded"
onClick={handleClear}
>
Clear
清除
</button>
</>
) : (
Expand All @@ -77,7 +80,7 @@ export default function ImageUploader({ imageList = [], onUpload, onPick }) {
onClick={() => fileInputRef.current?.click()}
disabled={!onUpload}
>
<span>{!onUpload ? "Pick Image" : "Upload Image"}</span>
<span>{!onUpload ? "模特图片" : "上传衣服"}</span>
</button>
)}
</div>
Expand Down
85 changes: 58 additions & 27 deletions components/ImagePipeline/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,69 +10,105 @@ const apiUrls = ["/load_example", "/load_example_1", "/load_example_2"];
const top_garment = [
{
id: 0,
url: "https://humanaigc-outfitanyone.hf.space/--replicas/o90fr/file=/tmp/gradio/f3ba321017355c5a0c8051d3f438e881cc87b945/top222.JPG",
url: "https://humanaigc-outfitanyone.hf.space/file=/tmp/gradio/f3ba321017355c5a0c8051d3f438e881cc87b945/top222.JPG",
},
{
id: 1,
url: "https://humanaigc-outfitanyone.hf.space/--replicas/o90fr/file=/tmp/gradio/65ff53dc99803d44d4e07facd195cda873856968/top5.png",
url: "https://humanaigc-outfitanyone.hf.space/file=/tmp/gradio/65ff53dc99803d44d4e07facd195cda873856968/top5.png",
},
{
id: 2,
url: "https://humanaigc-outfitanyone.hf.space/--replicas/o90fr/file=/tmp/gradio/79df244bb1e3a712b3612fdd0bebf93ff40a88a8/top333.png",
url: "https://humanaigc-outfitanyone.hf.space/file=/tmp/gradio/79df244bb1e3a712b3612fdd0bebf93ff40a88a8/top333.png",
},
{
id: 3,
url: "https://humanaigc-outfitanyone.hf.space/--replicas/o90fr/file=/tmp/gradio/3b0d73532b2296848b39c332c018211fb1d8f8c6/dress1.png",
url: "https://humanaigc-outfitanyone.hf.space/file=/tmp/gradio/3b0d73532b2296848b39c332c018211fb1d8f8c6/dress1.png",
},
{
id: 4,
url: "https://humanaigc-outfitanyone.hf.space/--replicas/o90fr/file=/tmp/gradio/30275a32330224953f3bd08c3e536fd451706bab/dress2.png",
url: "https://humanaigc-outfitanyone.hf.space/file=/tmp/gradio/30275a32330224953f3bd08c3e536fd451706bab/dress2.png",
},
];

const lower_garment = [
{
id: 0,
url: "https://humanaigc-outfitanyone.hf.space/--replicas/o90fr/file=/tmp/gradio/b231ba8252f242cb5734a28f45b669d4c4bfd965/bottom1.png",
url: "https://humanaigc-outfitanyone.hf.space/file=/tmp/gradio/b231ba8252f242cb5734a28f45b669d4c4bfd965/bottom1.png",
},
{
id: 1,
url: "https://humanaigc-outfitanyone.hf.space/--replicas/o90fr/file=/tmp/gradio/17850932298f412c6d307504e6694510c3983592/bottom2.PNG",
url: "https://humanaigc-outfitanyone.hf.space/file=/tmp/gradio/17850932298f412c6d307504e6694510c3983592/bottom2.PNG",
},
{
id: 2,
url: "https://humanaigc-outfitanyone.hf.space/--replicas/o90fr/file=/tmp/gradio/166442933d4f5841ac2a19568ac6b1fdfd495e35/bottom3.JPG",
url: "https://humanaigc-outfitanyone.hf.space/file=/tmp/gradio/166442933d4f5841ac2a19568ac6b1fdfd495e35/bottom3.JPG",
},
{
id: 3,
url: "https://humanaigc-outfitanyone.hf.space/--replicas/o90fr/file=/tmp/gradio/27316c1d97f31a0eeef64d42202e1beadb08483a/bottom4.PNG",
url: "https://humanaigc-outfitanyone.hf.space/file=/tmp/gradio/27316c1d97f31a0eeef64d42202e1beadb08483a/bottom4.PNG",
},
{
id: 4,
url: "https://humanaigc-outfitanyone.hf.space/--replicas/o90fr/file=/tmp/gradio/94c62681b3f3086ea00a63df9a9ceb85fe7b04e8/bottom5.png",
url: "https://humanaigc-outfitanyone.hf.space/file=/tmp/gradio/94c62681b3f3086ea00a63df9a9ceb85fe7b04e8/bottom5.png",
},
];

const models = [
{
id: 0,
url: "https://humanaigc-outfitanyone.hf.space/file=/tmp/gradio/91baf552252b7f9c6416f3175f35e98070565a57/Rouyan_0.png",
},
{
id: 1,
url: "https://humanaigc-outfitanyone.hf.space/--replicas/o90fr/file=/tmp/gradio/f7dce00cee84dadceb24526d4ce5cc5999855c9d/Rouyan_2.png",
url: "https://humanaigc-outfitanyone.hf.space/file=/tmp/gradio/f7dce00cee84dadceb24526d4ce5cc5999855c9d/Rouyan_2.png",
},
{
id: 2,
url: "https://humanaigc-outfitanyone.hf.space/--replicas/o90fr/file=/tmp/gradio/28dbd2deba1e160bfadffbc3675ba4dcac20ca58/Eva_0.png",
url: "https://humanaigc-outfitanyone.hf.space/file=/tmp/gradio/28dbd2deba1e160bfadffbc3675ba4dcac20ca58/Eva_0.png",
},
{
id: 3,
url: "https://humanaigc-outfitanyone.hf.space/--replicas/o90fr/file=/tmp/gradio/2f060521cb67195666c59ccd0e47ecc2587a4100/Simon_1.png",
url: "https://humanaigc-outfitanyone.hf.space/file=/tmp/gradio/2f060521cb67195666c59ccd0e47ecc2587a4100/Simon_1.png",
},
{
id: 4,
url: "https://humanaigc-outfitanyone.hf.space/file=/tmp/gradio/3a2287f20c44729f5c7804235f113de32c769baf/Eva_1.png",
},
{
id: 5,
url: "https://humanaigc-outfitanyone.hf.space/file=/tmp/gradio/9a02f1f9b4db87c22a3341612edeaca4b65920e0/Simon_0.png",
},
{
id: 6,
url: "https://humanaigc-outfitanyone.hf.space/--replicas/o90fr/file=/tmp/gradio/ef12488138e32ba30930bd342a53fbc409ad00a9/Xuanxuan_0.png",
url: "https://humanaigc-outfitanyone.hf.space/file=/tmp/gradio/ef12488138e32ba30930bd342a53fbc409ad00a9/Xuanxuan_0.png",
},
{
id: 7,
url: "https://humanaigc-outfitanyone.hf.space/file=/tmp/gradio/daca749076bd63a3d8c8a97225a031123e6b432a/Xuanxuan_2.png",
},
{
id: 8,
url: "https://humanaigc-outfitanyone.hf.space/file=/tmp/gradio/951c48e394c297c0632753d1a5fa5b79c59c9a36/Yaqi_1.png",
},
{
id: 9,
url: "https://humanaigc-outfitanyone.hf.space/file=/tmp/gradio/6f793bb1d75f34cdc2c980467ef2f2c242fe9b56/Yifeng_0.png",
},
{
id: 10,
url: "https://humanaigc-outfitanyone.hf.space/file=/tmp/gradio/4c5c245e2e96bf61ea1e606d11e31d0a915575e1/Yifeng_3.png",
},
{
id: 11,
url: "https://humanaigc-outfitanyone.hf.space/file=/tmp/gradio/57c66d2b92687a8e1ab12034a9a40d5ae1936ff7/Rouyan_1.png",
},
{
id: 12,
url: "https://humanaigc-outfitanyone.hf.space/file=/tmp/gradio/64f42706321086bbcc24d37a29a5be87da06ef59/Yifeng_2.png",
},
{
id: 13,
url: "https://humanaigc-outfitanyone.hf.space/--replicas/o90fr/file=/tmp/gradio/53974d6ff65483b035a8437be33a9b2c4764b021/Yaqi_0.png",
url: "https://humanaigc-outfitanyone.hf.space/file=/tmp/gradio/53974d6ff65483b035a8437be33a9b2c4764b021/Yaqi_0.png",
},
];

Expand All @@ -85,7 +121,7 @@ export default function ImagePipeline() {
useEffect(() => {
(async () => {
const a = await client(
"https://humanaigc-outfitanyone.hf.space/--replicas/o90fr/",
"https://humanaigc-outfitanyone.hf.space/",
{}
);
setApp(a);
Expand Down Expand Up @@ -159,14 +195,11 @@ export default function ImagePipeline() {
return (
<div className="lg:flex self-stretch h-full flex-col pb-8">
<h2 className="text-3xl font-bold text-center py-5">
Put Clothes on Models. Try it yourself, choose a picture, press
'Generate'
算法妈妈虚拟试衣服务
</h2>
<div className="lg:flex lg:gap-4 h-full pb-6 items-stretch">
<div className="flex flex-col border-2 rounded-3xl border-base-300 p-4 flex-1">
<h2 className="text-xl text-center pb-4">
Select model (right now you can only choose one from the list)
</h2>
<h2 className="text-xl text-center pb-4">选择模特</h2>
<ImageUploader
imageList={models}
onUpload={null}
Expand All @@ -178,9 +211,7 @@ export default function ImagePipeline() {
</div>

<div className="flex flex-col self-stretch h-full border-2 rounded-3xl border-base-300 p-4 flex-1">
<h2 className="text-xl text-center pb-4">
Select top and bottom garment or upload your own
</h2>
<h2 className="text-xl text-center pb-4">选择或上传上装和下装</h2>
<div className="h-1/2">
<ImageUploader
imageList={top_garment}
Expand Down Expand Up @@ -212,20 +243,20 @@ export default function ImagePipeline() {
<GrNext size={28} className="rotate-90 lg:rotate-0 text-base-300" />
</div>
<div className="flex flex-col self-stretch flex-1 border-2 rounded-3xl border-base-300 p-4">
<h2 className="text-xl text-center pb-4">Result</h2>
<h2 className="text-xl text-center pb-4">虚拟试衣效果</h2>
<div className="text-center py-4">
{isLoading ? (
<button className="btn w-full">
<span className="loading loading-spinner"></span>
waiting...
搭配生成中...
</button>
) : (
<button
className="btn btn-primary w-full"
onClick={handleGenerate}
disabled={!imageData[0]?.path || !imageData[1]?.path}
>
Generate
生成搭配
</button>
)}
</div>
Expand Down
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"dev": "PORT=3001 next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"engines": {
"node": "18.x"
},
"dependencies": {
"@gradio/client": "^0.9.1",
"next": "14.0.4",
Expand Down
Loading