Skip to content

Commit f94a738

Browse files
committed
新增图片生成图片
1 parent 14fdef3 commit f94a738

File tree

5 files changed

+206
-34
lines changed

5 files changed

+206
-34
lines changed

LICENSE

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
The MIT License (MIT)
22

3-
Copyright (c) Hyperf
3+
Copyright (c) imactool <chinauser1208@gmail.come>
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal
@@ -9,13 +9,13 @@ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
99
copies of the Software, and to permit persons to whom the Software is
1010
furnished to do so, subject to the following conditions:
1111

12-
The above copyright notice and this permission notice shall be included in all
13-
copies or substantial portions of the Software.
12+
The above copyright notice and this permission notice shall be included in
13+
all copies or substantial portions of the Software.
1414

1515
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1616
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1717
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1818
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1919
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21-
SOFTWARE.
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
THE SOFTWARE.

README.md

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@
44
55
> 我对它进行了一些改造,大部分功能保持了相同。在这里感谢一下 RuliLG ,实现了如此强大好用的 stable-diffusion 组件。
66
7+
基于 Replicate API 的 Stable Diffusion 实现。
8+
- 🎨 Built-in prompt helper to create better images
9+
- 🚀 Store the results in your database
10+
- 🎇 Generate multiple images in the same API call
11+
- 💯 Supports both (text to image) and (image to image)
12+
713

814
鸣谢:原作:[RuliLG](https://github.com/RuliLG),特此鸣谢!
915

@@ -22,7 +28,7 @@ php bin/hyperf.php migrate
2228
```
2329
至此,配置完成。
2430

25-
```
31+
```php
2632
return [
2733
'url' => env('REPLICATE_URL', 'https://api.replicate.com/v1/predictions'),
2834
'token' => env('REPLICATE_TOKEN'),
@@ -35,8 +41,8 @@ return [
3541

3642
## 使用
3743

38-
### 生成
39-
```
44+
### 文字生成图片(Text to Image)
45+
```php
4046
use Imactool\HyperfStableDiffusion\Prompt;
4147
use Imactool\HyperfStableDiffusion\StableDiffusion;
4248

@@ -52,9 +58,36 @@ use Imactool\HyperfStableDiffusion\StableDiffusion;
5258
)->generate(3);
5359
```
5460

61+
### 图片生成图片(Image to Image)
62+
```php
63+
use Imactool\HyperfStableDiffusion\Prompt;
64+
use Imactool\HyperfStableDiffusion\StableDiffusion;
65+
use Intervention\Image\ImageManager;
66+
67+
//这里使用了 intervention/image 扩展来处理图片文件,你也可以更换为其他的
68+
$sourceImg = (string) (new ImageManager(['driver' => 'imagick']))->make('path/image/source.png')->encode('data-url');
69+
70+
$prompt = 'Petite 21-year-old Caucasian female gamer streaming from her bedroom with pastel pink pigtails and gaming gear. Dynamic and engaging image inspired by colorful LED lights and the energy of Twitch culture, in 1920x1080 resolution.';
71+
$result = StableDiffusion::make()
72+
->converVersion('a991dcab77024471af6a89ef758d98d1a54c5a25fc52a06ccfd7754b7ad04b35')
73+
->withPrompt(
74+
Prompt::make()
75+
->with($prompt)
76+
)
77+
->inputParams('image',$sourceImg)
78+
->inputParams('negative_prompt', 'disfigured, kitsch, ugly, oversaturated, greain, low-res, Deformed, blurry, bad anatomy, disfigured, poorly drawn face, mutation, mutated, extra limb, ugly, poorly drawn hands, missing limb, blurry, floating limbs, disconnected limbs, malformed hands, blur, out of focus, long neck, long body, ugly, disgusting, poorly drawn, childish, mutilated, mangled, old, surreal, calligraphy, sign, writing, watermark, text, body out of frame, extra legs, extra arms, extra feet, out of frame, poorly drawn feet, cross-eye, blurry, bad anatomy')
79+
->inputParams('strength', 0.5)
80+
->inputParams('upscale', 2)
81+
->inputParams('num_inference_steps', 25)
82+
->inputParams('guidance_scale', 7.5)
83+
->inputParams('scheduler', 'EulerAncestralDiscrete')
84+
->generate(1);
85+
```
86+
87+
5588
### 查询结果
5689

57-
```
90+
```php
5891
use Imactool\HyperfStableDiffusion\StableDiffusion;
5992
$freshResults = StableDiffusion::get($replicate_id);
6093

src/NegativePrompt.php

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
/**
5+
* This file is part of the imactool/hyperf-stable-diffusion.
6+
*
7+
* (c) imactool <chinauser1208@gmail.come>
8+
* This source file is subject to the MIT license that is bundled
9+
* with this source code in the file LICENSE.
10+
*/
11+
namespace Imactool\HyperfStableDiffusion;
12+
13+
class NegativePrompt
14+
{
15+
public function __construct(
16+
protected string $negative_prompt = ''
17+
) {
18+
}
19+
20+
public static function make(): self
21+
{
22+
return new NegativePrompt();
23+
}
24+
25+
public function with(string $negative_prompt): static
26+
{
27+
$this->negative_prompt = $negative_prompt;
28+
return $this;
29+
}
30+
31+
public function userNegativePrompt(): string
32+
{
33+
return $this->negative_prompt;
34+
}
35+
}

src/Prompt.php

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public function with(string $prompt): static
4242
return $this;
4343
}
4444

