Fooocus icon indicating copy to clipboard operation
Fooocus copied to clipboard

API very undocumented

Open g0dSE opened this issue 1 year ago • 17 comments

I am trying to use the api by clicking "Use via API"

But the actual endpoints themself are barely documented? I wanna be able to just put in a prompt and be done with it..?

I am trying to do this:

import { client } from "@gradio/client";
import { createRequire } from "module";
const require = createRequire(import.meta.url);
global.EventSource = require('eventsource');

const app = await client("http://127.0.0.1:7865/");

const response_0 = await fetch("https://raw.githubusercontent.com/gradio-app/gradio/main/test/test_files/bus.png");
const exampleImage = await response_0.blob();

const result = await app.predict(29, [
    "realistic portrait photo of beautiful woman with blonde hair and her labrador dog, hair roots slightly faded, latina, influencer, light blue eyes, no makeup, instagram",
    "unrealistic, saturated, high contrast, big nose, painting, drawing, sketch, cartoon, anime, manga, render, CG, 3d, watermark, signature, label",
    ["Fooocus V2", "Fooocus Photograph", "Fooocus Negative"],
    "Speed",
    "896x1152 <span style='color: grey;'> ∣ 7:9</span>",
    1,
    "8082836497533172128",
    2,
    3,
    "realisticStockPhoto_v10.safetensors",
    "None",
    0.1,
    "SDXL_FILM_PHOTOGRAPHY_STYLE_BetaV0.4.safetensors",
    0.25,
    "None",
    1,
    "None",
    1,
    "None",
    1,
    false,
    "Howdy!", // string  in 'parameter_73' Textbox component		
    "Disabled", // string  in 'Upscale or Variation:' Radio component
    exampleImage, 	// blob in 'Drag above image to here' Image component		
    ["Left"], // string[] (array of strings) in 'Outpaint Direction' Checkboxgroup component
    exampleImage, 	// blob in 'Drag above image to here' Image component		
    "Howdy!", // string  in 'Inpaint Additional Prompt' Textbox component
    exampleImage, 	// blob in 'Image' Image component		
    0, // number (numeric value between 0.0 and 1.0) in 'Stop At' Slider component		
    0, // number (numeric value between 0.0 and 2.0) in 'Weight' Slider component		
    "ImagePrompt", // string  in 'Type' Radio component
    exampleImage, 	// blob in 'Image' Image component		
    0, // number (numeric value between 0.0 and 1.0) in 'Stop At' Slider component		
    0, // number (numeric value between 0.0 and 2.0) in 'Weight' Slider component		
    "ImagePrompt", // string  in 'Type' Radio component
    exampleImage, 	// blob in 'Image' Image component		
    0, // number (numeric value between 0.0 and 1.0) in 'Stop At' Slider component		
    0, // number (numeric value between 0.0 and 2.0) in 'Weight' Slider component		
    "ImagePrompt", // string  in 'Type' Radio component
    exampleImage, 	// blob in 'Image' Image component		
    0, // number (numeric value between 0.0 and 1.0) in 'Stop At' Slider component		
    0, // number (numeric value between 0.0 and 2.0) in 'Weight' Slider component		
    "ImagePrompt", // string  in 'Type' Radio component
]);

console.log(result.data);

But it doesn't work.

g0dSE avatar Dec 07 '23 03:12 g0dSE

I know this isn't the answer you're looking for but since the backend is basically comfyui you could probably use that instead. sending it to localhost:8188/prompt as the request

Saradominist avatar Dec 07 '23 11:12 Saradominist

I know this isn't the answer you're looking for but since the backend is basically comfyui you could probably use that instead. sending it to localhost:8188/prompt as the request

How would the request look like?

g0dSE avatar Dec 07 '23 16:12 g0dSE

ADDRESS = "127.0.0.1"
PORT = "8188"

def queue(prompt_workflow):
    p = {"prompt": prompt_workflow}
    data = json.dumps(p).encode("utf-8")
    requests.post(f"http://{ADDRESS}:{PORT}/prompt", data=data)

Here's a snippet from one of my older projects, should probably work for your use-case also. The parameters in the function would be a variable of a json file that has the information for comfyui.

