Spaces:
Running
Running
Upload 10 files
Browse files- src/services/gemini.js +30 -9
- src/views/AdminView.js +2 -7
- src/views/InstructorView.js +19 -11
src/services/gemini.js
CHANGED
|
@@ -28,18 +28,39 @@ Rules:
|
|
| 28 |
|
| 29 |
// System Instructions for the Dashboard Analyst
|
| 30 |
const ANALYST_INSTRUCTION = `
|
| 31 |
-
You are an expert Prompt Engineer and Pedagogy Analyst.
|
| 32 |
-
Your task is to analyze a batch of student prompts for a specific
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 33 |
Categorize each prompt into ONE of these categories:
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 40 |
|
| 41 |
Return ONLY a JSON object mapping category names to arrays of Student IDs.
|
| 42 |
-
Example: { "rough": ["id1"], "precise": ["id2", "id5"], "spam": ["id3"]
|
| 43 |
`;
|
| 44 |
|
| 45 |
/**
|
|
|
|
| 28 |
|
| 29 |
// System Instructions for the Dashboard Analyst
|
| 30 |
const ANALYST_INSTRUCTION = `
|
| 31 |
+
You are an expert Prompt Engineer and Pedagogy Analyst for a coding/AI prompting class.
|
| 32 |
+
Your task is to analyze a batch of student prompts for a specific challenge.
|
| 33 |
+
|
| 34 |
+
You will receive:
|
| 35 |
+
1. The Challenge Description (the goal students are trying to achieve)
|
| 36 |
+
2. A list of Student Submissions (their prompts)
|
| 37 |
+
|
| 38 |
Categorize each prompt into ONE of these categories:
|
| 39 |
+
|
| 40 |
+
1. "rough" (原石): The student only says vague things like "fix the error" or "make it work" WITHOUT explaining:
|
| 41 |
+
- What the error is
|
| 42 |
+
- What the expected behavior should be
|
| 43 |
+
- Any specific details about the problem
|
| 44 |
+
These are "rough diamonds" - they tried but need to be more specific.
|
| 45 |
+
|
| 46 |
+
2. "precise" (精確): Clean, well-structured prompt that clearly states:
|
| 47 |
+
- The goal or expected result
|
| 48 |
+
- Specific details or parameters
|
| 49 |
+
- Clear logic or reasoning
|
| 50 |
+
|
| 51 |
+
3. "gentle" (有禮): Uses polite language like "請", "謝謝", "拜託", "Please", "Thank you"
|
| 52 |
+
|
| 53 |
+
4. "creative" (創意): Unconventional, imaginative approach. Uses interesting parameters or unexpected methods that still address the challenge.
|
| 54 |
+
|
| 55 |
+
5. "spam" (無效): Content that is clearly UNRELATED to the challenge topic. Compare with other submissions to identify outliers that don't match what most students are trying to do. Examples:
|
| 56 |
+
- Random characters ("asdf", "123")
|
| 57 |
+
- Completely off-topic text
|
| 58 |
+
- Empty or near-empty responses
|
| 59 |
+
|
| 60 |
+
6. "parrot" (鸚鵡): Direct copy-paste of the challenge description without any modification or personal attempt.
|
| 61 |
|
| 62 |
Return ONLY a JSON object mapping category names to arrays of Student IDs.
|
| 63 |
+
Example: { "rough": ["id1"], "precise": ["id2", "id5"], "spam": ["id3"] }
|
| 64 |
`;
|
| 65 |
|
| 66 |
/**
|
src/views/AdminView.js
CHANGED
|
@@ -87,13 +87,8 @@ export function setupAdminEvents() {
|
|
| 87 |
loadChallenges();
|
| 88 |
|
| 89 |
document.getElementById('back-instructor-btn').addEventListener('click', () => {
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
window.location.hash = 'instructor';
|
| 93 |
-
} else {
|
| 94 |
-
window.location.hash = ''; // Main landing
|
| 95 |
-
}
|
| 96 |
-
localStorage.removeItem('vibecoding_admin_referer');
|
| 97 |
});
|
| 98 |
|
| 99 |
document.getElementById('add-challenge-btn').addEventListener('click', () => {
|
|
|
|
| 87 |
loadChallenges();
|
| 88 |
|
| 89 |
document.getElementById('back-instructor-btn').addEventListener('click', () => {
|
| 90 |
+
// Always go back to instructor view since admin is only accessible from there
|
| 91 |
+
window.location.hash = 'instructor';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 92 |
});
|
| 93 |
|
| 94 |
document.getElementById('add-challenge-btn').addEventListener('click', () => {
|
src/views/InstructorView.js
CHANGED
|
@@ -1461,22 +1461,30 @@ export function setupInstructorEvents() {
|
|
| 1461 |
if (!confirm('確定要退回此題目讓學員重做嗎?')) return;
|
| 1462 |
|
| 1463 |
// We need student ID (userId) and Challenge ID.
|
| 1464 |
-
// Currently showBroadcastModal only receives nickname, title, prompt.
|
| 1465 |
-
// We need to attach data-userid and data-challengeid to the modal.
|
| 1466 |
const modal = document.getElementById('broadcast-modal');
|
| 1467 |
const userId = modal.dataset.userId;
|
| 1468 |
const challengeId = modal.dataset.challengeId;
|
| 1469 |
const roomCode = localStorage.getItem('vibecoding_instructor_room');
|
| 1470 |
|
| 1471 |
-
|
| 1472 |
-
|
| 1473 |
-
|
| 1474 |
-
|
| 1475 |
-
|
| 1476 |
-
|
| 1477 |
-
|
| 1478 |
-
|
| 1479 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1480 |
}
|
| 1481 |
});
|
| 1482 |
// Prompt Viewer Logic
|
|
|
|
| 1461 |
if (!confirm('確定要退回此題目讓學員重做嗎?')) return;
|
| 1462 |
|
| 1463 |
// We need student ID (userId) and Challenge ID.
|
|
|
|
|
|
|
| 1464 |
const modal = document.getElementById('broadcast-modal');
|
| 1465 |
const userId = modal.dataset.userId;
|
| 1466 |
const challengeId = modal.dataset.challengeId;
|
| 1467 |
const roomCode = localStorage.getItem('vibecoding_instructor_room');
|
| 1468 |
|
| 1469 |
+
console.log('Reject attempt:', { userId, challengeId, roomCode });
|
| 1470 |
+
|
| 1471 |
+
if (!userId || !challengeId) {
|
| 1472 |
+
alert('找不到學員或題目資料,請重新開啟作品');
|
| 1473 |
+
return;
|
| 1474 |
+
}
|
| 1475 |
+
if (!roomCode) {
|
| 1476 |
+
alert('未連接到教室,請先加入教室');
|
| 1477 |
+
return;
|
| 1478 |
+
}
|
| 1479 |
+
|
| 1480 |
+
try {
|
| 1481 |
+
await resetProgress(userId, roomCode, challengeId);
|
| 1482 |
+
alert('已成功退回,學員將需要重新作答');
|
| 1483 |
+
// Close modal
|
| 1484 |
+
window.closeBroadcast();
|
| 1485 |
+
} catch (e) {
|
| 1486 |
+
console.error(e);
|
| 1487 |
+
alert('退回失敗: ' + e.message);
|
| 1488 |
}
|
| 1489 |
});
|
| 1490 |
// Prompt Viewer Logic
|