45-
public function toString(): string
45+
public function toString($inputParams = []): string
4646
{
4747
$prompt = $this->prompt;
4848
if ($this->author) {
@@ -61,6 +61,14 @@ public function toString(): string
6161
$prompt .= ', ' . implode(', ', array_values(array_unique($this->finishingTouches)));
6262
}
6363

64+
if (! empty($inputParams)) {
65+
$unsetKey = 'image';
66+
if (array_key_exists($unsetKey, $inputParams)) {
67+
unset($inputParams[$unsetKey]);
68+
}
69+
$prompt .= ', ' . implode(', ', array_values(array_unique($inputParams)));
70+
}
71+
6472
return $prompt;
6573
}
6674

src/StableDiffusion.php

Lines changed: 120 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -15,22 +15,99 @@
1515
use Hyperf\Context\ApplicationContext;
1616
use Hyperf\Guzzle\ClientFactory;
1717
use Imactool\HyperfStableDiffusion\Models\StableDiffusionResult;
18+
use PDOException;
1819
use Psr\Http\Client\ClientInterface;
1920

2021
class StableDiffusion
2122
{
23+
private array $inputParams = [];
24+
25+
private string $baseUrl = '';
26+
27+
private string $token = '';
28+
29+
private string $version = '';
30+
2231
private function __construct(
2332
public ?Prompt $prompt = null,
2433
private int $width = 512,
2534
private int $height = 512
2635
) {
2736
}
2837

38+
public function converUrl(string $url): self
39+
{
40+
$this->baseUrl = $url;
41+
return $this;
42+
}
43+
44+
public function getBaseUrl(): string
45+
{
46+
if (empty($this->baseUrl)) {
47+
$this->baseUrl = config('stable-diffusion.url');
48+
}
49+
return $this->baseUrl;
50+
}
51+
52+
public function converToken(string $token): self
53+
{
54+
$this->token = $token;
55+
return $this;
56+
}
57+
58+
public function getToken(): string
59+
{
60+
if (empty($this->token)) {
61+
$this->token = config('stable-diffusion.token');
62+
}
63+
return $this->token;
64+
}
65+
66+
public function converVersion(string $version): self
67+
{
68+
$this->version = $version;
69+
return $this;
70+
}
71+
72+
public function getVersion(): string
73+
{
74+
if (empty($this->version)) {
75+
$this->version = config('stable-diffusion.version');
76+
}
77+
return $this->version;
78+
}
79+
2980
public static function make(): self
3081
{
3182
return new self();
3283
}
3384

85+
public function getV2(string $replicateId)
86+
{
87+
$result = StableDiffusionResult::query()->where('replicate_id', $replicateId)->first();
88+
assert($result !== null, 'Unknown id');
89+
$idleStatuses = ['starting', 'processing'];
90+
if (! in_array($result->status, $idleStatuses)) {
91+
return $result;
92+
}
93+
94+
$response = $this->client()->get($result->url);
95+
96+
if ($response->getStatusCode() !== 200) {
97+
throw new Exception('Failed to retrieve data.');
98+
}
99+
100+
$responseData = json_decode((string) $response->getBody(), true);
101+
102+
$result->status = Arr::get($responseData, 'status', $result->status);
103+
$result->output = Arr::has($responseData, 'output') ? Arr::get($responseData, 'output') : null;
104+
$result->error = Arr::get($responseData, 'error');
105+
$result->predict_time = Arr::get($responseData, 'metrics.predict_time');
106+
$result->save();
107+
108+
return $result;
109+
}
110+
34111
public static function get(string $replicateId)
35112
{
36113
$result = StableDiffusionResult::query()->where('replicate_id', $replicateId)->first();
@@ -51,7 +128,7 @@ public static function get(string $replicateId)
51128
$responseData = json_decode((string) $response->getBody(), true);
52129

53130
$result->status = Arr::get($responseData, 'status', $result->status);
54-
$result->output = Arr::has($responseData,'output') ? Arr::get($responseData, 'output') : null;
131+
$result->output = Arr::has($responseData, 'output') ? Arr::get($responseData, 'output') : null;
55132
$result->error = Arr::get($responseData, 'error');
56133
$result->predict_time = Arr::get($responseData, 'metrics.predict_time');
57134
$result->save();
@@ -65,6 +142,20 @@ public function withPrompt(Prompt $prompt)
65142
return $this;
66143
}
67144

145+
/**
146+
* except prompt,other API parameters.
147+
*
148+
* @param string $key 参数本身
149+
* @param mixed $value 参数值
150+
*
151+
* @return $this
152+
*/
153+
public function inputParams(string $key, mixed $value)
154+
{
155+
$this->inputParams[$key] = $value;
156+
return $this;
157+
}
158+
68159
public function width(int $width)
69160
{
70161
assert($width > 0, 'Width must be greater than 0');
@@ -96,15 +187,19 @@ public function generate(int $numberOfImages)
96187
assert($this->prompt !== null, 'You must provide a prompt');
97188
assert($numberOfImages > 0, 'You must provide a number greater than 0');
98189

190+
$input = [
191+
'prompt' => $this->prompt->toString(),
192+
'num_outputs' => $numberOfImages,
193+
];
194+
195+
$input = array_merge($input, $this->inputParams);
196+
99197
$response = $this->client()->post(
100-
config('stable-diffusion.url'),
198+
$this->getBaseUrl(),
101199
[
102200
'json' => [
103-
'version' => config('stable-diffusion.version'),
104-
'input' => [
105-
'prompt' => $this->prompt->toString(),
106-
'num_outputs' => $numberOfImages,
107-
],
201+
'version' => $this->getVersion(),
202+
'input' => $input,
108203
],
109204
]
110205
);
@@ -114,39 +209,40 @@ public function generate(int $numberOfImages)
114209
$data = [
115210
'replicate_id' => $result['id'],
116211
'user_prompt' => $this->prompt->userPrompt(),
117-
'full_prompt' => $this->prompt->toString(),
212+
'full_prompt' => $this->prompt->toString($this->inputParams),
118213
'url' => $result['urls']['get'],
119214
'status' => $result['status'],
120215
'output' => isset($result['output']) ? $result['output'] : null,
121216
'error' => $result['error'],
122217
'predict_time' => null,
123218
];
124219

125-
try {
126-
StableDiffusionResult::create($data);
127-
}catch (\Exception $exception){
128-
// $msg = $exception->getMessage();
129-
if ($exception instanceof \PDOException) {
130-
$errorInfo = $exception->errorInfo;
131-
$code = $errorInfo[1];
132-
// $sql_state = $errorInfo[0];
133-
// $msg = isset($errorInfo[2]) ? $errorInfo[2] : $sql_state;
134-
}
135-
if ((int) $code !== 1062) {
136-
return $result;
137-
}
138-
}
220+
try {
221+
StableDiffusionResult::create($data);
222+
} catch (Exception $exception) {
223+
$msg = $exception->getMessage();
224+
var_dump(['data insert error' => $msg]);
225+
if ($exception instanceof PDOException) {
226+
$errorInfo = $exception->errorInfo;
227+
$code = $errorInfo[1];
228+
// $sql_state = $errorInfo[0];
229+
// $msg = isset($errorInfo[2]) ? $errorInfo[2] : $sql_state;
230+
}
231+
if ((int) $code !== 1062) {
232+
return $result;
233+
}
234+
}
139235

140236
return $result;
141237
}
142238

143239
private function client(): ClientInterface
144240
{
145241
return ApplicationContext::getContainer()->get(ClientFactory::class)->create([
146-
'base_uri' => config('stable-diffusion.base_uri'),
242+
// 'base_uri' => $this->getBaseUrl(),
147243
// 'timeout' => 10,
148244
'headers' => [
149-
'Authorization' => 'Token ' . config('stable-diffusion.token'),
245+
'Authorization' => 'Token ' . $this->getToken(),
150246
'Accept' => 'application/json',
151247
'Content-Type' => 'application/json',
152248
],

0 commit comments

Comments
 (0)