Saradominist avatar Dec 07 '23 16:12 Saradominist

ADDRESS = "127.0.0.1"
PORT = "8188"

def queue(prompt_workflow):
    p = {"prompt": prompt_workflow}
    data = json.dumps(p).encode("utf-8")
    requests.post(f"http://{ADDRESS}:{PORT}/prompt", data=data)

Here's a snippet from one of my older projects, should probably work for your use-case also. The parameters in the function would be a variable of a json file that has the information for comfyui.

You sure the port is 8188 can't reach that port even in browser?

For me the main UI is at: http://127.0.0.1:7865/

Also, when doing post request for the main UI it returns:

{
    "detail": "Not Found"
}

g0dSE avatar Dec 07 '23 16:12 g0dSE

Well its for the comfy ui backend part, so the request would be sending to 127.0.0.1:8188/prompt dont forget the subdomain of "prompt". I'm not sure if fooocus handles backend the same way the API comfy does you're gonna have to do some experimenting. But for debugging purposes while foocus is running try see if you can send something to this url 127.0.0.1:7865/prompt (default) is accessible through the browser

Saradominist avatar Dec 07 '23 17:12 Saradominist

Well its for the comfy ui backend part, so the request would be sending to 127.0.0.1:8188/prompt dont forget the subdomain of "prompt". I'm not sure if fooocus handles backend the same way the API comfy does you're gonna have to do some experimenting. But for debugging purposes while foocus is running try see if you can send something to this url 127.0.0.1:7865/prompt (default) is accessible through the browser

Yea that's when I get the json response

{"detail":"Not Found"}

g0dSE avatar Dec 07 '23 17:12 g0dSE

Okay so it's most likely that you have to structure the file being sent to the back-end in a way that when its being parsed the "detail" parameter is being filled correctly

Saradominist avatar Dec 07 '23 17:12 Saradominist

Okay so it's most likely that you have to structure the file being sent to the back-end in a way that when its being parsed the "detail" parameter is being filled correctly

Ok, how would I do that

g0dSE avatar Dec 07 '23 18:12 g0dSE

Ah well, that's where documentation comes in. So basically we're at square one again.. Sorry I couldn't be of help

Saradominist avatar Dec 07 '23 20:12 Saradominist

I am trying to use the api by clicking "Use via API"

But the actual endpoints themself are barely documented? I wanna be able to just put in a prompt and be done with it..?

I am trying to do this:

import { client } from "@gradio/client";
import { createRequire } from "module";
const require = createRequire(import.meta.url);
global.EventSource = require('eventsource');

const app = await client("http://127.0.0.1:7865/");

const response_0 = await fetch("https://raw.githubusercontent.com/gradio-app/gradio/main/test/test_files/bus.png");
const exampleImage = await response_0.blob();

const result = await app.predict(29, [
    "realistic portrait photo of beautiful woman with blonde hair and her labrador dog, hair roots slightly faded, latina, influencer, light blue eyes, no makeup, instagram",
    "unrealistic, saturated, high contrast, big nose, painting, drawing, sketch, cartoon, anime, manga, render, CG, 3d, watermark, signature, label",
    ["Fooocus V2", "Fooocus Photograph", "Fooocus Negative"],
    "Speed",
    "896x1152 <span style='color: grey;'> ∣ 7:9</span>",
    1,
    "8082836497533172128",
    2,
    3,
    "realisticStockPhoto_v10.safetensors",
    "None",
    0.1,
    "SDXL_FILM_PHOTOGRAPHY_STYLE_BetaV0.4.safetensors",
    0.25,
    "None",
    1,
    "None",
    1,
    "None",
    1,
    false,
    "Howdy!", // string  in 'parameter_73' Textbox component		
    "Disabled", // string  in 'Upscale or Variation:' Radio component
    exampleImage, 	// blob in 'Drag above image to here' Image component		
    ["Left"], // string[] (array of strings) in 'Outpaint Direction' Checkboxgroup component
    exampleImage, 	// blob in 'Drag above image to here' Image component		
    "Howdy!", // string  in 'Inpaint Additional Prompt' Textbox component
    exampleImage, 	// blob in 'Image' Image component		
    0, // number (numeric value between 0.0 and 1.0) in 'Stop At' Slider component		
    0, // number (numeric value between 0.0 and 2.0) in 'Weight' Slider component		
    "ImagePrompt", // string  in 'Type' Radio component
    exampleImage, 	// blob in 'Image' Image component		
    0, // number (numeric value between 0.0 and 1.0) in 'Stop At' Slider component		
    0, // number (numeric value between 0.0 and 2.0) in 'Weight' Slider component		
    "ImagePrompt", // string  in 'Type' Radio component
    exampleImage, 	// blob in 'Image' Image component		
    0, // number (numeric value between 0.0 and 1.0) in 'Stop At' Slider component		
    0, // number (numeric value between 0.0 and 2.0) in 'Weight' Slider component		
    "ImagePrompt", // string  in 'Type' Radio component
    exampleImage, 	// blob in 'Image' Image component		
    0, // number (numeric value between 0.0 and 1.0) in 'Stop At' Slider component		
    0, // number (numeric value between 0.0 and 2.0) in 'Weight' Slider component		
    "ImagePrompt", // string  in 'Type' Radio component
]);

