Skip to content

Commit a5b13bc

Browse files
committed
feat: support i18n for LearningAssistant component
1 parent 83b1ac5 commit a5b13bc

1 file changed

Lines changed: 67 additions & 11 deletions

File tree

docs/.vitepress/theme/components/LearningAssistant.vue

Lines changed: 67 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<div class="learning-assistant">
33
<div v-if="isOpen" class="chat-window">
44
<div class="chat-header">
5-
<span>学习助手 (Learning Assistant)</span>
5+
<span>{{ i18n.title }}</span>
66
<button @click="toggleChat" class="close-btn">×</button>
77
</div>
88
<div class="chat-messages" ref="messagesContainer">
@@ -17,10 +17,10 @@
1717
<input
1818
v-model="inputText"
1919
@keyup.enter="sendMessage"
20-
placeholder="你想了解什么工具?..."
20+
:placeholder="i18n.placeholder"
2121
:disabled="isLoading"
2222
/>
23-
<button @click="sendMessage" :disabled="isLoading || !inputText.trim()">发送</button>
23+
<button @click="sendMessage" :disabled="isLoading || !inputText.trim()">{{ i18n.send }}</button>
2424
</div>
2525
</div>
2626
<div v-else class="chat-toggle" @click="toggleChat">
@@ -30,7 +30,38 @@
3030
</template>
3131

