Skip to content

Commit c9f806f

Browse files
committed
add stablediffusionapi support.
1 parent f94a738 commit c9f806f

File tree

7 files changed

+520
-167
lines changed

7 files changed

+520
-167
lines changed

README.md

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
55
> 我对它进行了一些改造,大部分功能保持了相同。在这里感谢一下 RuliLG ,实现了如此强大好用的 stable-diffusion 组件。
66
7-
基于 Replicate API 的 Stable Diffusion 实现。
7+
基于 Replicate API 和 stablediffusionapi 的 Stable Diffusion 实现。
88
- 🎨 Built-in prompt helper to create better images
99
- 🚀 Store the results in your database
1010
- 🎇 Generate multiple images in the same API call
@@ -19,6 +19,7 @@
1919
composer require imactool/hyperf-stable-diffusion
2020
2121
```
22+
注意 表新增了`platform`平台字段。-- 后续会使用迁移增加,目前不考虑 :)
2223

2324
## 发布配置(包含配置文件和迁移文件)
2425

@@ -44,9 +45,9 @@ return [
4445
### 文字生成图片(Text to Image)
4546
```php
4647
use Imactool\HyperfStableDiffusion\Prompt;
47-
use Imactool\HyperfStableDiffusion\StableDiffusion;
48+
use Imactool\HyperfStableDiffusion\Replicate;
4849

