Add language assistant features and improve encryption handling: Implement a new route and controller method for sending messages to the language assistant, enhancing user interaction within lessons. Update the encryption utility to support both base64 and hex formats for better compatibility with existing data. Enhance localization files to include new terms related to the language assistant in English, German, and Spanish, improving user experience across languages.
This commit is contained in:
@@ -18,6 +18,26 @@
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<section class="surface-card course-assistant">
|
||||
<div>
|
||||
<span class="course-assistant__eyebrow">{{ $t('socialnetwork.vocab.courses.languageAssistantEyebrow') }}</span>
|
||||
<h3>{{ $t('socialnetwork.vocab.courses.languageAssistantCourseTitle') }}</h3>
|
||||
<p>{{ assistantAvailable ? $t('socialnetwork.vocab.courses.languageAssistantCourseReady') : $t('socialnetwork.vocab.courses.languageAssistantCourseSetup') }}</p>
|
||||
</div>
|
||||
<div class="course-assistant__actions">
|
||||
<button type="button" class="button-secondary" @click="openLanguageAssistantSettings">
|
||||
{{ $t('socialnetwork.vocab.courses.languageAssistantSettings') }}
|
||||
</button>
|
||||
<button
|
||||
v-if="assistantAvailable && currentLesson"
|
||||
type="button"
|
||||
@click="openLesson(currentLesson.id)"
|
||||
>
|
||||
{{ $t('socialnetwork.vocab.courses.languageAssistantOpenLesson') }}
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div v-if="isOwner" class="owner-actions">
|
||||
<button @click="showAddLessonDialog = true">{{ $t('socialnetwork.vocab.courses.addLesson') }}</button>
|
||||
<button @click="editCourse">{{ $t('socialnetwork.vocab.courses.edit') }}</button>
|
||||
@@ -128,6 +148,7 @@ export default {
|
||||
progress: [],
|
||||
chapters: [],
|
||||
showAddLessonDialog: false,
|
||||
assistantSettings: null,
|
||||
lessonFormTouched: false,
|
||||
newLesson: {
|
||||
lessonNumber: 1,
|
||||
@@ -172,6 +193,14 @@ export default {
|
||||
},
|
||||
canCreateLesson() {
|
||||
return this.isLessonNumberValid && this.isLessonTitleValid && this.isLessonChapterValid;
|
||||
},
|
||||
assistantAvailable() {
|
||||
if (!this.assistantSettings) {
|
||||
return false;
|
||||
}
|
||||
const enabled = this.assistantSettings.enabled !== false;
|
||||
const hasBaseUrl = Boolean(this.assistantSettings.baseUrl);
|
||||
return enabled && (this.assistantSettings.hasKey || hasBaseUrl);
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@@ -212,6 +241,14 @@ export default {
|
||||
console.error('Konnte Kapitel nicht laden:', e);
|
||||
}
|
||||
},
|
||||
async loadAssistantSettings() {
|
||||
try {
|
||||
const { data } = await apiClient.get('/api/settings/llm');
|
||||
this.assistantSettings = data;
|
||||
} catch (e) {
|
||||
this.assistantSettings = null;
|
||||
}
|
||||
},
|
||||
getLessonProgress(lessonId) {
|
||||
return this.progress.find(p => p.lessonId === lessonId);
|
||||
},
|
||||
@@ -285,12 +322,18 @@ export default {
|
||||
editCourse() {
|
||||
this.$router.push(`/socialnetwork/vocab/courses/${this.courseId}/edit`);
|
||||
},
|
||||
openLanguageAssistantSettings() {
|
||||
this.$router.push('/settings/language-assistant');
|
||||
},
|
||||
editLesson() {
|
||||
showInfo(this, 'Die Bearbeitung einzelner Lektionen folgt noch.');
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
await this.loadCourse();
|
||||
await Promise.all([
|
||||
this.loadCourse(),
|
||||
this.loadAssistantSettings()
|
||||
]);
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -304,6 +347,7 @@ export default {
|
||||
|
||||
.course-hero,
|
||||
.course-info,
|
||||
.course-assistant,
|
||||
.lessons-list,
|
||||
.course-state {
|
||||
margin-bottom: 16px;
|
||||
@@ -340,6 +384,39 @@ export default {
|
||||
padding: 16px 18px;
|
||||
}
|
||||
|
||||
.course-assistant {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
gap: 16px;
|
||||
padding: 18px 20px;
|
||||
}
|
||||
|
||||
.course-assistant__eyebrow {
|
||||
display: inline-block;
|
||||
margin-bottom: 8px;
|
||||
font-size: 0.75rem;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.06em;
|
||||
color: var(--color-text-muted);
|
||||
}
|
||||
|
||||
.course-assistant h3,
|
||||
.course-assistant p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.course-assistant p {
|
||||
margin-top: 6px;
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
|
||||
.course-assistant__actions {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.share-code {
|
||||
font-family: monospace;
|
||||
}
|
||||
@@ -614,4 +691,10 @@ export default {
|
||||
justify-content: flex-end;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.course-assistant {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user