@movk/nuxt-docs 1.8.0 → 1.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/app/app.config.ts +1 -2
- package/app/components/content/Mermaid.vue +7 -2
- package/modules/ai-chat/index.ts +3 -3
- package/modules/ai-chat/runtime/server/utils/getModel.ts +15 -9
- package/modules/ai-chat/runtime/server/utils/modelProviders.ts +34 -0
- package/modules/config.ts +3 -0
- package/package.json +7 -7
package/app/app.config.ts
CHANGED
|
@@ -81,10 +81,11 @@ const diagramRef = ref<HTMLElement | null>(null)
|
|
|
81
81
|
const isRendered = ref(false)
|
|
82
82
|
const hasError = ref(false)
|
|
83
83
|
const errorMessage = ref('')
|
|
84
|
+
const hasBeenVisible = ref(false)
|
|
84
85
|
|
|
85
86
|
const [isFullscreen, toggleFullscreen] = useToggle(false)
|
|
86
87
|
const { copy, copied } = useClipboard({ source: () => props.code })
|
|
87
|
-
const isVisible = useElementVisibility(containerRef)
|
|
88
|
+
const isVisible = useElementVisibility(containerRef, { threshold: 0.1 })
|
|
88
89
|
|
|
89
90
|
async function renderMermaid() {
|
|
90
91
|
if (!props.code || isRendered.value || !diagramRef.value) return
|
|
@@ -127,7 +128,11 @@ async function reRender() {
|
|
|
127
128
|
watch(
|
|
128
129
|
[isVisible, diagramRef],
|
|
129
130
|
([visible, el]) => {
|
|
130
|
-
|
|
131
|
+
// 记录曾经可见状态,避免快速滚动时错过渲染
|
|
132
|
+
if (visible) {
|
|
133
|
+
hasBeenVisible.value = true
|
|
134
|
+
}
|
|
135
|
+
if (hasBeenVisible.value && el && !isRendered.value) {
|
|
131
136
|
renderMermaid()
|
|
132
137
|
}
|
|
133
138
|
},
|
package/modules/ai-chat/index.ts
CHANGED
|
@@ -22,7 +22,7 @@ export interface AiChatModuleOptions {
|
|
|
22
22
|
*/
|
|
23
23
|
mcpPath?: string
|
|
24
24
|
/**
|
|
25
|
-
*
|
|
25
|
+
* 使用的 AI 模型
|
|
26
26
|
*/
|
|
27
27
|
model?: string
|
|
28
28
|
/**
|
|
@@ -46,7 +46,7 @@ export default defineNuxtModule<AiChatModuleOptions>({
|
|
|
46
46
|
models: []
|
|
47
47
|
},
|
|
48
48
|
setup(options, nuxt) {
|
|
49
|
-
const hasApiKey = !!(process.env.AI_GATEWAY_API_KEY || process.env.OPENROUTER_API_KEY)
|
|
49
|
+
const hasApiKey = !!(process.env.AI_GATEWAY_API_KEY || process.env.OPENROUTER_API_KEY || process.env.ZHIPU_API_KEY)
|
|
50
50
|
|
|
51
51
|
const { resolve } = createResolver(import.meta.url)
|
|
52
52
|
|
|
@@ -77,7 +77,7 @@ export default defineNuxtModule<AiChatModuleOptions>({
|
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
if (!hasApiKey) {
|
|
80
|
-
log.warn('[ai-chat] Module disabled: no
|
|
80
|
+
log.warn('[ai-chat] Module disabled: no API key found in environment variables.')
|
|
81
81
|
return
|
|
82
82
|
}
|
|
83
83
|
|
|
@@ -1,23 +1,29 @@
|
|
|
1
1
|
import { createGateway } from '@ai-sdk/gateway'
|
|
2
2
|
import { createOpenRouter } from '@openrouter/ai-sdk-provider'
|
|
3
|
+
import { modelProviderRegistry } from './modelProviders'
|
|
4
|
+
|
|
5
|
+
modelProviderRegistry.register('openrouter', ({ config, modelId }) => {
|
|
6
|
+
const openRouter = createOpenRouter({
|
|
7
|
+
apiKey: config.openRouterApiKey as string | undefined
|
|
8
|
+
})
|
|
9
|
+
return openRouter.chat(modelId)
|
|
10
|
+
})
|
|
3
11
|
|
|
4
12
|
/**
|
|
5
13
|
* 获取 AI 模型实例
|
|
6
|
-
*
|
|
7
|
-
* @returns AI SDK 模型实例
|
|
14
|
+
* 优先使用注册的提供商,否则回退到 AI Gateway
|
|
8
15
|
*/
|
|
9
16
|
export function getModel(modelId: string) {
|
|
10
17
|
const config = useRuntimeConfig()
|
|
18
|
+
const parsed = modelProviderRegistry.parseModelId(modelId)
|
|
11
19
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
}
|
|
17
|
-
return openRouter.chat(modelId.replace('openrouter/', ''))
|
|
20
|
+
if (parsed) {
|
|
21
|
+
const factory = modelProviderRegistry.get(parsed.prefix)
|
|
22
|
+
if (factory) {
|
|
23
|
+
return factory({ config, modelId: parsed.modelId })
|
|
24
|
+
}
|
|
18
25
|
}
|
|
19
26
|
|
|
20
|
-
// AI Gateway 模型(默认)
|
|
21
27
|
const gateway = createGateway({
|
|
22
28
|
apiKey: config.aiGatewayApiKey as string | undefined
|
|
23
29
|
})
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { LanguageModel } from 'ai'
|
|
2
|
+
|
|
3
|
+
export interface ModelProviderContext {
|
|
4
|
+
config: ReturnType<typeof useRuntimeConfig>
|
|
5
|
+
modelId: string
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export type ModelProviderFactory = (context: ModelProviderContext) => LanguageModel
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* 模型提供商注册表
|
|
12
|
+
*/
|
|
13
|
+
class ModelProviderRegistry {
|
|
14
|
+
private providers = new Map<string, ModelProviderFactory>()
|
|
15
|
+
|
|
16
|
+
register(prefix: string, factory: ModelProviderFactory): void {
|
|
17
|
+
this.providers.set(prefix, factory)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
get(prefix: string): ModelProviderFactory | undefined {
|
|
21
|
+
return this.providers.get(prefix)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
parseModelId(modelId: string): { prefix: string, modelId: string } | null {
|
|
25
|
+
const separatorIndex = modelId.indexOf('/')
|
|
26
|
+
if (separatorIndex === -1) return null
|
|
27
|
+
return {
|
|
28
|
+
prefix: modelId.slice(0, separatorIndex),
|
|
29
|
+
modelId: modelId.slice(separatorIndex + 1)
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export const modelProviderRegistry = new ModelProviderRegistry()
|
package/modules/config.ts
CHANGED
|
@@ -10,6 +10,9 @@ export default defineNuxtModule({
|
|
|
10
10
|
},
|
|
11
11
|
async setup(_options, nuxt) {
|
|
12
12
|
const { resolve } = createResolver(import.meta.url)
|
|
13
|
+
|
|
14
|
+
nuxt.options.alias['#ai-chat'] = resolve('./ai-chat/runtime')
|
|
15
|
+
|
|
13
16
|
const dir = nuxt.options.rootDir
|
|
14
17
|
const url = inferSiteURL()
|
|
15
18
|
const meta = await getPackageJsonMetadata(dir)
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@movk/nuxt-docs",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.8.
|
|
4
|
+
"version": "1.8.1",
|
|
5
5
|
"private": false,
|
|
6
6
|
"description": "Modern Nuxt 4 documentation theme with auto-generated component docs, AI chat assistant, MCP server, and complete developer experience optimization.",
|
|
7
7
|
"author": "YiXuan <mhaibaraai@gmail.com>",
|
|
@@ -28,9 +28,9 @@
|
|
|
28
28
|
"README.md"
|
|
29
29
|
],
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@ai-sdk/gateway": "^3.0.
|
|
31
|
+
"@ai-sdk/gateway": "^3.0.19",
|
|
32
32
|
"@ai-sdk/mcp": "^1.0.11",
|
|
33
|
-
"@ai-sdk/vue": "^3.0.
|
|
33
|
+
"@ai-sdk/vue": "^3.0.45",
|
|
34
34
|
"@iconify-json/lucide": "^1.2.86",
|
|
35
35
|
"@iconify-json/ph": "^1.2.2",
|
|
36
36
|
"@iconify-json/simple-icons": "^1.2.67",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"@nuxt/content": "^3.11.0",
|
|
42
42
|
"@nuxt/image": "^2.0.0",
|
|
43
43
|
"@nuxt/kit": "^4.2.2",
|
|
44
|
-
"@nuxt/ui": "^4.
|
|
44
|
+
"@nuxt/ui": "^4.4.0",
|
|
45
45
|
"@nuxtjs/mcp-toolkit": "^0.6.2",
|
|
46
46
|
"@nuxtjs/seo": "^3.3.0",
|
|
47
47
|
"@octokit/rest": "^22.0.1",
|
|
@@ -50,9 +50,9 @@
|
|
|
50
50
|
"@vercel/speed-insights": "^1.3.1",
|
|
51
51
|
"@vueuse/core": "^14.1.0",
|
|
52
52
|
"@vueuse/nuxt": "^14.1.0",
|
|
53
|
-
"ai": "^6.0.
|
|
53
|
+
"ai": "^6.0.45",
|
|
54
54
|
"defu": "^6.1.4",
|
|
55
|
-
"dompurify": "^3.
|
|
55
|
+
"dompurify": "^3.3.1",
|
|
56
56
|
"exsolve": "^1.0.8",
|
|
57
57
|
"git-url-parse": "^16.1.0",
|
|
58
58
|
"mermaid": "^11.12.2",
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
"ohash": "^2.0.11",
|
|
64
64
|
"pathe": "^2.0.3",
|
|
65
65
|
"pkg-types": "^2.3.0",
|
|
66
|
-
"prettier": "^3.8.
|
|
66
|
+
"prettier": "^3.8.1",
|
|
67
67
|
"scule": "^1.3.0",
|
|
68
68
|
"shiki": "^3.21.0",
|
|
69
69
|
"shiki-stream": "^0.1.4",
|