summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/client/common/group.component.js10
-rw-r--r--app/client/common/header.component.js14
-rw-r--r--app/client/dashboard/actions.js1
-rw-r--r--app/client/dashboard/dashboard.component.js71
-rw-r--r--app/client/dashboard/dashboard.reducer.js16
-rw-r--r--app/client/dashboard/dashboardHeader.component.js39
-rw-r--r--app/client/dashboard/filelist.component.js46
-rw-r--r--app/client/dashboard/gallery.component.js33
-rw-r--r--app/client/dashboard/index.js2
-rw-r--r--app/client/dashboard/tasklist.component.js45
-rw-r--r--app/client/index.jsx8
-rw-r--r--app/client/live/actions.js21
-rw-r--r--app/client/live/player.js21
-rw-r--r--app/client/live/reducer.js28
-rw-r--r--app/client/pix2pix/index.js (renamed from app/client/live/index.js)8
-rw-r--r--app/client/socket.js9
-rw-r--r--app/client/store.js4
-rw-r--r--app/client/system/system.reducer.js106
-rw-r--r--app/client/types.js31
-rw-r--r--app/client/util.js6
-rw-r--r--app/relay/index.js6
-rw-r--r--app/relay/interpreters.js22
-rw-r--r--app/relay/modules/index.js13
-rw-r--r--app/relay/modules/pix2pix.js71
-rw-r--r--app/relay/modules/pix2pixhd.js5
-rw-r--r--app/relay/modules/samplernn.js61
-rw-r--r--app/relay/modules/test.js36
-rw-r--r--app/relay/runner.js68
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