refactor lexica tab and move to the second panel

pull/378/head
Abdullah Alfaraj 2023-09-24 14:44:38 +03:00
parent 069cf512a1
commit fb82d20406
8 changed files with 230 additions and 312 deletions

View File

@ -741,9 +741,6 @@
<sp-label>ControlNet</sp-label>
</div>
<div class="sp-tab" id="sp-lexica-tab" style="display: none">
<sp-label>Lexica</sp-label>
</div>
<div
class="sp-tab"
id="sp-image_search-tab"
@ -854,14 +851,6 @@
value="prompts-library"
>Prompts Library</sp-radio
>
<sp-radio
title=""
class="rbSubTab"
id="rbLexica"
data-tab-name="sp-lexica-tab"
value="lexica"
>Lexica</sp-radio
>
</sp-radio-group>
</div>
<div id="viewerSubTab">
@ -897,48 +886,6 @@
</div>
<div class="sp-tab-page" id="sp-control_net-tab-page"></div>
<div class="sp-tab-page" id="sp-lexica-tab-page">
<div class="subTabOptionsContainer"></div>
<div class="flexContainer">
<sp-label slot="label"
>Explore Lexica for prompts and inspiration</sp-label
>
</div>
<div></div>
<div>
<sp-textfield
id="LexicaSearchField"
type="text"
placeholder="cute cats"
value=""
><sp-label slot="label">Search:</sp-label></sp-textfield
>
<button
class="btnSquare search-button"
id="btnSearchLexica"
title="user prompt(text) to Search Lexica"
></button>
<button
class="btnSquare reverse_image_serach"
id="btnReverseSearchLexica"
title="User the selected area (image) on canvas to Search Lexica"
></button>
</div>
<sp-textarea id="lexicaPrompt" style="margin-bottom: 3px">
</sp-textarea>
<div class="viewer-container" id="divLexicaImagesContainer">
<img
class="history-image"
id="history_image_test"
data-metadata_json_string='{"a":1}'
src="https://source.unsplash.com/random"
/>
</div>
</div>
<div class="sp-tab-page" id="sp-image_search-tab-page">
<div class="subTabOptionsContainer"></div>
@ -1232,6 +1179,9 @@
<div id="historyImagesContainer"></div>
<sp-divider class="line-divider" size="large"></sp-divider>
<sp-divider class="line-divider" size="large"></sp-divider>
<div class="lexicaContainer"></div>
<sp-divider class="line-divider" size="large"></sp-divider>
<sp-divider class="line-divider" size="large"></sp-divider>
</div>
</uxp-panel>

View File