console.log(result.data);

But it doesn't work.

  1. Fooocus didn't receive enough input values (needed: 45, got: 43). Add:
"None",
1,

before false

  1. try "896×1152" instead of "896x1152 ∣ 7:9", gradio use '×' spilt the string. 😂

byrain avatar Dec 08 '23 09:12 byrain

can anyone paste working complete code ?

Novosti1 avatar Dec 09 '23 03:12 Novosti1


from gradio_client import Client

client = Client("http://127.0.0.1:7865/", serialize=False)
result = client.predict(
	"Howdy!",	# str in 'parameter_10' Textbox component
	"Howdy!",	# str in 'Negative Prompt' Textbox component
	["Fooocus V2"],	# List[str] in 'Selected Styles' Checkboxgroup component
	"Speed",	# str in 'Performance' Radio component
	"1152×896 <span style='color: grey;'> | 1:2</span>",	# str in 'Aspect Ratios' Radio component
	1,	# int | float (numeric value between 1 and 32)in 'Image Number' Slider component
	"123",	# str in 'Seed' Textbox component
	0,	# int | float (numeric value between 0.0 and 30.0)in 'Image Sharpness' Slider component
	1,	# int | float (numeric value between 1.0 and 30.0)in 'Guidance Scale' Slider component
	"juggernautXL_version6Rundiffusion.safetensors",	# str (Option from: ['juggernautXL_version6Rundiffusion.safetensors', 'realisticStockPhoto_v10.safetensors', 'bluePencilXL_v050.safetensors', 'DreamShaper_8_pruned.safetensors'])in 'Base Model (SDXL only)' Dropdown component
	"None",	# str (Option from: ['None', 'juggernautXL_version6Rundiffusion.safetensors', 'realisticStockPhoto_v10.safetensors', 'bluePencilXL_v050.safetensors', 'DreamShaper_8_pruned.safetensors'])in 'Refiner (SDXL or SD 1.5)' Dropdown component
	0.1,	# int | float (numeric value between 0.1 and 1.0)in 'Refiner Switch At' Slider component
	"None",	# str (Option from: ['None', 'sd_xl_offset_example-lora_1.0.safetensors', 'SDXL_FILM_PHOTOGRAPHY_STYLE_BetaV0.4.safetensors', 'sdxl_lcm_lora.safetensors'])in 'LoRA 1' Dropdown component
	-2,	# int | float (numeric value between -2 and 2)in 'Weight' Slider component
	"None",	# str (Option from: ['None', 'sd_xl_offset_example-lora_1.0.safetensors', 'SDXL_FILM_PHOTOGRAPHY_STYLE_BetaV0.4.safetensors', 'sdxl_lcm_lora.safetensors'])in 'LoRA 2' Dropdown component
	-2,	# int | float (numeric value between -2 and 2)in 'Weight' Slider component
	"None",	# str (Option from: ['None', 'sd_xl_offset_example-lora_1.0.safetensors', 'SDXL_FILM_PHOTOGRAPHY_STYLE_BetaV0.4.safetensors', 'sdxl_lcm_lora.safetensors'])in 'LoRA 3' Dropdown component
	-2,	# int | float (numeric value between -2 and 2)in 'Weight' Slider component
	"None",	# str (Option from: ['None', 'sd_xl_offset_example-lora_1.0.safetensors', 'SDXL_FILM_PHOTOGRAPHY_STYLE_BetaV0.4.safetensors', 'sdxl_lcm_lora.safetensors'])in 'LoRA 4' Dropdown component
	-2,	# int | float (numeric value between -2 and 2)in 'Weight' Slider component
	"None",	# str (Option from: ['None', 'sd_xl_offset_example-lora_1.0.safetensors', 'SDXL_FILM_PHOTOGRAPHY_STYLE_BetaV0.4.safetensors', 'sdxl_lcm_lora.safetensors'])in 'LoRA 5' Dropdown component
	-2,	# int | float (numeric value between -2 and 2)in 'Weight' Slider component
	True,	# bool in 'Input Image' Checkbox component
	"Howdy!",	# str in 'parameter_73' Textbox component
	"Disabled",	# str in 'Upscale or Variation:' Radio component
	"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQImWNgYGBgAAAABQABh6FO1AAAAABJRU5ErkJggg==",	# str (filepath or URL to image)in 'Drag above image to here' Image component
	["Left"],	# List[str] in 'Outpaint Direction' Checkboxgroup component
	"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQImWNgYGBgAAAABQABh6FO1AAAAABJRU5ErkJggg==",	# str (filepath or URL to image)in 'Drag above image to here' Image component
	"Howdy!",	# str in 'Inpaint Additional Prompt' Textbox component
	"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQImWNgYGBgAAAABQABh6FO1AAAAABJRU5ErkJggg==",	# str (filepath or URL to image)in 'Image' Image component
	0,	# int | float (numeric value between 0.0 and 1.0)in 'Stop At' Slider component
	0,	# int | float (numeric value between 0.0 and 2.0)in 'Weight' Slider component
	"ImagePrompt",	# str in 'Type' Radio component
	"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQImWNgYGBgAAAABQABh6FO1AAAAABJRU5ErkJggg==",	# str (filepath or URL to image)in 'Image' Image component
	0,	# int | float (numeric value between 0.0 and 1.0)in 'Stop At' Slider component
	0,	# int | float (numeric value between 0.0 and 2.0)in 'Weight' Slider component
	"ImagePrompt",	# str in 'Type' Radio component
	"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQImWNgYGBgAAAABQABh6FO1AAAAABJRU5ErkJggg==",	# str (filepath or URL to image)in 'Image' Image component
	0,	# int | float (numeric value between 0.0 and 1.0)in 'Stop At' Slider component
	0,	# int | float (numeric value between 0.0 and 2.0)in 'Weight' Slider component
	"ImagePrompt",	# str in 'Type' Radio component
	"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQImWNgYGBgAAAABQABh6FO1AAAAABJRU5ErkJggg==",	# str (filepath or URL to image)in 'Image' Image component																			  
	0,	# int | float (numeric value between 0.0 and 1.0)in 'Stop At' Slider component																  
	0,	# int | float (numeric value between 0.0 and 2.0)in 'Weight' Slider component
	"ImagePrompt",	# str in 'Type' Radio component
	fn_index=29
)
print(result)


