@@ -186,7 +186,7 @@ <h4 style="margin: 0 0 10px 0;" data-i18n="uploadedSkills">Uploaded Skills</h4>
186186
187187 // Global version date variable (format: vYear.Month.Day)
188188 const GLOBAL_VERSION_DATE = "v2026.03.26" ;
189- const GLOBAL_VERSION_LAST_MODIFIED = "2026-03-26 21:29:58 " ;
189+ const GLOBAL_VERSION_LAST_MODIFIED = "2026-03-26 21:45:55 " ;
190190
191191 // Set version date
192192 function setVersionDate ( )
@@ -4295,186 +4295,34 @@ <h3 style="color: #4CAF50;">${title}</h3>
42954295 }
42964296 }
42974297
4298- // AI代码生成主函数
4298+ // AI代码生成主函数 - 系统提示词需要极度精简,因为使用GET URL传递,有长度限制
42994299 async function generateAICode ( description ) {
4300- const config = await loadBlocksConfigForAI ( ) ;
4301-
4302- // 构建提示词
4303- let systemPrompt = `You are a code generator for Petoi robot Blockly-based visual programming. Generate JavaScript code that uses the available helper functions.
4304-
4305- IMPORTANT RULES:
4306- 1. Only generate JavaScript code - NO explanations, NO markdown code blocks, NO comments unless necessary
4307- 2. Use ONLY the provided helper functions - do not invent new ones
4308- 3. Always use await for async functions
4309- 4. Include checkStopExecution() at appropriate points in loops
4310- 5. All code must be valid JavaScript that can be executed in an async context
4311- 6. CRITICAL: For ALL motion/action commands, use sendAndWait() to wait for the robot's completion token BEFORE executing the next command. NEVER fire-and-forget motion commands.
4312- 7. Define sendAndWait() and delayAfterToken() helpers at the top of generated code as shown in CODE PATTERNS
4313- 8. Use delayAfterToken(ms) instead of delay(ms) for delays between actions - it starts timing from when the robot finished, not when the command was sent
4314-
4315- AVAILABLE HELPER FUNCTIONS:
4316- - checkStopExecution(): Call at the start of code and in loops to respect stop signals
4317- - checkStopExecutionInLoop(): Use inside loops for stop checking with yield
4318- - webRequest(command, timeout=5000, needResponse=true): Send command to robot via WebSocket/Serial
4319- - waitForSerialTokenLine(token, timeout, fromIndex): Wait for robot completion token in serial mode
4320- - delay(ms): Promise-based delay with stop checking
4321- - encodeCommand(token, params): Encode command with token and parameters
4322- - parseSingleResult(rawResult): Parse numeric result from response
4323- - parseAllJointsResult(rawResult): Parse joint angles array from response
4324- - console: Standard console object for logging
4325-
4326- AVAILABLE COMMANDS (token-based):
4327- ` ;
4328-
4329- // 从配置添加命令信息
4330- if ( config && config . command_reference && config . command_reference . token_commands ) {
4331- const commands = config . command_reference . token_commands ;
4332- for ( const [ token , info ] of Object . entries ( commands ) ) {
4333- systemPrompt += `- ${ token } : ${ info . description || '' } | Params: ${ info . params || 'none' } | Example: ${ info . example || '' } \n` ;
4334- }
4335- }
4336-
4337- systemPrompt += `
4338- MOTION COMMANDS (lowercase k* or d, NO encodeCommand needed):
4339- Posture: stand=kup, balance=kbalance, sit=ksit, rest=d, stretch=kstr, buttUp=kbuttUp, calibration=kcalib
4340- Gait: step=kvtF, spinL=kvtL, spinR=kvtR, walkF=kwkF, walkL=kwkL, walkR=kwkR, backF=kbkF, backL=kbkL, backR=kbkR, trotF=ktrF, trotL=ktrL, trotR=ktrR, crawlF=kcrF, crawlL=kcrL, crawlR=kcrR, strideF=kgpF, strideL=kgpL, strideR=kgpR, pushF=kphF, pushL=kphL, moonwalk=kmw
4341- Behavior: hi/wave=khi, handshake=khsk, highFive=kfiv, hug=khg, handsUp=khu, nod=knd, comeHere=kcmh, goodBoy=kgdb, cheers=kchr, pee=kpee, sniff=ksnf, check=kck, dig=kdg, angry=kang, scratch=kscrh, waveHead=kwh, beTable=ktbl, playDead=kpd, roll=krl, recover=krc, pushUp=kpu, pushUp1hand=kpu1, kick=kkc, leapOver=klpov, testServo=kts
4342- Acrobatic(⚠️high stress): handstand=khds, boxing=kbx, backflip=kflipD, frontflip=kflipF, jump=kjmp
4343- Arm: pickD/F/L/R=kpickD/F/L/R, putD/F/L/R=kputD/F/L/R, shoot=klaunch, throwF/L/R=ktossF/L/R, hunt=khunt, showOff=kshowOff, clap=kclap
4344- Direction suffix: append L=left, R=right, X=random to any skill for directional variants.
4345-
4346- IMPORTANT: ALWAYS use a single k* command for named actions. NEVER compose complex joint movements when a built-in skill exists. Command pattern: k + abbreviated name (e.g. handshake=khsk, hi=khi).
4347-
4348- I/O COMMANDS (UPPERCASE, MUST use encodeCommand):
4349- - Digital input: encodeCommand("Rd", [34]) for "Rd 34"
4350- - Analog input: encodeCommand("Ra", [34]) for "Ra 34"
4351- - Digital output: encodeCommand("Wd", [34, 1]) for "Wd 34 1"
4352- - Analog output: encodeCommand("Wa", [2, 128]) for "Wa 2 128"
4353-
4354- MUSIC COMMANDS - CRITICAL DISTINCTION:
4355- - SHORT melodies (1-10 notes): lowercase "b" + ASCII string - NO encodeCommand
4356- Example: await webRequest("b 14 4 16 4 18 2", 5000, true)
4357- LIMITATION: ASCII 'b' format has ~200 byte limit. Each "b 14 4" takes 6+ bytes.
4358-
4359- - LONG melodies (10+ notes, up to 1250 notes): UPPERCASE "B" + BINARY encoding - MUST use encodeCommand
4360- Example: const melody = encodeCommand("B", [14, 4, 16, 4, 18, 2, 14, 2]);
4361- await webRequest(melody, 30000, true);
4362- CAPACITY: NyBoard supports ~250 notes, BiBoard supports ~1250 notes in binary format
4363-
4364- - NOTES use numbers 0-35 (0 or -1 for silence, 14=middle C3, 26=middle C4)
4365- - DURATIONS: 1=1sec, 2=1/2sec, 4=1/4sec, 8=1/8sec, 16=1/16sec
4366- - For melodies >30 notes: ALWAYS use UPPERCASE B with encodeCommand, increase timeout to 30-60s
4367-
4368- SENSOR/JOINT COMMANDS (lowercase, NO encodeCommand):
4369- - Query joints: "j" or "j 0" for single joint
4370- - Gyro enable: encodeCommand("g", ["B"]) - special case, g is lowercase but uses encodeCommand
4371- - Gyro disable: encodeCommand("g", ["b"])
4372-
4373- EXTENSION COMMANDS (UPPERCASE X*, MUST use encodeCommand with ~ terminator):
4374- - Ultrasonic: encodeCommand("XU", [9, 9]) returns "XU 9 9~" (bytes format internally)
4375- - Camera activate: encodeCommand("XCr", []) returns "XCr~"
4376- - Camera poll: encodeCommand("XCP", []) returns "XCP~"
4377- - Gesture enable: encodeCommand("XGr", []) returns "XGr~"
4378- - Gesture poll: encodeCommand("XGp", []) returns "XGp~"
4379- - Gesture exit: encodeCommand("Xg", []) returns "Xg~"
4380-
4381- IMPORTANT ENCODING RULES:
4382- 1. LOWERCASE commands (k*, m, i, j, b for short melodies, d): Send directly as string, NO encodeCommand
4383- 2. UPPERCASE single letter (R, W, g with params B/b): Use encodeCommand(token, params)
4384- 3. UPPERCASE multi-letter (XU, XCr, XCP, XGr, XGp, Xg): Use encodeCommand(token, params), adds ~ automatically
4385- 4. MUSIC FORMAT RULES (CRITICAL):
4386- - Short (≤10 notes): await webRequest("b 14 4 16 4...", timeout, true) - ASCII format
4387- - Long (>10 notes): const m = encodeCommand("B", [14,4,16,4...]); await webRequest(m, 30000, true) - BINARY format
4388- - Note: UPPERCASE B uses binary encoding, supports 250-1250 notes vs 10-20 for lowercase b
4389- 5. When in doubt: Motion/short music use direct strings, I/O/sensors/long music use encodeCommand
4390-
4391- CRITICAL: WAITING FOR ROBOT TOKEN BEFORE NEXT COMMAND
4392- Every command MUST wait for the robot's completion token before executing the next command.
4393- Use the sendAndWait() helper which handles both Serial and WebSocket modes:
4394-
4395- // Helper: send command and wait for robot completion token
4396- async function sendAndWait(cmd, timeout, token) {
4397- const __from = (typeof serialBuffer === 'string')
4398- ? serialBuffer.length
4399- : ((typeof window !== 'undefined' && typeof window.serialBuffer === 'string') ? window.serialBuffer.length : undefined);
4400- await webRequest(cmd, timeout, true);
4401- if (!((typeof window !== 'undefined') && window.petoiClient) && typeof waitForSerialTokenLine === 'function') {
4402- await waitForSerialTokenLine(token, timeout, __from);
4403- }
4404- if (typeof window !== 'undefined') window.__lastTokenReceivedAt = Date.now();
4405- }
4406-
4407- // Helper: delay after token received (respects stop)
4408- async function delayAfterToken(ms) {
4409- const __tokenAt = (typeof window !== 'undefined' && typeof window.__lastTokenReceivedAt === 'number') ? window.__lastTokenReceivedAt : Date.now();
4410- const __endAt = __tokenAt + ms;
4411- while (Date.now() < __endAt) {
4412- checkStopExecution();
4413- const __wait = Math.min(100, __endAt - Date.now());
4414- if (__wait > 0) await new Promise(r => setTimeout(r, __wait));
4415- }
4416- }
4417-
4418- CODE PATTERNS (ALWAYS use sendAndWait for motion/action commands):
4419- // Motion gait (token: 'k'):
4420- await sendAndWait("kwkF", 20000, 'k');
4421-
4422- // Motion posture (token: first char of command, e.g. 'k' for kup, 'd' for rest):
4423- await sendAndWait("kup", 10000, 'k');
4424- await sendAndWait("d", 10000, 'd');
4425-
4426- // Motion with delay (delay starts AFTER robot completes):
4427- await sendAndWait("kup", 10000, 'k');
4428- await delayAfterToken(1000);
4429-
4430- // Acrobatic (token: 'k'):
4431- await sendAndWait("kbx", 20000, 'k');
4432-
4433- // Joint control - sequential (token: 'm'):
4434- await sendAndWait(encodeCommand("m", [0, 30, 1, -20]), 15000, 'm');
4435-
4436- // Joint control - simultaneous (token: 'i'):
4437- await sendAndWait(encodeCommand("i", [0, 30, 1, -20]), 30000, 'i');
4438-
4439- // Read sensor (token varies, use webRequest directly for queries):
4440- const cmd = encodeCommand("Ra", [34]);
4441- const result = await webRequest(cmd, 5000, true);
4442- const value = parseSingleResult(result);
4443-
4444- // Query all joints:
4445- const result = await webRequest("j", 5000, true);
4446- const angles = parseAllJointsResult(result);
4447-
4448- // Play short melody (token: 'b'):
4449- await sendAndWait("b 20 4", 5000, 'b');
4450-
4451- // Play long melody (token: 'B'):
4452- const melody = encodeCommand("B", [14,4,16,4,18,2,14,4,16,4,18,2,21,4,19,4,18,4,16,4,14,2]);
4453- await sendAndWait(melody, 30000, 'B');
4454-
4455- // Ultrasonic sensor:
4456- const cmd = encodeCommand("XU", [9, 9]);
4457- const result = await webRequest(cmd, 5000, true);
4458- const distance = parseSingleResult(result);
4459-
4460- // Gyro control:
4461- await sendAndWait(encodeCommand("g", ["B"]), 5000, 'G');
4462- await sendAndWait(encodeCommand("g", ["b"]), 5000, 'G');
4463-
4464- // Loop with stop checking:
4465- for (let i = 0; i < 5; i++) {
4466- await checkStopExecutionInLoop();
4467- await sendAndWait("kwkF", 20000, 'k');
4468- }
4469-
4470- // Multiple sequential actions (each waits for token before next):
4471- await sendAndWait("kup", 10000, 'k');
4472- await delayAfterToken(500);
4473- await sendAndWait("khi", 10000, 'k');
4474- await delayAfterToken(1000);
4475- await sendAndWait("ksit", 10000, 'k');
4476-
4477- Respond with ONLY executable JavaScript code, nothing else.` ;
4300+ const systemPrompt = `Petoi robot JS code generator. Output ONLY executable async JS, no markdown/comments.
4301+
4302+ HELPERS (already defined, just call them):
4303+ await sendAndWait(cmd,timeout,token) - send cmd, wait for robot token. MUST use for all motion.
4304+ await delayAfterToken(ms) - delay after robot completes. Use between actions.
4305+ checkStopExecution() - call in loops.
4306+ await webRequest(cmd,timeout,true) - for sensor queries.
4307+ encodeCommand(token,params) - for UPPERCASE cmds (Rd,Ra,Wd,Wa,XU,g,B,m,i).
4308+ parseSingleResult(r) / parseAllJointsResult(r) - parse responses.
4309+
4310+ SKILLS (k* cmds, send as string, token='k', rest d token='d'):
4311+ Posture: stand=kup,balance=kbalance,sit=ksit,rest=d,stretch=kstr,buttUp=kbuttUp,calib=kcalib
4312+ Gait: step=kvtF,spinL=kvtL,spinR=kvtR,walkF=kwkF,walkL=kwkL,walkR=kwkR,backF=kbkF,backL=kbkL,backR=kbkR,trotF=ktrF,trotL=ktrL,trotR=ktrR,crawlF=kcrF,crawlL=kcrL,crawlR=kcrR,strideF=kgpF,strideL=kgpL,strideR=kgpR,pushF=kphF,pushL=kphL,moonwalk=kmw
4313+ Behavior: hi=khi,handshake=khsk,highFive=kfiv,hug=khg,handsUp=khu,nod=knd,comeHere=kcmh,goodBoy=kgdb,cheers=kchr,pee=kpee,sniff=ksnf,check=kck,dig=kdg,angry=kang,scratch=kscrh,waveHead=kwh,beTable=ktbl,playDead=kpd,roll=krl,recover=krc,pushUp=kpu,pushUp1=kpu1,kick=kkc,leapOver=klpov
4314+ Acrobatic: handstand=khds,boxing=kbx,backflip=kflipD,frontflip=kflipF,jump=kjmp
4315+ Arm: pickD/F/L/R=kpickD/F/L/R,putD/F/L/R=kputD/F/L/R,shoot=klaunch,throwF/L/R=ktossF/L/R,hunt=khunt,showOff=kshowOff,clap=kclap
4316+ Suffix: L=left,R=right,X=random. Use k+abbreviation for unknown actions.
4317+
4318+ I/O: encodeCommand("Rd",[pin])/"Ra"/"Wd",[pin,val]/"Wa"
4319+ Music: short b "b 14 4 16 4",long encodeCommand("B",[14,4,16,4...]) Notes:0-35,Duration:1/2/4/8/16
4320+ Joints: "j"=query,encodeCommand("m",[id,angle,...])=seq,encodeCommand("i",[...])=sim
4321+ Sensor: encodeCommand("XU",[9,9])=ultrasonic,encodeCommand("g",["B"])=gyroOn,"g",["b"]=off
4322+ Gesture: encodeCommand("XGr",[])=enable,"XGp"=poll,"Xg"=exit
4323+
4324+ PATTERN: await sendAndWait("khi",10000,'k'); await delayAfterToken(500); await sendAndWait("khsk",10000,'k');
4325+ RULE: ALWAYS use built-in k* skill for named actions. NEVER compose joint movements for actions that have a skill command.` ;
44784326
44794327 const userPrompt = `Generate JavaScript code for: "${ description } "` ;
44804328 const fullPrompt = userPrompt ;
0 commit comments