init
This commit is contained in:
parent
160ca6dfd1
commit
a6115d0733
@ -24,7 +24,7 @@ export default defineConfig({
|
|||||||
],
|
],
|
||||||
|
|
||||||
socialLinks: [
|
socialLinks: [
|
||||||
{ icon: 'github', link: 'https://github.com/vuejs/vitepress' }
|
{ icon: 'github', link: 'https://github.com/LSTM-Kirigaya/openmcp-client' }
|
||||||
],
|
],
|
||||||
footer: {
|
footer: {
|
||||||
message: '缩短LLM到Agent的最后一公里',
|
message: '缩短LLM到Agent的最后一公里',
|
||||||
|
193
.vitepress/theme/components/KTab/index.vue
Normal file
193
.vitepress/theme/components/KTab/index.vue
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
<template>
|
||||||
|
<div class="k-tabs" :style="panelStyle">
|
||||||
|
<div class="k-tabs-tags">
|
||||||
|
<div class="k-tabs-tag-item" v-for="pane of tabsContainer.paneInfos" :key="pane.id"
|
||||||
|
:ref="el => tabsContainer.getPanes(el, pane.id)" @click="tabsContainer.switchLabel(pane.id)"
|
||||||
|
:class="{ 'active-tab': tabsContainer.lastPaneId === pane.id }">
|
||||||
|
<span :class="pane.labelClass"></span>
|
||||||
|
<span>{{ pane.label }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="k-tabs-content" :ref="el => tabsContainer.panelContainer = el">
|
||||||
|
<slot></slot>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { reactive, useSlots, provide, nextTick, computed, onMounted } from 'vue';
|
||||||
|
|
||||||
|
type PaneInfo = {
|
||||||
|
id: number;
|
||||||
|
label: string;
|
||||||
|
labelClass: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
interface TabsContainer {
|
||||||
|
paneInfos: PaneInfo[];
|
||||||
|
panes: HTMLElement[];
|
||||||
|
lastPaneId?: number;
|
||||||
|
activeLabel: string;
|
||||||
|
panelContainer?: any;
|
||||||
|
height: string;
|
||||||
|
getPanes: (el: any, id: string | number) => void;
|
||||||
|
switchLabel: (id: number) => void;
|
||||||
|
updateLabels: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const slots = useSlots();
|
||||||
|
let maxChildHeight = 0;
|
||||||
|
|
||||||
|
function resizeTab(id: number) {
|
||||||
|
const container = tabsContainer.panelContainer;
|
||||||
|
if (container) {
|
||||||
|
const panels = Array.from(container.children) as HTMLElement[];
|
||||||
|
|
||||||
|
const currentPanel = panels[id];
|
||||||
|
if (currentPanel) {
|
||||||
|
maxChildHeight = Math.max(maxChildHeight, currentPanel.clientHeight);
|
||||||
|
tabsContainer.height = maxChildHeight + 'px';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const panelStyle = computed(() => ({
|
||||||
|
height: tabsContainer.height
|
||||||
|
}));
|
||||||
|
|
||||||
|
const tabsContainer: TabsContainer = reactive({
|
||||||
|
paneInfos: [],
|
||||||
|
panes: [],
|
||||||
|
lastPaneId: 0,
|
||||||
|
activeLabel: '',
|
||||||
|
hoverBar: null,
|
||||||
|
panelContainer: undefined,
|
||||||
|
height: '0',
|
||||||
|
getPanes(el: HTMLElement | null, id: string | number) {
|
||||||
|
if (el) {
|
||||||
|
this.panes[id] = el;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
switchLabel(id: number) {
|
||||||
|
if (this.lastPaneId === id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.lastPaneId = id;
|
||||||
|
this.activeLabel = this.paneInfos[id]?.label || '';
|
||||||
|
|
||||||
|
const container = tabsContainer.panelContainer;
|
||||||
|
const panels = Array.from(container.children) as HTMLElement[];
|
||||||
|
|
||||||
|
panels.forEach((panel, index) => {
|
||||||
|
console.log('index', index);
|
||||||
|
console.log('id', id);
|
||||||
|
|
||||||
|
panel.style.transition = 'opacity 0.3s ease';
|
||||||
|
if (index === id) {
|
||||||
|
panel.style.display = 'block';
|
||||||
|
setTimeout(() => {
|
||||||
|
panel.style.opacity = '1';
|
||||||
|
}, 150);
|
||||||
|
} else {
|
||||||
|
panel.style.opacity = '0';
|
||||||
|
setTimeout(() => {
|
||||||
|
panel.style.display = 'none';
|
||||||
|
}, 300);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
nextTick(() => {
|
||||||
|
resizeTab(id);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
updateLabels() {
|
||||||
|
const defaultChildren = slots.default?.() || [];
|
||||||
|
|
||||||
|
this.paneInfos = [];
|
||||||
|
for (const index in defaultChildren) {
|
||||||
|
const vnode = defaultChildren[index];
|
||||||
|
this.paneInfos.push({
|
||||||
|
id: Number(index),
|
||||||
|
label: vnode.props?.label || '',
|
||||||
|
labelClass: vnode.props?.labelClass || '',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (this.paneInfos.length > 0) {
|
||||||
|
this.activeLabel = this.paneInfos[0]?.label || '';
|
||||||
|
nextTick(() => {
|
||||||
|
resizeTab(0);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
tabsContainer.updateLabels();
|
||||||
|
onMounted(() => {
|
||||||
|
if (tabsContainer.panelContainer) {
|
||||||
|
const panels = Array.from(tabsContainer.panelContainer.children) as HTMLElement[];
|
||||||
|
panels.forEach((panel, index) => {
|
||||||
|
panel.style.position = 'absolute';
|
||||||
|
|
||||||
|
if (index != tabsContainer.lastPaneId) {
|
||||||
|
panel.style.display = 'none';
|
||||||
|
panel.style.opacity = '0';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.k-tabs {
|
||||||
|
position: relative;
|
||||||
|
height: fit-content;
|
||||||
|
}
|
||||||
|
|
||||||
|
.k-tabs-tags {
|
||||||
|
display: flex;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
width: 100%;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.k-tabs-tag-item {
|
||||||
|
background-color: var(--vp-button-alt-bg);
|
||||||
|
color: white;
|
||||||
|
border-radius: .5em;
|
||||||
|
margin-right: 10px;
|
||||||
|
padding: 2px 8px;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
display: inline-block;
|
||||||
|
text-decoration: none;
|
||||||
|
cursor: pointer;
|
||||||
|
white-space: nowrap;
|
||||||
|
user-select: none;
|
||||||
|
transition: background-color 0.3s ease, transform 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.k-tabs-tag-item:hover {
|
||||||
|
background-color: var(--vp-c-brand-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.k-tabs-tag-item.active-tab {
|
||||||
|
background-color: var(--vp-c-brand-3);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 414px) {
|
||||||
|
.k-tabs-tags {
|
||||||
|
overflow-x: scroll
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.hover-bar {
|
||||||
|
background-color: var(--vp-c-brand-3);
|
||||||
|
border-radius: .9em .9em 0 0;
|
||||||
|
transition: .35s ease-in-out;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
.k-tabs-content>* {
|
||||||
|
transition: opacity 0.3s ease;
|
||||||
|
}
|
||||||
|
</style>
|
103
.vitepress/theme/components/bilibli-player/index.vue
Normal file
103
.vitepress/theme/components/bilibli-player/index.vue
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
<template>
|
||||||
|
<div class="wrapper">
|
||||||
|
<div class="bilibili-player-container">
|
||||||
|
<iframe v-if="isPlaying" :src="playerUrl" frameborder="0" allowfullscreen></iframe>
|
||||||
|
|
||||||
|
<div v-else class="cover-container" @click="playVideo">
|
||||||
|
<img :src="props.cover" class="cover-image" />
|
||||||
|
<button class="play-button">
|
||||||
|
<svg viewBox="0 0 24 24" width="48" height="48">
|
||||||
|
<path fill="currentColor" d="M8 5v14l11-7z" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref } from 'vue'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
url: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
cover: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const isPlaying = ref(false);
|
||||||
|
const playerUrl = ref(props.url);
|
||||||
|
|
||||||
|
function playVideo() {
|
||||||
|
isPlaying.value = true
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.wrapper {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bilibili-player-container {
|
||||||
|
position: relative;
|
||||||
|
width: 72.36vw;
|
||||||
|
height: 38.26vw;
|
||||||
|
aspect-ratio: 16/9;
|
||||||
|
border-radius: .5em;
|
||||||
|
overflow: hidden;
|
||||||
|
border: 2px solid var(--vp-c-brand-3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cover-container {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cover-image {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
.play-button {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
width: 64px;
|
||||||
|
height: 64px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: var(--vp-c-brand-3);
|
||||||
|
border: none;
|
||||||
|
color: var(--vp-c-bg);
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
transition: transform 0.2s ease, background-color 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.play-button:hover {
|
||||||
|
transform: translate(-50%, -50%) scale(1.1);
|
||||||
|
background-color: var(--vp-c-brand-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.play-button svg {
|
||||||
|
margin-left: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
iframe {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
</style>
|
@ -29,8 +29,8 @@
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
max-width: 500px;
|
max-width: 380px;
|
||||||
max-height: 500px;
|
max-height: 380px;
|
||||||
height: 99%;
|
height: 99%;
|
||||||
object-fit: contain;
|
object-fit: contain;
|
||||||
transform: translate(-50%, -50%);
|
transform: translate(-50%, -50%);
|
||||||
|
@ -29,7 +29,15 @@ const props = defineProps({
|
|||||||
image: {
|
image: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true
|
required: true
|
||||||
}
|
},
|
||||||
|
label: {
|
||||||
|
type: String,
|
||||||
|
required: false
|
||||||
|
},
|
||||||
|
labelClass: {
|
||||||
|
type: String,
|
||||||
|
required: false
|
||||||
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -4,6 +4,8 @@ import type { Theme } from 'vitepress';
|
|||||||
import DefaultTheme from 'vitepress/theme';
|
import DefaultTheme from 'vitepress/theme';
|
||||||
import HeroImage from './components/home/HeroImage.vue';
|
import HeroImage from './components/home/HeroImage.vue';
|
||||||
import TwoSideLayout from './components/home/TwoSideLayout.vue';
|
import TwoSideLayout from './components/home/TwoSideLayout.vue';
|
||||||
|
import KTab from './components/KTab/index.vue';
|
||||||
|
import BiliPlayer from './components/bilibli-player/index.vue';
|
||||||
|
|
||||||
import './style.css';
|
import './style.css';
|
||||||
|
|
||||||
@ -16,5 +18,7 @@ export default {
|
|||||||
},
|
},
|
||||||
enhanceApp({ app, router, siteData }) {
|
enhanceApp({ app, router, siteData }) {
|
||||||
app.component('TwoSideLayout', TwoSideLayout);
|
app.component('TwoSideLayout', TwoSideLayout);
|
||||||
|
app.component('KTab', KTab);
|
||||||
|
app.component('BiliPlayer', BiliPlayer);
|
||||||
}
|
}
|
||||||
} satisfies Theme
|
} satisfies Theme
|
||||||
|
@ -140,3 +140,14 @@
|
|||||||
.two-side-layout .image-container {
|
.two-side-layout .image-container {
|
||||||
display: unset !important;
|
display: unset !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.VPHero .image-container img {
|
||||||
|
box-shadow: unset !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
iframe {
|
||||||
|
border: 2px solid var(--vp-c-brand-3);
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
||||||
|
transition: border-color 0.3s ease;
|
||||||
|
}
|
||||||
|
BIN
images/openmcp-default.png
Normal file
BIN
images/openmcp-default.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 31 KiB |
BIN
images/opensource.png
Normal file
BIN
images/opensource.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.3 MiB |
49
index.md
49
index.md
@ -17,32 +17,59 @@ hero:
|
|||||||
- theme: alt
|
- theme: alt
|
||||||
text: GitHub
|
text: GitHub
|
||||||
link: https://github.com/LSTM-Kirigaya/openmcp-client
|
link: https://github.com/LSTM-Kirigaya/openmcp-client
|
||||||
|
|
||||||
features:
|
|
||||||
- title: 集成调试环境
|
|
||||||
details: 将检查器与 MCP 客户端功能相结合,实现无缝开发和测试
|
|
||||||
- title: 全面的项目管理
|
|
||||||
details: 提供完整的项目级控制面板,实现高效的 MCP 项目监督
|
|
||||||
- title: 多模型支持
|
|
||||||
details: 支持多种大语言模型,具备灵活的集成能力
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
||||||
|
<BiliPlayer
|
||||||
|
url="//player.bilibili.com/player.html?isOutside=true&aid=114445745397200&bvid=BV1zYGozgEHcautoplay=false"
|
||||||
|
cover="https://picx.zhimg.com/80/v2-8c1f5d99066ed272554146ed8caf7cc3_1440w.png"
|
||||||
|
/>
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
<br>
|
<br>
|
||||||
<br>
|
<br>
|
||||||
|
<hr>
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
|
||||||
# OpenMCP 为谁准备?
|
# OpenMCP 为谁准备?
|
||||||
|
|
||||||
<a href="https://qm.qq.com/cgi-bin/qm/qr?k=C6ZUTZvfqWoI12lWe7L93cWa1hUsuVT0&jump_from=webapi&authKey=McW6B1ogTPjPDrCyGttS890tMZGQ1KB3QLuG4aqVNRaYp4vlTSgf2c6dMcNjMuBD" target="_blank" style="display: inline-block; padding: 2px 8px; font-size: 0.8rem; background-color: var(--vp-c-brand-3); color: white; border-radius: .5em; text-decoration: none; margin-right: 10px;">开源社区爱好者</a><a href="https://qm.qq.com/cgi-bin/qm/qr?k=C6ZUTZvfqWoI12lWe7L93cWa1hUsuVT0&jump_from=webapi&authKey=McW6B1ogTPjPDrCyGttS890tMZGQ1KB3QLuG4aqVNRaYp4vlTSgf2c6dMcNjMuBD" target="_blank" style="display: inline-block; padding: 2px 8px; font-size: 0.8rem; background-color: var(--vp-button-alt-bg); color: white; border-radius: .5em; text-decoration: none; margin-right: 10px;">专业软件工程师</a><a href="https://qm.qq.com/cgi-bin/qm/qr?k=C6ZUTZvfqWoI12lWe7L93cWa1hUsuVT0&jump_from=webapi&authKey=McW6B1ogTPjPDrCyGttS890tMZGQ1KB3QLuG4aqVNRaYp4vlTSgf2c6dMcNjMuBD" target="_blank" style="display: inline-block; padding: 2px 8px; font-size: 0.8rem; background-color: var(--vp-button-alt-bg); color: white; border-radius: .5em; text-decoration: none; margin-right: 10px;">AI研发科学家</a>
|
<br>
|
||||||
|
|
||||||
|
<KTab>
|
||||||
<TwoSideLayout
|
<TwoSideLayout
|
||||||
|
label="专业软件工程师"
|
||||||
:texts="[
|
:texts="[
|
||||||
'在编辑器中写完代码直接测试,无需打开第三方软件。提供极其丰富的功能和特性。',
|
'测试左移,让你的开发与测试一体化,无需打开第三方软件。提供极其丰富的功能和特性。',
|
||||||
'在左侧面板自由而优雅地管理、调试和测试你的智能体。',
|
'在左侧面板自由而优雅地管理、调试和测试你的智能体。',
|
||||||
'大模型调用工具的每一个细节一览无余,不满意的调用结果直接一键复现。',
|
'大模型调用工具的每一个细节一览无余,不满意的调用结果直接一键复现。',
|
||||||
'每一次对话都会显示各项性能指标,方便进行成本管理。',
|
'每一次对话都会显示各项性能指标,方便进行成本管理。',
|
||||||
'系统提示词管理面板,让您轻松用 mcp 服务器和系统提示词构建您的智能体应用。',
|
'系统提示词管理面板,让您轻松用 mcp 服务器和系统提示词构建您的智能体应用。',
|
||||||
'每一次测试的细节都会 100% 跟随 git 进行版本控制,方便你分享你的每一次试验结果,也方便你零成本复现别人的 mcp 项目。'
|
|
||||||
]"
|
]"
|
||||||
image="/images/openmcp.chatbot.png"
|
image="/images/openmcp.chatbot.png"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<TwoSideLayout
|
||||||
|
label="开源社区爱好者"
|
||||||
|
:texts="[
|
||||||
|
'测试左移,让你的开发与测试一体化,无需打开第三方软件。提供极其丰富的功能和特性。',
|
||||||
|
'OpenMCP 完全开源,您不仅可以免费试用此产品,也可以一起加入我们,实现你的关于 Agent 的奇思妙想',
|
||||||
|
'完全公开技术细节,您不必担心,您的创意和token会遭到剽窃',
|
||||||
|
'可持久化的系统提示词管理面板,让您可以将实际的 mcp 服务器的系统提示词进行测试,以便于在社区内进行分享',
|
||||||
|
'每一次测试的细节都会 100% 跟随 git 进行版本控制,方便你分享你的每一次试验结果,也方便你零成本复现别人的 mcp 项目。'
|
||||||
|
]"
|
||||||
|
image="/images/opensource.png"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TwoSideLayout
|
||||||
|
label="AI研发科学家"
|
||||||
|
:texts="[
|
||||||
|
'测试左移,让你的开发与测试一体化,无需打开第三方软件。提供极其丰富的功能和特性。',
|
||||||
|
'只需几行代码,就能快速将您的科研成果以做成 mcp 服务器,从而接入任意大模型,以实现用户友好型的交互界面。',
|
||||||
|
'所有实验数据与配置参数均自动纳入Git版本管理系统,确保研究成果可追溯、可复现,便于学术交流与论文复现。',
|
||||||
|
'基于 OpenMCP 快速完成您的 demo,缩短创新到落地的距离',
|
||||||
|
]"
|
||||||
|
image="/images/openmcp.chatbot.png"
|
||||||
|
/>
|
||||||
|
|
||||||
|
</KTab>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user