DevepNoName avatar Dec 09 '23 21:12 DevepNoName

What kind of image is this? "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQImWNgYGBgAAAABQABh6FO1AAAAABJRU5ErkJggg==", # str (filepath or URL to image)in 'Image' Image component

Cant I just say: False, # bool in 'Input Image' Checkbox component for a simplified example.

Do you also have a more simplified example, please?

miraculix95 avatar Dec 19 '23 17:12 miraculix95

What kind of image is this? "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQImWNgYGBgAAAABQABh6FO1AAAAABJRU5ErkJggg==", # str (filepath or URL to image)in 'Image' Image component

Cant I just say: False, # bool in 'Input Image' Checkbox component for a simplified example.

Do you also have a more simplified example, please?

Base64 Image encoded (google it)

DevepNoName avatar Dec 19 '23 18:12 DevepNoName

I still do not get it. Shouldnt it be something like image.jg instead of a weird long number?

miraculix95 avatar Dec 21 '23 03:12 miraculix95

This is how far I've got

  1. Open F12 > network panel in a browser
  2. Use whatever function you need in fooocus
  3. In the network panel check the last 2 join messages and right click on the messages sent to fooocus (green indicator) 4.After right click Copy the message and use it later in python

image eg the 2nd last message is

{"data":[null,false,"__art___","",["Fooocus V2","Fooocus Enhance","Fooocus Sharp"],"Speed","1152×896 <span style=\"color: grey;\"> ∣ 9:7</span>",1,"png","2887978505541915116",false,2,4,"juggernautXL_v8Rundiffusion.safetensors","None",0.5,true,"sd_xl_offset_example-lora_1.0.safetensors",0.1,true,"None",1,true,"None",1,true,"None",1,true,"None",1,false,"uov","Disabled",null,[],null,"",null,false,false,false,1.5,0.8,0.3,7,"dpmpp_2m_sde_gpu","karras",-1,-1,-1,-1,-1,-1,false,false,false,false,64,128,"joint",0.25,false,1.01,1.02,0.99,0.95,false,false,"v2.6",1,0.618,false,false,0,true,"fooocus",null,0.5,0.6,"ImagePrompt",null,0.5,0.6,"ImagePrompt",null,0.5,0.6,"ImagePrompt",null,0.5,0.6,"ImagePrompt"],"event_data":null,"fn_index":40,"session_hash":"cb6b2mjcea4"}

