File size: 5,530 Bytes
5fe33ce
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
class ImageGenerator {
    constructor() {
        this.baseURL = 'https://soiz-flux-1-dev-serverless.hf.space/generate';
        this.prompt = '';
        this.negativePrompt = '';
        this.width = 512;
        this.height = 512;
        this.steps = 25;
        this.cfgs = 7;
        this.sampler = 'DPM++ 2M';
        this.strength = 0.7;
        this.seed = -1;
        this.returnType = 'dataURL'; // dataURL or blobURL
    }

    // Generate URL for fetching
    generateFetchURL() {
        return `${this.baseURL}?prompt=${encodeURIComponent(this.prompt)}&negative_prompt=${encodeURIComponent(this.negativePrompt)}&width=${this.width}&height=${this.height}&steps=${this.steps}&cfgs=${this.cfgs}&sampler=${encodeURIComponent(this.sampler)}&strength=${this.strength}&seed=${this.seed}`;
    }

    // Return parameters as JSON for debugging
    getParametersAsJSON() {
        return JSON.stringify({
            prompt: this.prompt,
            negativePrompt: this.negativePrompt,
            width: this.width,
            height: this.height,
            steps: this.steps,
            cfgs: this.cfgs,
            sampler: this.sampler,
            strength: this.strength,
            seed: this.seed
        });
    }

    // Fetch function to generate the image
    async fetchImage() {
        const url = this.generateFetchURL();
        try {
            const response = await fetch(url);
            if (!response.ok) throw new Error('Failed to generate image');

            const blob = await response.blob();
            if (this.returnType === 'blobURL') {
                return URL.createObjectURL(blob);
            } else {
                // Convert Blob to Data URL
                return await new Promise((resolve, reject) => {
                    const reader = new FileReader();
                    reader.onloadend = () => resolve(reader.result);
                    reader.onerror = reject;
                    reader.readAsDataURL(blob);
                });
            }
        } catch (error) {
            console.error(error);
            throw new Error('Error generating image: ' + error.message);
        }
    }

    getInfo() {
        return {
            id: 'imageGenerator',
            name: 'Image Generator',
            blocks: [
                { opcode: 'setPrompt', blockType: Scratch.BlockType.COMMAND, text: 'set prompt to [TEXT]', arguments: { TEXT: { type: Scratch.ArgumentType.STRING, defaultValue: '1girl, halo, white wings, blue sky' } } },
                { opcode: 'setNegativePrompt', blockType: Scratch.BlockType.COMMAND, text: 'set negative prompt to [TEXT]', arguments: { TEXT: { type: Scratch.ArgumentType.STRING, defaultValue: 'blurry, low quality' } } },
                { opcode: 'setWidth', blockType: Scratch.BlockType.COMMAND, text: 'set width to [NUM]', arguments: { NUM: { type: Scratch.ArgumentType.NUMBER, defaultValue: 512 } } },
                { opcode: 'setHeight', blockType: Scratch.BlockType.COMMAND, text: 'set height to [NUM]', arguments: { NUM: { type: Scratch.ArgumentType.NUMBER, defaultValue: 512 } } },
                { opcode: 'setSteps', blockType: Scratch.BlockType.COMMAND, text: 'set steps to [NUM]', arguments: { NUM: { type: Scratch.ArgumentType.NUMBER, defaultValue: 25 } } },
                { opcode: 'setCfgScale', blockType: Scratch.BlockType.COMMAND, text: 'set CFG Scale to [NUM]', arguments: { NUM: { type: Scratch.ArgumentType.NUMBER, defaultValue: 7 } } },
                { opcode: 'setSampler', blockType: Scratch.BlockType.COMMAND, text: 'set sampler to [TEXT]', arguments: { TEXT: { type: Scratch.ArgumentType.STRING, defaultValue: 'DPM++ 2M' } } },
                { opcode: 'setStrength', blockType: Scratch.BlockType.COMMAND, text: 'set strength to [NUM]', arguments: { NUM: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0.7 } } },
                { opcode: 'setSeed', blockType: Scratch.BlockType.COMMAND, text: 'set seed to [NUM]', arguments: { NUM: { type: Scratch.ArgumentType.NUMBER, defaultValue: -1 } } },
                { opcode: 'setReturnType', blockType: Scratch.BlockType.COMMAND, text: 'set return type to [TYPE]', arguments: { TYPE: { type: Scratch.ArgumentType.STRING, menu: 'returnTypes', defaultValue: 'dataURL' } } },
                { opcode: 'generateImage', blockType: Scratch.BlockType.REPORTER, text: 'generate image' },
                { opcode: 'getFetchURL', blockType: Scratch.BlockType.REPORTER, text: 'get fetch URL' },
                { opcode: 'getParametersJSON', blockType: Scratch.BlockType.REPORTER, text: 'get parameters as JSON' }
            ],
            menus: {
                returnTypes: { acceptReporters: true, items: ['dataURL', 'blobURL'] }
            }
        };
    }

    // Block functions
    setPrompt(args) { this.prompt = args.TEXT; }
    setNegativePrompt(args) { this.negativePrompt = args.TEXT; }
    setWidth(args) { this.width = args.NUM; }
    setHeight(args) { this.height = args.NUM; }
    setSteps(args) { this.steps = args.NUM; }
    setCfgScale(args) { this.cfgs = args.NUM; }
    setSampler(args) { this.sampler = args.TEXT; }
    setStrength(args) { this.strength = args.NUM; }
    setSeed(args) { this.seed = args.NUM; }
    setReturnType(args) { this.returnType = args.TYPE; }

    generateImage() { return this.fetchImage(); }
    getFetchURL() { return this.generateFetchURL(); }
    getParametersJSON() { return this.getParametersAsJSON(); }
}

// Register the extension
Scratch.extensions.register(new ImageGenerator());