-
Notifications
You must be signed in to change notification settings - Fork 17
/
index.mjs
executable file
·124 lines (101 loc) · 4.91 KB
/
index.mjs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
#!/usr/bin/env node
import fs from 'fs'
import path, { dirname } from 'path'
import { execSync } from 'child_process'
import minimist from 'minimist'
import JSON5 from 'json5'
import readline from 'readline'
import { promisify } from 'util'
import open from 'open'
// ESM shenanigans for dealing with local files
import { fileURLToPath } from 'url'
import { getModel, getModelInputs, getModelNameWithVersion } from './lib/models.js'
import { isValidToken, redactToken } from './lib/token.js'
const readlineSync = await import('readline-sync').then(module => module.default)
const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)
const args = minimist(process.argv.slice(2), {
boolean: ['run-after-setup', 'debug'],
default: {
'run-after-setup': true,
debug: false,
model: 'black-forest-labs/flux-dev'
}
})
args.packageName = args._[0] || 'my-replicate-app'
if (args.debug) {
console.debug({ args })
}
// Display version number if --version flag is present
if (args.version) {
const { version } = JSON.parse(fs.readFileSync(path.join(__dirname, 'package.json'), 'utf8'))
console.log(version)
process.exit()
}
console.log(`Creating project "${args.packageName}"...`)
console.log(`Model: ${args.model}...`)
console.log('Copying files...')
const templateDir = path.join(__dirname, 'template')
const targetDir = path.join(process.cwd(), args.packageName)
fs.cpSync(templateDir, targetDir, { recursive: true })
// Copy hidden files too
const gitignoreSrc = path.join(templateDir, 'gitignore')
const gitignoreDest = path.join(targetDir, '.gitignore')
fs.copyFileSync(gitignoreSrc, gitignoreDest)
// Get env from existing REPLICATE_API_TOKEN, or prompt user to get it from the browser
const envFile = path.join(targetDir, '.env')
if (process.env.REPLICATE_API_TOKEN) {
fs.writeFileSync(envFile, `REPLICATE_API_TOKEN=${process.env.REPLICATE_API_TOKEN}`)
console.log(`Adding API token ${redactToken(process.env.REPLICATE_API_TOKEN)} to .env file...`)
} else {
console.log('API token not found in environment.')
const rl = readline.createInterface({ input: process.stdin, output: process.stdout })
const question = promisify(rl.question).bind(rl)
const answer = await question('Open your browser to copy a Replicate API token? (Y/n) ')
if (answer.toLowerCase() === 'y' || answer === '') {
await open('https://replicate.com/account/api-tokens?utm_campaign=create-replicate&utm_source=project')
const token = readlineSync.question('Paste your API token here: ', { hideEchoBack: true })
// Add the pasted token to the user's local .env file for when they run their project
fs.writeFileSync(envFile, `REPLICATE_API_TOKEN=${token}`)
// Also add the pasted token to THIS script's environment, so we can use it to make Replicate API calls
process.env.REPLICATE_API_TOKEN = token
console.log(`API token ${redactToken(process.env.REPLICATE_API_TOKEN)} written to .env file`)
}
}
// Check use-provided API token looks legit before proceeding
if (!isValidToken(process.env.REPLICATE_API_TOKEN)) {
console.log('Invalid API token:', redactToken(process.env.REPLICATE_API_TOKEN))
console.log('Go to https://replicate.com/account, copy a valid token, then re-run this command')
process.exit()
}
console.log('Setting package name...')
execSync(`npm pkg set name=${args.packageName}`, { cwd: targetDir, stdio: 'ignore' })
console.log('Installing dependencies...')
execSync('npm install', { cwd: targetDir, stdio: 'ignore' })
console.log('Fetching model metadata using Replicate API...')
const model = await getModel(args.model)
// If user has provided a model version, use it. Otherwise, use the latest version
const modelVersionRegexp = /.*:[a-fA-F0-9]{64}$/
const modelNameWithVersion = args.model.match(modelVersionRegexp) ? args.model : getModelNameWithVersion(model)
const inputs = getModelInputs(model)
const indexFile = path.join(targetDir, 'index.js')
const indexFileContents = fs.readFileSync(indexFile, 'utf8')
const newContents = indexFileContents
.replace('{{MODEL}}', modelNameWithVersion)
.replace('\'{{INPUTS}}\'', JSON5.stringify(inputs, null, 2))
fs.writeFileSync(indexFile, newContents)
console.log('App created successfully!')
if (args['run-after-setup']) {
console.log(`Running command: \`node ${args.packageName}/index.js\`\n`)
console.log('--- START OF OUTPUT ---')
execSync('node index.js', { cwd: targetDir, stdio: 'inherit' })
console.log('--- END OF OUTPUT ---')
} else {
console.log('To run your app, execute the following command:')
console.log(`cd ${args.packageName} && node index.js`)
}
console.log('')
console.log('To learn more about configuring this model check out the documentation:')
console.log(` - Model API Documentation: https://replicate.com/${model.owner}/${model.name}/api`)
console.log(' - Replicate Documentation: https://replicate.com/docs/get-started/nodejs')
console.log(' - Replicate JavaScript Client: https://github.com/replicate/replicate-javascript#readme')