diff --git a/web/src/i18n/locales/en.json b/web/src/i18n/locales/en.json
index 1420319..df2217d 100644
--- a/web/src/i18n/locales/en.json
+++ b/web/src/i18n/locales/en.json
@@ -5690,6 +5690,7 @@
"语音 & 音频": "Audio & Speech",
"支持模型": "Supported Models",
"速率限制": "Rate Limits",
- "常见问题": "FAQ"
+ "常见问题": "FAQ",
+ "本页目录": "On this page"
}
}
\ No newline at end of file
diff --git a/web/src/i18n/locales/zh-CN.json b/web/src/i18n/locales/zh-CN.json
index 582b24f..0250766 100644
--- a/web/src/i18n/locales/zh-CN.json
+++ b/web/src/i18n/locales/zh-CN.json
@@ -5549,6 +5549,7 @@
"语音 & 音频": "语音 & 音频",
"支持模型": "支持模型",
"速率限制": "速率限制",
- "常见问题": "常见问题"
+ "常见问题": "常见问题",
+ "本页目录": "本页目录"
}
}
\ No newline at end of file
diff --git a/web/src/pages/Docs/index.jsx b/web/src/pages/Docs/index.jsx
index 83c9b52..bb2a2a7 100644
--- a/web/src/pages/Docs/index.jsx
+++ b/web/src/pages/Docs/index.jsx
@@ -38,6 +38,7 @@ import {
Music,
Video,
FileText,
+ List,
} from 'lucide-react';
/* ─── DOCS SECTIONS ─── */
@@ -95,8 +96,8 @@ function SectionTitle({ id, icon: Icon, children }) {
}
/* ─── SubSection ─── */
-function SubSection({ children, className = '' }) {
- return
{children}
;
+function SubSection({ id, children, className = '' }) {
+ return {children}
;
}
/* ─── Paragraph ─── */
@@ -145,6 +146,90 @@ function InfoCard({ icon: Icon, title, children, className = '' }) {
);
}
+/* ─── Right Page TOC ─── */
+function RightToc({ contentRef, HEADER_OFFSET, activeSection }) {
+ const { t } = useTranslation();
+ const [tocItems, setTocItems] = useState([]);
+ const [activeTocId, setActiveTocId] = useState('');
+
+ // Build TOC from all h2/h3 headings in the content area
+ useEffect(() => {
+ if (!contentRef.current) return;
+ const timer = setTimeout(() => {
+ const headings = contentRef.current.querySelectorAll('h2[id], h3[id]');
+ const items = [];
+ headings.forEach((h) => {
+ items.push({
+ id: h.id,
+ text: h.textContent.trim(),
+ level: h.tagName === 'H2' ? 2 : 3,
+ });
+ });
+ setTocItems(items);
+ }, 100);
+ return () => clearTimeout(timer);
+ }, [contentRef, activeSection]);
+
+ // TOC scroll-spy
+ useEffect(() => {
+ if (tocItems.length === 0) return;
+ const observer = new IntersectionObserver(
+ (entries) => {
+ for (const entry of entries) {
+ if (entry.isIntersecting) {
+ setActiveTocId(entry.target.id);
+ break;
+ }
+ }
+ },
+ { rootMargin: `-${HEADER_OFFSET}px 0px -80% 0px`, threshold: 0 }
+ );
+
+ tocItems.forEach((item) => {
+ const el = document.getElementById(item.id);
+ if (el) observer.observe(el);
+ });
+
+ return () => observer.disconnect();
+ }, [tocItems, HEADER_OFFSET]);
+
+ const scrollToHeading = (id) => {
+ const el = document.getElementById(id);
+ if (!el) return;
+ const top = el.getBoundingClientRect().top + window.scrollY - HEADER_OFFSET;
+ window.scrollTo({ top, behavior: 'smooth' });
+ };
+
+ if (tocItems.length === 0) return null;
+
+ return (
+
+ );
+}
+
/* ─── MAIN DOCS PAGE ─── */
export default function Docs() {
const { t } = useTranslation();
@@ -256,7 +341,7 @@ export default function Docs() {
)}
{/* ── Content ── */}
-
+
{/* ── Section: 概述 ── */}
{t('概述')}
@@ -321,13 +406,13 @@ export default function Docs() {
API 密钥是与 TuringToken 通信的凭证。每个密钥可以设置额度上限、有效期和 IP 白名单。
- 创建密钥
+ 创建密钥
登录后进入 控制台 → API Key,
点击"新建 API Key",填写名称后即可生成。请务必妥善保存密钥,关闭页面后将无法再次查看完整密钥。
- 使用密钥
+ 使用密钥
在所有 API 请求中,通过 Bearer Token 方式传递密钥:
- 基础请求
+ 基础请求
- 流式输出
+ 流式输出
设置 stream: true 即可启用 SSE 流式响应:
- Node.js SDK 示例
+ Node.js SDK 示例
{t('语音 & 音频')}
支持语音转文字(STT)和文字转语音(TTS),兼容 OpenAI Audio API 格式。
- 语音转文字 (STT)
+ 语音转文字 (STT)
- 文字转语音 (TTS)
+ 文字转语音 (TTS)
+
+ {/* ── Right Page TOC ── */}
+
);