3232
<script setup>
33-
import { ref, nextTick, onMounted } from 'vue'
33+
import { ref, nextTick, onMounted, computed, watch } from 'vue'
34+
import { useData } from 'vitepress'
35+
36+
const { lang } = useData()
37+
38+
const isEn = computed(() => lang.value === 'en')
39+
40+
const i18n = computed(() => {
41+
return isEn.value ? {
42+
title: 'Learning Assistant',
43+
placeholder: 'What tool would you like to know about?...',
44+
send: 'Send',
45+
welcome: 'Hello! I am your learning assistant. What do you need? Which tool would you like to use (AstronClaw or Loomy)? I will recommend and guide you to the next step.',
46+
systemPrompt: `You are a project learning assistant. Your task is to ask the user what they need or which tool they want to use (AstronClaw or Loomy) and make recommendations, always guiding the user to the next step. Please keep your answers short and friendly. Be sure to answer the user's questions based on the content in the [Knowledge Base Reference] (if it exists).\n`,
47+
errorFallback: 'Sorry, I encountered some issues. Please try again later.',
48+
errorPrefix: 'Request failed: ',
49+
knowledgeBaseTitle: '\n\n[Knowledge Base Reference]\n',
50+
chapter: 'Chapter: ',
51+
content: 'Content: '
52+
} : {
53+
title: '学习助手 (Learning Assistant)',
54+
placeholder: '你想了解什么工具?...',
55+
send: '发送',
56+
welcome: '你好!我是你的学习助手。请问你有什么需求?希望使用哪款工具(AstronClaw 或 Loomy)?我会为你推荐并引导你进行下一步操作。',
57+
systemPrompt: `你是一个项目学习助手,你的任务是提问用户有什么需求/希望使用哪款工具(AstronClaw 或 Loomy)并进行推荐,永远引导用户进行下一步操作。请保持回答简短友好。请务必基于【知识库参考信息】中的内容来回答用户的问题(如果存在)。\n`,
58+
errorFallback: '抱歉,我遇到了一些问题,请稍后再试。',
59+
errorPrefix: '请求失败: ',
60+
knowledgeBaseTitle: '\n\n【知识库参考信息】\n',
61+
chapter: '章节: ',
62+
content: '内容: '
63+
}
64+
})
3465
3566
const isOpen = ref(false)
3667
const isLoading = ref(false)
@@ -40,10 +71,24 @@ const messagesContainer = ref(null)
4071
const messages = ref([
4172
{
4273
role: 'assistant',
43-
content: '你好!我是你的学习助手。请问你有什么需求?希望使用哪款工具(AstronClaw 或 Loomy)?我会为你推荐并引导你进行下一步操作。'
74+
content: i18n.value.welcome
4475
}
4576
])
4677
78+
watch(lang, () => {
79+
// If only the welcome message is there, update it to the new language
80+
if (messages.value.length === 1 && messages.value[0].role === 'assistant') {
81+
messages.value[0].content = i18n.value.welcome
82+
} else {
83+
// Optionally add a welcome message in the new language if they switch during a chat
84+
messages.value.push({
85+
role: 'assistant',
86+
content: i18n.value.welcome
87+
})
88+
scrollToBottom()
89+
}
90+
})
91+
4792
let docsIndex = []
4893
4994
onMounted(async () => {
@@ -71,10 +116,21 @@ const scrollToBottom = async () => {
71116
72117
function searchDocs(query) {
73118
if (!docsIndex.length) return ''
119+
// Filter docs index based on current language
120+
// docsIndex items have URLs like "/guide/..." or "/en/guide/..."
121+
const currentLangDocs = docsIndex.filter(doc => {
122+
if (isEn.value) {
123+
return doc.url.startsWith('/en/')
124+
} else {
125+
return !doc.url.startsWith('/en/')
126+
}
127+
})
128+
129+
if (!currentLangDocs.length) return ''
74130
const keywords = query.toLowerCase().match(/[a-z0-9]+|[\u4e00-\u9fa5]/g) || []
75131
if (!keywords.length) return ''
76132
77-
const results = docsIndex.map(doc => {
133+
const results = currentLangDocs.map(doc => {
78134
let score = 0
79135
const text = (doc.heading + ' ' + doc.content).toLowerCase()
80136
@@ -101,7 +157,7 @@ function searchDocs(query) {
101157
102158
if (results.length === 0) return ''
103159
104-
return '\n\n【知识库参考信息】\n' + results.map(r => `章节: ${r.heading}\n内容: ${r.content}`).join('\n\n')
160+
return i18n.value.knowledgeBaseTitle + results.map(r => `${i18n.value.chapter}${r.heading}\n${i18n.value.content}${r.content}`).join('\n\n')
105161
}
106162
107163
const sendMessage = async () => {
@@ -114,7 +170,7 @@ const sendMessage = async () => {
114170
scrollToBottom()
115171
116172
const context = searchDocs(text)
117-
const systemPrompt = `你是一个项目学习助手,你的任务是提问用户有什么需求/希望使用哪款工具(AstronClaw 或 Loomy)并进行推荐,永远引导用户进行下一步操作。请保持回答简短友好。请务必基于【知识库参考信息】中的内容来回答用户的问题(如果存在)。\n${context}`
173+
const systemPrompt = `${i18n.value.systemPrompt}${context}`
118174
119175
try {
120176
// Use the local Vercel serverless function endpoint instead of Railway
@@ -130,7 +186,7 @@ const sendMessage = async () => {
130186
role: 'system',
131187
content: systemPrompt
132188
},
133-
...messages.value.filter(m => m.role !== 'assistant' || (m.content !== '抱歉,我遇到了一些问题,请稍后再试。' && !m.content.startsWith('请求失败:'))).map(m => ({ role: m.role, content: m.content }))
189+
...messages.value.filter(m => m.role !== 'assistant' || (m.content !== i18n.value.errorFallback && !m.content.startsWith(i18n.value.errorPrefix))).map(m => ({ role: m.role, content: m.content }))
134190
]
135191
})
136192
})
@@ -147,11 +203,11 @@ const sendMessage = async () => {
147203
content: data.choices[0].message.content
148204
})
149205
} else {
150-
messages.value.push({ role: 'assistant', content: '抱歉,我遇到了一些问题,请稍后再试。' })
206+
messages.value.push({ role: 'assistant', content: i18n.value.errorFallback })
151207
}
152208
} catch (error) {
153209
console.error('Error calling AI:', error)
154-
messages.value.push({ role: 'assistant', content: `请求失败: ${error.message}` })
210+
messages.value.push({ role: 'assistant', content: `${i18n.value.errorPrefix}${error.message}` })
155211
} finally {
156212
isLoading.value = false
157213
scrollToBottom()

0 commit comments

Comments
 (0)