then the very last message is {"data":[null],"event_data":null,"fn_index":41,"session_hash":"cb6b2mjcea4"}

somehow both are needed then invoke in python as


def convert_msg_to_api_call(msg={}, client=None):
    if 'data' in msg:
        if msg['data'][0] == None:
            del msg['data'][0]
        result = client.predict(	
    		fn_index=msg['fn_index'],
            *msg['data'],
        )
        return result

from gradio_client import Client

client = Client("http://localhost:7865/")
null = None
false = False
true = True

# the next line contains the 2nd last message copied from F12
msg =  {"data":[null,false,"__fox___","",["Fooocus V2","Fooocus Enhance","Fooocus Sharp"],"Speed","1152×896 <span style=\"color: grey;\"> ∣ 9:7</span>",2,"png","6453127819374729619",false,2,4,"juggernautXL_v8Rundiffusion.safetensors","None",0.5,true,"sd_xl_offset_example-lora_1.0.safetensors",0.1,true,"None",1,true,"None",1,true,"None",1,true,"None",1,false,"uov","Disabled",null,[],null,"",null,false,false,false,1.5,0.8,0.3,7,"dpmpp_2m_sde_gpu","karras",-1,-1,-1,-1,-1,-1,false,false,false,false,64,128,"joint",0.25,false,1.01,1.02,0.99,0.95,false,false,"v2.6",1,0.618,false,false,0,true,"fooocus",null,0.5,0.6,"ImagePrompt",null,0.5,0.6,"ImagePrompt",null,0.5,0.6,"ImagePrompt",null,0.5,0.6,"ImagePrompt"],"event_data":null,"fn_index":40,"session_hash":"cb6b2mjcea4"}

r1= convert_msg_to_api_call(msg=msg, client=client)
print(r1)
#the next line contains the last message from network panel 
msg =  {"data":[null],"event_data":null,"fn_index":41,"session_hash":"cb6b2mjcea4"}
r2= convert_msg_to_api_call(msg=msg, client=client)

I still get an error after the 2nd invocation but the images are created in the output folder

(check your fooocus logs)

alexvx2 avatar Mar 29 '24 10:03 alexvx2

This is still accurate I would assume? I'm considering building an iOS native app that could hit the API endpoints of Fooocus, with some nice improvements over the mobile browser interface (persistent sessions for one).

But if the API's still have low documentation that may be a lot more effort than just building a SwiftUI app.

Proryanator avatar Jun 22 '24 02:06 Proryanator