|
|
const express = require('express') |
|
|
const app = express() |
|
|
const path = require('path') |
|
|
const fg = require('fast-glob') |
|
|
|
|
|
const port = 3000 |
|
|
const imgExt = 'jpeg' |
|
|
|
|
|
app.use(express.urlencoded({ extended: true })) |
|
|
|
|
|
app.use(function(req, res, next) { |
|
|
res.header("Access-Control-Allow-Origin", "*") |
|
|
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept") |
|
|
next() |
|
|
}) |
|
|
|
|
|
app.use('/lora', express.static('networks/lora')) |
|
|
app.use('/styles', express.static('networks/styles')) |
|
|
app.use('/checkpoints', express.static('networks/checkpoints')) |
|
|
app.use('/embeddings', express.static('networks/embeddings')) |
|
|
app.use('/hypernets', express.static('networks/hypernets')) |
|
|
app.use('/poses', express.static('networks/poses')) |
|
|
app.use('/gallery', express.static('networks/gallery')) |
|
|
|
|
|
|
|
|
app.get('/images', (req, res) => { |
|
|
|
|
|
const searchTerm = req.query.search || null |
|
|
const searchType = req.query.type || 'lora' |
|
|
let images = [] |
|
|
|
|
|
if (searchType == "styles") { |
|
|
|
|
|
|
|
|
|
|
|
const fs = require('fs') |
|
|
const {parse} = require ('csv-parse') |
|
|
const pattern = searchTerm ? `.*?${searchTerm}.*` : '.*' |
|
|
const re = new RegExp(pattern, 'gi') |
|
|
|
|
|
let index = -1 |
|
|
|
|
|
fs.createReadStream('networks/styles.csv') |
|
|
.pipe(parse({ delimiter: ',', columns: true, trim: true })) |
|
|
.on('data', (row) => { |
|
|
if (row.name.match(re) || row.prompt.match(re)) { |
|
|
let imageData = { |
|
|
filename: row.name + "." + imgExt, |
|
|
path: "styles/", |
|
|
name: row.name, |
|
|
author: null, |
|
|
tags: null, |
|
|
keywords: null, |
|
|
weight: null, |
|
|
prompt: row.prompt, |
|
|
mtimeMs: index++, |
|
|
mtime: null, |
|
|
} |
|
|
images.push(imageData); |
|
|
} |
|
|
}) |
|
|
.on('end', () => { |
|
|
res.json(images) |
|
|
}); |
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
|
|
|
|
if (searchType == "gallery") { |
|
|
|
|
|
|
|
|
let pattern = '' |
|
|
let extraPattern = '' |
|
|
let _onlyDirectories = true |
|
|
|
|
|
if (searchTerm) { |
|
|
if (searchTerm.split(">").length > 1) { |
|
|
pattern = searchTerm.split(">")[0] ? `*${searchTerm.split(">")[0]}*` : '*' |
|
|
extraPattern = '/' + (searchTerm.split(">")[1] ? `*${searchTerm.split(">")[1]}*` : '*') |
|
|
_onlyDirectories = false |
|
|
} else { |
|
|
pattern = `*${searchTerm}*` |
|
|
} |
|
|
} else { |
|
|
pattern = '*' |
|
|
} |
|
|
|
|
|
const files = fg.globSync([`networks/${searchType}/**/${pattern}${extraPattern}`], { onlyDirectories: _onlyDirectories, dot: false, caseSensitiveMatch: false, stats: true }) |
|
|
|
|
|
images = files.map(file => { |
|
|
|
|
|
|
|
|
|
|
|
let filename = (file.name.indexOf("." + imgExt) > -1) ? file.name : file.name + "." + imgExt |
|
|
let path = file.path.replace(file.name, '').replace('networks/', '').toLowerCase() |
|
|
|
|
|
|
|
|
return { |
|
|
filename: filename, |
|
|
path: path, |
|
|
} |
|
|
}) |
|
|
res.json(images) |
|
|
|
|
|
} else if (searchType == "poses") { |
|
|
|
|
|
|
|
|
let pattern = '' |
|
|
let extraPattern = '' |
|
|
let _onlyDirectories = false |
|
|
let ext = "png" |
|
|
|
|
|
if (searchTerm) { |
|
|
if (searchTerm.split(">").length > 1) { |
|
|
pattern = searchTerm.split(">")[0] ? `*${searchTerm.split(">")[0]}*` : '*' |
|
|
extraPattern = '/' + (searchTerm.split(">")[1] ? `*${searchTerm.split(">")[1]}*` : '*') |
|
|
extraPattern += "." + ext |
|
|
} else { |
|
|
pattern = `*${searchTerm}*` |
|
|
extraPattern += "." + ext |
|
|
} |
|
|
} else { |
|
|
pattern = '*' |
|
|
extraPattern += "." + ext |
|
|
} |
|
|
|
|
|
const files = fg.globSync([`networks/${searchType}/*/${pattern}${extraPattern}`], { onlyDirectories: _onlyDirectories, dot: false, caseSensitiveMatch: false, stats: true }) |
|
|
|
|
|
images = files.flatMap(file => { |
|
|
|
|
|
let filename = (file.name.indexOf("." + ext) > -1) ? file.name : file.name + "." + ext |
|
|
let path = file.path.replace(file.name, '').replace('networks/', '').toLowerCase() |
|
|
|
|
|
let name = /poses\/(.+?)\//.exec(path)[1] |
|
|
|
|
|
if (filename.match(/\. \([0-9]+\)\./)) { return [] } |
|
|
|
|
|
|
|
|
return { |
|
|
filename: filename, |
|
|
path: path, |
|
|
name: name |
|
|
} |
|
|
}) |
|
|
res.json(images) |
|
|
|
|
|
} else { |
|
|
|
|
|
let ext = null |
|
|
if (searchType == "lora" || searchType == "checkpoints") { |
|
|
ext = "safetensors" |
|
|
} else if (searchType == "embeddings" || searchType == "hypernets") { |
|
|
ext = "(pt|safetensors)" |
|
|
} else { |
|
|
return res.status(400).send({ |
|
|
message: 'Invalid type requested.' |
|
|
}); |
|
|
} |
|
|
|
|
|
let pattern = '' |
|
|
let extraPattern = '' |
|
|
|
|
|
if (searchTerm) { |
|
|
if (searchTerm.split(">").length > 1) { |
|
|
pattern = searchTerm.split(">")[0] ? `*${searchTerm.split(">")[0]}*` : '*' |
|
|
extraPattern = '/' + (searchTerm.split(">")[1] ? `*${searchTerm.split(">")[1]}*` : '*') |
|
|
} else { |
|
|
pattern = `*${searchTerm}*` |
|
|
extraPattern = "." + ext |
|
|
} |
|
|
} else { |
|
|
pattern = '*' |
|
|
extraPattern = "." + ext |
|
|
} |
|
|
|
|
|
const files = fg.globSync([`networks/${searchType}/**/${pattern}${extraPattern}`], { dot: false, caseSensitiveMatch: false, stats: true }) |
|
|
|
|
|
images = files.map(file => { |
|
|
|
|
|
|
|
|
|
|
|
let filematch = file.name.match(/(.*)\.(.*?)$/) |
|
|
let filename = filematch ? filematch[1] + "." + imgExt : "" |
|
|
let noext = filematch ? filematch[1] : "" |
|
|
let words = noext.split(' ') |
|
|
let path = file.path.replace(file.name, '').replace('networks/', '').toLowerCase() |
|
|
let name = noext.match(/^(.*)_([0-9a-zA-Z]+)\s/) |
|
|
name = name ? name[1] : null |
|
|
let author = noext.match(/_([0-9a-zA-Z]+)\s/) |
|
|
author = author ? author[1] : null |
|
|
let hashtagWords = words.filter(word => word.startsWith("#")) |
|
|
let tags = hashtagWords.map(word => word.slice(1)) |
|
|
let weight = noext.match(/{(?:[0-9]*\.?[0-9]+\s?-)?([0-9]*\.?[0-9]+)}/) |
|
|
weight = weight ? weight[1] : "1.0" |
|
|
|
|
|
|
|
|
let keywords = filename.match(/\[(.*)\]/) |
|
|
|
|
|
|
|
|
if (keywords) { |
|
|
keywords = keywords[1] |
|
|
keywords = keywords.replaceAll(/©️/g, ':') |
|
|
keywords = keywords.replaceAll(/≻/g, '>') |
|
|
keywords = keywords.replaceAll(/≺/g, '<') |
|
|
keywords = keywords.replaceAll(/(\w+?) \((\w+?)\)/gi, '$1 \\($2\\)') |
|
|
keywords = keywords.replaceAll('[', '') |
|
|
keywords = keywords.replaceAll(']', ', ') |
|
|
} |
|
|
|
|
|
let prompt = null |
|
|
if (searchType == "lora") { |
|
|
prompt = `${keywords ? keywords+" " : ""}<lora:${noext}:${weight}>` |
|
|
} else if (searchType == "hypernets") { |
|
|
prompt = `${keywords ? keywords+" " : ""}<hypernet:${noext}:${weight}>` |
|
|
} else { |
|
|
prompt = noext |
|
|
} |
|
|
|
|
|
|
|
|
return { |
|
|
filename: filename, |
|
|
path: path, |
|
|
name: name, |
|
|
author: author, |
|
|
tags: tags, |
|
|
keywords: keywords, |
|
|
weight: weight, |
|
|
prompt: prompt, |
|
|
mtimeMs: file.stats.mtimeMs, |
|
|
mtime: file.stats.mtime, |
|
|
} |
|
|
}) |
|
|
|
|
|
res.json(images) |
|
|
} |
|
|
|
|
|
} |
|
|
}) |
|
|
|
|
|
|
|
|
app.get('/moreImages', (req, res) => { |
|
|
|
|
|
const search = req.query.search || res.status(400).send({ |
|
|
message: 'Missing query.' |
|
|
}); |
|
|
const type = req.query.type |
|
|
|
|
|
|
|
|
const filteredSearch = search.replaceAll('$','\\$') |
|
|
.replaceAll('^','\\^') |
|
|
.replaceAll('?','\\?') |
|
|
.replaceAll('(','\\(') |
|
|
.replaceAll(')','\\)') |
|
|
.replaceAll('[','\\[') |
|
|
.replaceAll(']','\\]') |
|
|
.replaceAll('{','\\{') |
|
|
.replaceAll('}','\\}') |
|
|
|
|
|
const ext = (type == "poses") ? "png" : imgExt |
|
|
const noext = filteredSearch.substring(filteredSearch.lastIndexOf('/') + 1).replace('.' + ext, '') |
|
|
const searchPath = filteredSearch.substring(0, filteredSearch.lastIndexOf('/')) |
|
|
|
|
|
|
|
|
|
|
|
const query = `networks/${searchPath}/${noext}(.*|).${ext}` |
|
|
const queryFolder = `networks/${searchPath}/${noext}/*.${ext}` |
|
|
const files = fg.globSync([query, queryFolder], { dot: false, caseSensitiveMatch: false, stats: true }) |
|
|
|
|
|
const images = files.map(file => { |
|
|
const path = file.path.replace(file.name, '').replace('networks/', '').toLowerCase() |
|
|
|
|
|
|
|
|
return { |
|
|
filename: file.name, |
|
|
path: path, |
|
|
mtimeMs: file.stats.mtimeMs, |
|
|
mtime: file.stats.mtime, |
|
|
} |
|
|
}) |
|
|
|
|
|
res.json(images) |
|
|
}) |
|
|
|
|
|
app.listen(port, () => { |
|
|
console.log(`Server running at http://localhost:${port}`) |
|
|
}) |