Text Classification
Transformers
Safetensors
English
nli
cross-encoder
qwen3.5
reranker
image-text-to-text
Instructions to use ldov/openjevv with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use ldov/openjevv with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-classification", model="ldov/openjevv")# Load model directly from transformers import AutoModel model = AutoModel.from_pretrained("ldov/openjevv", device_map="auto") - Notebooks
- Google Colab
- Kaggle
File size: 12,639 Bytes
e46c127 | 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 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 | // Mineflayer skill server for minecraft.py: the NLI model picks a skill, this process executes it in a real Minecraft world.
// node mc_bot.js [--port 25570] [--http 3007]
// GET /state -> inventory / stations / visible blocks
// POST /act {skill, arg, n} -> {ok, msg} skills: collect | craft | place | smelt | explore
// POST /reset {x, z} -> clear inventory, teleport to a fresh spot
const mineflayer = require('mineflayer')
const { pathfinder, Movements, goals } = require('mineflayer-pathfinder')
const { Vec3 } = require('vec3')
const http = require('http')
const argv = process.argv.slice(2)
const opt = (k, d) => { const i = argv.indexOf(k); return i >= 0 ? argv[i + 1] : d }
const bot = mineflayer.createBot({ host: '127.0.0.1', port: +opt('--port', 25570), username: opt('--name', 'jev'), version: '1.20.4' })
bot.loadPlugin(pathfinder)
let mcData, ready = false
const sleep = ms => new Promise(r => setTimeout(r, ms))
// text-level groups: the planner only ever sees these names
const BLOCKS = { log: n => n.endsWith('_log') && !n.startsWith('stripped'), stone: n => n === 'stone', iron_ore: n => n === 'iron_ore' || n === 'deepslate_iron_ore' }
const ITEMS = { log: n => n.endsWith('_log'), planks: n => n.endsWith('_planks'), stick: n => n === 'stick', cobblestone: n => n === 'cobblestone' }
const DROPS = { log: 'log', stone: 'cobblestone', iron_ore: 'raw_iron' }
const RADIUS = { log: 48, stone: 32, iron_ore: 64 }
const itemMatch = g => ITEMS[g] || (n => n === g)
const count = g => bot.inventory.items().filter(i => itemMatch(g)(i.name)).reduce((s, i) => s + i.count, 0)
const blockIds = g => Object.values(mcData.blocksByName).filter(b => BLOCKS[g](b.name)).map(b => b.id)
const bad = new Set()
bot.once('spawn', async () => {
mcData = require('minecraft-data')(bot.version)
const mv = new Movements(bot)
mv.allow1by1towers = true; mv.canDig = true; mv.allowParkour = true
bot.pathfinder.setMovements(mv)
bot.pathfinder.thinkTimeout = 10000
for (const c of ['gamerule doDaylightCycle false', 'time set day', 'gamerule doWeatherCycle false', 'weather clear', 'gamerule keepInventory true', 'difficulty peaceful']) { bot.chat('/' + c); await sleep(150) }
if (opt('--viewer', null)) require('prismarine-viewer').mineflayer(bot, { port: +opt('--viewer'), firstPerson: opt('--view', 'first') === 'first', viewDistance: 5 })
ready = true
console.log('bot ready at', bot.entity.position.floored().toString())
})
bot.on('kicked', r => console.log('kicked', r))
bot.on('error', e => console.log('error', e.message))
bot.on('death', () => console.log('bot died'))
function findNear(g) {
const pos = bot.findBlocks({ matching: blockIds(g), maxDistance: RADIUS[g], count: 64 }).filter(p => !bad.has(p.toString()))
const me = bot.entity.position
// prefer exposed blocks that are not high above the head (tree tops need towers, buried blocks need tunnels)
const exposed = p => [[1, 0, 0], [-1, 0, 0], [0, 1, 0], [0, 0, 1], [0, 0, -1]].some(d => { const b = bot.blockAt(p.offset(...d)); return b && b.name === 'air' })
const cost = p => p.distanceTo(me) + 4 * Math.max(0, p.y - me.y - 3) + (p.distanceTo(me) < 24 && !exposed(p) ? 10 : 0)
return pos.map(p => [cost(p), p]).sort((a, b) => a[0] - b[0]).map(x => x[1])
}
const station = name => bot.findBlock({ matching: mcData.blocksByName[name].id, maxDistance: 32 })
function state() {
const inv = {}
for (const i of bot.inventory.items()) {
const g = Object.keys(ITEMS).find(k => ITEMS[k](i.name)) || i.name
inv[g] = (inv[g] || 0) + i.count
}
const p = bot.entity.position
return {
inventory: inv, pos: [Math.round(p.x), Math.round(p.y), Math.round(p.z)], health: bot.health,
near: { crafting_table: !!station('crafting_table'), furnace: !!station('furnace') },
visible: Object.fromEntries(Object.keys(BLOCKS).map(g => [g, findNear(g).length > 0]))
}
}
async function withTimeout(p, ms, what) {
let t
// stop() with no active path would cancel the *next* goto, so only clean up after a real timeout
const timer = new Promise((_, rej) => { t = setTimeout(() => { bot.pathfinder.setGoal(null); try { bot.stopDigging() } catch (e) {} ; rej(new Error(`timeout: ${what}`)) }, ms) })
try { return await Promise.race([p, timer]) } finally { clearTimeout(t) }
}
async function pickupNear(pos) {
await sleep(350)
for (let k = 0; k < 3; k++) {
const e = Object.values(bot.entities).filter(e => e.name === 'item' && e.position.distanceTo(pos) < 6).sort((a, b) => a.position.distanceTo(bot.entity.position) - b.position.distanceTo(bot.entity.position))[0]
if (!e) return
try { await withTimeout(bot.pathfinder.goto(new goals.GoalNear(e.position.x, e.position.y, e.position.z, 0.7)), 15000, 'pickup') } catch (err) { return }
await sleep(300)
}
}
async function collect(g, n) {
if (!BLOCKS[g]) return { ok: false, msg: `unknown block group ${g}` }
const drop = DROPS[g], start = count(drop)
for (let tries = 0; count(drop) < start + n && tries < n * 3 + 4; tries++) {
const cands = findNear(g)
if (!cands.length) break
const block = bot.blockAt(cands[0])
try {
await withTimeout(bot.pathfinder.goto(new goals.GoalNear(block.position.x, block.position.y, block.position.z, 3)), 60000, 'path to ' + g)
if (!bot.canDigBlock(block)) throw new Error('block out of reach')
const tool = bot.pathfinder.bestHarvestTool(block)
if (tool) await bot.equip(tool, 'hand')
if (!block.canHarvest(bot.heldItem ? bot.heldItem.type : null)) return { ok: false, msg: `cannot harvest ${g} without a suitable pickaxe` }
await withTimeout(bot.dig(block), 30000, 'dig ' + g)
await pickupNear(block.position)
} catch (e) { bad.add(cands[0].toString()); console.log('collect err', e.message) }
}
const got = count(drop) - start
return got > 0 ? { ok: true, msg: `collected ${got} ${drop}` } : { ok: false, msg: `no reachable ${g} block found nearby` }
}
// bot.craft() clicks the next ingredient while the previous one is still on the cursor (swap -> garbage in the grid),
// so the clicks are done here: pick a stack, right-click one item into each grid slot, put the rest back, take the result.
async function craftOnce(recipe, table) {
const win = recipe.requiresTable ? await bot.openBlock(table) : bot.inventory, w = recipe.requiresTable ? 3 : 2
const click = async (slot, btn) => { await bot.clickWindow(slot, btn, 0); await sleep(60) }
try {
const dests = {}
if (recipe.inShape) recipe.inShape.forEach((row, y) => row.forEach((ing, x) => { if (ing.id !== -1) (dests[ing.id] = dests[ing.id] || []).push(1 + x + w * y) }))
else recipe.ingredients.forEach((ing, k) => (dests[ing.id] = dests[ing.id] || []).push(1 + k))
for (const [id, slots] of Object.entries(dests)) {
let from = null
for (const d of slots) {
if (!win.selectedItem) { // stacks may be fragmented (4 + 4 + 2 planks): take the next one when the cursor runs empty
const src = win.findInventoryItem(+id, null)
if (!src) throw new Error('missing ingredient')
from = src.slot
await click(from, 0)
}
await click(d, 1)
}
if (win.selectedItem) await click(from, 0)
}
for (let i = 0; i < 40 && !win.slots[0]; i++) await sleep(50)
if (!win.slots[0]) throw new Error('no crafting result appeared')
await click(0, 0)
await click(win.firstEmptyInventorySlot(), 0)
} finally {
if (recipe.requiresTable) bot.closeWindow(win)
await sleep(250)
}
}
async function craft(name) {
const ids = Object.values(mcData.itemsByName).filter(i => itemMatch(name)(i.name)).map(i => i.id)
const table = station('crafting_table')
let recipe = null
for (const id of ids) { recipe = bot.recipesFor(id, null, 1, table || null)[0]; if (recipe) break }
if (!recipe) return { ok: false, msg: `cannot craft ${name}: missing ingredients${table ? '' : ' or no crafting table nearby'}` }
if (recipe.requiresTable) await withTimeout(bot.pathfinder.goto(new goals.GoalNear(table.position.x, table.position.y, table.position.z, 2)), 60000, 'path to table')
const before = count(name)
try { await craftOnce(recipe, table) } catch (e) { console.log('craft err', e.message); return { ok: false, msg: `crafting ${name} failed: ${e.message}` } }
return { ok: count(name) > before, msg: `crafted ${count(name) - before} ${name}` }
}
async function place(name) {
const item = bot.inventory.items().find(i => i.name === name)
if (!item) return { ok: false, msg: `no ${name} in the inventory` }
const p = bot.entity.position.floored()
for (let r = 1; r <= 3; r++) for (let dx = -r; dx <= r; dx++) for (let dz = -r; dz <= r; dz++) for (const dy of [0, 1, -1]) {
if (Math.max(Math.abs(dx), Math.abs(dz)) !== r) continue
const ref = bot.blockAt(p.offset(dx, dy - 1, dz)), above = bot.blockAt(p.offset(dx, dy, dz))
if (!ref || !above || ref.boundingBox !== 'block' || above.name !== 'air') continue
try {
await bot.equip(item, 'hand')
await bot.lookAt(ref.position.offset(0.5, 1, 0.5))
await bot.placeBlock(ref, new Vec3(0, 1, 0))
return { ok: true, msg: `placed ${name}` }
} catch (e) { console.log('place err', e.message) }
}
return { ok: false, msg: `no free spot to place ${name}` }
}
async function smelt(input) {
const fb = station('furnace')
if (!fb) return { ok: false, msg: 'no furnace nearby' }
const raw = bot.inventory.items().find(i => i.name === input), fuel = bot.inventory.items().find(i => ITEMS.planks(i.name) || i.name === 'coal')
if (!raw) return { ok: false, msg: `no ${input} in the inventory` }
if (!fuel) return { ok: false, msg: 'no fuel (planks) in the inventory' }
await withTimeout(bot.pathfinder.goto(new goals.GoalNear(fb.position.x, fb.position.y, fb.position.z, 2)), 60000, 'path to furnace')
const f = await bot.openFurnace(fb), n = raw.count
const nfuel = Math.min(fuel.count, fuel.name === 'coal' ? Math.ceil(n / 8) : Math.ceil(n * 2 / 3))
await f.putFuel(fuel.type, null, nfuel); await f.putInput(raw.type, null, n)
for (let t = 0; t < n * 12 + 8; t++) { await sleep(1000); const o = f.outputItem(); if (o && o.count >= n) break; if (!f.inputItem() && f.fuel <= 0 && t > 3) break }
const out = f.outputItem()
if (out) await f.takeOutput()
if (f.inputItem()) await f.takeInput()
f.close()
return out ? { ok: true, msg: `smelted ${out.count} ${out.name}` } : { ok: false, msg: 'smelting produced nothing (not enough fuel?)' }
}
let heading = Math.random() * 2 * Math.PI // kept per episode: a fresh random direction every call is a random walk that goes nowhere
async function explore() {
const a = heading + (Math.random() - 0.5) * 0.6, p = bot.entity.position.clone()
try { await withTimeout(bot.pathfinder.goto(new goals.GoalXZ(p.x + 60 * Math.cos(a), p.z + 60 * Math.sin(a))), 60000, 'explore') } catch (e) { heading += 1.2 }
return { ok: true, msg: `walked ${Math.round(bot.entity.position.distanceTo(p))} blocks` }
}
async function reset(x, z) {
bot.chat('/clear'); await sleep(200)
// start on dry land with trees in sight (otherwise half of the episodes begin in the ocean)
for (let k = 0; k < 12; k++) {
bot.chat(`/spreadplayers ${x + 300 * k} ${z} 0 40 false ${bot.username}`); await sleep(4000)
const feet = bot.blockAt(bot.entity.position.floored())
if (findNear('log').length > 3 && feet && feet.name !== 'water') break
}
bad.clear(); heading = Math.random() * 2 * Math.PI
return { ok: true, msg: 'reset to ' + bot.entity.position.floored().toString() }
}
let busy = false
http.createServer((req, res) => {
let body = ''
req.on('data', c => { body += c })
req.on('end', async () => {
const send = o => { res.writeHead(200, { 'content-type': 'application/json' }); res.end(JSON.stringify(o)) }
if (!ready) return send({ ok: false, msg: 'bot not ready' })
if (req.url === '/state') return send(state())
if (busy) return send({ ok: false, msg: 'busy' })
busy = true
let out
try {
const a = JSON.parse(body || '{}')
if (req.url === '/reset') out = await reset(a.x || 0, a.z || 0)
else out = await withTimeout({ collect: () => collect(a.arg, a.n || 1), craft: () => craft(a.arg), place: () => place(a.arg), smelt: () => smelt(a.arg), explore }[a.skill](), 240000, a.skill)
} catch (e) { out = { ok: false, msg: 'error: ' + e.message } }
busy = false
send({ ...out, state: state() })
})
}).listen(+opt('--http', 3007), '127.0.0.1', () => console.log('skill server on', opt('--http', 3007)))
|