assessmentarchitect / index.html
Hma47's picture
Update index.html
cdc177b verified
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AssessmentArchitect Pro - Intelligent Assessment Strategy Platform</title>
<style>
:root {
--primary: #ea580c;
--secondary: #f59e0b;
--accent: #fb923c;
--background: #f8fafc;
--surface: #ffffff;
--text: #1e293b;
--text-secondary: #64748b;
--border: #e2e8f0;
--success: #10b981;
--warning: #f59e0b;
--error: #dc2626;
--shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: linear-gradient(135deg, #f1f5f9 0%, #e2e8f0 100%);
color: var(--text);
line-height: 1.6;
min-height: 100vh;
padding: 15px;
transition: all 0.3s ease;
}
/* RTL Support */
[dir="rtl"] {
text-align: right;
}
[dir="rtl"] .container {
direction: rtl;
}
[dir="rtl"] .api-key-section {
margin: 15px 15px 15px auto;
}
[dir="rtl"] .language-switcher {
right: auto;
left: 15px;
}
/* Language Selection Landing */
.language-landing {
display: block;
max-width: 800px;
margin: 50px auto;
background: var(--surface);
border-radius: 16px;
box-shadow: var(--shadow-lg);
padding: 40px;
text-align: center;
}
.language-landing h1 {
font-size: 2.5rem;
font-weight: 800;
background: linear-gradient(135deg, var(--primary) 0%, var(--secondary) 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
margin-bottom: 15px;
}
.language-landing p {
font-size: 1.1rem;
color: var(--text-secondary);
margin-bottom: 30px;
}
.language-selector {
margin-bottom: 25px;
}
.language-selector label {
display: block;
margin-bottom: 10px;
font-weight: 600;
color: var(--text);
font-size: 1.1rem;
}
.language-selector select {
width: 100%;
padding: 15px 20px;
border: 2px solid var(--border);
border-radius: 12px;
font-size: 1.1rem;
font-family: inherit;
background: var(--surface);
transition: all 0.2s ease;
margin-bottom: 20px;
}
.language-selector select:focus {
outline: none;
border-color: var(--primary);
box-shadow: 0 0 0 3px rgba(234, 88, 12, 0.1);
}
.api-key-landing {
margin-bottom: 25px;
}
.api-key-landing label {
display: block;
margin-bottom: 10px;
font-weight: 600;
color: var(--text);
font-size: 1.1rem;
}
.api-key-landing input {
width: 100%;
padding: 15px 20px;
border: 2px solid var(--border);
border-radius: 12px;
font-size: 1.1rem;
background: var(--surface);
transition: all 0.2s ease;
font-family: 'Courier New', monospace;
}
.api-key-landing input:focus {
outline: none;
border-color: var(--primary);
box-shadow: 0 0 0 3px rgba(234, 88, 12, 0.1);
}
.start-btn {
background: linear-gradient(135deg, var(--primary) 0%, var(--secondary) 100%);
color: white;
padding: 18px 40px;
border: none;
border-radius: 12px;
font-size: 1.2rem;
font-weight: 700;
cursor: pointer;
transition: all 0.3s ease;
width: 100%;
margin-bottom: 20px;
}
.start-btn:hover {
transform: translateY(-2px);
box-shadow: 0 12px 24px -8px rgba(234, 88, 12, 0.4);
}
.start-btn:disabled {
opacity: 0.7;
cursor: not-allowed;
transform: none;
}
/* Cache Management Section */
.cache-management {
background: rgba(234, 88, 12, 0.05);
border: 1px solid rgba(234, 88, 12, 0.1);
border-radius: 12px;
padding: 20px;
margin-top: 20px;
}
.cache-management h3 {
color: var(--primary);
font-size: 1.1rem;
font-weight: 700;
margin-bottom: 15px;
text-align: center;
}
.cache-status {
background: rgba(16, 185, 129, 0.1);
border: 1px solid rgba(16, 185, 129, 0.2);
color: var(--success);
padding: 12px 16px;
border-radius: 8px;
margin-bottom: 15px;
font-size: 0.9rem;
text-align: center;
font-weight: 500;
}
.cache-status.no-cache {
background: rgba(156, 163, 175, 0.1);
border: 1px solid rgba(156, 163, 175, 0.2);
color: var(--text-secondary);
}
.clear-cache-btn {
background: linear-gradient(135deg, var(--warning) 0%, #f59e0b 100%);
color: white;
padding: 12px 24px;
border: none;
border-radius: 8px;
font-size: 1rem;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
width: 100%;
}
.clear-cache-btn:hover {
transform: translateY(-1px);
box-shadow: 0 8px 16px -4px rgba(245, 158, 11, 0.4);
}
.clear-cache-btn:active {
transform: translateY(0);
}
/* Translation Loading Overlay */
.translation-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(234, 88, 12, 0.9);
display: none;
justify-content: center;
align-items: center;
z-index: 10000;
color: white;
text-align: center;
}
.translation-content {
background: rgba(255, 255, 255, 0.1);
padding: 40px;
border-radius: 16px;
backdrop-filter: blur(10px);
max-width: 400px;
width: 90%;
}
.translation-spinner {
width: 50px;
height: 50px;
border: 4px solid rgba(255, 255, 255, 0.3);
border-radius: 50%;
border-top-color: white;
animation: spin 1s ease-in-out infinite;
margin: 0 auto 20px;
}
.translation-progress {
background: rgba(255, 255, 255, 0.2);
border-radius: 10px;
height: 8px;
margin: 20px 0;
overflow: hidden;
}
.translation-progress-bar {
background: white;
height: 100%;
width: 0%;
transition: width 0.3s ease;
}
/* Main Application (Hidden Initially) */
.main-app {
display: none;
}
.container {
max-width: 1200px;
margin: 0 auto;
background: var(--surface);
border-radius: 16px;
box-shadow: var(--shadow-lg);
overflow: hidden;
position: relative;
}
/* API Key Section - Static Position Top Left */
.api-key-section {
background: rgba(234, 88, 12, 0.05);
border: 1px solid rgba(234, 88, 12, 0.1);
border-radius: 8px;
padding: 12px;
margin: 15px;
max-width: 280px;
}
.api-key-section label {
font-size: 12px;
font-weight: 600;
color: var(--primary);
margin-bottom: 6px;
display: block;
}
.api-key-section input {
width: 100%;
padding: 8px 12px;
border: 1px solid var(--border);
border-radius: 6px;
font-size: 14px;
background: var(--surface);
transition: all 0.2s ease;
font-family: 'Courier New', monospace;
}
.api-key-section input:focus {
outline: none;
border-color: var(--primary);
box-shadow: 0 0 0 3px rgba(234, 88, 12, 0.1);
}
/* Language Switcher in Main App */
.language-switcher {
position: absolute;
top: 15px;
right: 15px;
display: flex;
gap: 10px;
align-items: center;
z-index: 100;
}
.language-switcher select {
background: rgba(234, 88, 12, 0.05);
border: 1px solid rgba(234, 88, 12, 0.1);
border-radius: 8px;
padding: 8px 12px;
font-size: 12px;
cursor: pointer;
transition: all 0.2s ease;
}
.language-switcher select:hover {
background: rgba(234, 88, 12, 0.1);
}
.clear-cache-mini {
background: var(--warning);
color: white;
border: none;
padding: 6px 12px;
border-radius: 4px;
font-size: 0.8rem;
cursor: pointer;
transition: all 0.2s ease;
}
.clear-cache-mini:hover {
background: #d97706;
}
/* Main Content */
.main-content {
padding: 20px 30px 30px;
}
/* Header */
.header {
text-align: center;
margin-bottom: 25px;
padding-bottom: 20px;
border-bottom: 2px solid var(--border);
}
.header h1 {
font-size: 2.5rem;
font-weight: 800;
background: linear-gradient(135deg, var(--primary) 0%, var(--secondary) 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
margin-bottom: 8px;
}
.header .subtitle {
font-size: 1.1rem;
color: var(--text-secondary);
font-weight: 500;
}
.header .description {
font-size: 1rem;
color: var(--text-secondary);
margin-top: 12px;
max-width: 700px;
margin-left: auto;
margin-right: auto;
}
/* Configuration Section */
.config-section {
background: var(--surface);
border-radius: 16px;
padding: 25px;
box-shadow: var(--shadow);
margin-bottom: 25px;
transition: all 0.3s ease;
}
.config-section:hover {
box-shadow: var(--shadow-lg);
}
.config-item {
display: flex;
flex-direction: column;
}
.config-label {
font-size: 0.875rem;
font-weight: 600;
color: var(--text);
margin-bottom: 8px;
}
.config-select,
.config-textarea {
padding: 12px;
border: 2px solid var(--border);
border-radius: 8px;
font-size: 0.875rem;
font-family: inherit;
background: var(--background);
color: var(--text);
transition: all 0.2s ease;
}
.config-select:focus,
.config-textarea:focus {
outline: none;
border-color: var(--primary);
box-shadow: 0 0 0 3px rgba(234, 88, 12, 0.1);
}
.config-textarea {
resize: vertical;
min-height: 80px;
}
/* Questions Section */
.questions-section {
background: var(--surface);
border-radius: 16px;
padding: 30px;
box-shadow: var(--shadow);
margin-bottom: 25px;
transition: all 0.3s ease;
}
.questions-section:hover {
box-shadow: var(--shadow-lg);
}
.section-title {
font-size: 1.5rem;
font-weight: 600;
color: var(--text);
margin-bottom: 25px;
text-align: center;
position: relative;
}
.section-title::after {
content: '';
position: absolute;
bottom: -8px;
left: 50%;
transform: translateX(-50%);
width: 60px;
height: 3px;
background: linear-gradient(90deg, var(--primary), var(--secondary));
border-radius: 2px;
}
.question-item {
margin-bottom: 25px;
padding: 20px;
background: var(--background);
border-radius: 12px;
border: 1px solid var(--border);
transition: all 0.3s ease;
}
.question-item:hover {
border-color: var(--accent);
box-shadow: var(--shadow);
}
.question-number {
display: inline-flex;
align-items: center;
justify-content: center;
width: 32px;
height: 32px;
background: linear-gradient(135deg, var(--primary), var(--secondary));
color: white;
border-radius: 50%;
font-weight: 600;
font-size: 0.875rem;
margin-right: 12px;
flex-shrink: 0;
}
[dir="rtl"] .question-number {
margin-right: 0;
margin-left: 12px;
}
.question-label {
display: flex;
align-items: flex-start;
font-size: 1rem;
font-weight: 600;
color: var(--text);
margin-bottom: 15px;
line-height: 1.4;
}
.question-textarea {
width: 100%;
min-height: 80px;
padding: 15px;
border: 2px solid var(--border);
border-radius: 12px;
font-size: 1rem;
font-family: inherit;
background: var(--surface);
color: var(--text);
transition: all 0.2s ease;
resize: vertical;
}
.question-textarea:focus {
outline: none;
border-color: var(--primary);
box-shadow: 0 0 0 3px rgba(234, 88, 12, 0.1);
}
.question-textarea::placeholder {
color: var(--text-secondary);
}
/* Generate Button */
.generate-section {
text-align: center;
margin-bottom: 25px;
}
.generate-button {
display: inline-flex;
align-items: center;
gap: 12px;
padding: 18px 40px;
font-size: 1.125rem;
font-weight: 600;
color: white;
background: linear-gradient(135deg, var(--primary), var(--secondary));
border: none;
border-radius: 12px;
cursor: pointer;
transition: all 0.3s ease;
box-shadow: var(--shadow);
position: relative;
overflow: hidden;
min-width: 320px;
}
.generate-button:hover:not(:disabled) {
transform: translateY(-2px);
box-shadow: 0 12px 24px -8px rgba(234, 88, 12, 0.4);
}
.generate-button:active {
transform: translateY(0);
}
.generate-button:disabled {
opacity: 0.7;
cursor: not-allowed;
transform: none;
}
.button-text {
transition: opacity 0.2s ease;
}
.loading-spinner {
display: none;
width: 20px;
height: 20px;
border: 2px solid rgba(255, 255, 255, 0.3);
border-top: 2px solid white;
border-radius: 50%;
animation: spin 1s linear infinite;
}
[dir="rtl"] .loading-spinner {
margin-right: 0;
margin-left: 8px;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
/* Progress Bar */
.progress-container {
width: 100%;
height: 8px;
background: var(--border);
border-radius: 4px;
overflow: hidden;
margin-top: 15px;
}
.progress-bar {
height: 100%;
background: linear-gradient(90deg, var(--primary), var(--secondary));
width: 0%;
transition: width 0.3s ease;
border-radius: 4px;
}
/* Output Section */
.output-section {
background: var(--surface);
border-radius: 16px;
padding: 30px;
box-shadow: var(--shadow);
transition: all 0.3s ease;
}
.output-section:hover {
box-shadow: var(--shadow-lg);
}
.output-content {
background: var(--background);
border: 2px solid var(--border);
border-radius: 12px;
padding: 20px;
min-height: 200px;
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
font-size: 0.875rem;
line-height: 1.6;
color: var(--text);
white-space: pre-wrap;
word-wrap: break-word;
max-height: 600px;
overflow-y: auto;
transition: all 0.2s ease;
}
.output-content:focus {
outline: none;
border-color: var(--primary);
box-shadow: 0 0 0 3px rgba(234, 88, 12, 0.1);
}
.output-content:empty::before {
content: attr(data-placeholder);
color: var(--text-secondary);
font-style: italic;
font-family: inherit;
}
/* Error Messages */
.error-message {
background: rgba(220, 38, 38, 0.1);
border: 1px solid rgba(220, 38, 38, 0.2);
color: var(--error);
padding: 12px 16px;
border-radius: 8px;
margin: 10px 0;
font-size: 0.9rem;
display: none;
}
/* Status Messages */
.status-message {
background: rgba(234, 88, 12, 0.1);
border: 1px solid rgba(234, 88, 12, 0.2);
color: var(--primary);
padding: 12px 16px;
border-radius: 8px;
margin: 10px 0;
font-size: 0.9rem;
text-align: center;
font-weight: 500;
display: none;
}
/* Hidden sections */
.hidden {
display: none !important;
}
/* Footer */
.footer {
text-align: center;
padding: 20px;
background: rgba(234, 88, 12, 0.05);
border-top: 1px solid var(--border);
color: var(--text-secondary);
font-size: 0.9rem;
}
/* Responsive Design */
@media (max-width: 768px) {
body {
padding: 10px;
}
.language-landing {
margin: 20px auto;
padding: 30px 20px;
}
.api-key-section {
margin: 10px;
max-width: none;
}
.main-content {
padding: 15px 20px 20px;
}
.header h1 {
font-size: 2rem;
}
.config-section,
.questions-section,
.output-section {
padding: 20px 15px;
}
.question-item {
padding: 15px;
}
.question-label {
flex-direction: column;
align-items: flex-start;
gap: 8px;
}
.question-number {
margin-right: 0;
margin-bottom: 8px;
}
.generate-button {
width: 100%;
margin: 25px 0;
padding: 16px 32px;
font-size: 1.1rem;
}
.language-switcher {
position: static;
text-align: center;
margin-bottom: 20px;
flex-direction: column;
gap: 10px;
}
}
@media (max-width: 480px) {
.language-landing h1 {
font-size: 2rem;
}
.header h1 {
font-size: 1.8rem;
}
}
/* Dark mode support */
@media (prefers-color-scheme: dark) {
:root {
--background: #0f172a;
--surface: #1e293b;
--text: #f1f5f9;
--text-secondary: #94a3b8;
--border: #334155;
}
body {
background: linear-gradient(135deg, #0f172a 0%, #1e293b 100%);
}
}
</style>
</head>
<body>
<!-- Translation Loading Overlay -->
<div class="translation-overlay" id="translationOverlay">
<div class="translation-content">
<div class="translation-spinner"></div>
<h2 id="translationTitle">Translating Interface...</h2>
<p id="translationMessage">Please wait while we translate the interface to your selected language.</p>
<div class="translation-progress">
<div class="translation-progress-bar" id="translationProgressBar"></div>
</div>
<p id="translationProgress">0%</p>
</div>
</div>
<!-- Language Selection Landing Page -->
<div class="language-landing" id="languageLanding">
<h1 data-translate="app_title">AssessmentArchitect Pro</h1>
<p data-translate="welcome_message">Welcome! Please select your preferred language and enter your API key to get started with intelligent assessment strategy building.</p>
<div class="language-selector">
<label for="languageSelect" data-translate="select_language">🌐 Select Language</label>
<select id="languageSelect">
<option value="en">🇺🇸 English</option>
<option value="es">🇪🇸 Español (Spanish)</option>
<option value="fr">🇫🇷 Français (French)</option>
<option value="de">🇩🇪 Deutsch (German)</option>
<option value="it">🇮🇹 Italiano (Italian)</option>
<option value="pt">🇵🇹 Português (Portuguese)</option>
<option value="ru">🇷🇺 Русский (Russian)</option>
<option value="ja">🇯🇵 日本語 (Japanese)</option>
<option value="ko">🇰🇷 한국어 (Korean)</option>
<option value="zh">🇨🇳 中文 (Chinese)</option>
<option value="ar">🇸🇦 العربية (Arabic)</option>
<option value="hi">🇮🇳 हिन्दी (Hindi)</option>
<option value="bn">🇧🇩 বাংলা (Bengali)</option>
<option value="ur">🇵🇰 اردو (Urdu)</option>
<option value="tr">🇹🇷 Türkçe (Turkish)</option>
<option value="pl">🇵🇱 Polski (Polish)</option>
<option value="nl">🇳🇱 Nederlands (Dutch)</option>
<option value="sv">🇸🇪 Svenska (Swedish)</option>
<option value="da">🇩🇰 Dansk (Danish)</option>
<option value="no">🇳🇴 Norsk (Norwegian)</option>
<option value="fi">🇫🇮 Suomi (Finnish)</option>
<option value="cs">🇨🇿 Čeština (Czech)</option>
<option value="hu">🇭🇺 Magyar (Hungarian)</option>
<option value="ro">🇷🇴 Română (Romanian)</option>
<option value="bg">🇧🇬 Български (Bulgarian)</option>
<option value="hr">🇭🇷 Hrvatski (Croatian)</option>
<option value="sr">🇷🇸 Српски (Serbian)</option>
<option value="sk">🇸🇰 Slovenčina (Slovak)</option>
<option value="sl">🇸🇮 Slovenščina (Slovenian)</option>
<option value="et">🇪🇪 Eesti (Estonian)</option>
<option value="lv">🇱🇻 Latviešu (Latvian)</option>
<option value="lt">🇱🇹 Lietuvių (Lithuanian)</option>
<option value="el">🇬🇷 Ελληνικά (Greek)</option>
<option value="he">🇮🇱 עברית (Hebrew)</option>
<option value="th">🇹🇭 ไทย (Thai)</option>
<option value="vi">🇻🇳 Tiếng Việt (Vietnamese)</option>
<option value="km">🇰🇭 ខ្មែរ (Khmer)</option>
<option value="my">🇲🇲 မြန်မာ (Myanmar)</option>
<option value="ta">🇮🇳 தமிழ் (Tamil)</option>
<option value="te">🇮🇳 తెలుగు (Telugu)</option>
<option value="kn">🇮🇳 ಕನ್ನಡ (Kannada)</option>
<option value="ml">🇮🇳 മലയാളം (Malayalam)</option>
<option value="gu">🇮🇳 ગુજરાતી (Gujarati)</option>
<option value="pa">🇮🇳 ਪੰਜਾਬੀ (Punjabi)</option>
<option value="ne">🇳🇵 नेपाली (Nepali)</option>
<option value="si">🇱🇰 සිංහල (Sinhala)</option>
<option value="id">🇮🇩 Bahasa Indonesia</option>
<option value="ms">🇲🇾 Bahasa Melayu (Malay)</option>
<option value="tl">🇵🇭 Filipino</option>
<option value="sw">🇰🇪 Kiswahili (Swahili)</option>
<option value="zu">🇿🇦 isiZulu (Zulu)</option>
<option value="xh">🇿🇦 isiXhosa (Xhosa)</option>
<option value="af">🇿🇦 Afrikaans</option>
<option value="am">🇪🇹 አማርኛ (Amharic)</option>
<option value="ha">🇳🇬 Hausa</option>
<option value="yo">🇳🇬 Yorùbá (Yoruba)</option>
<option value="ig">🇳🇬 Igbo</option>
<option value="so">🇸🇴 Soomaali (Somali)</option>
<option value="rw">🇷🇼 Kinyarwanda</option>
<option value="ny">🇲🇼 Chichewa</option>
<option value="mg">🇲🇬 Malagasy</option>
<option value="sn">🇿🇼 Shona</option>
<option value="st">🇱🇸 Sesotho</option>
<option value="tn">🇧🇼 Setswana</option>
<option value="ts">🇿🇦 Xitsonga</option>
<option value="ve">🇿🇦 Tshivenda</option>
<option value="ss">🇸🇿 SiSwati</option>
<option value="nr">🇿🇦 isiNdebele</option>
<option value="fa">🇮🇷 فارسی (Persian)</option>
<option value="ps">🇦🇫 پښتو (Pashto)</option>
<option value="ku">🇮🇶 کوردی (Kurdish)</option>
<option value="sd">🇵🇰 سنڌي (Sindhi)</option>
<option value="ug">🇨🇳 ئۇيغۇرچە (Uyghur)</option>
<option value="kk">🇰🇿 Қазақша (Kazakh)</option>
<option value="ky">🇰🇬 Кыргызча (Kyrgyz)</option>
<option value="uz">🇺🇿 O'zbekcha (Uzbek)</option>
<option value="tg">🇹🇯 Тоҷикӣ (Tajik)</option>
<option value="tk">🇹🇲 Türkmençe (Turkmen)</option>
<option value="mn">🇲🇳 Монгол (Mongolian)</option>
<option value="bo">🇨🇳 བོད་ཡིག (Tibetan)</option>
<option value="dz">🇧🇹 རྫོང་ཁ (Dzongkha)</option>
<option value="lo">🇱🇦 ລາວ (Lao)</option>
<option value="ka">🇬🇪 ქართული (Georgian)</option>
<option value="hy">🇦🇲 Հայերեն (Armenian)</option>
<option value="az">🇦🇿 Azərbaycan (Azerbaijani)</option>
<option value="be">🇧🇾 Беларуская (Belarusian)</option>
<option value="uk">🇺🇦 Українська (Ukrainian)</option>
<option value="mk">🇲🇰 Македонски (Macedonian)</option>
<option value="sq">🇦🇱 Shqip (Albanian)</option>
<option value="mt">🇲🇹 Malti (Maltese)</option>
<option value="is">🇮🇸 Íslenska (Icelandic)</option>
<option value="fo">🇫🇴 Føroyskt (Faroese)</option>
<option value="ga">🇮🇪 Gaeilge (Irish)</option>
<option value="gd">🏴󠁧󠁢󠁳󠁣󠁴󠁿 Gàidhlig (Scottish Gaelic)</option>
<option value="cy">🏴󠁧󠁢󠁷󠁬󠁳󠁿 Cymraeg (Welsh)</option>
<option value="br">🇫🇷 Brezhoneg (Breton)</option>
<option value="eu">🇪🇸 Euskera (Basque)</option>
<option value="ca">🇪🇸 Català (Catalan)</option>
<option value="gl">🇪🇸 Galego (Galician)</option>
<option value="oc">🇫🇷 Occitan</option>
<option value="co">🇫🇷 Corsu (Corsican)</option>
<option value="sc">🇮🇹 Sardu (Sardinian)</option>
<option value="rm">🇨🇭 Rumantsch (Romansh)</option>
<option value="lb">🇱🇺 Lëtzebuergesch (Luxembourgish)</option>
<option value="fy">🇳🇱 Frysk (Frisian)</option>
</select>
</div>
<div class="api-key-landing">
<label for="apiKeyLanding" data-translate="api_key_label">🔑 OpenAI API Key</label>
<input type="password" id="apiKeyLanding" placeholder="Enter your OpenAI API key" data-translate-placeholder="api_key_placeholder">
</div>
<button class="start-btn" id="startBtn" data-translate="start_button">🚀 Start Assessment Builder</button>
<!-- Cache Management Section -->
<div class="cache-management">
<h3>🗄️ Translation Cache Management</h3>
<div class="cache-status" id="cacheStatusDisplay">
💾 No cached translations found
</div>
<button class="clear-cache-btn" id="clearCacheBtn" onclick="clearAllTranslationCache()">
🗑️ Clear Translation Cache
</button>
</div>
</div>
<!-- Main Application -->
<div class="main-app" id="mainApp">
<div class="container">
<!-- Language Switcher -->
<div class="language-switcher">
<select id="languageSwitcher" onchange="switchLanguage()">
<option value="en">🇺🇸 English</option>
</select>
<button class="clear-cache-mini" onclick="clearAllTranslationCache()" title="Clear Translation Cache">
🗑️ Clear Cache
</button>
</div>
<!-- API Key Section - Static Position Top Left -->
<div class="api-key-section">
<label for="apiKey" data-translate="api_key_short">🔑 API Key</label>
<input type="password" id="apiKey" data-translate-placeholder="api_key_placeholder" autocomplete="off">
</div>
<div class="main-content">
<!-- Header -->
<div class="header">
<h1 data-translate="app_title">AssessmentArchitect Pro</h1>
<p class="subtitle" data-translate="app_subtitle">Intelligent Assessment Strategy Platform</p>
<p class="description" data-translate="app_description">Design comprehensive, effective assessment strategies through guided questions and AI-powered insights. Create assessments that measure learning objectives, accommodate diverse needs, and drive educational excellence.</p>
</div>
<!-- Configuration Section -->
<section class="config-section">
<div class="config-item">
<label for="additionalContext" class="config-label" data-translate="additional_context_label">Additional Context (Optional)</label>
<textarea
id="additionalContext"
class="config-textarea"
data-translate-placeholder="additional_context_placeholder"
></textarea>
</div>
</section>
<!-- Questions Section -->
<section class="questions-section">
<h2 class="section-title" data-translate="questions_section_title">Assessment Strategy Questions</h2>
<div class="question-item">
<label for="q1" class="question-label">
<span class="question-number">1</span>
<span data-translate="question_1">What are the clear learning objectives for this assessment?</span>
</label>
<textarea
id="q1"
class="question-textarea"
data-translate-placeholder="question_1_placeholder"
required
></textarea>
</div>
<div class="question-item">
<label for="q2" class="question-label">
<span class="question-number">2</span>
<span data-translate="question_2">How does this assessment align with real-world scenarios and challenges?</span>
</label>
<textarea
id="q2"
class="question-textarea"
data-translate-placeholder="question_2_placeholder"
required
></textarea>
</div>
<div class="question-item">
<label for="q3" class="question-label">
<span class="question-number">3</span>
<span data-translate="question_3">Does the assessment measure both breadth and depth of student knowledge?</span>
</label>
<textarea
id="q3"
class="question-textarea"
data-translate-placeholder="question_3_placeholder"
required
></textarea>
</div>
<div class="question-item">
<label for="q4" class="question-label">
<span class="question-number">4</span>
<span data-translate="question_4">What mix of question types will best evaluate student understanding?</span>
</label>
<textarea
id="q4"
class="question-textarea"
data-translate-placeholder="question_4_placeholder"
required
></textarea>
</div>
<div class="question-item">
<label for="q5" class="question-label">
<span class="question-number">5</span>
<span data-translate="question_5">How will this assessment provide opportunities for student feedback and reflection?</span>
</label>
<textarea
id="q5"
class="question-textarea"
data-translate-placeholder="question_5_placeholder"
required
></textarea>
</div>
<div class="question-item">
<label for="q6" class="question-label">
<span class="question-number">6</span>
<span data-translate="question_6">Is the assessment designed to accommodate different learning needs and preferences?</span>
</label>
<textarea
id="q6"
class="question-textarea"
data-translate-placeholder="question_6_placeholder"
required
></textarea>
</div>
<div class="question-item">
<label for="q7" class="question-label">
<span class="question-number">7</span>
<span data-translate="question_7">How will the assessment results be used to inform and improve teaching practices?</span>
</label>
<textarea
id="q7"
class="question-textarea"
data-translate-placeholder="question_7_placeholder"
required
></textarea>
</div>
<div class="question-item">
<label for="q8" class="question-label">
<span class="question-number">8</span>
<span data-translate="question_8">Does the assessment strategy include both formative and summative components?</span>
</label>
<textarea
id="q8"
class="question-textarea"
data-translate-placeholder="question_8_placeholder"
required
></textarea>
</div>
<div class="question-item">
<label for="q9" class="question-label">
<span class="question-number">9</span>
<span data-translate="question_9">How will the assessment measure higher-order thinking skills and critical reasoning?</span>
</label>
<textarea
id="q9"
class="question-textarea"
data-translate-placeholder="question_9_placeholder"
required
></textarea>
</div>
<div class="question-item">
<label for="q10" class="question-label">
<span class="question-number">10</span>
<span data-translate="question_10">What methods will be used to ensure the assessment is fair, valid, and reliable?</span>
</label>
<textarea
id="q10"
class="question-textarea"
data-translate-placeholder="question_10_placeholder"
required
></textarea>
</div>
</section>
<!-- Generate Button -->
<section class="generate-section">
<button id="generateStrategyBtn" class="generate-button">
<span class="button-text" data-translate="generate_button">🎯 Generate Assessment Strategy</span>
<div class="loading-spinner" id="loadingSpinner"></div>
</button>
<div class="progress-container">
<div class="progress-bar" id="strategyProgress"></div>
</div>
</section>
<!-- Output Section -->
<section class="output-section">
<h2 class="section-title" data-translate="output_section_title">Generated Assessment Strategy</h2>
<div class="output-content" id="strategyOutput" contenteditable="true" data-translate="output_placeholder" data-placeholder="Your comprehensive assessment strategy will appear here..."></div>
</section>
<!-- Error and Status Messages -->
<div class="error-message" id="errorMessage"></div>
<div class="status-message" id="statusMessage"></div>
</div>
<!-- Footer -->
<div class="footer">
Created by Shift Mind AI Labs
</div>
</div>
</div>
<script>
// Global variables
let currentLanguage = 'en';
let translationCache = {};
let isTranslating = false;
// RTL languages list
const rtlLanguages = ['ar', 'he', 'fa', 'ur', 'ps', 'ku', 'sd', 'ug'];
// Language names mapping
const languageNames = {
'en': 'English', 'es': 'Spanish', 'fr': 'French', 'de': 'German', 'it': 'Italian',
'pt': 'Portuguese', 'ru': 'Russian', 'ja': 'Japanese', 'ko': 'Korean', 'zh': 'Chinese',
'ar': 'Arabic', 'hi': 'Hindi', 'bn': 'Bengali', 'ur': 'Urdu', 'tr': 'Turkish',
'pl': 'Polish', 'nl': 'Dutch', 'sv': 'Swedish', 'da': 'Danish', 'no': 'Norwegian',
'fi': 'Finnish', 'cs': 'Czech', 'hu': 'Hungarian', 'ro': 'Romanian', 'bg': 'Bulgarian',
'hr': 'Croatian', 'sr': 'Serbian', 'sk': 'Slovak', 'sl': 'Slovenian', 'et': 'Estonian',
'lv': 'Latvian', 'lt': 'Lithuanian', 'el': 'Greek', 'he': 'Hebrew', 'th': 'Thai',
'vi': 'Vietnamese', 'km': 'Khmer', 'my': 'Myanmar', 'ta': 'Tamil', 'te': 'Telugu',
'kn': 'Kannada', 'ml': 'Malayalam', 'gu': 'Gujarati', 'pa': 'Punjabi', 'ne': 'Nepali',
'si': 'Sinhala', 'id': 'Indonesian', 'ms': 'Malay', 'tl': 'Filipino', 'sw': 'Swahili',
'zu': 'Zulu', 'xh': 'Xhosa', 'af': 'Afrikaans', 'am': 'Amharic', 'ha': 'Hausa',
'yo': 'Yoruba', 'ig': 'Igbo', 'so': 'Somali', 'rw': 'Kinyarwanda', 'ny': 'Chichewa',
'mg': 'Malagasy', 'sn': 'Shona', 'st': 'Sesotho', 'tn': 'Setswana', 'ts': 'Xitsonga',
've': 'Tshivenda', 'ss': 'SiSwati', 'nr': 'isiNdebele', 'fa': 'Persian', 'ps': 'Pashto',
'ku': 'Kurdish', 'sd': 'Sindhi', 'ug': 'Uyghur', 'kk': 'Kazakh', 'ky': 'Kyrgyz',
'uz': 'Uzbek', 'tg': 'Tajik', 'tk': 'Turkmen', 'mn': 'Mongolian', 'bo': 'Tibetan',
'dz': 'Dzongkha', 'lo': 'Lao', 'ka': 'Georgian', 'hy': 'Armenian', 'az': 'Azerbaijani',
'be': 'Belarusian', 'uk': 'Ukrainian', 'mk': 'Macedonian', 'sq': 'Albanian', 'mt': 'Maltese',
'is': 'Icelandic', 'fo': 'Faroese', 'ga': 'Irish', 'gd': 'Scottish Gaelic', 'cy': 'Welsh',
'br': 'Breton', 'eu': 'Basque', 'ca': 'Catalan', 'gl': 'Galician', 'oc': 'Occitan',
'co': 'Corsican', 'sc': 'Sardinian', 'rm': 'Romansh', 'lb': 'Luxembourgish', 'fy': 'Frisian'
};
// Current API key
let currentApiKey = '';
// App Configuration
const AppConfig = {
API_BASE_URL: 'https://api.openai.com/v1/chat/completions',
MODEL: 'gpt-4o-mini',
MAX_TOKENS: 3000,
TEMPERATURE: 0.7
};
// App State Management
const AppState = {
apiKey: '',
isGenerating: false,
currentStrategy: '',
setApiKey(key) {
this.apiKey = key;
this.saveToLocalStorage();
},
setGenerating(generating) {
this.isGenerating = generating;
UIController.updateGeneratingState(generating);
},
saveToLocalStorage() {
try {
localStorage.setItem('assessmentarchitect_apiKey', this.apiKey);
} catch (e) {
console.warn('Could not save to localStorage:', e);
}
},
loadFromLocalStorage() {
try {
this.apiKey = localStorage.getItem('assessmentarchitect_apiKey') || '';
} catch (e) {
console.warn('Could not load from localStorage:', e);
}
}
};
// Initialize the application
function initializeApp() {
// Load saved language and API key
const savedLanguage = localStorage.getItem('assessmentarchitect_language') || 'en';
const savedApiKey = localStorage.getItem('assessmentarchitect_api_key') || '';
currentLanguage = savedLanguage;
currentApiKey = savedApiKey;
// Set language selector
document.getElementById('languageSelect').value = currentLanguage;
document.getElementById('apiKeyLanding').value = currentApiKey;
// Load translation cache
const cached = localStorage.getItem('assessmentarchitect_translations');
if (cached) {
translationCache = JSON.parse(cached);
}
// Apply direction for current language
applyDirection(currentLanguage);
// Update cache status
updateCacheStatus();
// Show appropriate screen
if (currentApiKey && currentLanguage) {
showMainApp();
} else {
showLanguageLanding();
}
}
// Update cache status display
function updateCacheStatus() {
const cacheStatusDisplay = document.getElementById('cacheStatusDisplay');
const cachedLanguages = Object.keys(translationCache).map(key => key.replace('assessmentarchitect_', ''));
if (cachedLanguages.length > 0) {
cacheStatusDisplay.classList.remove('no-cache');
cacheStatusDisplay.textContent = `💾 Cached translations for ${cachedLanguages.length} language(s): ${cachedLanguages.join(', ')}`;
} else {
cacheStatusDisplay.classList.add('no-cache');
cacheStatusDisplay.textContent = '💾 No cached translations found';
}
}
// Clear all translation cache
function clearAllTranslationCache() {
if (confirm('Are you sure you want to clear all cached translations? This will require re-downloading translations for all languages.')) {
translationCache = {};
localStorage.removeItem('assessmentarchitect_translations');
updateCacheStatus();
// Show confirmation message
const originalStatus = document.getElementById('cacheStatusDisplay').textContent;
document.getElementById('cacheStatusDisplay').textContent = '🗑️ Translation cache cleared successfully!';
setTimeout(() => {
updateCacheStatus();
}, 2000);
// If currently using a non-English language, offer to reload
if (currentLanguage !== 'en') {
if (confirm('The current language translations have been cleared. Would you like to reload the translations now?')) {
translateInterface(currentLanguage);
}
}
}
}
// Apply language direction
function applyDirection(language) {
currentLanguage = language;
// Set document language and direction
document.documentElement.lang = language;
document.documentElement.dir = rtlLanguages.includes(language) ? 'rtl' : 'ltr';
// Save language preference
localStorage.setItem('assessmentarchitect_language', language);
}
// Switch language
async function switchLanguage() {
const newLanguage = document.getElementById('languageSwitcher').value;
if (newLanguage === currentLanguage) return;
currentLanguage = newLanguage;
localStorage.setItem('assessmentarchitect_language', newLanguage);
applyDirection(newLanguage);
if (newLanguage !== 'en') {
await translateInterface(newLanguage);
} else {
// Reset to English
restoreOriginalText();
}
}
// Translate interface
async function translateInterface(targetLanguage) {
if (isTranslating) return;
const cacheKey = `assessmentarchitect_${targetLanguage}`;
// Check if translations are cached
if (translationCache[cacheKey]) {
showTranslationStatus('💾 Translations cached - instant loading!', false);
applyTranslations(translationCache[cacheKey]);
return;
}
// Show first-time translation message
showTranslationStatus('🔄 First time translation - will be cached for future use', true);
isTranslating = true;
try {
const apiKey = document.getElementById('apiKey').value || document.getElementById('apiKeyLanding').value;
if (!apiKey) {
throw new Error('API key required for translation');
}
// Get all translatable elements
const elements = document.querySelectorAll('[data-translate]');
const textsToTranslate = [];
const elementMap = {};
elements.forEach((element, index) => {
const key = element.getAttribute('data-translate');
let text = '';
if (element.tagName === 'INPUT' || element.tagName === 'TEXTAREA') {
text = element.placeholder;
} else {
text = element.textContent.trim();
}
if (text && !elementMap[key]) {
elementMap[key] = text;
textsToTranslate.push({ key, text });
}
});
// Translate in batches
const batchSize = 10;
const translations = {};
for (let i = 0; i < textsToTranslate.length; i += batchSize) {
const batch = textsToTranslate.slice(i, i + batchSize);
const progress = Math.round(((i + batch.length) / textsToTranslate.length) * 100);
updateTranslationProgress(progress);
const batchTexts = batch.map(item => item.text).join('\n---\n');
const prompt = `Translate the following text to ${languageNames[targetLanguage]}. Provide ONLY the exact translation without any explanations, additional information, or formatting. Separate each translation with ---:\n\n${batchTexts}`;
const response = await fetch('https://api.openai.com/v1/chat/completions', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${apiKey}`
},
body: JSON.stringify({
model: 'gpt-4o-mini',
messages: [{ role: 'user', content: prompt }],
max_tokens: 2000,
temperature: 0.3
})
});
if (!response.ok) {
throw new Error('Translation API request failed');
}
const data = await response.json();
const translatedTexts = data.choices[0].message.content.split('---').map(t => t.trim());
batch.forEach((item, index) => {
if (translatedTexts[index]) {
translations[item.key] = translatedTexts[index];
}
});
}
// Cache translations
translationCache[cacheKey] = translations;
localStorage.setItem('assessmentarchitect_translations', JSON.stringify(translationCache));
// Apply translations
applyTranslations(translations);
updateTranslationProgress(100);
setTimeout(() => {
hideTranslationOverlay();
showTranslationStatus('💾 Translations cached - instant loading!', false);
updateCacheStatus();
}, 500);
} catch (error) {
console.error('Translation error:', error);
hideTranslationOverlay();
alert('Translation failed. Please check your API key and try again.');
} finally {
isTranslating = false;
}
}
// Apply translations to elements
function applyTranslations(translations) {
const elements = document.querySelectorAll('[data-translate]');
elements.forEach(element => {
const key = element.getAttribute('data-translate');
if (translations[key]) {
if (element.tagName === 'INPUT' || element.tagName === 'TEXTAREA') {
element.placeholder = translations[key];
} else {
element.textContent = translations[key];
}
// Update data-placeholder for output area
if (element.hasAttribute('data-placeholder')) {
element.setAttribute('data-placeholder', translations[key]);
}
}
});
}
// Restore original English text
function restoreOriginalText() {
const originalTexts = {
'app_title': 'AssessmentArchitect Pro',
'welcome_message': 'Welcome! Please select your preferred language and enter your API key to get started with intelligent assessment strategy building.',
'select_language': '🌐 Select Language',
'api_key_label': '🔑 OpenAI API Key',
'api_key_placeholder': 'Enter your OpenAI API key',
'start_button': '🚀 Start Assessment Builder',
'api_key_short': '🔑 API Key',
'app_subtitle': 'Intelligent Assessment Strategy Platform',
'app_description': 'Design comprehensive, effective assessment strategies through guided questions and AI-powered insights. Create assessments that measure learning objectives, accommodate diverse needs, and drive educational excellence.',
'additional_context_label': 'Additional Context (Optional)',
'additional_context_placeholder': 'Provide any additional context or specific requirements for your assessment strategy...',
'questions_section_title': 'Assessment Strategy Questions',
'question_1': 'What are the clear learning objectives for this assessment?',
'question_1_placeholder': 'Describe the specific learning objectives and outcomes this assessment should measure...',
'question_2': 'How does this assessment align with real-world scenarios and challenges?',
'question_2_placeholder': 'Explain how this assessment connects to practical applications and real-world contexts...',
'question_3': 'Does the assessment measure both breadth and depth of student knowledge?',
'question_3_placeholder': 'Describe how the assessment will evaluate comprehensive understanding and detailed knowledge...',
'question_4': 'What mix of question types will best evaluate student understanding?',
'question_4_placeholder': 'Outline the variety of question formats and assessment methods you plan to use...',
'question_5': 'How will this assessment provide opportunities for student feedback and reflection?',
'question_5_placeholder': 'Describe mechanisms for student self-assessment and reflective learning...',
'question_6': 'Is the assessment designed to accommodate different learning needs and preferences?',
'question_6_placeholder': 'Explain how the assessment will be inclusive and accessible to diverse learners...',
'question_7': 'How will the assessment results be used to inform and improve teaching practices?',
'question_7_placeholder': 'Describe how assessment data will guide instructional improvements and curriculum development...',
'question_8': 'Does the assessment strategy include both formative and summative components?',
'question_8_placeholder': 'Outline the balance between ongoing assessment and final evaluation methods...',
'question_9': 'How will the assessment measure higher-order thinking skills and critical reasoning?',
'question_9_placeholder': 'Describe how the assessment will evaluate analysis, synthesis, evaluation, and creative thinking...',
'question_10': 'What methods will be used to ensure the assessment is fair, valid, and reliable?',
'question_10_placeholder': 'Explain quality assurance measures and validation approaches for the assessment...',
'generate_button': '🎯 Generate Assessment Strategy',
'output_section_title': 'Generated Assessment Strategy',
'output_placeholder': 'Your comprehensive assessment strategy will appear here...'
};
applyTranslations(originalTexts);
}
// Show translation status
function showTranslationStatus(message, showProgress) {
const overlay = document.getElementById('translationOverlay');
const messageEl = document.getElementById('translationMessage');
const progressContainer = overlay.querySelector('.translation-progress');
messageEl.textContent = message;
progressContainer.style.display = showProgress ? 'block' : 'none';
overlay.style.display = 'flex';
if (!showProgress) {
setTimeout(hideTranslationOverlay, 1500);
}
}
// Update translation progress
function updateTranslationProgress(percentage) {
const progressBar = document.getElementById('translationProgressBar');
const progressText = document.getElementById('translationProgress');
progressBar.style.width = percentage + '%';
progressText.textContent = percentage + '%';
}
// Hide translation overlay
function hideTranslationOverlay() {
document.getElementById('translationOverlay').style.display = 'none';
}
// Show language landing page
function showLanguageLanding() {
document.getElementById('languageLanding').style.display = 'block';
document.getElementById('mainApp').style.display = 'none';
}
// Show main application
function showMainApp() {
document.getElementById('languageLanding').style.display = 'none';
document.getElementById('mainApp').style.display = 'block';
// Set API key in main app
document.getElementById('apiKey').value = currentApiKey;
// Update language switcher
const switcher = document.getElementById('languageSwitcher');
switcher.innerHTML = '';
const allOptions = document.getElementById('languageSelect').innerHTML;
switcher.innerHTML = allOptions;
switcher.value = currentLanguage;
}
// Show error message
function showError(message) {
const errorDiv = document.getElementById('errorMessage');
errorDiv.textContent = message;
errorDiv.style.display = 'block';
setTimeout(() => {
errorDiv.style.display = 'none';
}, 5000);
}
// API Service Module
const APIService = {
async callAPI(prompt) {
const languageName = languageNames[currentLanguage] || 'English';
// Modify prompt to include language instruction
const languagePrompt = currentLanguage !== 'en'
? `\n\nIMPORTANT: Generate all content in ${languageName} language.`
: '';
const payload = {
model: AppConfig.MODEL,
messages: [{ role: 'user', content: prompt + languagePrompt }],
max_tokens: AppConfig.MAX_TOKENS,
temperature: AppConfig.TEMPERATURE
};
const response = await fetch(AppConfig.API_BASE_URL, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${currentApiKey}`
},
body: JSON.stringify(payload)
});
if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData.error?.message || `HTTP ${response.status}: ${response.statusText}`);
}
const data = await response.json();
return data.choices[0].message.content;
}
};
// UI Controller Module
const UIController = {
elements: {},
init() {
this.elements = {
apiKeyInput: document.getElementById('apiKey'),
additionalContext: document.getElementById('additionalContext'),
generateButton: document.getElementById('generateStrategyBtn'),
loadingSpinner: document.getElementById('loadingSpinner'),
buttonText: document.querySelector('.button-text'),
progressBar: document.getElementById('strategyProgress'),
strategyOutput: document.getElementById('strategyOutput'),
questionInputs: {}
};
// Get all question inputs
for (let i = 1; i <= 10; i++) {
this.elements.questionInputs[`q${i}`] = document.getElementById(`q${i}`);
}
this.setupEventListeners();
},
setupEventListeners() {
this.elements.apiKeyInput.addEventListener('input', (e) => {
AppState.setApiKey(e.target.value.trim());
});
this.elements.generateButton.addEventListener('click', () => {
App.generateStrategy();
});
},
updateGeneratingState(isGenerating) {
if (isGenerating) {
this.elements.generateButton.disabled = true;
this.elements.buttonText.style.opacity = '0';
this.elements.loadingSpinner.style.display = 'block';
this.elements.progressBar.style.width = '20%';
} else {
this.elements.generateButton.disabled = false;
this.elements.buttonText.style.opacity = '1';
this.elements.loadingSpinner.style.display = 'none';
this.elements.progressBar.style.width = '100%';
}
},
setStrategyOutput(content) {
this.elements.strategyOutput.textContent = content;
},
showError(message) {
showError(message);
this.setStrategyOutput(`Error: ${message}`);
}
};
// Error Handler Module
const ErrorHandler = {
handleError(error) {
console.error('Application error:', error);
let userMessage = 'An unexpected error occurred. Please try again.';
if (error.message.includes('API key')) {
userMessage = 'Invalid API key. Please check your OpenAI API key and try again.';
} else if (error.message.includes('network') || error.message.includes('fetch')) {
userMessage = 'Network error. Please check your internet connection and try again.';
} else if (error.message.includes('rate limit')) {
userMessage = 'Rate limit exceeded. Please wait a moment before trying again.';
} else if (error.message.includes('quota')) {
userMessage = 'API quota exceeded. Please check your OpenAI account usage.';
}
UIController.showError(userMessage);
}
};
// Input Validator Module
const InputValidator = {
validateInputs() {
const apiKey = UIController.elements.apiKeyInput.value.trim();
if (!apiKey) {
throw new Error('Please enter your API key.');
}
// Check if all required questions are answered
for (let i = 1; i <= 10; i++) {
const answer = UIController.elements.questionInputs[`q${i}`].value.trim();
if (!answer) {
throw new Error(`Please answer question ${i}.`);
}
}
return true;
}
};
// Prompt Builder Module
const PromptBuilder = {
buildFinalStrategyPrompt() {
const language = languageNames[currentLanguage] || 'English';
const additionalContext = UIController.elements.additionalContext.value.trim();
const responses = {
"Learning Objectives": UIController.elements.questionInputs.q1.value.trim(),
"Real-World Alignment": UIController.elements.questionInputs.q2.value.trim(),
"Breadth and Depth": UIController.elements.questionInputs.q3.value.trim(),
"Question Type Mix": UIController.elements.questionInputs.q4.value.trim(),
"Feedback & Reflection": UIController.elements.questionInputs.q5.value.trim(),
"Accommodations": UIController.elements.questionInputs.q6.value.trim(),
"Teaching Improvement": UIController.elements.questionInputs.q7.value.trim(),
"Formative and Summative": UIController.elements.questionInputs.q8.value.trim(),
"Higher-Order Skills": UIController.elements.questionInputs.q9.value.trim(),
"Fairness & Reliability": UIController.elements.questionInputs.q10.value.trim()
};
let responsesText = "";
let i = 1;
for (const [question, answer] of Object.entries(responses)) {
responsesText += `${i}. ${question}: ${answer}\n`;
i++;
}
return `
Develop an effective assessment strategy that leads to the best outcomes based on the user responses below. Consider the following key questions and their answers: ${responsesText} ${ additionalContext ? "\nAdditional Context: " + additionalContext : "" } Produce a comprehensive, professional, and actionable assessment strategy that:
- Clearly defines learning objectives.
- Aligns with real-world scenarios and challenges.
- Measures both breadth and depth of student knowledge.
- Utilizes an appropriate mix of question types.
- Provides opportunities for student feedback and reflection.
- Accommodates different learning needs and preferences.
- Uses assessment results to improve teaching practices.
- Balances formative and summative assessments.
- Measures higher-order thinking and critical reasoning.
- Ensures fairness, validity, and reliability.
Output the final strategy in ${language} as a detailed written plan.
1. **Opening**: Acknowledge the request and provide an overview of your approach.
2. **Main Content**: Address each component of the instruction systematically:
- Use clear section headers for multi-part requests.
- Provide specific examples where helpful.
- Include relevant context or background information.
- Address potential misconceptions or common confusion points.
3. **Supporting Details**: Add relevant supporting information, sources, or methodology explanations.
4. **Conclusion**: Summarize key points and offer additional resources or next steps if applicable.
Ensure that all aspects of the original instruction are addressed, the response is appropriately detailed for the intended audience, the information is accurate and up-to-date, the format matches any specified requirements, and the language is clear, professional, and accessible. Complete this instruction with precision, ensuring no element is overlooked and the response fully satisfies the stated requirements.
`;
}
};
// Main App Module
const App = {
init() {
AppState.loadFromLocalStorage();
UIController.init();
// Load saved API key
if (AppState.apiKey) {
UIController.elements.apiKeyInput.value = AppState.apiKey;
}
console.log('AssessmentArchitect Pro initialized');
},
async generateStrategy() {
if (AppState.isGenerating) return;
try {
// Validate inputs
InputValidator.validateInputs();
// Update state
AppState.setGenerating(true);
// Update API key in state
const apiKey = UIController.elements.apiKeyInput.value.trim();
AppState.setApiKey(apiKey);
// Clear previous output
UIController.setStrategyOutput('Generating assessment strategy...');
// Build prompt and call API
const prompt = PromptBuilder.buildFinalStrategyPrompt();
const result = await APIService.callAPI(prompt);
// Update output
UIController.setStrategyOutput(result);
AppState.currentStrategy = result;
} catch (error) {
ErrorHandler.handleError(error);
} finally {
AppState.setGenerating(false);
}
}
};
// Start button click handler
document.getElementById('startBtn').addEventListener('click', async function() {
const selectedLanguage = document.getElementById('languageSelect').value;
const apiKey = document.getElementById('apiKeyLanding').value.trim();
if (!apiKey) {
alert('Please enter your OpenAI API key');
return;
}
currentLanguage = selectedLanguage;
currentApiKey = apiKey;
// Save preferences
localStorage.setItem('assessmentarchitect_language', selectedLanguage);
localStorage.setItem('assessmentarchitect_api_key', apiKey);
// Apply direction
applyDirection(selectedLanguage);
if (selectedLanguage !== 'en') {
await translateInterface(selectedLanguage);
}
// Show main app
showMainApp();
});
// Language selector change handler
document.getElementById('languageSelect').addEventListener('change', async function() {
const selectedLanguage = this.value;
applyDirection(selectedLanguage);
});
// API key sync between landing and main app
document.getElementById('apiKeyLanding').addEventListener('input', function() {
currentApiKey = this.value;
localStorage.setItem('assessmentarchitect_api_key', this.value);
document.getElementById('apiKey').value = this.value;
});
document.getElementById('apiKey').addEventListener('input', function() {
currentApiKey = this.value;
localStorage.setItem('assessmentarchitect_api_key', this.value);
document.getElementById('apiKeyLanding').value = this.value;
});
// Initialize the application when page loads
document.addEventListener('DOMContentLoaded', function() {
initializeApp();
App.init();
});
</script>
</body>
</html>