49-
$result = StableDiffusion::make()->withPrompt(
50+
$result = Replicate::make()->withPrompt(
5051
Prompt::make()
5152
->with('a panda sitting on the streets of New York after a long day of walking')
5253
->photograph()
@@ -61,14 +62,14 @@ use Imactool\HyperfStableDiffusion\StableDiffusion;
6162
### 图片生成图片(Image to Image)
6263
```php
6364
use Imactool\HyperfStableDiffusion\Prompt;
64-
use Imactool\HyperfStableDiffusion\StableDiffusion;
65+
use Imactool\HyperfStableDiffusion\Replicate;
6566
use Intervention\Image\ImageManager;
6667

6768
//这里使用了 intervention/image 扩展来处理图片文件,你也可以更换为其他的
6869
$sourceImg = (string) (new ImageManager(['driver' => 'imagick']))->make('path/image/source.png')->encode('data-url');
6970

7071
$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+
$result = Replicate::make()
7273
->converVersion('a991dcab77024471af6a89ef758d98d1a54c5a25fc52a06ccfd7754b7ad04b35')
7374
->withPrompt(
7475
Prompt::make()
@@ -88,8 +89,8 @@ $result = StableDiffusion::make()
8889
### 查询结果
8990

9091
```php
91-
use Imactool\HyperfStableDiffusion\StableDiffusion;
92-
$freshResults = StableDiffusion::get($replicate_id);
92+
use Imactool\HyperfStableDiffusion\Replicate;
93+
$freshResults = Replicate::get($replicate_id);
9394

9495
```
9596

@@ -157,6 +158,33 @@ Additionally, you can add custom styles with the following methods:
157158

158159
To learn more on how to build prompts for Stable Diffusion, please [enter this link](https://beta.dreamstudio.ai/prompt-guide).
159160

161+
## 基于 stablediffusionapi 平台 [https://stablediffusionapi.com/docs/](https://stablediffusionapi.com/docs/)
162+
或者 [Postman Collection](https://documenter.getpostman.com/view/18679074/2s83zdwReZ)
163+
164+
### 文字生成图片(Text to Image)
165+
```php
166+
use Imactool\HyperfStableDiffusion\StableDiffusion;
167+
168+
$res = StableDiffusion::make()
169+
->useDreamboothApiV4()
170+
->withPayload('key', '')
171+
->withPayload('model_id', 'anything-v4')
172+
->withPayload('prompt', 'ultra realistic close up portrait ((beautiful pale cyberpunk female with heavy black eyeliner)), blue eyes, shaved side haircut, hyper detail, cinematic lighting, magic neon, dark red city, Canon EOS R3, nikon, f/1.4, ISO 200, 1/160s, 8K, RAW, unedited, symmetrical balance, in-frame, 8K')
173+
->withPayload('negative_prompt', 'painting, extra fingers, mutated hands, poorly drawn hands, poorly drawn face, deformed, ugly, blurry, bad anatomy, bad proportions, extra limbs, cloned face, skinny, glitchy, double torso, extra arms, extra hands, mangled fingers, missing lips, ugly face, distorted face, extra legs, anime')
174+
->withPayload('width', '512')
175+
->withPayload('height', '512')
176+
->withPayload('samples', '1')
177+
->withPayload('num_inference_steps', '30')
178+
->withPayload('seed', null)
179+
->withPayload('guidance_scale', '7.5')
180+
->withPayload('webhook', null)
181+
->withPayload('track_id', null)
182+
->text2img();
183+
184+
var_dump( $res);
185+
186+
```
187+
160188

161189
## License
162190

publish/migrations/create_stable_diffusion_results_table.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ public function up(): void
2222
Schema::create('stable_diffusion_results', function (Blueprint $table) {
2323
$table->bigIncrements('id');
2424
$table->string('replicate_id')->unique();
25+
$table->string('platform')->comment('with platform');
2526
$table->text('user_prompt');
2627
$table->mediumText('full_prompt');
2728
$table->string('url');

src/Models/StableDiffusionResult.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
/**
1717
* @property int $id
1818
* @property string $replicate_id
19+
* @property string $platform
1920
* @property string $user_prompt
2021
* @property string $full_prompt
2122
* @property string $url
@@ -36,7 +37,7 @@ class StableDiffusionResult extends Model
3637
/**
3738
* The attributes that are mass assignable.
3839
*/
39-
protected array $fillable = ['replicate_id','user_prompt','full_prompt','url','status', 'output', 'error', 'predict_time'];
40+
protected array $fillable = ['replicate_id', 'platform', 'user_prompt', 'full_prompt', 'url', 'status', 'output', 'error', 'predict_time'];
4041

4142
/**
4243
* The attributes that should be cast to native types.

src/Replicate.php

Lines changed: 254 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,254 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
/**
5+
* This file is part of the imactool/hyperf-stable-diffusion.
6+
*
7+
* (c) imactool <[email protected]>
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+
use Exception;
14+
use Hyperf\Collection\Arr;
15+
use Hyperf\Context\ApplicationContext;
16+
use Hyperf\Guzzle\ClientFactory;
17+
use Imactool\HyperfStableDiffusion\Models\StableDiffusionResult;
18+
use PDOException;
19+
use Psr\Http\Client\ClientInterface;
20+
21+
class Replicate
22+
{
23+
private static $platform = 'replicate';
24+
25+
private array $inputParams = [];
26+
27+
private string $baseUrl = '';
28+
29+
private string $token = '';
30+
31+
private string $version = '';
32+
33+
private function __construct(
34+
public ?Prompt $prompt = null,
35+
private int $width = 512,
36+
private int $height = 512
37+
) {
38+
}
39+
40+
public function converUrl(string $url): self
41+
{
42+
$this->baseUrl = $url;
43+
return $this;
44+
}
45+
46+
public function getBaseUrl(): string
47+
{
48+
if (empty($this->baseUrl)) {
49+
$this->baseUrl = config('stable-diffusion.url');
50+
}
51+
return $this->baseUrl;
52+
}
53+
54+
public function converToken(string $token): self
55+
{
56+
$this->token = $token;
57+
return $this;
58+
}
59+
60+
public function getToken(): string
61+
{
62+
if (empty($this->token)) {
63+
$this->token = config('stable-diffusion.token');
64+
}
65+
return $this->token;
66+
}
67+
68+
public function converVersion(string $version): self
69+
{
70+
$this->version = $version;
71+
return $this;
72+
}
73+
74+
public function getVersion(): string
75+
{
76+
if (empty($this->version)) {
77+
$this->version = config('stable-diffusion.version');
78+
}
79+
return $this->version;
80+
}
81+
82+
public static function make(): self
83+
{
84+
return new self();
85+
}
86+
87+
public function getV2(string $replicateId)
88+
{
89+
$result = StableDiffusionResult::query()->where('replicate_id', $replicateId)->first();
90+
assert($result !== null, 'Unknown id');
91+
$idleStatuses = ['starting', 'processing'];
92+
if (! in_array($result->status, $idleStatuses)) {
93+
return $result;
94+
}
95+
96+
$response = $this->client()->get($result->url);
97+
98+
if ($response->getStatusCode() !== 200) {
99+
throw new Exception('Failed to retrieve data.');
100+
}
101+
102+
$responseData = json_decode((string) $response->getBody(), true);
103+
104+
$result->status = Arr::get($responseData, 'status', $result->status);
105+
$result->output = Arr::has($responseData, 'output') ? Arr::get($responseData, 'output') : null;
106+
$result->error = Arr::get($responseData, 'error');
107+
$result->predict_time = Arr::get($responseData, 'metrics.predict_time');
108+
$result->save();
109+
110+
return $result;
111+
}
112+
113+
public static function get(string $replicateId)
114+
{
115+
$result = StableDiffusionResult::query()->where('replicate_id', $replicateId)->first();
116+
assert($result !== null, 'Unknown id');
117+
$idleStatuses = ['starting', 'processing'];
118+
if (! in_array($result->status, $idleStatuses)) {
119+
return $result;
120+
}
121+
122+
$response = self::make()
123+
->client()
124+
->get($result->url);
125+
126+
if ($response->getStatusCode() !== 200) {
127+
throw new Exception('Failed to retrieve data.');
128+
}
129+
130+
$responseData = json_decode((string) $response->getBody(), true);
131+
132+
$result->status = Arr::get($responseData, 'status', $result->status);
133+
$result->output = Arr::has($responseData, 'output') ? Arr::get($responseData, 'output') : null;
134+
$result->error = Arr::get($responseData, 'error');
135+
$result->predict_time = Arr::get($responseData, 'metrics.predict_time');
136+
$result->save();
137+
138+
return $result;
139+
}
140+
141+
public function withPrompt(Prompt $prompt)
142+
{
143+
$this->prompt = $prompt;
144+
return $this;
145+
}
146+
147+
/**
148+
* except prompt,other API parameters.
149+
*
150+
* @param string $key 参数本身
151+
* @param mixed $value 参数值
152+
*
153+
* @return $this
154+
*/
155+
public function inputParams(string $key, mixed $value)
156+
{
157+
$this->inputParams[$key] = $value;
158+
return $this;
159+
}
160+
161+
public function width(int $width)
162+
{
163+
assert($width > 0, 'Width must be greater than 0');
164+
if ($width <= 768) {
165+
assert($width <= 768 && $this->width <= 1024, 'Width must be lower than 768 and height lower than 1024');
166+
} else {
167+
assert($width <= 1024 && $this->width <= 768, 'Width must be lower than 1024 and height lower than 768');
168+
}
169+
$this->width = $width;
170+
return $this;
171+
}
172+
173+
public function height(int $height)
174+
{
175+
assert($height > 0, 'Height must be greater than 0');
176+
if ($height <= 768) {
177+
assert($height <= 768 && $this->width <= 1024, 'Height must be lower than 768 and width lower than 1024');
178+
} else {
179+
assert($height <= 1024 && $this->width <= 768, 'Height must be lower than 1024 and width lower than 768');
180+
}
181+
182+
$this->height = $height;
183+
184+
return $this;
185+
}
186+
187+
public function generate(int $numberOfImages)
188+
{
189+
assert($this->prompt !== null, 'You must provide a prompt');
190+
assert($numberOfImages > 0, 'You must provide a number greater than 0');
191+
192+
$input = [
193+
'prompt' => $this->prompt->toString(),
194+
'num_outputs' => $numberOfImages,
195+
];
196+
197+
$input = array_merge($input, $this->inputParams);
198+
199+
$response = $this->client()->post(
200+
$this->getBaseUrl(),
201+
[
202+
'json' => [
203+
'version' => $this->getVersion(),
204+
'input' => $input,
205+
],
206+
]
207+
);
208+
209+
$result = json_decode($response->getBody()->getContents(), true);
210+
211+
$data = [
212+
'replicate_id' => $result['id'],
213+
'platform' => self::$platform,
214+
'user_prompt' => $this->prompt->userPrompt(),
215+
'full_prompt' => $this->prompt->toString($this->inputParams),
216+
'url' => $result['urls']['get'],
217+
'status' => $result['status'],
218+
'output' => isset($result['output']) ? $result['output'] : null,
219+
'error' => $result['error'],
220+
'predict_time' => null,
221+
];
222+
223+
try {
224+
StableDiffusionResult::create($data);
225+
} catch (Exception $exception) {
226+
$msg = $exception->getMessage();
227+
var_dump(['data insert error' => $msg]);
228+
if ($exception instanceof PDOException) {
229+
$errorInfo = $exception->errorInfo;
230+
$code = $errorInfo[1];
231+
// $sql_state = $errorInfo[0];
232+
// $msg = isset($errorInfo[2]) ? $errorInfo[2] : $sql_state;
233+
}
234+
if ((int) $code !== 1062) {
235+
return $result;
236+
}
237+
}
238+
239+
return $result;
240+
}
241+
242+
private function client(): ClientInterface
243+
{
244+
return ApplicationContext::getContainer()->get(ClientFactory::class)->create([
245+
// 'base_uri' => $this->getBaseUrl(),
246+
// 'timeout' => 10,
247+
'headers' => [
248+
'Authorization' => 'Token ' . $this->getToken(),
249+
'Accept' => 'application/json',
250+
'Content-Type' => 'application/json',
251+
],
252+
]);
253+
}
254+
}

0 commit comments

Comments
 (0)