diff options
| author | Jules <jules@asdf.us> | 2018-09-22 10:47:50 -0400 |
|---|---|---|
| committer | Jules <jules@asdf.us> | 2018-09-22 10:47:50 -0400 |
| commit | 7e39114e27520e382f26368ae8f4d08ae7f3071b (patch) | |
| tree | 01e7f210b0c3a119622e92d56d01f5c7951ad631 /app/client | |
| parent | 46889933fd9c36c527014410823e88a7d838d239 (diff) | |
| parent | 8d1c19852fcce52e369978dfc195d5da4f12180a (diff) | |
merge
Diffstat (limited to 'app/client')
| -rw-r--r-- | app/client/auth/auth.gate.js | 20 | ||||
| -rw-r--r-- | app/client/auth/auth.reducer.js | 1 | ||||
| -rw-r--r-- | app/client/common/browser.component.js | 18 | ||||
| -rw-r--r-- | app/client/common/fileList.component.js | 9 | ||||
| -rw-r--r-- | app/client/common/fileViewer.component.js | 111 | ||||
| -rw-r--r-- | app/client/dashboard/dashboard.component.js | 2 | ||||
| -rw-r--r-- | app/client/index.jsx | 7 | ||||
| -rw-r--r-- | app/client/modules/pix2pixhd/pix2pixhd.actions.js | 6 | ||||
| -rw-r--r-- | app/client/modules/pix2pixhd/views/pix2pixhd.train.js | 24 | ||||
| -rw-r--r-- | app/client/modules/pix2pixhd/views/sequence.editor.js | 177 | ||||
| -rw-r--r-- | app/client/system/system.reducer.js | 9 | ||||
| -rw-r--r-- | app/client/util/format.js | 28 |
12 files changed, 289 insertions, 123 deletions
diff --git a/app/client/auth/auth.gate.js b/app/client/auth/auth.gate.js index 076ec54..40f244f 100644 --- a/app/client/auth/auth.gate.js +++ b/app/client/auth/auth.gate.js @@ -46,34 +46,36 @@ class AuthRouter extends Component { class AuthGate extends Component { render(){ - if (true && !this.props.auth.initialized) { + const { auth, env, actions } = this.props + if (env.production && !auth.initialized) { console.log('loading auth') return <div className='loading'>Loading</div> } - if (true || this.props.auth.isAuthenticated) { - console.log('authenticated...') - if (this.props.auth.returnTo) { - let { returnTo } = this.props.auth + if (env.development || auth.isAuthenticated) { + if (auth.returnTo) { + let { returnTo } = auth if (!returnTo || returnTo.match(/(login|logout|signup)/i)) { returnTo = '/' } console.log('history.push', returnTo) - this.props.actions.setReturnTo(null) + actions.setReturnTo(null) history.push(returnTo) return <div>Launching app</div> } - console.log('rendering as normal') return <div>{this.props.children}</div> } return <AuthRouter {...this.props} /> } componentDidMount(){ - this.props.actions.checkin() + if (this.props.env.production) { + this.props.actions.checkin() + } } } const mapStateToProps = (state) => ({ - auth: state.auth + env: state.system.env, + auth: state.auth, }); const mapDispatchToProps = (dispatch) => ({ diff --git a/app/client/auth/auth.reducer.js b/app/client/auth/auth.reducer.js index a56f94a..80b1ec5 100644 --- a/app/client/auth/auth.reducer.js +++ b/app/client/auth/auth.reducer.js @@ -11,7 +11,6 @@ const authInitialState = { } const auth = (state = authInitialState, action) => { - console.log(action) switch(action.type) { case types.auth.set_token: return { diff --git a/app/client/common/browser.component.js b/app/client/common/browser.component.js index 50b31cf..19cd0f6 100644 --- a/app/client/common/browser.component.js +++ b/app/client/common/browser.component.js @@ -11,19 +11,23 @@ class Browser extends Component { state = { dir: '/', files: [], + file: null, loading: true } + componentDidMount() { this.fetch(this.state.dir) } + handlePick(file) { console.log(file) if (file.dir) { this.fetch([this.state.dir, file.name].join('/').replace('//','/')) } else { - this.fetchFile([this.state.dir, file.name].join('/').replace('//','/')) + this.setState({ file: { ...file, path: this.state.dir } }) } } + fetch(dir) { console.log('fetch', dir) const { tool: module } = this.props.app @@ -33,15 +37,7 @@ class Browser extends Component { this.setState({ dir, files, loading: false }) }) } - fetchFile(fn) { - console.log('fetch file', fn) - const { tool: module } = this.props.app - this.setState({ file: null, loadingFile: true }) - actions.socket.read_file({ module, fn }).then(file => { - console.log(file) - this.setState({ file, loadingFile: false }) - }) - } + render() { const { app } = this.props const { @@ -68,7 +64,7 @@ class Browser extends Component { }} onClickParent={e => { console.log('navigate up') - this.fetch(this.state.dir.split('/').slice(0, -1).join('/') || '/') + this.fetch(dir.split('/').slice(0, -1).join('/') || '/') }} /> {loadingFile && <Loading />} diff --git a/app/client/common/fileList.component.js b/app/client/common/fileList.component.js index f932274..8f79148 100644 --- a/app/client/common/fileList.component.js +++ b/app/client/common/fileList.component.js @@ -122,7 +122,14 @@ export const FileRow = props => { <div className={"date " + util.carbon_date(date)}>{moment(date).format("YYYY-MM-DD")}</div> } {fields.has('datetime') && - <div className={"datetime " + util.carbon_date(date)}>{moment(date).format("YYYY-MM-DD h:mm a")}</div> + <div className={"datetime"}> + <span class={'date ' + util.carbon_date(date)}> + {moment(date).format("YYYY-MM-DD")} + </span> + <span class={'time ' + util.carbon_time(date)}> + {moment(date).format("H:mm")} + </span> + </div> } {fields.has('size') && <div className={"size " + size[0]}>{size[1]}</div> diff --git a/app/client/common/fileViewer.component.js b/app/client/common/fileViewer.component.js index bc71f20..b1cabd4 100644 --- a/app/client/common/fileViewer.component.js +++ b/app/client/common/fileViewer.component.js @@ -1,4 +1,7 @@ import { h, Component } from 'preact' +import { connect } from 'react-redux' + +import actions from '../actions' const image_types = { 'jpg': 'image/jpeg', @@ -18,33 +21,85 @@ const video_types = { 'mp4': 'video/mp4', } -export default function FileViewer({ file }) { - const { - error, - name, path, - date, size, - buf, - } = file - if (error) { - return <div className='fileViewer'>{error}</div> +class FileViewer extends Component { + state = { + loading: false, + stale: false, + buffer: {} + } + + fetch() { + const { file, path } = this.props + if (!file) return + if (this.state.loading) { + this.setState({ stale: true }) + return + } + const fn = [path || file.path, file.name].join('/').replace('//','/') + console.log('fetch file', fn) + const { tool: module } = this.props.app + this.setState({ buffer: null, loading: true }) + actions.socket.read_file({ module, fn }).then(buffer => { + console.log('fetched buffer') + const { stale } = this.state + this.setState({ buffer, loading: false, stale: false, }, () => { + if (stale) { + console.log('stale, fetching...') + this.fetch() + } + }) + }) + } + + componentDidMount(){ + this.fetch() } - if (!buf) { - return <div className='fileViewer'>File empty</div> + + componentDidUpdate(nextProps){ + if (this.props.file !== nextProps.file) { + this.fetch() + } } - const ext = name.split('.').slice(-1)[0].toLowerCase() - let tag; - if (ext in image_types) { - tag = <img src={getURLFor(buf, image_types[ext])} /> - } else if (ext in audio_types) { - tag = <audio src={getURLFor(buf, audio_types[ext])} controls autoplay /> - } else if (ext in video_types) { - tag = <video src={getURLFor(buf, audio_types[ext])} controls autoplay /> - } else { - tag = <div className='text'>{ab2str(buf)}</div> + + render() { + const { file } = this.props + if (!file) { + return <div className='fileViewer'></div> + } + const { loading, buffer } = this.state + if (loading) { + return <div className='fileViewer'>Loading...</div> + } + const { + error, + name, path, + date, size, + buf, + } = buffer + if (error) { + return <div className='fileViewer'>{error}</div> + } + if (!name) { + return <div className='fileViewer'></div> + } + if (!buf) { + return <div className='fileViewer'>File empty</div> + } + const ext = extension(name) + let tag; + if (ext in image_types) { + tag = <img src={getURLFor(buf, image_types[ext])} /> + } else if (ext in audio_types) { + tag = <audio src={getURLFor(buf, audio_types[ext])} controls autoplay /> + } else if (ext in video_types) { + tag = <video src={getURLFor(buf, video_types[ext])} controls autoplay /> + } else { + tag = <div className='text'>{ab2str(buf)}</div> + } + return ( + <div className='fileViewer'>{tag}</div> + ) } - return ( - <div className='fileViewer'>{tag}</div> - ) } const getURLFor = (buf, type) => { @@ -55,3 +110,11 @@ const getURLFor = (buf, type) => { } const ab2str = buf => String.fromCharCode.apply(null, new Uint8Array(buf)) + +const extension = fn => fn.split('.').slice(-1)[0].toLowerCase() + +const mapStateToProps = state => ({ + app: state.system.app, +}) + +export default connect(mapStateToProps)(FileViewer) diff --git a/app/client/dashboard/dashboard.component.js b/app/client/dashboard/dashboard.component.js index cbfdd33..8f47049 100644 --- a/app/client/dashboard/dashboard.component.js +++ b/app/client/dashboard/dashboard.component.js @@ -48,7 +48,7 @@ class Dashboard extends Component { linkFiles files={renders[key]} orderBy='date desc' - fields={'name date epoch size'} + fields={'name datetime epoch size'} onClick={key === 'samplernn' ? (file, e) => { e.preventDefault() e.stopPropagation() diff --git a/app/client/index.jsx b/app/client/index.jsx index cda528c..4e0c38d 100644 --- a/app/client/index.jsx +++ b/app/client/index.jsx @@ -30,13 +30,10 @@ const app = ( <Auth.Gate> <BrowserRouter> <div className='everybody'> - <Route path='/' children={(props) => <div>{console.log(props.location.pathname)}</div>} /> <Route exact path='/system' component={System} /> <Route exact path='/dashboard' component={Dashboard} /> <Route exact path='/browse' component={Browser} /> <Route exact path='/logout' component={Auth.Logout} /> - <Route exact path='/login' component={() => { <Redirect to='/' /> }} /> - <Route exact path='/signup' component={() => { <Redirect to='/' /> }} /> {module_list} <Route exact path='/' component={Dashboard} /> <Route path='/' component={Header} /> @@ -46,5 +43,9 @@ const app = ( </Auth.Gate> </Provider> ) +/* + <Route exact path='/login' component={() => { <Redirect to='/' /> }} /> + <Route exact path='/signup' component={() => { <Redirect to='/' /> }} /> +*/ render(app, document.getElementById('container')) diff --git a/app/client/modules/pix2pixhd/pix2pixhd.actions.js b/app/client/modules/pix2pixhd/pix2pixhd.actions.js index a17eeab..2c72f06 100644 --- a/app/client/modules/pix2pixhd/pix2pixhd.actions.js +++ b/app/client/modules/pix2pixhd/pix2pixhd.actions.js @@ -205,7 +205,7 @@ export const list_epochs = (checkpoint_name) => (dispatch) => { export const count_dataset = (checkpoint_name) => (dispatch) => { const module = pix2pixhdModule.name util.allProgress([ - actions.socket.count_directory({ module, dir: 'sequences/' + checkpoint_name + '/' }), + actions.socket.list_directory({ module, dir: 'sequences/' + checkpoint_name + '/' }), actions.socket.count_directory({ module, dir: 'datasets/' + checkpoint_name + '/train_A/' }), ], (percent, i, n) => { console.log('pix2pixhd load progress', i, n) @@ -215,12 +215,14 @@ export const count_dataset = (checkpoint_name) => (dispatch) => { data: { module: 'pix2pixhd' }, }) }).then(res => { - const [sequenceCount, datasetCount] = res //, datasets, results, output, datasetUsage, lossReport] = res + const [sequence, datasetCount] = res //, datasets, results, output, datasetUsage, lossReport] = res + const sequenceCount = sequence.length console.log(sequenceCount, datasetCount) dispatch({ type: types.pix2pixhd.load_dataset_count, data: { name: checkpoint_name, + sequence, sequenceCount, datasetCount, } diff --git a/app/client/modules/pix2pixhd/views/pix2pixhd.train.js b/app/client/modules/pix2pixhd/views/pix2pixhd.train.js index 957b068..6aade36 100644 --- a/app/client/modules/pix2pixhd/views/pix2pixhd.train.js +++ b/app/client/modules/pix2pixhd/views/pix2pixhd.train.js @@ -19,6 +19,7 @@ import NewDatasetForm from '../../../dataset/dataset.new' import UploadStatus from '../../../dataset/upload.status' import DatasetComponent from '../../../dataset/dataset.component' +import SequenceEditor from './sequence.editor' import pix2pixhdModule from '../pix2pixhd.module' @@ -34,9 +35,10 @@ class Pix2PixHDTrain extends Component { augment_make: 20, } } - componentWillMount(){ + componentDidMount(){ const id = this.props.match.params.id || localStorage.getItem('pix2pixhd.last_id') - console.log('load dataset:', id) + const dataset = localStorage.getItem('pix2pixhd.last_dataset') + console.log('load dataset:', id, dataset) const { match, pix2pixhd, actions } = this.props if (id === 'new') return if (id) { @@ -47,9 +49,13 @@ class Pix2PixHDTrain extends Component { } else { this.props.history.push('/pix2pixhd/new/') } + if (dataset) { + this.setState({ checkpoint_name: dataset }) + } } componentDidUpdate(prevProps, prevState){ if (prevState.checkpoint_name !== this.state.checkpoint_name) { + localStorage.setItem('pix2pixhd.last_dataset', this.state.checkpoint_name) this.setState({ epoch: 'latest' }) this.props.actions.list_epochs(this.state.checkpoint_name) this.props.actions.count_dataset(this.state.checkpoint_name) @@ -114,6 +120,18 @@ class Pix2PixHDTrain extends Component { value={this.state.epoch} /> </Group> + </div> + </div> + <div> + <Group title='Sequence Editor'> + <SequenceEditor + module={pix2pixhdModule} + checkpoint={this.props.pix2pixhd.checkpoint} + /> + </Group> + </div> + <div className='columns'> + <div className='column'> <Group title='Augmentation Grid'> <AugmentationGrid checkpoint={this.props.pix2pixhd.checkpoint} @@ -132,7 +150,7 @@ class Pix2PixHDTrain extends Component { this.props.remote.augment_task(this.state.checkpoint_name, { ...this.state, augment_take: 10, - augment_make: 150, + augment_make: 149, no_symlinks: true, mov: true, folder_id: this.props.pix2pixhd.data.resultsFolder.id diff --git a/app/client/modules/pix2pixhd/views/sequence.editor.js b/app/client/modules/pix2pixhd/views/sequence.editor.js index 9693805..6a5da39 100644 --- a/app/client/modules/pix2pixhd/views/sequence.editor.js +++ b/app/client/modules/pix2pixhd/views/sequence.editor.js @@ -3,78 +3,137 @@ import { bindActionCreators } from 'redux' import { connect } from 'react-redux' import { Route, Link } from 'react-router-dom' -import { Loading, FileList, FileViewer } from '../../common' +import { Loading, FileList, FileViewer } from '../../../common' -import actions from '../actions' +import actions from '../../../actions' + +const initialState = { + dir: '/', + frameA: null, + frameB: null, + selection: null, + loading: true +} + +/* + when the sequence editor loads, + reset the selection + reset the two frames + set the two frames to the beginning and end of the video + when mousing over the video + ideally you would see a tiny thumbnail preview of the frame :) + - click to start a selection, drag over, mouseup to end the selection + this should update the start/end frame + ... + so there are two things you could do with this + 1) create an entirely new dataset + 2) add frames to an existing dataset + ... + method 1) + - requires minimal setup, just a server script which.. + - creates the new sequence folder + - symlinks the frames + - runs build_dataset + - create appropriate file object, using parent dataset's folder_id + - enqueue initial training + ---> we can then train on basic subsets, with more control, like we do already... + - tell parent dataset thing the new sequence name + ... + method 2) + - requires sequence editor to be aware of its own dataset + - requires sequence editor to know whether a sequence is original or not +*/ class SequenceEditor extends Component { - state = { - dir: '/', - files: [], - loading: true + state = { ...initialState } + + constructor() { + super() + this.handleMouseDown = this.handleMouseDown.bind(this) + this.handleMouseMove = this.handleMouseMove.bind(this) + this.handleMouseEnter = this.handleMouseEnter.bind(this) + this.handleMouseLeave = this.handleMouseLeave.bind(this) + this.handleMouseUp = this.handleMouseUp.bind(this) } + componentDidMount() { - this.fetch(this.state.dir) + const { checkpoint } = this.props + window.addEventListener('mousemove', this.handleMouseMove) + window.addEventListener('mouseup', this.handleMouseUp) + if (checkpoint && checkpoint.sequence) { + console.log(checkpoint) + const frameA = checkpoint.sequence[0] + const frameB = checkpoint.sequence[checkpoint.sequence.length-1] + this.setState({ + ...initialState, + frameA, + frameB, + }) + } } - handlePick(file) { - console.log(file) - if (file.dir) { - this.fetch([this.state.dir, file.name].join('/').replace('//','/')) - } else { - this.fetchFile([this.state.dir, file.name].join('/').replace('//','/')) + + componentDidUpdate(prevProps) { + const { checkpoint } = this.props + if (checkpoint !== prevProps.checkpoint) { + console.log(checkpoint) + const frameA = checkpoint.sequence[0] + const frameB = checkpoint.sequence[checkpoint.sequence.length-1] + this.setState({ + ...initialState, + frameA, + frameB, + }) } } - fetch(dir) { - console.log('fetch', dir) - const { tool: module } = this.props.app - this.setState({ dir, file: null, loading: true }) - actions.socket.list_directory({ module, dir }).then(files => { - console.log(files) - this.setState({ dir, files, loading: false }) - }) + + componentWillUnmount(){ + window.removeEventListener('mouseup', this.handleMouseUp) + window.removeEventListener('mousemove', this.handleMouseMove) + } + + handleMouseDown(e) { + this.setState({ dragging: true }) + } + handleMouseMove(e) { + } + handleMouseEnter(e) { + } + handleMouseLeave(e) { } - fetchFile(fn) { - console.log('fetch file', fn) - const { tool: module } = this.props.app - this.setState({ file: null, loadingFile: true }) - actions.socket.read_file({ module, fn }).then(file => { - console.log(file) - this.setState({ file, loadingFile: false }) - }) + handleMouseUp(e) { + this.setState({ dragging: false }) } + + handlePick(file) { + console.log(file) + // this.setState({ dir, file: null, loading: true }) + } + render() { - const { app } = this.props + const { app, checkpoint } = this.props const { - loading, dir, files, - loadingFile, file, + loading, + selection, + frameA, frameB, } = this.state - console.log(this.props, this.state) - // return ( - // <div className='app browser'> - // <h1>{dir}{dir[dir.length-1] !== '/' && '/'}</h1> - // {app.tool}<br/> - // {loading && <Loading />} - // <FileList - // files={files} - // groupDirectories - // parentDirectory={dir !== '/'} - // orderBy='name asc' - // fields={'name datetime size'} - // onClick={(file, e) => { - // e.preventDefault() - // e.stopPropagation() - // console.log('picked a result', file) - // this.handlePick(file) - // }} - // onClickParent={e => { - // console.log('navigate up') - // this.fetch(this.state.dir.split('/').slice(0, -1).join('/') || '/') - // }} - // /> - // {loadingFile && <Loading />} - // {file && <FileViewer file={file} />} - // </div> - // ) + // console.log(this.props, this.state) + const width = 200 + const path = "sequences/" + checkpoint.name + return ( + <div className='sequenceEditor'> + <div + className='timeline' + style={{ width }} + mouseDown={this.handleSelectionStart} + mouseEnter={this.handleMouseEnter} + mouseLeave={this.handleMouseLeave} + > + {selection && <div className='selection' style={selection}></div>} + </div> + <FileViewer path={path} file={this.state.frameA} /> + <FileViewer path={path} file={this.state.frameB} /> + </div> + ) } } diff --git a/app/client/system/system.reducer.js b/app/client/system/system.reducer.js index 387b454..5f9e4ac 100644 --- a/app/client/system/system.reducer.js +++ b/app/client/system/system.reducer.js @@ -9,8 +9,13 @@ const systemInitialState = { site: { name: 'loading', }, + env: { + env: process.env.NODE_ENV, + production: process.env.NODE_ENV === 'production', + development: process.env.NODE_ENV !== 'production', + }, app: { - tool: localStorage.getItem('system.last_tool') || 'pix2pix', + tool: localStorage.getItem('system.last_tool') || 'pix2pixhd', }, server: { connected: false, @@ -43,7 +48,7 @@ const systemInitialState = { stderr: "", } -const modules = ['pix2pix','samplernn','pix2wav'].reduce((a,b) => (a[b]=b,a),{}) +const modules = ['pix2pix','pix2pixhd','pix2wav','samplernn','morph'].reduce((a,b) => (a[b]=b,a),{}) const systemReducer = (state = systemInitialState, action) => { // console.log(action.type) diff --git a/app/client/util/format.js b/app/client/util/format.js index e436a3e..ee1f47f 100644 --- a/app/client/util/format.js +++ b/app/client/util/format.js @@ -38,6 +38,22 @@ export function carbon_date (date, no_bold) { { color = "quiet" } return color } +export function carbon_time (date, no_bold) { + var span = (+new Date() - new Date(date)) / 1000, color + if (! no_bold && span < 3600) // modified this hour + { color = "new" } + else if (span < 3 * 3600) // modifed last 3 hours + { color = "recent" } + else if (span < 12 * 3600) // modifed last 12 hours + { color = "med" } + else if (span < 24 * 3600) // modifed last day + { color = "old" } + else if (span < 48 * 3600) // modifed last two days + { color = "older" } + else + { color = "quiet" } + return color +} export function hush_views (n, bias, no_bold) { var txt = commatize(n, 1000) bias = bias || 1 @@ -71,21 +87,19 @@ export function hush_size (n, bias, no_bold) { if (n < 1000000) { return ["quiet", txt + " kb."] } - else if (n < (20000000/bias)) { + if (n < (20000000/bias)) { return ["quiet", txt + " mb."] } - else if (n < (50000000/bias)) { + if (n < (50000000/bias)) { return ["old", txt + " mb."] } - else if (n < (80000000/bias)) { + if (n < (80000000/bias)) { return ["med", txt + " mb."] } - else if (no_bold || n < (170000000/bias)) { + if (no_bold || n < (170000000/bias)) { return ["recent", txt + " mb."] } - else { - return ["new", txt + " mb."] - } + return ["new", txt + " mb."] } export function hush_null (n, unit, no_bold) { var s = unit ? n + " " + unit + "." : n |