@ -57,7 +57,7 @@ const settings_tab = require('./utility/tab/settings')
//load tabs
const image_search_tab = require('./utility/tab/image_search_tab')
const lexica_tab = require('./utility/tab/lexica_tab')
// const share_tab = require('./utility/tab/share_tab')
const api = require('./utility/api')
@ -90,6 +90,7 @@ const {
extra_page,
selection_ts,
stores,
lexica,
} = require('./typescripts/dist/bundle')
const io = require('./utility/io')
@ -1678,11 +1679,6 @@ const submenu = {
'data-tab-name': 'sp-prompts-library-tab',
},
lexica: {
value: 'lexica',
Label: 'Lexica',
'data-tab-name': 'sp-lexica-tab',
},
image_search: {
value: 'image_search',
Label: 'Image Search',

View File

@ -34,5 +34,8 @@ export * as tool_bar from './tool_bar/tool_bar'
export * as extra_page from './extra_page/extra_page'
export * as selection_ts from './util/ts/selection'
export * as stores from './stores'
export { default as lexica } from './lexical/lexical'
export { toJS } from 'mobx'
export { default as node_fs } from 'fs'

View File

@ -6,6 +6,7 @@ import { Grid } from '../util/grid'
import { MoveToCanvasSvg } from '../util/elements'
import { io } from '../util/oldSystem'
import { ErrorBoundary } from '../util/errorBoundary'
import { urlToCanvas } from '../util/ts/general'
export const store = new AStore({
images: [],
@ -15,11 +16,6 @@ export const store = new AStore({
height: 50,
})
async function urlToCanvas(url: string) {
const image_file_name = 'search_image_temp.png'
await io.IO.urlToLayer(url, image_file_name)
}
const ImageSearch = observer(() => {
console.log('rendered')
return (
@ -45,7 +41,10 @@ const ImageSearch = observer(() => {
{
ComponentType: MoveToCanvasSvg,
callback: (index: number) => {
urlToCanvas(store.data.images[index])
urlToCanvas(
store.data.images[index],
'search_image_temp.png'
)
},
title: 'Copy Image to Canvas',
},

View File

@ -1,6 +1,113 @@
//TODO: delete lexical_tab.js and lexica tab from html
import { observer } from 'mobx-react'
import React from 'react'
import React, { TextareaHTMLAttributes } from 'react'
import ReactDOM from 'react-dom/client'
import { AStore } from '../main/astore'
import {
ImageSearchSvg,
MoveToCanvasSvg,
PenSvg,
SpTextfield,
} from '../util/elements'
import { ErrorBoundary } from '../util/errorBoundary'
import { requestGet } from '../util/ts/api'
import { Grid } from '../util/grid'
import { urlToCanvas } from '../util/ts/general'
import sd_tab_util from '../sd_tab/util'
import { setPrompt } from '../multiTextarea'
import { Collapsible } from '../util/collapsible'
import Locale from '../locale/locale'
interface LexicaItem {
id: string
gallery: string
src: string
srcSmall: string
prompt: string
width: number
height: number
seed: string
grid: boolean
model: string
guidance: number
promptid: string
nsfw: boolean
}
export const store = new AStore({
search_query: 'cute cats' as string,
lexica_items: [] as LexicaItem[],
height: 100,
width: 100,
thumbnails: [] as string[],
images: [] as string[],
lexica_prompt: '' as string,
textarea_position: 'static' as 'static' | 'fixed',
textarea_display: 'none' as 'none' | undefined,
})
async function requestLexica(search_query: string) {
const lexica_url = `https://lexica.art/api/v1/search?q=${search_query}`
const url_encoded = encodeURI(lexica_url)
const result = await requestGet(url_encoded)
console.log('result:', result)
return result
}
async function loadSettingsToUI(lexica_item: LexicaItem) {
try {
setPrompt({ positive: lexica_item.prompt })
sd_tab_util.store.data.width = lexica_item.width
sd_tab_util.store.data.height = lexica_item.height
sd_tab_util.store.data.seed = lexica_item.seed
sd_tab_util.store.data.cfg = lexica_item.guidance
} catch (e) {
console.warn(e)
}
}
const windowEventListener = document
.querySelector('#search_second_panel')!
.addEventListener('scroll', () => {
const taLexicaPromptElement = document.querySelector(
'#lexicaPrompt'
) as any
const originalPosition = taLexicaPromptElement.offsetTop
const currentPosition =
//@ts-ignore
document.querySelectorAll('.lexicaContainer')[0].offsetTop
store.data.textarea_display = 'none'
})
function onThumbnailClick(lexical_item: LexicaItem) {
store.data.lexica_prompt = lexical_item.prompt
const taLexicaPromptElement = document.querySelector('#lexicaPrompt') as any
const originalPosition = taLexicaPromptElement.offsetTop
const containerPosition =
//@ts-ignore
document.querySelectorAll('.lexicaContainer')[0].offsetTop
const isScrolledPast = containerPosition < originalPosition
store.data.textarea_display = undefined
}
async function searchForSimilarImage(lexica_item: LexicaItem) {
try {
store.data.search_query = lexica_item.src
const result_json = await requestLexica(store.data.search_query)
const lexica_items = result_json.images
store.data.lexica_items = lexica_items
} catch (e) {
console.warn(e)
}
}
@observer
export class Lexical extends React.Component {
@ -19,19 +126,30 @@ export class Lexical extends React.Component {
</div>
<div></div>
<div>
{/* <sp-label slot="label">Search:</sp-label> */}
<sp-textfield
id="LexicaSearchField"
type="text"
placeholder="cute cats"
value=""
>
<sp-label slot="label">Search:</sp-label>
</sp-textfield>
// placeholder="cute cats"
value={store.data.search_query}
onInput={(event: any) => {
store.data.search_query = event.target.value
}}
></sp-textfield>
<button
className="btnSquare search-button"
id="btnSearchLexica"
title="user prompt(text) to Search Lexica"
onClick={async () => {
const search_query = store.data.search_query
const result_json = await requestLexica(
search_query
)
const lexica_items = result_json.images
store.data.lexica_items = lexica_items
}}
></button>
<button
@ -42,7 +160,12 @@ export class Lexical extends React.Component {
</div>
<sp-textarea
id="lexicaPrompt"
style="margin-bottom: 3px"
style={{
marginBottom: '3px',
position: 'fixed',
display: store.data.textarea_display,
}}
value={store.data.lexica_prompt}
></sp-textarea>
<div className="viewer-container" id="divLexicaImagesContainer">
<img
@ -52,7 +175,87 @@ export class Lexical extends React.Component {
src="https://source.unsplash.com/random"
/>
</div>
<div>
<sp-slider
min={85}
max={300}
onInput={(
event: React.ChangeEvent<HTMLInputElement>
) => {
const new_value = event.target.value
store.updateProperty('height', new_value)
store.updateProperty('width', new_value)
}}
show-value="true"
>
<sp-label slot="label">Image Size:</sp-label>
</sp-slider>
<Grid
thumbnails={store.data.lexica_items.map(
(item: LexicaItem) => {
return item.srcSmall
}
)}
width={store.data.width}
height={store.data.height}
callback={(index: number, evt: any) => {
onThumbnailClick(store.data.lexica_items[index])
}}
action_buttons={[
{
ComponentType: MoveToCanvasSvg,
callback: (index: number) => {
urlToCanvas(
store.data.lexica_items[index].src,
'lexica.png'
)
},
title: 'Copy Image to Canvas',
},
{
ComponentType: PenSvg,
callback: (index: number) => {
loadSettingsToUI(
store.data.lexica_items[index]
)
},
title: 'Apply Settings',
},
{
ComponentType: ImageSearchSvg,
callback: (index: number) => {
searchForSimilarImage(
store.data.lexica_items[index]
)
},
title: 'Search For Similar Images',
},
]}
></Grid>
</div>
</div>
)
}
}
const containers = document.querySelectorAll('.lexicaContainer')!
containers.forEach((container) => {
const root = ReactDOM.createRoot(container)
root.render(
//<React.StrictMode>
<ErrorBoundary>
<div style={{ border: '2px solid #6d6c6c', padding: '3px' }}>
<Collapsible defaultIsOpen={true} label={Locale('Lexical')}>
<Lexical></Lexical>
</Collapsible>
</div>
</ErrorBoundary>
//</React.StrictMode>
)
})
export default {
store: store,
}

View File

@ -8,7 +8,7 @@ const elemSelectorForLocale = {
'#sp-viewer-tab sp-label': 'Viewer',
'#sp-control_net-tab sp-label': 'ControlNet',
// '#sp-history-tab sp-label': 'History',
'#sp-lexica-tab sp-label': 'Lexica',
// '#sp-lexica-tab sp-label': 'Lexica',
'#sp-image_search-tab sp-label': 'Image Search',
'#sp-prompts-library-tab sp-label': 'Prompts library',
'#sp-horde-tab sp-label': 'Horde',

View File

@ -1,3 +1,5 @@
import { io } from '../oldSystem'
export function autoResize(textarea: any, text_content: string, delay = 300) {
try {
let g_style_timeout: any
@ -43,3 +45,7 @@ export function autoResize(textarea: any, text_content: string, delay = 300) {
)
}
}
export async function urlToCanvas(url: string, image_name = 'image.png') {
await io.IO.urlToLayer(url, image_name)
}

View File

@ -1,239 +0,0 @@
const thumbnail = require('../../thumbnail')
const api = require('../api')
const io = require('../io')
const html_manip = require('../html_manip')
class Lexica {
constructor(items = []) {
//items is json object return from lexica request
this.items = items
}
delete() {
this.items = []
}
}
async function requestHostedUrl(base64) {
try {
const payload = {
key: '6d207e02198a847aa98d0a2a901485a5',
source: base64,
}
const url = 'https://freeimage.host/api/1/upload'
const result_json = await api.requestFormDataPost(url, payload)
const image_url = result_json.image.url
return image_url
} catch (e) {
console.warn(e)
}
}
async function requestLexica(search_query) {
const lexica_url = `https://lexica.art/api/v1/search?q=${search_query}`
const url_encoded = encodeURI(lexica_url)
result = await api.requestGet(url_encoded)
console.log('result:', result)
return result
}
function displayAllLexicaImages(lexica_items) {
const lexicaMasterImageContainer = document.getElementById(
'divLexicaImagesContainer'
)
lexicaMasterImageContainer.innerHTML = ''
for (item of lexica_items) {
displayLexicaImage(item)
}
}
function displayLexicaImage(lexica_item) {
// let lexica_item = {
// id: '0482ee68-0368-4eca-8846-5930db866b33',
// gallery: 'https://lexica.art?q=0482ee68-0368-4eca-8846-5930db866b33',
// src: 'https://lexica-serve-encoded-images.sharif.workers.dev/md/0482ee68-0368-4eca-8846-5930db866b33',
// srcSmall:
// 'https://lexica-serve-encoded-images.sharif.workers.dev/sm/0482ee68-0368-4eca-8846-5930db866b33',
// prompt: 'cute chubby blue fruits icons for mobile game ui ',
// width: 512,
// height: 512,
// seed: '1413536227',
// grid: false,
// model: 'stable-diffusion',
// guidance: 7,
// promptid: 'd9868972-dad8-477d-8e5a-4a0ae1e9b72b',
// nsfw: false,
// }
const lexicaMasterImageContainer = document.getElementById(
'divLexicaImagesContainer'
)
img_html = document.createElement('img')
img_html.classList.add('viewer-image')
img_html.src = lexica_item.srcSmall
img_html.style.width = '100px'
const thumbnail_container = thumbnail.Thumbnail.wrapImgInContainer(
img_html,
'viewer-image-container'
)
async function loadOnCanvas(lexica_item) {
// lexica_item.
try {
const link = lexica_item.src
const image_file_name = 'lexica_image.png'
await io.IO.urlToLayer(link, image_file_name)
} catch (e) {
console.warn('loadOnCanvas(): ', lexica_item, e)
}
}
async function loadSettingsToUI(lexica_item) {
try {
const settings = {
prompt: lexica_item.prompt,
width: lexica_item.width,
height: lexica_item.height,
seed: lexica_item.seed,
cfg_scale: lexica_item.guidance,
}
g_ui_settings_object.autoFillInSettings(settings)
} catch (e) {
console.warn(e)
}
}
async function searchForSimilarImage(lexica_item) {
try {
document.getElementById('LexicaSearchField').value = lexica_item.src
const result_json = await requestLexica(lexica_item.src)
const lexica_items = result_json.images
displayAllLexicaImages(lexica_items)
} catch (e) {
console.warn(e)
}
}
thumbnail.Thumbnail.addSPButtonToContainer(
thumbnail_container,
'svg_sp_btn_canvas',
'Load on Canvas',
loadOnCanvas,
lexica_item
)
thumbnail.Thumbnail.addSPButtonToContainer(
thumbnail_container,
'svg_sp_btn',
'load settings',
loadSettingsToUI,
lexica_item
)
thumbnail.Thumbnail.addSPButtonToContainer(
thumbnail_container,
'svg_sp_btn_search',
'Search for Similar Image',
searchForSimilarImage,
lexica_item
)
thumbnail_container.addEventListener('click', () => {
setLexicaPromptValue(lexica_item.prompt)
// taLexicaPrompt.style.position = 'fixed'
const originalPosition = taLexicaPrompt.offsetTop
const currentPosition = document.querySelector('body > div').scrollTop
const isScrolledPast = currentPosition > originalPosition
if (isScrolledPast) {
taLexicaPrompt.style.position = 'fixed'
} else {
taLexicaPrompt.style.position = 'static'
}
})
lexicaMasterImageContainer.appendChild(thumbnail_container)
}
const taLexicaPrompt = document.querySelector('#lexicaPrompt')
function setLexicaPromptValue(input) {
taLexicaPrompt.value = input
}
function getLexicaPromptValue() {
return taLexicaPrompt.value
}
document
.getElementById('btnSearchLexica')
.addEventListener('click', async () => {
const search_query = document.getElementById('LexicaSearchField').value
const result_json = await requestLexica(search_query)
const lexica_items = result_json.images
const lexica_obj = getLexicaObject()
lexica_obj.items = lexica_items
displayAllLexicaImages(lexica_items)
})
document
.getElementById('btnReverseSearchLexica')
.addEventListener('click', async () => {
//*) check if selection is valid
//*) get base64 from selection
//*) request global url from base64
//*) request Lexica search
try {
const width = html_manip.getWidth()
const height = html_manip.getHeight()
const selectionInfo = await psapi.getSelectionInfoExe()
const base64 =
await io.IO.getSelectionFromCanvasAsBase64Interface_New(
width,
height,
selectionInfo,
true
)
const hosted_url = await requestHostedUrl(base64)
const result_json = await requestLexica(hosted_url)
const lexica_items = result_json.images
displayAllLexicaImages(lexica_items)
} catch (e) {
console.warn(e)
}
})
const windowEventListener = document
.querySelector('body > div')
.addEventListener('scroll', () => {
const originalPosition = taLexicaPrompt.offsetTop
const currentPosition = document.querySelector('body > div').scrollTop
taLexicaPrompt.style.position = 'static'
// const isScrolledPast = currentPosition > originalPosition
// if (isScrolledPast) {
// taLexicaPrompt.style.position = 'fixed'
// } else {
// taLexicaPrompt.style.position = 'static'
// }
})
const g_lexica_obj = new Lexica()
function getLexicaObject() {
return g_lexica_obj
}
function setLexicaObject(lexica_obj) {
g_lexica_obj = lexica_obj
}
module.exports = {
requestLexica,
displayLexicaImage,
displayAllLexicaImages,
requestHostedUrl,
Lexica,
getLexicaObject,
setLexicaObject,
}