-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathworker.js
159 lines (136 loc) · 4.93 KB
/
worker.js
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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
require('dotenv').config()
const fs = require("fs");
const Replicate = require("replicate");
const { v4: uuidv4 } = require("uuid");
const axios = require("axios");
var admin = require("firebase-admin");
var serviceAccount = require("./service-account.json");
const { firestore } = require('firebase-admin');
const replicateToken = process.env.REPLICATE_API_TOKEN;
const TIME_TO_SHOW_AN_IMAGE_MS = 15 * 1000;
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL:process.env.FIREBASE_DATABASE_URL,
storageBucket: process.env.FIREBASE_STORAGE_BUCKET,
});
var db = admin.database();
var queueRef = db.ref("queue");
var readyRef = db.ref("ready")
var completedRef = db.ref("completed");
const configRef = db.ref("config")
// Read all values where status is pending
queueRef.orderByChild("status")
.equalTo("pending")
.on("value", function (snapshot) {
// Set status to processing and initiate generation
console.log(`Got ${snapshot.numChildren()} to process`);
snapshot.forEach(async function (childSnapshot) {
configRef.child("totalCount").set(admin.database.ServerValue.increment(1));
childSnapshot.ref.update({ status: "processing", processing_started_at: Date.now() });
const url = await generateImage(childSnapshot.val().text);
if (!url) {
// If it fails, just remove the entry
childSnapshot.ref.remove();
return;
}
childSnapshot.ref.update({ status: "ready", processing_completed_at: Date.now() });
await moveToReady(childSnapshot,url);
});
});
queueRef.orderByChild("status")
.equalTo("processing")
.on("value", function (snapshot) {
const currentTime = Date.now();
const timeLimit = 15 * 60 * 1000; // 15 minutes in milliseconds
snapshot.forEach(function (childSnapshot) {
const processing_start_at = childSnapshot.val().processing_started_at;
if (currentTime - processing_start_at > timeLimit) {
// Remove the record if processing started more than 15 minutes ago
childSnapshot.ref.remove();
}
});
});
async function moveToReady(newEntry,url){
await readyRef.push({
...newEntry.val(),
keyInQueue: newEntry.key,
status: "ready",
url,
completed_at: Date.now() // Do not use server timestamp here, because that will cause on("value") to be called multiple times for the same entry
})
}
readyRef.orderByChild("completed_at")
.limitToFirst(1)
.on("value",function(snapshot){
if(!snapshot.exists()) return;
snapshot.forEach(function(childSnapshot){
moveToCompleted(childSnapshot)
setTimeout(function(){
childSnapshot.ref.remove()
},TIME_TO_SHOW_AN_IMAGE_MS)
})
});
async function moveToCompleted(newEntry){
const refToEntryInQueue = newEntry.val().keyInQueue
if(refToEntryInQueue){
queueRef.child(refToEntryInQueue).remove()
}
completedRef.push({
...newEntry.val(),
status: "completed",
})
}
async function generateImage(prompt) {
const replicate = new Replicate({
auth: process.env.REPLICATE_API_TOKEN,
});
// https://replicate.com/stability-ai/sdxl
const modelParameters = {
prompt,
};
console.log("Generating image...");
let imageUrl;
try {
const result = await replicate.run(
"stability-ai/sdxl:2b017d9b67edd2ee1401238df49d75da53c523f36e363881e057f5dc3ed3c5b2",
{
input: modelParameters
}
);
// Output comes as an image URL as the first result in an array
if (result && result[0]) {
imageUrl = result[0];
} else {
console.error("No image generated");
return null;
}
} catch (e) {
console.error("Error generating image", e);
return null;
}
if (imageUrl) {
// Download the file from this URL and upload to Firebase Storage
const result = await axios.get(imageUrl, {
responseType: "arraybuffer",
});
// Upload file to Firebase Storage
const bucket = admin.storage().bucket();
const filename = `${uuidv4()}.png`;
const file = bucket.file(filename);
const buffer = Buffer.from(result.data, "binary");
// Set the image as public and get public path
await file.save(buffer, {
metadata: {
contentType: "image/png",
cacheControl: "public, max-age=86400",
},
public: true,
});
const publicUrl = `https://storage.googleapis.com/${bucket.name}/${file.name}`;
console.log("Image generated and uploaded", publicUrl);
return publicUrl;
} else {
console.error("No image generated");
return null;
}
}