diff options
| author | Jules Laplace <julescarbon@gmail.com> | 2018-05-25 19:54:38 +0200 |
|---|---|---|
| committer | Jules Laplace <julescarbon@gmail.com> | 2018-05-25 19:54:38 +0200 |
| commit | 5a4de48a6d63cb383832f6ef85b21699a511b755 (patch) | |
| tree | 4c4fd18d26f8b5c95a6788d138ed62869357c975 /app | |
| parent | 1a99af129427275c22e8276e75fa4b8da6602129 (diff) | |
stubbing in a lot of stuff!
Diffstat (limited to 'app')
28 files changed, 755 insertions, 46 deletions
diff --git a/app/client/common/group.component.js b/app/client/common/group.component.js new file mode 100644 index 0000000..5dc9ddf --- /dev/null +++ b/app/client/common/group.component.js @@ -0,0 +1,10 @@ +import { h, Component } from 'preact' + +export default function Group (props){ + return ( + <div className='group'> + <h3>{this.props.title}</h3> + {this.props.children} + </div> + ) +} diff --git a/app/client/common/header.component.js b/app/client/common/header.component.js index b5a484e..1e27856 100644 --- a/app/client/common/header.component.js +++ b/app/client/common/header.component.js @@ -1,10 +1,24 @@ import { h, Component } from 'preact' +import { Link } from 'react-router-dom'; import { connect } from 'react-redux' function Header(props) { + const tools = "pix2pix samplernn style_transfer_video style_transfer_audio".split(" ").map((s,i) => { + return <option value={s}>{s}</option> + }) return ( <header> <b>live cortex</b> + <span> + <select> + {tools} + </select> + </span> + <span><Link to="/dashboard">dashboard</Link></span> + <span>checkpoints</span> + <span>datasets</span> + <span>results</span> + <span>live</span> <span>{props.fps} fps</span> </header> ) diff --git a/app/client/dashboard/actions.js b/app/client/dashboard/actions.js new file mode 100644 index 0000000..01c0a96 --- /dev/null +++ b/app/client/dashboard/actions.js @@ -0,0 +1 @@ +import types from '../types' diff --git a/app/client/dashboard/dashboard.component.js b/app/client/dashboard/dashboard.component.js new file mode 100644 index 0000000..6db42ae --- /dev/null +++ b/app/client/dashboard/dashboard.component.js @@ -0,0 +1,71 @@ +import { h, Component } from 'preact' +import { bindActionCreators } from 'redux' +import { connect } from 'react-redux' + +import Player from '../common/player.component' +import Group from '../common/group.component' +import Slider from '../common/slider.component' +import Select from '../common/select.component' +import Button from '../common/button.component' + +import DashboardHeader from './dashboardheader.component' +import TaskList from './tasklist.component' +import FileList from './filelist.component' +import Gallery from './gallery.component' + +import * as liveActions from './actions' + +class Dashboard extends Component { + constructor(props){ + super() + } + componentWillUpdate(nextProps) { + // if (nextProps.opt.checkpoint_name && nextProps.opt.checkpoint_name !== this.props.opt.checkpoint_name) { + // this.props.actions.list_epochs(nextProps.opt.checkpoint_name) + // } + } + render(){ + const { tasks, files, images, site } = this.props + return ( + <div className='dashboard'> + <DashboardHeader /> + <div className='params'> + <div className='column'> + <Group title='Completed Tasks'> + <TaskList tasks={tasks} /> + </Group> + <Group title='Upcoming Tasks'> + <TaskList tasks={tasks} /> + </Group> + </div> + <div className='column'> + <Group title='Your Datasets'> + <FileList files={files} /> + </Group> + <Group title='Results'> + <FileList files={files} /> + </Group> + <Group title='Audio Player'> + <FileList files={files} /> + </Group> + </div> + </div> + <div> + <Gallery images={images} /> + </div> + </div> + ) + } +} +const mapStateToProps = state => ({ + site: state.system.site, + images: state.system.images, + tasks: state.system.tasks, + files: state.system.files +}) + +const mapDispatchToProps = (dispatch, ownProps) => ({ + actions: bindActionCreators(liveActions, dispatch) +}) + +export default connect(mapStateToProps, mapDispatchToProps)(Dashboard) diff --git a/app/client/dashboard/dashboard.reducer.js b/app/client/dashboard/dashboard.reducer.js new file mode 100644 index 0000000..c5b3d4a --- /dev/null +++ b/app/client/dashboard/dashboard.reducer.js @@ -0,0 +1,16 @@ +import moment from 'moment' +let FileSaver = require('file-saver') + +const dashboardInitialState = { + loading: false, + error: null, +} + +const dashboardReducer = (state = dashboardInitialState, action) => { + switch(action.type) { + default: + return state + } +} + +export default dashboardReducer diff --git a/app/client/dashboard/dashboardHeader.component.js b/app/client/dashboard/dashboardHeader.component.js new file mode 100644 index 0000000..492dfd8 --- /dev/null +++ b/app/client/dashboard/dashboardHeader.component.js @@ -0,0 +1,39 @@ +import { h, Component } from 'preact' +import { connect } from 'react-redux' +import { bindActionCreators } from 'redux' +import * as liveActions from '../live/actions' + +import * as util from '../util' + +class DashboardHeader extends Component { + constructor(props){ + super(props) + this.handleClick = this.handleClick.bind(this) + } + handleClick(e){ + this.props.onClick && this.props.onClick() + } + render() { + const { currentTask, site } = this.props + const eta = ((currentTask.epochs - currentTask.epoch) * 180 / 60) + " minutes" + return ( + <div class='dashboardHeader heading'> + <h3>{site.name}</h3> + Currently {util.gerund(currentTask.activity)} {currentTask.library} on {currentTask.dataset}<br/> + Epoch: {currentTask.epoch} / {currentTask.epochs}, ETA {eta}<br/> + <br/> + Want to play live? <button>Pause at the end of this epoch</button> + </div> + ) + } +} + +const mapStateToProps = state => ({ + currentTask: state.system.currentTask, + site: state.system.site, +}) + +const mapDispatchToProps = (dispatch, ownProps) => ({ +}) + +export default connect(mapStateToProps, mapDispatchToProps)(DashboardHeader) diff --git a/app/client/dashboard/filelist.component.js b/app/client/dashboard/filelist.component.js new file mode 100644 index 0000000..2833ec8 --- /dev/null +++ b/app/client/dashboard/filelist.component.js @@ -0,0 +1,46 @@ +import { h, Component } from 'preact' +import { bindActionCreators } from 'redux' +import { connect } from 'react-redux' +import * as util from '../util' + +class FileList extends Component { + constructor(props){ + super() + } + render(){ + const { files } = this.props + let time = 0 + const fileList = files.map(file => { + const eta = (time + (file.epochs) * 180 / 60) + " min." + time += (file.epochs) * 180 / 60 + let dataset_type, dataset_name + if (file.dataset.indexOf('/') !== -1) { + [dataset_type, dataset_name] = file.dataset.split('/') + } else { + dataset_name = file.dataset + } + return ( + <div class='row'> + <div class='activity'>{file.activity} {file.library} {dataset_type}</div> + <div class='dataset'>{dataset_name}</div> + <div class='epochs'>{file.epochs} ep.</div> + <div class='eta'>{eta}</div> + </div> + ) + }) + return ( + <div class='filelist rows'> + {fileList} + </div> + ) + } +} + +const mapStateToProps = state => ({ +}) + +const mapDispatchToProps = (dispatch, ownProps) => ({ + // actions: bindActionCreators(liveActions, dispatch) +}) + +export default connect(mapStateToProps, mapDispatchToProps)(FileList) diff --git a/app/client/dashboard/gallery.component.js b/app/client/dashboard/gallery.component.js new file mode 100644 index 0000000..0e1f44d --- /dev/null +++ b/app/client/dashboard/gallery.component.js @@ -0,0 +1,33 @@ +import { h, Component } from 'preact' +import { bindActionCreators } from 'redux' +import { connect } from 'react-redux' + +class Gallery extends Component { + constructor(props){ + super() + } + render(){ + const { title, images } = this.props + images.push(images[0]) + const imageList = images.map(image => { + return ( + <div> + <img src={image.url} /> + </div> + ) + }) + return ( + <div class='gallery'> + {imageList} + </div> + ) + } +} +const mapStateToProps = state => ({ +}) + +const mapDispatchToProps = (dispatch, ownProps) => ({ + // actions: bindActionCreators(liveActions, dispatch) +}) + +export default connect(mapStateToProps, mapDispatchToProps)(Gallery) diff --git a/app/client/dashboard/index.js b/app/client/dashboard/index.js new file mode 100644 index 0000000..29b1ecf --- /dev/null +++ b/app/client/dashboard/index.js @@ -0,0 +1,2 @@ +export default { +}
\ No newline at end of file diff --git a/app/client/dashboard/tasklist.component.js b/app/client/dashboard/tasklist.component.js new file mode 100644 index 0000000..fa002de --- /dev/null +++ b/app/client/dashboard/tasklist.component.js @@ -0,0 +1,45 @@ +import { h, Component } from 'preact' +import { bindActionCreators } from 'redux' +import { connect } from 'react-redux' + +class TaskList extends Component { + constructor(props){ + super() + } + render(){ + const { title, tasks } = this.props + let time = 0 + const taskList = tasks.map(task => { + const eta = (time + (task.epochs) * 180 / 60) + " min." + time += (task.epochs) * 180 / 60 + let dataset_type, dataset_name + if (task.dataset.indexOf('/') !== -1) { + [dataset_type, dataset_name] = task.dataset.split('/') + } else { + dataset_name = task.dataset + } + return ( + <div class='row'> + <div class='activity'>{task.activity} {task.library} {dataset_type}</div> + <div class='dataset'>{dataset_name}</div> + <div class='epochs'>{task.epochs} ep.</div> + <div class='eta'>{eta}</div> + </div> + ) + }) + return ( + <div class='taskList rows'> + {taskList} + </div> + ) + } +} + +const mapStateToProps = state => ({ +}) + +const mapDispatchToProps = (dispatch, ownProps) => ({ + // actions: bindActionCreators(liveActions, dispatch) +}) + +export default connect(mapStateToProps, mapDispatchToProps)(TaskList) diff --git a/app/client/index.jsx b/app/client/index.jsx index d30c73f..a084306 100644 --- a/app/client/index.jsx +++ b/app/client/index.jsx @@ -7,15 +7,17 @@ import { store, history } from './store' import socket from './socket' import Header from './common/header.component' -import Live from './live' +import Dashboard from './dashboard/dashboard.component' +import LivePix2Pix from './pix2pix' const app = ( <Provider store={store}> <BrowserRouter> <div> + <Route path='/' component={Dashboard} /> + <Route path='/live/' component={LivePix2Pix} /> + <Route path='/dashboard/' component={Dashboard} /> <Header /> - <Route path='/' component={Live} /> - <Route path='/live/' component={Live} /> </div> </BrowserRouter> </Provider> diff --git a/app/client/live/actions.js b/app/client/live/actions.js index c9927b3..e63854e 100644 --- a/app/client/live/actions.js +++ b/app/client/live/actions.js @@ -1,52 +1,53 @@ import * as socket from '../socket' +import types from '../types' export const get_params = () => { socket.get_params() - return { type: 'GET_PARAMS', } + return { type: types.player.get_params, } } export const set_param = (key, value) => { console.log('set param', key, value) socket.set_param(key, value) - return { type: 'SET_PARAM', key, value, } + return { type: types.player.set_param, key, value, } } export const list_checkpoints = () => { socket.list_checkpoints() - return { type: 'LOADING_CHECKPOINTS', } + return { type: types.player.loading_checkpoints, } } export const list_epochs = (path) => { socket.list_epochs(path) - return { type: 'LOADING_EPOCHS', } + return { type: types.player.loading_epochs, } } export const list_sequences = () => { socket.list_sequences() - return { type: 'LOADING_SEQUENCES', } + return { type: types.player.loading_sequences } } export const load_sequence = (sequence) => { socket.load_sequence(sequence) - return { type: 'LOADING_SEQUENCE', } + return { type: types.player.loading_sequence, } } export const load_epoch = (checkpoint, epoch) => { socket.load_epoch(checkpoint, epoch) - return { type: 'LOADING_CHECKPOINT', } + return { type: types.player.loading_checkpoint, } } export const seek = (frame) => { socket.seek(frame) - return { type: 'SEEKING', } + return { type: types.player.seeking, } } export const pause = (frame) => { socket.pause(pause) - return { type: 'PAUSING', } + return { type: types.player.pausing, } } export const play = (frame) => { socket.play() - return { type: 'PLAYING', } + return { type: types.player.playing, } } diff --git a/app/client/live/player.js b/app/client/live/player.js index b39d717..ac5f0c8 100644 --- a/app/client/live/player.js +++ b/app/client/live/player.js @@ -1,5 +1,6 @@ import { store } from '../store' import Whammy from './whammy' +import types from '../types' let fps = 0, last_frame let recording = false, saving = false @@ -9,7 +10,7 @@ export function startRecording(){ videoWriter = new Whammy.Video(10) recording = true store.dispatch({ - type: 'START_RECORDING', + type: types.player.start_recording, }) } @@ -17,12 +18,12 @@ export function stopRecording(){ if (!recording) return recording = false store.dispatch({ - type: 'SAVING_VIDEO', + type: types.player.saving_video, }) videoWriter.compile(false, function(blob){ - console.log(blob) + // console.log(blob) store.dispatch({ - type: 'SAVE_VIDEO', + type: types.player.save_video, blob: blob, }) }) @@ -37,23 +38,25 @@ export function onFrame (data) { const url = URL.createObjectURL(blob) const img = new Image () img.onload = function() { + img.onload = null last_frame = data.meta URL.revokeObjectURL(url) - const canvas = document.querySelector('.player canvas') + let canvas = document.querySelector('.player canvas') + if (! canvas) return console.error('no canvas for frame') const ctx = canvas.getContext('2d') ctx.drawImage(img, 0, 0, canvas.width, canvas.height) if (recording) { console.log('record frame') videoWriter.add(canvas) store.dispatch({ - type: 'ADD_RECORD_FRAME', + type: types.player.add_record_frame, }) } if (saving) { saving = false canvas.toBlob(function(blob) { store.dispatch({ - type: 'SAVE_FRAME', + type: types.player.save_frame, blob: blob, }) }) @@ -65,11 +68,11 @@ export function onFrame (data) { setInterval(() => { store.dispatch({ - type: 'SET_FPS', + type: types.player.set_fps, fps: fps, }) store.dispatch({ - type: 'CURRENT_FRAME', + type: types.player.current_frame, meta: last_frame, }) fps = 0 diff --git a/app/client/live/reducer.js b/app/client/live/reducer.js index 8fa6edd..60bcb41 100644 --- a/app/client/live/reducer.js +++ b/app/client/live/reducer.js @@ -1,6 +1,6 @@ -import { combineReducers } from 'redux' import moment from 'moment' -let FileSaver = require('file-saver') +import FileSaver from 'file-saver' +import types from '../types' const liveInitialState = { loading: false, @@ -17,7 +17,7 @@ const liveReducer = (state = liveInitialState, action) => { let results; switch(action.type) { - case 'LOAD_PARAMS': + case types.player.load_params: if (! action.opt || ! Object.keys(action.opt).length) { return state } @@ -28,7 +28,7 @@ const liveReducer = (state = liveInitialState, action) => { opt: action.opt, } - case 'SET_PARAM': + case types.player.set_param: return { ...state, opt: { @@ -37,14 +37,14 @@ const liveReducer = (state = liveInitialState, action) => { } } - case 'LIST_CHECKPOINTS': + case types.player.list_checkpoints: return { ...state, checkpoints: action.checkpoints, epochs: [], } - case 'LIST_EPOCHS': + case types.player.list_epochs: return { ...state, epochs: (action.epochs || []).map(a => [ a == 'latest' ? Infinity : a, a ]) @@ -52,25 +52,25 @@ const liveReducer = (state = liveInitialState, action) => { .map(a => a[1]) } - case 'LIST_SEQUENCES': + case types.player.list_sequences: return { ...state, sequences: action.sequences, } - case 'SET_FPS': + case types.player.set_fps: return { ...state, fps: action.fps, } - case 'CURRENT_FRAME': + case types.player.current_frame: return action.meta ? { ...state, frame: action.meta } : state - case 'START_RECORDING': + case types.player.start_recording: return { ...state, opt: { @@ -78,7 +78,7 @@ const liveReducer = (state = liveInitialState, action) => { recording: true, } } - case 'ADD_RECORD_FRAME': + case types.player.add_record_frame: return { ...state, opt: { @@ -87,7 +87,7 @@ const liveReducer = (state = liveInitialState, action) => { } } - case 'SAVE_FRAME': + case types.player.save_frame: FileSaver.saveAs( action.blob, state.opt.checkpoint_name + "_" + @@ -96,7 +96,7 @@ const liveReducer = (state = liveInitialState, action) => { ) return state - case 'SAVING_VIDEO': + case types.player.saving_video: return { ...state, opt: { @@ -104,7 +104,7 @@ const liveReducer = (state = liveInitialState, action) => { savingVideo: true, } } - case 'SAVE_VIDEO': + case types.player.save_video: FileSaver.saveAs( action.blob, state.opt.checkpoint_name + "_" + diff --git a/app/client/live/index.js b/app/client/pix2pix/index.js index 94af289..9d41fbc 100644 --- a/app/client/live/index.js +++ b/app/client/pix2pix/index.js @@ -8,11 +8,11 @@ import Slider from '../common/slider.component' import Select from '../common/select.component' import Button from '../common/button.component' -import { startRecording, stopRecording, saveFrame } from './player' +import { startRecording, stopRecording, saveFrame } from '../live/player' -import * as liveActions from './actions' +import * as liveActions from '../live/actions' -class App extends Component { +class LivePix2Pix extends Component { constructor(props){ super() props.actions.get_params() @@ -249,4 +249,4 @@ const mapDispatchToProps = (dispatch, ownProps) => ({ actions: bindActionCreators(liveActions, dispatch) }) -export default connect(mapStateToProps, mapDispatchToProps)(App) +export default connect(mapStateToProps, mapDispatchToProps)(LivePix2Pix) diff --git a/app/client/socket.js b/app/client/socket.js index a2a745e..ea6f380 100644 --- a/app/client/socket.js +++ b/app/client/socket.js @@ -17,25 +17,25 @@ socket.on('res', (data) => { break case 'get_params': store.dispatch({ - type: 'LOAD_PARAMS', + type: types.socket.load_params, opt: data.res, }) break case 'list_checkpoints': store.dispatch({ - type: 'LIST_CHECKPOINTS', + type: types.socket.list_checkpoints, checkpoints: data.res, }) break case 'list_sequences': store.dispatch({ - type: 'LIST_SEQUENCES', + type: types.socket.list_sequences, sequences: data.res, }) break case 'list_epochs': store.dispatch({ - type: 'LIST_EPOCHS', + type: types.socket.list_epochs, epochs: data.res, }) break @@ -49,6 +49,7 @@ socket.on('frame', player.onFrame) socket.on('status', (data) => { console.log('got status', data.key, data.value) + store.dispatch({ type: types.socket.status }) switch (data.key) { case 'processing': store.dispatch({ diff --git a/app/client/store.js b/app/client/store.js index 863161d..600e53c 100644 --- a/app/client/store.js +++ b/app/client/store.js @@ -6,9 +6,13 @@ import createHistory from 'history/createBrowserHistory' import { routerReducer } from 'react-router-redux' // import navReducer from './nav.reducer' +import systemReducer from './system/system.reducer' +import dashboardReducer from './dashboard/dashboard.reducer' import liveReducer from './live/reducer' const appReducer = combineReducers({ + system: systemReducer, + dashboard: dashboardReducer, live: liveReducer, router: routerReducer, }) diff --git a/app/client/system/system.reducer.js b/app/client/system/system.reducer.js new file mode 100644 index 0000000..bc19fd1 --- /dev/null +++ b/app/client/system/system.reducer.js @@ -0,0 +1,106 @@ +import moment from 'moment' +let FileSaver = require('file-saver') + +const systemInitialState = { + loading: false, + error: null, + + site: { + name: 'Lens Cortex', + }, + currentTask: { + id: 1072, + activity: 'train', + library: 'pix2pix', + dataset: 'video/woods_final', + epoch: 87, + epochs: 100, + }, + images: [ + { + url: 'https://s3.amazonaws.com/i.asdf.us/bucky/data/4282/woodscaled_4_true_20180521_2125.png', + }, + { + url: 'https://s3.amazonaws.com/i.asdf.us/bucky/data/4282/woodscaled_4_true_20180521_2146%20(1).png', + }, + { + url: 'https://s3.amazonaws.com/i.asdf.us/bucky/data/4282/woodscaled_4_true_20180521_2149.png', + }, + { + url: 'https://s3.amazonaws.com/i.asdf.us/bucky/data/4282/woodscaled_4_true_20180521_2150.png', + }, + ], + tasks: [ + { + id: 1073, + activity: 'train', + library: 'pix2pix', + dataset: 'video/woods_green', + epochs: 100, + }, + { + id: 1073, + activity: 'train', + library: 'samplernn', + dataset: 'bobby_brown_-_every_little_step', + epochs: 6, + }, + { + id: 1073, + activity: 'train', + library: 'pix2pix', + checkpoint: 'lyra_voice_layers', + dataset: 'audio/lyra_improv', + epochs: 30, + }, + { + id: 1073, + activity: 'train', + library: 'pix2pix', + checkpoint: 'lyra_melody_lines', + dataset: 'audio/lyra_improv', + epochs: 30, + }, + { + id: 1073, + activity: 'train', + library: 'pix2pix', + checkpoint: 'ensemble_chords', + dataset: 'audio/lyra_improv', + epochs: 30, + }, + { + id: 1073, + activity: 'generate', + library: 'samplernn', + dataset: 'coccoglass3', + opt: { time: 5, count: 6 }, + }, + { + id: 1073, + activity: 'train', + library: 'pix2pix', + dataset: 'video/woods_green', + epochs: 100, + }, + { + id: 1073, + activity: 'train', + library: 'samplernn', + dataset: 'bobby_brown_-_every_little_step', + epochs: 6, + }, + ], + files: [ + { id: 2, library: 'samplernn', checkpoint: 'jwcglassbeat', dataset: 'jwcglassbeat', epoch: 18, duration: 30, batch_size: 5, filename: 'jwcglassbeat-ep18.mp3', size: 3 * 1024 * 1024, date: Date.now(), opt: "{}", } + ] +} + +const systemReducer = (state = systemInitialState, action) => { + switch(action.type) { + default: + return state + } +} + +export default systemReducer diff --git a/app/client/types.js b/app/client/types.js new file mode 100644 index 0000000..782a225 --- /dev/null +++ b/app/client/types.js @@ -0,0 +1,31 @@ +export default { + socket: { + load_params: 'LOAD_PARAMS', + list_sequences: 'LIST_SEQUENCES', + list_epochs: 'LIST_EPOCHS', + }, + player: { + get_params: 'GET_PARAMS', + set_param: 'SET_PARAM', + + loading_checkpoints: 'LOADING_CHECKPOINTS', + list_checkpoints: 'LIST_CHECKPOINTS', + + loading_sequences: 'LOADING_SEQUENCES', + load_sequence: 'LOAD_SEQUENCE', + + loading_epochs: 'LOADING_EPOCHS', + load_epoch: 'LOAD_EPOCH', + + set_fps: 'SET_FPS', + seeking: 'SEEKING', + pausing: 'PAUSING', + playing: 'PLAYING', + current_frame: 'CURRENT_FRAME', + start_recording: 'START_RECORDING', + add_record_frame: 'ADD_RECORD_FRAME', + save_frame: 'SAVE_FRAME', + saving_video: 'SAVING_VIDEO', + save_video: 'SAVE_VIDEO', + } +}
\ No newline at end of file diff --git a/app/client/util.js b/app/client/util.js new file mode 100644 index 0000000..db9fa8c --- /dev/null +++ b/app/client/util.js @@ -0,0 +1,6 @@ +export function timeInSeconds(n){ + return (n / 10).toFixed(1) + ' s.' +} +export function gerund(s){ + return s.replace(/e?$/, 'ing') +} diff --git a/app/relay/index.js b/app/relay/index.js index 00f3dfa..d43f221 100644 --- a/app/relay/index.js +++ b/app/relay/index.js @@ -2,9 +2,11 @@ require('dotenv').config() const io = require('socket.io-client') const zerorpc = require('zerorpc') -const Readable = require('stream').Readable; +const Readable = require('stream').Readable +const runner = require('./runner') + +let remote = io.connect(process.env.SOCKETIO_REMOTE) -let remote = io.connect(process.env.SOCKETIO_REMOTE); remote.on('cmd', (data) => { console.log('cmd data', data) if (! data.cmd) { diff --git a/app/relay/interpreters.js b/app/relay/interpreters.js new file mode 100644 index 0000000..1adb95e --- /dev/null +++ b/app/relay/interpreters.js @@ -0,0 +1,22 @@ +export default { + pytorch: { + cmd: process.env.PYTORCH_BIN, + gpu: true, + }, + tensorflow: { + cmd: process.env.TENSORFLOW_BIN, + gpu: true, + }, + python: { + cmd: process.env.PYTHON_BIN, + gpu: false, + }, + bash: { + cmd: process.env.BASH_BIN || '/bin/bash', + gpu: false, + } + perl: { + cmd: process.env.PERL_BIN || '/usr/bin/perl', + gpu: false, + } +}
\ No newline at end of file diff --git a/app/relay/modules/index.js b/app/relay/modules/index.js new file mode 100644 index 0000000..65ec75c --- /dev/null +++ b/app/relay/modules/index.js @@ -0,0 +1,13 @@ +import pix2pix from './pix2pix' +// import pix2pixhd from './pix2pixhd' +import samplernn from './samplernn' +import test from './test' +// torch-warp? +// audio style transfer? +// cyclegan? +export default { + pix2pix, + // pix2pixhd, + samplernn, + test, +}
\ No newline at end of file diff --git a/app/relay/modules/pix2pix.js b/app/relay/modules/pix2pix.js new file mode 100644 index 0000000..3727964 --- /dev/null +++ b/app/relay/modules/pix2pix.js @@ -0,0 +1,71 @@ +import path from 'path' + +const name = 'pix2pix' +const cwd = process.env.PIX2PIX_CWD || path.join(process.env.HOME, 'code/' + name + '/') + +const dataset = { + type: 'pytorch', + script: 'datasets/combine_A_and_B.py', + params: (task) => { + } +// python datasets/combine_A_and_B.py \ +// --fold_A /home/lens/Desktop/thumbs/woodscaled_4/A \ +// --fold_B /home/lens/Desktop/thumbs/woodscaled_4/B \ +// --fold_AB datasets/woodscaled_4/ +} +const train = { + type: 'pytorch', + script: 'train.py', + params: (task) => { + }, +// python train.py \ +// --dataroot "./datasets/$dataset" \ +// --name "$dataset" \ +// --model pix2pix \ +// --loadSize 264 \ +// --fineSize 256 \ +// --which_model_netG unet_256 \ +// --which_direction AtoB \ +// --lambda_B 100 \ +// --dataset_mode aligned \ +// --epoch_count $epochs \ +// --which_epoch latest \ +// --continue_train \ +// --no_lsgan --norm batch --pool_size 0 +} +const generate = { + type: 'pytorch', + script: 'generate.py', + params: (task) => { + }, +} +const live = { + type: 'pytorch', + script: 'live-mogrify.py', + params: (task) => { + }, + // python live-mogrify.py \ + // --dataroot "./sequences/$sequence" \ + // --start_img "./sequences/$sequence/frame_00001.png" \ + // --experiment "$checkpoint" \ + // --name "$checkpoint" \ + // --recursive --recursive-frac 0.1 \ + // --sequence --sequence-frac 0.3 \ + // --process-frac 0.5 \ + // --transition \ + // --transition-min 0.05 \ + // --how_many 100000 --transition-period 1000 \ + // --loadSize 256 --fineSize 256 \ + // --just-copy --poll_delay 0.09 \ + // --model test --which_model_netG unet_256 \ + // --which_direction AtoB --dataset_mode recursive \ + // --which_epoch latest \ + // --norm batch +} + +export default { + name, cwd, + activities: { + dataset, train, generate, live, + } +} diff --git a/app/relay/modules/pix2pixhd.js b/app/relay/modules/pix2pixhd.js new file mode 100644 index 0000000..9aa30d0 --- /dev/null +++ b/app/relay/modules/pix2pixhd.js @@ -0,0 +1,5 @@ +import path from 'path' + +export default { + enabled: false, +}
\ No newline at end of file diff --git a/app/relay/modules/samplernn.js b/app/relay/modules/samplernn.js new file mode 100644 index 0000000..4181a32 --- /dev/null +++ b/app/relay/modules/samplernn.js @@ -0,0 +1,61 @@ +import path from 'path' + +const name = 'samplernn' +const cwd = process.env.TEST_CWD || path.join(process.env.HOME, 'code/' + name + '/') + +const fetch = { + type: 'perl', + script: 'get.pl', + params: (task) => { + } + // perl get.pl url +} +const dataset = { + type: 'perl', + script: 'dataset.pl', + params: (task) => { + } + // perl dataset.pl filename.flac +} +const train = { + type: 'pytorch', + script: 'train.py', + params: (task) => { + }, + onComplete: publish, + // python train.py \ + // --exp $checkpoint_name --dataset $dataset_name \ + // --frame_sizes 8 2 --n_rnn 2 \ + // --sample_length $sample_length \ + // --n_samples $n_samples \ + // --keep_old_checkpoints False \ + // --epoch_limit $epoch_limit \ +} +const generate = { + type: 'pytorch', + script: 'generate.py', + params: (task) => { + }, + onComplete: publish, + // python generate.py \ + // --exp $checkpoint_name --dataset $dataset_name \ + // --frame_sizes 8 2 --n_rnn 2 \ + // --sample_length $sample_length \ + // --n_samples $n_samples \ + // --keep_old_checkpoints False \ + // --epoch_limit $epoch_limit \ +} +const publish = { + type: 'perl', + script: 'latest.pl', + params: (task) => { + } +} +// after train and generate, run perl latest.pl -l $checkpoint_name + +export default { + name, cwd, + activities: { + dataset, train, generate, + } +} diff --git a/app/relay/modules/test.js b/app/relay/modules/test.js new file mode 100644 index 0000000..bfac514 --- /dev/null +++ b/app/relay/modules/test.js @@ -0,0 +1,36 @@ +import path from 'path' + +const name = 'test' +const cwd = process.env.TEST_CWD || './test/module/' + +const dataset = { + type: 'perl', + script: 'test.pl', + params: (task) => { + } +} +const train = { + type: 'perl', + script: 'test.pl', + params: (task) => { + } +} +const generate = { + type: 'perl', + script: 'test.pl', +} +const render = { + type: 'perl', + script: 'test.pl', +} +const live = { + type: 'pytorch', + script: 'test.py', +} + +export default { + name, cwd, + activities: { + dataset, train, generate, render, live, + } +} diff --git a/app/relay/runner.js b/app/relay/runner.js new file mode 100644 index 0000000..caa2ded --- /dev/null +++ b/app/relay/runner.js @@ -0,0 +1,68 @@ +// monitors which process is currently running +// kills it if need be.... murder + +import { spawn } from 'child_process' +import interpreters from './interpreters' +import modules from './modules' +import { kill } from 'tree-kill' + +var state = { + current_cpu_task: null, + current_gpu_task: null, +} + +export function get_current_cpu_task(){ + return state.current_cpu_task +} + +export function get_current_gpu_task(){ + return state.current_gpu_task +} + +export function build_params(module, task) { + const activity = module.activities[task.activity] + const interpreter = interpreters[activity.type] + if (typeof activity.params === 'function') { + params = activity.params(task) + } + else { + const opt = JSON.parse(task.opt) + const opt_params = Object.keys(opt).map(key => { + const flag = '--' + key.replace(/-/g, '_') + const value = opt[key] + if (value === 'true') { + return [flag] + } + return [flag, value] + }).reduce((acc, cur) => acc.concat(cur), []) + params = [ activity.script ].concat(activity.params || []).concat(opt_params) + } + return { + activity, + params + } +} + +export function run_task(module_name, task){ + const module = modules['module_name'] + if (! module) throw new Error("No such module") + const { activity, interpreter, params } = build_params(module, task) + console.log('running task', activity.name) + console.log(activity.interpreter, params) + const subprocess = spawn(activity.interpreter, params) + if (activity.gpu) { + state.current_gpu_task = subprocess + } else { + state.current_cpu_task = subprocess + } + subprocess.on('error', (err) => { + console.log('process error', subprocess.pid, err) + }) + subprocess.on('close', () => { + console.log('process ended', subprocess.pid) + }) +} + +export function kill_task(subprocess){ + kill(subprocess.pid) +}
\ No newline at end of file |
