forked from Gitlink/gitlink-cli
169 lines
7.7 KiB
HTML
169 lines
7.7 KiB
HTML
{% extends "base.html" %}
|
||
{% block content %}
|
||
|
||
<div class="max-w-4xl mx-auto">
|
||
<a href="/skills/" class="text-blue-600 hover:underline text-sm mb-4 inline-block">← 返回首页</a>
|
||
|
||
<h1 class="text-3xl font-bold text-gray-800 mb-2">{{ info.title }}</h1>
|
||
|
||
{% if skill_name.startswith("lab-") and info.intro %}
|
||
<div class="bg-green-50 border border-green-200 rounded-xl p-4 mb-6 text-sm text-green-800">
|
||
{{ info.intro }}
|
||
</div>
|
||
{% endif %}
|
||
|
||
<!-- 功能介绍 + 预期输出 -->
|
||
<div class="space-y-2 mb-6">
|
||
<details class="bg-white border border-gray-200 rounded-xl overflow-hidden">
|
||
<summary class="px-4 py-3 cursor-pointer font-medium text-gray-700 hover:bg-gray-50 transition flex items-center gap-2">
|
||
<span class="text-blue-500">📖</span> 功能介绍
|
||
</summary>
|
||
<div class="px-4 py-3 text-sm text-gray-600 border-t border-gray-100">
|
||
{% if info.intro %}{{ info.intro }}{% endif %}
|
||
</div>
|
||
</details>
|
||
<details class="bg-white border border-gray-200 rounded-xl overflow-hidden">
|
||
<summary class="px-4 py-3 cursor-pointer font-medium text-gray-700 hover:bg-gray-50 transition flex items-center gap-2">
|
||
<span class="text-blue-500">📋</span> 预期输出格式与内容
|
||
</summary>
|
||
<div class="px-4 py-3 text-sm text-gray-600 border-t border-gray-100">
|
||
{% if info.output_desc %}{{ info.output_desc|replace('\n', '<br>')|safe }}{% else %}
|
||
<p>生成中文分析报告,包含:总览、详细分析、排行榜、建议等。</p>
|
||
{% endif %}
|
||
</div>
|
||
</details>
|
||
</div>
|
||
|
||
<!-- 输入表单 -->
|
||
<div class="bg-white rounded-xl shadow-sm p-6 mb-8">
|
||
<label class="block font-medium text-gray-700 mb-2">{{ info.prompt_label }}</label>
|
||
<input id="user-input" type="text"
|
||
class="w-full border rounded-lg px-4 py-3 text-gray-700 focus:ring-2 focus:ring-blue-300 focus:border-blue-400 outline-none"
|
||
placeholder="{{ info.prompt_placeholder }}">
|
||
<p id="hint-text" class="text-sm text-gray-400 mt-2"></p>
|
||
<button onclick="runSkill()" id="run-btn"
|
||
class="mt-4 bg-blue-600 hover:bg-blue-700 text-white font-medium px-6 py-3 rounded-lg transition disabled:opacity-50">
|
||
🚀 开始分析
|
||
</button>
|
||
</div>
|
||
|
||
<!-- 进度 -->
|
||
<div id="progress" class="hidden mb-6">
|
||
<div class="bg-white rounded-xl shadow-sm p-6">
|
||
<div class="flex items-center gap-3 mb-4">
|
||
<div class="animate-spin w-5 h-5 border-2 border-blue-600 border-t-transparent rounded-full"></div>
|
||
<span class="text-gray-600 font-medium">AI 正在分析中...</span>
|
||
</div>
|
||
<div id="log" class="text-sm text-gray-500 space-y-1 font-mono max-h-48 overflow-y-auto"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 报告输出 -->
|
||
<div id="report" class="hidden">
|
||
<div class="bg-white rounded-xl shadow-sm p-6 overflow-auto">
|
||
<div id="report-content" class="markdown-body"></div>
|
||
</div>
|
||
<div class="mt-4 flex gap-3">
|
||
<button onclick="downloadTxt()" class="text-sm bg-gray-100 hover:bg-gray-200 text-gray-700 px-4 py-2 rounded-lg transition font-medium">
|
||
📥 下载 TXT
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 错误 -->
|
||
<div id="error" class="hidden bg-red-50 border border-red-200 rounded-xl p-6 text-red-700"></div>
|
||
</div>
|
||
|
||
<script>
|
||
const skillName = "{{ skill_name }}";
|
||
const hints = {
|
||
"research-tracker": "例如:微服务框架、AI Agent、DevOps 流水线、大模型、数据可视化",
|
||
"contributor-insight": "例如:ci4s/ci4sManagement-cloud, jiangtx/gitlink-cli",
|
||
"issue-triage": "例如:Gitlink/gitlink-cli, ci4s/ci4sManagement-cloud",
|
||
"ci-health": "例如:jiangtx/gitlink-cli, Gitlink/gitlink-cli",
|
||
"lab-hotspot": "例如:大模型、AI Agent、微服务、DevOps、数据可视化",
|
||
"lab-insight": "例如:ci4s/ci4sManagement-cloud, Gitlink/gitlink-cli",
|
||
"lab-compliance": "例如:ci4s/ci4sManagement-cloud, Gitlink/gitlink-cli",
|
||
"lab-match": "例如:ci4s/ci4sManagement-cloud, Gitlink/gitlink-cli",
|
||
"lab-track": "例如:ci4s/ci4sManagement-cloud, Gitlink/gitlink-cli",
|
||
};
|
||
document.getElementById('hint-text').textContent = '💡 ' + (hints[skillName] || '');
|
||
|
||
function runSkill() {
|
||
const input = document.getElementById('user-input').value.trim();
|
||
if (!input) { alert('请输入参数'); return; }
|
||
|
||
document.getElementById('progress').classList.remove('hidden');
|
||
document.getElementById('report').classList.add('hidden');
|
||
document.getElementById('error').classList.add('hidden');
|
||
document.getElementById('run-btn').disabled = true;
|
||
document.getElementById('log').innerHTML = '<div>⏳ 提交中...</div>';
|
||
|
||
fetch('/api/run', {
|
||
method: 'POST',
|
||
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
|
||
body: `skill=${encodeURIComponent(skillName)}&input=${encodeURIComponent(input)}`
|
||
})
|
||
.then(r => r.json())
|
||
.then(data => {
|
||
if (data.error) {
|
||
document.getElementById('error').classList.remove('hidden');
|
||
document.getElementById('error').textContent = '❌ ' + data.error;
|
||
return;
|
||
}
|
||
|
||
document.getElementById('log').innerHTML = '<div class="text-green-600">✅ 分析完成</div>';
|
||
|
||
// Render Markdown
|
||
const reportDiv = document.getElementById('report-content');
|
||
reportDiv.innerHTML = marked.parse(data.report || '');
|
||
document.getElementById('report').classList.remove('hidden');
|
||
|
||
// Render Mermaid diagrams (find code.language-mermaid)
|
||
document.querySelectorAll('code.language-mermaid').forEach((code) => {
|
||
const pre = code.parentElement;
|
||
const div = document.createElement('div');
|
||
div.className = 'mermaid';
|
||
div.textContent = code.textContent;
|
||
pre.parentElement.replaceChild(div, pre);
|
||
});
|
||
if (typeof mermaid !== 'undefined') {
|
||
mermaid.run({ nodes: document.querySelectorAll('.mermaid') });
|
||
}
|
||
})
|
||
.catch(err => {
|
||
document.getElementById('error').classList.remove('hidden');
|
||
document.getElementById('error').textContent = '❌ 请求失败: ' + err.message;
|
||
})
|
||
.finally(() => {
|
||
document.getElementById('progress').classList.add('hidden');
|
||
document.getElementById('run-btn').disabled = false;
|
||
});
|
||
}
|
||
|
||
function downloadTxt() {
|
||
const text = document.getElementById('report-content').textContent;
|
||
const blob = new Blob([text], { type: 'text/plain;charset=utf-8' });
|
||
const a = document.createElement('a');
|
||
a.href = URL.createObjectURL(blob);
|
||
a.download = 'report-' + new Date().toISOString().slice(0,10) + '.txt';
|
||
a.click();
|
||
URL.revokeObjectURL(a.href);
|
||
}
|
||
</script>
|
||
|
||
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
|
||
<script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"></script>
|
||
<script>mermaid.initialize({ startOnLoad: false, theme: 'default' });</script>
|
||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.5.1/github-markdown.min.css">
|
||
<style>
|
||
#report-content.markdown-body { padding: 0; }
|
||
#report-content.markdown-body table { display: table; width: 100%; }
|
||
#report-content.markdown-body pre { background: #f6f8fa; border-radius: 6px; position: relative; }
|
||
#report-content.markdown-body code { font-size: 13px; }
|
||
#report-content.markdown-body img { max-width: 100%; }
|
||
/* Mermaid SVG should be visible */
|
||
#report-content.markdown-body .mermaid svg { max-width: 100%; height: auto; }
|
||
</style>
|
||
{% endblock %}
|