cc8dd1070a
- Add macOS menu-bar dictation app with local ASR models (SenseVoice/Qwen3),
global Option hotkey, and bottom overlay
- Add cloud ASR/LLM providers (Anthropic, Volcengine, Bailian, and more) with
provider logos, model listing, and connection checks
- Add shared 7-day usage stats UI (UsageStatsCluster / SevenDayUsageChart)
- Add iOS onboarding step 6 for polish LLM setup; hide custom-language-model
diagnostic toggle behind DEBUG
- Unify iOS onboarding tagline with the macOS brand line ("开口即文字。")
- Rewrite README (Chinese-first, product-oriented) and refresh GitHub Pages
752 lines
31 KiB
HTML
752 lines
31 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-Hans">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
|
||
<!-- Primary SEO -->
|
||
<title>OSGKeyboard — 开口即文字 · iOS & Mac 语音输入</title>
|
||
<meta name="description" content="OSGKeyboard:iPhone、iPad、Mac 通用的语音输入工具。本地识别,AI 润色,任意 App 即说即写。Tap or hold Option — polished text lands at your cursor.">
|
||
<meta name="keywords" content="voice keyboard, dictation, speech to text, iOS keyboard, macOS dictation, 语音输入, 听写, OSGKeyboard, 开口即文字">
|
||
<meta name="author" content="OSGKeyboard">
|
||
<meta name="robots" content="index, follow, max-image-preview:large">
|
||
<meta name="theme-color" content="#0a0a0b">
|
||
<link rel="canonical" href="https://hkgood.github.io/OSGKeyboard/">
|
||
<link rel="icon" href="assets/app-icon.png" type="image/png">
|
||
<link rel="apple-touch-icon" href="assets/app-icon.png">
|
||
|
||
<!-- Open Graph -->
|
||
<meta property="og:type" content="website">
|
||
<meta property="og:site_name" content="OSGKeyboard">
|
||
<meta property="og:title" content="OSGKeyboard — 开口即文字 · iOS & Mac 语音输入">
|
||
<meta property="og:description" content="本地识别,AI 润色,任意 App 即说即写。iPhone、iPad、Mac 通用。">
|
||
<meta property="og:url" content="https://hkgood.github.io/OSGKeyboard/">
|
||
<meta property="og:image" content="https://hkgood.github.io/OSGKeyboard/assets/app-icon.png">
|
||
<meta property="og:image:width" content="1024">
|
||
<meta property="og:image:height" content="1024">
|
||
<meta property="og:locale" content="en_US">
|
||
<meta property="og:locale:alternate" content="zh_CN">
|
||
|
||
<!-- Twitter -->
|
||
<meta name="twitter:card" content="summary_large_image">
|
||
<meta name="twitter:title" content="OSGKeyboard — 开口即文字">
|
||
<meta name="twitter:description" content="iPhone、iPad、Mac 语音输入。本地识别,AI 润色,任意 App 即说即写。">
|
||
<meta name="twitter:image" content="https://hkgood.github.io/OSGKeyboard/assets/app-icon.png">
|
||
|
||
<!-- Structured data -->
|
||
<script type="application/ld+json">
|
||
{
|
||
"@context": "https://schema.org",
|
||
"@type": "SoftwareApplication",
|
||
"name": "OSGKeyboard",
|
||
"operatingSystem": "iOS 26.0 or later, macOS 14.0 or later",
|
||
"applicationCategory": "UtilitiesApplication",
|
||
"url": "https://hkgood.github.io/OSGKeyboard/",
|
||
"image": "https://hkgood.github.io/OSGKeyboard/assets/app-icon.png",
|
||
"description": "Voice input for iPhone, iPad, and Mac. On-device recognition, AI polish, personal dictionary, and iCloud sync. Speak in any app — polished text lands at your cursor.",
|
||
"softwareVersion": "0.5.3",
|
||
"isAccessibleForFree": true,
|
||
"offers": { "@type": "Offer", "price": "0", "priceCurrency": "USD" },
|
||
"author": { "@type": "Organization", "name": "OSGKeyboard" },
|
||
"featureList": [
|
||
"Custom keyboard for iOS and iPadOS",
|
||
"macOS global dictation with Option hotkey",
|
||
"On-device speech recognition",
|
||
"AI text polish with multiple LLM providers",
|
||
"Personal dictionary with iCloud sync",
|
||
"Post-polish translation"
|
||
]
|
||
}
|
||
</script>
|
||
|
||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@24,300,0,0" rel="stylesheet">
|
||
|
||
<style>
|
||
:root {
|
||
color-scheme: light dark;
|
||
--bg: #ffffff;
|
||
--bg-soft: #f7f7f8;
|
||
--text: #0c0c0e;
|
||
--text-secondary: #55555f;
|
||
--text-tertiary: #90909a;
|
||
--line: rgba(0, 0, 0, 0.08);
|
||
--accent: #2d8a4a;
|
||
--accent-soft: rgba(45, 138, 74, 0.10);
|
||
--nav-bg: rgba(255, 255, 255, 0.72);
|
||
--max: 1020px;
|
||
--radius: 18px;
|
||
}
|
||
|
||
@media (prefers-color-scheme: dark) {
|
||
:root {
|
||
--bg: #0a0a0b;
|
||
--bg-soft: #131316;
|
||
--text: #f4f4f6;
|
||
--text-secondary: #a6a6b0;
|
||
--text-tertiary: #6e6e78;
|
||
--line: rgba(255, 255, 255, 0.10);
|
||
--accent: #4cc46e;
|
||
--accent-soft: rgba(76, 196, 110, 0.14);
|
||
--nav-bg: rgba(10, 10, 11, 0.72);
|
||
}
|
||
}
|
||
|
||
* { box-sizing: border-box; }
|
||
html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; }
|
||
|
||
body {
|
||
margin: 0;
|
||
font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI", system-ui, sans-serif;
|
||
background: var(--bg);
|
||
color: var(--text);
|
||
line-height: 1.6;
|
||
-webkit-font-smoothing: antialiased;
|
||
text-rendering: optimizeLegibility;
|
||
}
|
||
|
||
a { color: inherit; text-decoration: none; }
|
||
|
||
.material-symbols-outlined {
|
||
font-variation-settings: 'FILL' 0, 'wght' 300, 'GRAD' 0, 'opsz' 24;
|
||
line-height: 1;
|
||
user-select: none;
|
||
}
|
||
|
||
.wrap {
|
||
max-width: var(--max);
|
||
margin: 0 auto;
|
||
padding: 0 1.5rem;
|
||
}
|
||
|
||
/* Nav */
|
||
.nav {
|
||
position: sticky;
|
||
top: 0;
|
||
z-index: 20;
|
||
background: var(--nav-bg);
|
||
backdrop-filter: blur(20px) saturate(1.6);
|
||
-webkit-backdrop-filter: blur(20px) saturate(1.6);
|
||
border-bottom: 1px solid var(--line);
|
||
}
|
||
|
||
.nav-inner {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
min-height: 60px;
|
||
gap: 1rem;
|
||
}
|
||
|
||
.brand {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.6rem;
|
||
font-weight: 650;
|
||
letter-spacing: -0.01em;
|
||
}
|
||
|
||
.brand img { width: 28px; height: 28px; border-radius: 7px; }
|
||
|
||
.nav-right { display: flex; align-items: center; gap: 0.5rem; }
|
||
|
||
.lang-toggle {
|
||
display: inline-flex;
|
||
padding: 2px;
|
||
border-radius: 999px;
|
||
border: 1px solid var(--line);
|
||
}
|
||
|
||
.lang-toggle button {
|
||
border: 0;
|
||
background: transparent;
|
||
color: var(--text-tertiary);
|
||
font: inherit;
|
||
font-size: 0.8rem;
|
||
font-weight: 600;
|
||
padding: 0.3rem 0.7rem;
|
||
border-radius: 999px;
|
||
cursor: pointer;
|
||
transition: color 0.2s, background 0.2s;
|
||
}
|
||
|
||
.lang-toggle button.active { background: var(--text); color: var(--bg); }
|
||
|
||
.ghost-link {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 0.35rem;
|
||
font-size: 0.85rem;
|
||
font-weight: 600;
|
||
color: var(--text-secondary);
|
||
padding: 0.4rem 0.6rem;
|
||
border-radius: 999px;
|
||
transition: color 0.2s;
|
||
}
|
||
.ghost-link:hover { color: var(--text); }
|
||
.ghost-link .material-symbols-outlined { font-size: 18px; }
|
||
|
||
/* Buttons */
|
||
.btn {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 0.45rem;
|
||
font-weight: 600;
|
||
font-size: 0.95rem;
|
||
padding: 0.75rem 1.3rem;
|
||
border-radius: 999px;
|
||
transition: transform 0.15s ease, opacity 0.15s ease;
|
||
}
|
||
.btn:hover { transform: translateY(-1px); }
|
||
.btn .material-symbols-outlined { font-size: 20px; }
|
||
|
||
.btn-primary { background: var(--accent); color: #fff; }
|
||
.btn-quiet { color: var(--text); border: 1px solid var(--line); }
|
||
|
||
/* Hero */
|
||
.hero { padding: 5.5rem 0 3.5rem; }
|
||
|
||
.hero-grid {
|
||
display: grid;
|
||
grid-template-columns: 1.05fr 0.95fr;
|
||
gap: 3rem;
|
||
align-items: center;
|
||
}
|
||
|
||
@media (max-width: 860px) {
|
||
.hero { padding: 3.5rem 0 2.5rem; }
|
||
.hero-grid { grid-template-columns: 1fr; gap: 2.5rem; }
|
||
.hero-visual { order: -1; }
|
||
}
|
||
|
||
.eyebrow {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 0.5rem;
|
||
font-size: 0.8rem;
|
||
font-weight: 600;
|
||
color: var(--accent);
|
||
margin-bottom: 1.25rem;
|
||
}
|
||
.eyebrow .material-symbols-outlined { font-size: 17px; }
|
||
|
||
h1 {
|
||
margin: 0 0 1.25rem;
|
||
font-size: clamp(2.3rem, 5.4vw, 3.6rem);
|
||
line-height: 1.05;
|
||
letter-spacing: -0.035em;
|
||
font-weight: 700;
|
||
}
|
||
|
||
.lead {
|
||
margin: 0 0 2rem;
|
||
font-size: 1.14rem;
|
||
color: var(--text-secondary);
|
||
max-width: 33rem;
|
||
}
|
||
|
||
.hero-cta { display: flex; flex-wrap: wrap; gap: 0.75rem; margin-bottom: 1.75rem; }
|
||
|
||
.hero-meta {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 0.5rem 1.25rem;
|
||
font-size: 0.85rem;
|
||
color: var(--text-tertiary);
|
||
}
|
||
.hero-meta span { display: inline-flex; align-items: center; gap: 0.35rem; }
|
||
.hero-meta .material-symbols-outlined { font-size: 17px; color: var(--accent); }
|
||
|
||
/* Phone mock */
|
||
.phone {
|
||
max-width: 300px;
|
||
margin: 0 auto;
|
||
border-radius: 40px;
|
||
padding: 10px;
|
||
background: var(--bg-soft);
|
||
border: 1px solid var(--line);
|
||
box-shadow: 0 40px 90px rgba(0, 0, 0, 0.18);
|
||
}
|
||
|
||
.phone-screen {
|
||
border-radius: 32px;
|
||
overflow: hidden;
|
||
background: #16161a;
|
||
display: flex;
|
||
flex-direction: column;
|
||
min-height: 440px;
|
||
}
|
||
|
||
.screen-top { padding: 1.3rem 1.2rem 0.4rem; color: #f4f4f6; }
|
||
.screen-app { font-size: 0.8rem; color: #8a8a94; margin: 0 0 0.15rem; }
|
||
.screen-line { font-size: 0.95rem; line-height: 1.5; margin: 0; color: #e8e8ec; }
|
||
.screen-caret { color: #4cc46e; font-weight: 700; }
|
||
|
||
.kb {
|
||
margin-top: auto;
|
||
background: #1e1e22;
|
||
border-top: 1px solid rgba(255,255,255,0.06);
|
||
padding: 0.9rem 0.9rem 1.1rem;
|
||
}
|
||
|
||
.kb-bar { display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.75rem; }
|
||
.kb-chip {
|
||
font-size: 0.68rem;
|
||
font-weight: 600;
|
||
color: #cfcfd6;
|
||
padding: 0.28rem 0.6rem;
|
||
border-radius: 999px;
|
||
background: rgba(255,255,255,0.08);
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 0.3rem;
|
||
}
|
||
.kb-chip .material-symbols-outlined { font-size: 14px; }
|
||
|
||
.kb-mic {
|
||
width: 60px; height: 60px;
|
||
margin: 0.2rem auto 0;
|
||
border-radius: 50%;
|
||
background: var(--accent);
|
||
display: grid;
|
||
place-items: center;
|
||
color: #fff;
|
||
box-shadow: 0 0 0 8px var(--accent-soft);
|
||
position: relative;
|
||
}
|
||
.kb-mic .material-symbols-outlined { font-size: 28px; }
|
||
.kb-mic::after {
|
||
content: "";
|
||
position: absolute;
|
||
inset: -8px;
|
||
border-radius: 50%;
|
||
border: 2px solid var(--accent);
|
||
opacity: 0;
|
||
animation: ring 2.6s ease-out infinite;
|
||
}
|
||
@keyframes ring {
|
||
0% { transform: scale(0.85); opacity: 0.5; }
|
||
100% { transform: scale(1.55); opacity: 0; }
|
||
}
|
||
|
||
/* Section */
|
||
section.block { padding: 3.5rem 0; }
|
||
.block-head { max-width: 40rem; margin: 0 0 2.75rem; }
|
||
.block-head h2 {
|
||
margin: 0 0 0.6rem;
|
||
font-size: clamp(1.6rem, 3.2vw, 2.1rem);
|
||
letter-spacing: -0.025em;
|
||
font-weight: 700;
|
||
}
|
||
.block-head p { margin: 0; color: var(--text-secondary); font-size: 1.02rem; }
|
||
|
||
/* Features — light, editorial, no heavy cards */
|
||
.features {
|
||
display: grid;
|
||
grid-template-columns: repeat(3, 1fr);
|
||
gap: 2rem 2.5rem;
|
||
}
|
||
@media (max-width: 780px) { .features { grid-template-columns: repeat(2, 1fr); gap: 2rem; } }
|
||
@media (max-width: 480px) { .features { grid-template-columns: 1fr; } }
|
||
|
||
.feature .ficon {
|
||
width: 44px; height: 44px;
|
||
border-radius: 12px;
|
||
background: var(--accent-soft);
|
||
color: var(--accent);
|
||
display: grid;
|
||
place-items: center;
|
||
margin-bottom: 0.9rem;
|
||
}
|
||
.feature .ficon .material-symbols-outlined { font-size: 24px; }
|
||
.feature h3 { margin: 0 0 0.35rem; font-size: 1.02rem; font-weight: 650; letter-spacing: -0.01em; }
|
||
.feature p { margin: 0; font-size: 0.93rem; color: var(--text-secondary); }
|
||
|
||
/* Steps */
|
||
.steps {
|
||
display: grid;
|
||
grid-template-columns: repeat(3, 1fr);
|
||
gap: 2.5rem;
|
||
counter-reset: s;
|
||
}
|
||
@media (max-width: 720px) { .steps { grid-template-columns: 1fr; gap: 2rem; } }
|
||
|
||
.step { position: relative; padding-top: 0.5rem; }
|
||
.step::before {
|
||
counter-increment: s;
|
||
content: counter(s);
|
||
display: grid;
|
||
place-items: center;
|
||
width: 30px; height: 30px;
|
||
border-radius: 50%;
|
||
border: 1.5px solid var(--accent);
|
||
color: var(--accent);
|
||
font-size: 0.85rem;
|
||
font-weight: 700;
|
||
margin-bottom: 0.85rem;
|
||
}
|
||
.step h3 { margin: 0 0 0.35rem; font-size: 1.05rem; font-weight: 650; }
|
||
.step p { margin: 0; color: var(--text-secondary); font-size: 0.95rem; }
|
||
|
||
/* Platforms */
|
||
.platforms {
|
||
display: grid;
|
||
grid-template-columns: repeat(2, 1fr);
|
||
gap: 1.25rem;
|
||
}
|
||
@media (max-width: 640px) { .platforms { grid-template-columns: 1fr; } }
|
||
|
||
.platform {
|
||
padding: 1.5rem;
|
||
border-radius: var(--radius);
|
||
border: 1px solid var(--line);
|
||
background: var(--bg-soft);
|
||
}
|
||
.platform-head {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.6rem;
|
||
margin-bottom: 0.75rem;
|
||
}
|
||
.platform-head .material-symbols-outlined { font-size: 22px; color: var(--accent); }
|
||
.platform h3 { margin: 0; font-size: 1.05rem; font-weight: 650; }
|
||
.platform p { margin: 0; font-size: 0.93rem; color: var(--text-secondary); line-height: 1.55; }
|
||
|
||
/* Closing */
|
||
.closing {
|
||
border-top: 1px solid var(--line);
|
||
border-bottom: 1px solid var(--line);
|
||
padding: 3.5rem 0;
|
||
}
|
||
.closing-inner {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
gap: 1.5rem;
|
||
}
|
||
.closing h2 { margin: 0 0 0.5rem; font-size: 1.5rem; letter-spacing: -0.02em; }
|
||
.closing p { margin: 0; color: var(--text-secondary); max-width: 34rem; }
|
||
.closing .lock { display: inline-flex; align-items: center; gap: 0.4rem; color: var(--accent); font-weight: 600; font-size: 0.85rem; margin-bottom: 0.75rem; }
|
||
.closing .lock .material-symbols-outlined { font-size: 18px; }
|
||
|
||
/* Footer */
|
||
footer { padding: 2.5rem 0 3rem; color: var(--text-tertiary); font-size: 0.85rem; }
|
||
.footer-inner { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 0.75rem; align-items: center; }
|
||
.footer-links { display: flex; flex-wrap: wrap; gap: 1.1rem; }
|
||
.footer-links a { color: var(--text-secondary); }
|
||
.footer-links a:hover { color: var(--text); }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<header class="nav">
|
||
<div class="wrap nav-inner">
|
||
<a class="brand" href="#top">
|
||
<img src="assets/app-icon.png" width="28" height="28" alt="OSGKeyboard app icon">
|
||
OSGKeyboard
|
||
</a>
|
||
<div class="nav-right">
|
||
<div class="lang-toggle" role="group" aria-label="Language">
|
||
<button type="button" data-lang="en">EN</button>
|
||
<button type="button" class="active" data-lang="zh">中文</button>
|
||
</div>
|
||
<a class="ghost-link" href="https://github.com/hkgood/OSGKeyboard" rel="noopener">
|
||
<span class="material-symbols-outlined" aria-hidden="true">code</span>
|
||
<span data-i18n="nav.github">GitHub</span>
|
||
</a>
|
||
</div>
|
||
</div>
|
||
</header>
|
||
|
||
<main id="top">
|
||
<!-- Hero -->
|
||
<section class="hero">
|
||
<div class="wrap hero-grid">
|
||
<div>
|
||
<div class="eyebrow">
|
||
<span class="material-symbols-outlined" aria-hidden="true">verified</span>
|
||
<span data-i18n="hero.eyebrow">iOS · iPadOS · macOS</span>
|
||
</div>
|
||
<h1 data-i18n="hero.title">开口即文字。</h1>
|
||
<p class="lead" data-i18n="hero.lead">iPhone、iPad、Mac 通用的语音输入工具。本地识别,AI 润色,任意 App 即说即写。</p>
|
||
<div class="hero-cta">
|
||
<a class="btn btn-primary" href="https://github.com/hkgood/OSGKeyboard" rel="noopener">
|
||
<span class="material-symbols-outlined" aria-hidden="true">download</span>
|
||
<span data-i18n="hero.cta.primary">立即获取</span>
|
||
</a>
|
||
<a class="btn btn-quiet" href="privacy/">
|
||
<span class="material-symbols-outlined" aria-hidden="true">shield</span>
|
||
<span data-i18n="hero.cta.secondary">隐私政策</span>
|
||
</a>
|
||
</div>
|
||
<div class="hero-meta">
|
||
<span><span class="material-symbols-outlined" aria-hidden="true">devices</span><span data-i18n="hero.meta1">默认本地识别</span></span>
|
||
<span><span class="material-symbols-outlined" aria-hidden="true">auto_awesome</span><span data-i18n="hero.meta2">AI 自动润色</span></span>
|
||
<span><span class="material-symbols-outlined" aria-hidden="true">apps</span><span data-i18n="hero.meta3">任意 App 可用</span></span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="hero-visual">
|
||
<div class="phone">
|
||
<div class="phone-screen">
|
||
<div class="screen-top">
|
||
<p class="screen-app" data-i18n="mock.app">Notes</p>
|
||
<p class="screen-line" data-i18n="mock.line">Tomorrow at 3 PM, sync with the design team on the new onboarding flow.<span class="screen-caret">|</span></p>
|
||
</div>
|
||
<div class="kb">
|
||
<div class="kb-bar">
|
||
<span class="kb-chip"><span class="material-symbols-outlined" aria-hidden="true">devices</span><span data-i18n="mock.chipEngine">On-device</span></span>
|
||
<span class="kb-chip"><span class="material-symbols-outlined" aria-hidden="true">translate</span><span data-i18n="mock.chipTranslate">Translate</span></span>
|
||
</div>
|
||
<div class="kb-mic"><span class="material-symbols-outlined" aria-hidden="true">mic</span></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- Platforms -->
|
||
<section class="block wrap">
|
||
<div class="block-head">
|
||
<h2 data-i18n="platforms.title">两个平台,同一种体验</h2>
|
||
<p data-i18n="platforms.subtitle">手机上用键盘,Mac 上按住 Option — 说完即落字。</p>
|
||
</div>
|
||
<div class="platforms">
|
||
<div class="platform">
|
||
<div class="platform-head">
|
||
<span class="material-symbols-outlined" aria-hidden="true">smartphone</span>
|
||
<h3 data-i18n="platform.ios.t">iOS / iPadOS</h3>
|
||
</div>
|
||
<p data-i18n="platform.ios.b">自定义键盘 + Flow 会话。点按麦克风说话,连续听写不用跳 App。灵动岛显示录音状态。</p>
|
||
</div>
|
||
<div class="platform">
|
||
<div class="platform-head">
|
||
<span class="material-symbols-outlined" aria-hidden="true">laptop_mac</span>
|
||
<h3 data-i18n="platform.mac.t">macOS</h3>
|
||
</div>
|
||
<p data-i18n="platform.mac.b">菜单栏常驻,按住 Option 全局听写。底部浮层实时反馈,支持 SenseVoice / Qwen3 本地模型。</p>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- Features -->
|
||
<section class="block wrap">
|
||
<div class="block-head">
|
||
<h2 data-i18n="features.title">开口即写,所需尽在此</h2>
|
||
<p data-i18n="features.subtitle">本地优先,AI 加持 — 从识别到润色,一条链路搞定。</p>
|
||
</div>
|
||
<div class="features">
|
||
<div class="feature">
|
||
<div class="ficon"><span class="material-symbols-outlined" aria-hidden="true">mic</span></div>
|
||
<h3 data-i18n="feat.dictation.t">点按听写</h3>
|
||
<p data-i18n="feat.dictation.b">点一下开始,再点一下结束。单次最长 3.5 分钟,倒计时实时显示。</p>
|
||
</div>
|
||
<div class="feature">
|
||
<div class="ficon"><span class="material-symbols-outlined" aria-hidden="true">devices</span></div>
|
||
<h3 data-i18n="feat.ondevice.t">本地识别</h3>
|
||
<p data-i18n="feat.ondevice.b">iOS 端侧 SpeechAnalyzer;Mac 可选 SenseVoice / Qwen3。默认不上传录音。</p>
|
||
</div>
|
||
<div class="feature">
|
||
<div class="ficon"><span class="material-symbols-outlined" aria-hidden="true">auto_awesome</span></div>
|
||
<h3 data-i18n="feat.polish.t">AI 润色</h3>
|
||
<p data-i18n="feat.polish.b">自动补标点、整理结构。内置润色开箱即用,也可接入 DeepSeek、OpenAI 等 API。</p>
|
||
</div>
|
||
<div class="feature">
|
||
<div class="ficon"><span class="material-symbols-outlined" aria-hidden="true">translate</span></div>
|
||
<h3 data-i18n="feat.translate.t">润色后翻译</h3>
|
||
<p data-i18n="feat.translate.b">润色完成后一键翻译为 English、中文、日本語、한국어 等。</p>
|
||
</div>
|
||
<div class="feature">
|
||
<div class="ficon"><span class="material-symbols-outlined" aria-hidden="true">menu_book</span></div>
|
||
<h3 data-i18n="feat.dict.t">个性词库</h3>
|
||
<p data-i18n="feat.dict.b">人名、产品名、专业术语 — AI 润色时原样保留,iCloud 多设备同步。</p>
|
||
</div>
|
||
<div class="feature">
|
||
<div class="ficon"><span class="material-symbols-outlined" aria-hidden="true">cloud_sync</span></div>
|
||
<h3 data-i18n="feat.sync.t">iCloud 同步</h3>
|
||
<p data-i18n="feat.sync.b">设置、词库、听写历史在多设备间自动同步,换机无缝衔接。</p>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- How it works -->
|
||
<section class="block wrap">
|
||
<div class="block-head">
|
||
<h2 data-i18n="steps.title">三步,开始第一句话</h2>
|
||
<p data-i18n="steps.subtitle">设置一次,之后在任意输入处开口即写。</p>
|
||
</div>
|
||
<div class="steps">
|
||
<div class="step">
|
||
<h3 data-i18n="step1.t">安装并授权</h3>
|
||
<p data-i18n="step1.b">iOS 添加键盘并开启完全访问;Mac 授予麦克风与辅助功能权限。</p>
|
||
</div>
|
||
<div class="step">
|
||
<h3 data-i18n="step2.t">选引擎与润色</h3>
|
||
<p data-i18n="step2.b">本地识别 + 内置润色零配置可用;也可填入自己的 API Key 接入任意兼容模型。</p>
|
||
</div>
|
||
<div class="step">
|
||
<h3 data-i18n="step3.t">开口说话</h3>
|
||
<p data-i18n="step3.b">切换到 OSGKeyboard 键盘,或按住 Option 键。润色好的文字自动插入光标处。</p>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- Closing / privacy -->
|
||
<section class="closing">
|
||
<div class="wrap closing-inner">
|
||
<div>
|
||
<span class="lock"><span class="material-symbols-outlined" aria-hidden="true">lock</span><span data-i18n="close.badge">隐私优先</span></span>
|
||
<h2 data-i18n="close.title">你的声音,始终属于你</h2>
|
||
<p data-i18n="close.body">默认在设备端识别,录音不上传。润色只发送转写文字,不记录日常击键。云端引擎需你主动开启,并适用所配置服务商的隐私条款。</p>
|
||
</div>
|
||
<a class="btn btn-quiet" href="privacy/">
|
||
<span class="material-symbols-outlined" aria-hidden="true">description</span>
|
||
<span data-i18n="close.cta">查看隐私政策</span>
|
||
</a>
|
||
</div>
|
||
</section>
|
||
</main>
|
||
|
||
<footer class="wrap">
|
||
<div class="footer-inner">
|
||
<span data-i18n="footer.copy">© OSGKeyboard · v0.5.3 · 源码可见</span>
|
||
<span class="footer-links">
|
||
<a href="https://github.com/hkgood/OSGKeyboard" rel="noopener" data-i18n="footer.source">Source</a>
|
||
<a href="privacy/" data-i18n="footer.privacy">Privacy</a>
|
||
<a href="https://github.com/hkgood/OSGKeyboard/blob/main/LICENSE" rel="noopener" data-i18n="footer.license">License</a>
|
||
</span>
|
||
</div>
|
||
</footer>
|
||
|
||
<script>
|
||
const copy = {
|
||
en: {
|
||
"nav.github": "GitHub",
|
||
"hero.eyebrow": "iOS · iPadOS · macOS",
|
||
"hero.title": "Speak it. It's typed.",
|
||
"hero.lead": "Voice input for iPhone, iPad, and Mac. On-device recognition, AI polish — speak in any app.",
|
||
"hero.cta.primary": "Get it now",
|
||
"hero.cta.secondary": "Privacy",
|
||
"hero.meta1": "On-device by default",
|
||
"hero.meta2": "AI polish",
|
||
"hero.meta3": "Works in every app",
|
||
"mock.app": "Notes",
|
||
"mock.line": "Tomorrow at 3 PM, sync with the design team on the new onboarding flow.",
|
||
"mock.chipEngine": "Local",
|
||
"mock.chipTranslate": "Translate",
|
||
"platforms.title": "Two platforms, one experience",
|
||
"platforms.subtitle": "Keyboard on phone, hold Option on Mac — speak and it's typed.",
|
||
"platform.ios.t": "iOS / iPadOS",
|
||
"platform.ios.b": "Custom keyboard + Flow session. Tap the mic, dictate take after take without leaving your app. Live Activity on Dynamic Island.",
|
||
"platform.mac.t": "macOS",
|
||
"platform.mac.b": "Menu-bar app with global Option hotkey. Bottom overlay with live feedback. Optional SenseVoice / Qwen3 local models.",
|
||
"features.title": "Everything you need to type by voice",
|
||
"features.subtitle": "Local first, AI refined — recognition to polish in one flow.",
|
||
"feat.dictation.t": "Tap-to-talk",
|
||
"feat.dictation.b": "Tap to start, tap to stop. Up to 3.5 minutes per take with a live countdown.",
|
||
"feat.ondevice.t": "On-device recognition",
|
||
"feat.ondevice.b": "iOS SpeechAnalyzer; Mac SenseVoice / Qwen3 optional. Audio stays local by default.",
|
||
"feat.polish.t": "AI polish",
|
||
"feat.polish.b": "Punctuation and structure, three intensity levels. Built-in polish or bring your own DeepSeek / OpenAI API.",
|
||
"feat.translate.t": "Post-polish translation",
|
||
"feat.translate.b": "Translate into English, 中文, 日本語, 한국어 and more after polish.",
|
||
"feat.dict.t": "Personal dictionary",
|
||
"feat.dict.b": "Names, products, jargon — preserved verbatim by the AI, synced via iCloud.",
|
||
"feat.sync.t": "iCloud sync",
|
||
"feat.sync.b": "Settings, dictionary, and history sync across devices seamlessly.",
|
||
"steps.title": "Three steps to your first message",
|
||
"steps.subtitle": "Set up once, then dictate anywhere.",
|
||
"step1.t": "Install & authorize",
|
||
"step1.b": "Add the iOS keyboard with Full Access; grant mic + Accessibility on Mac.",
|
||
"step2.t": "Pick engine & polish",
|
||
"step2.b": "Local ASR + built-in polish works out of the box. Or add your own API key.",
|
||
"step3.t": "Start talking",
|
||
"step3.b": "Switch to OSGKeyboard, or hold Option on Mac. Polished text lands at your cursor.",
|
||
"close.badge": "Privacy first",
|
||
"close.title": "Your voice stays yours",
|
||
"close.body": "On-device recognition by default — audio is not uploaded. Polish receives text only; we never log keystrokes. Cloud engine requires explicit opt-in.",
|
||
"close.cta": "Read the privacy policy",
|
||
"footer.copy": "© OSGKeyboard · v0.5.3 · source available",
|
||
"footer.source": "Source",
|
||
"footer.privacy": "Privacy",
|
||
"footer.license": "License"
|
||
},
|
||
zh: {
|
||
"nav.github": "GitHub",
|
||
"hero.eyebrow": "iOS · iPadOS · macOS",
|
||
"hero.title": "开口即文字。",
|
||
"hero.lead": "iPhone、iPad、Mac 通用的语音输入工具。本地识别,AI 润色,任意 App 即说即写。",
|
||
"hero.cta.primary": "立即获取",
|
||
"hero.cta.secondary": "隐私政策",
|
||
"hero.meta1": "默认本地识别",
|
||
"hero.meta2": "AI 自动润色",
|
||
"hero.meta3": "任意 App 可用",
|
||
"mock.app": "备忘录",
|
||
"mock.line": "明天下午三点,和设计团队同步新引导流程。",
|
||
"mock.chipEngine": "本地",
|
||
"mock.chipTranslate": "翻译",
|
||
"platforms.title": "两个平台,同一种体验",
|
||
"platforms.subtitle": "手机上用键盘,Mac 上按住 Option — 说完即落字。",
|
||
"platform.ios.t": "iOS / iPadOS",
|
||
"platform.ios.b": "自定义键盘 + Flow 会话。点按麦克风说话,连续听写不用跳 App。灵动岛显示录音状态。",
|
||
"platform.mac.t": "macOS",
|
||
"platform.mac.b": "菜单栏常驻,按住 Option 全局听写。底部浮层实时反馈,支持 SenseVoice / Qwen3 本地模型。",
|
||
"features.title": "开口即写,所需尽在此",
|
||
"features.subtitle": "本地优先,AI 加持 — 从识别到润色,一条链路搞定。",
|
||
"feat.dictation.t": "点按听写",
|
||
"feat.dictation.b": "点一下开始,再点一下结束。单次最长 3.5 分钟,倒计时实时显示。",
|
||
"feat.ondevice.t": "本地识别",
|
||
"feat.ondevice.b": "iOS 端侧 SpeechAnalyzer;Mac 可选 SenseVoice / Qwen3。默认不上传录音。",
|
||
"feat.polish.t": "AI 润色",
|
||
"feat.polish.b": "自动补标点、整理结构。内置润色开箱即用,也可接入 DeepSeek、OpenAI 等 API。",
|
||
"feat.translate.t": "润色后翻译",
|
||
"feat.translate.b": "润色完成后一键翻译为 English、中文、日本語、한국어 等。",
|
||
"feat.dict.t": "个性词库",
|
||
"feat.dict.b": "人名、产品名、专业术语 — AI 润色时原样保留,iCloud 多设备同步。",
|
||
"feat.sync.t": "iCloud 同步",
|
||
"feat.sync.b": "设置、词库、听写历史在多设备间自动同步,换机无缝衔接。",
|
||
"steps.title": "三步,开始第一句话",
|
||
"steps.subtitle": "设置一次,之后在任意输入处开口即写。",
|
||
"step1.t": "安装并授权",
|
||
"step1.b": "iOS 添加键盘并开启完全访问;Mac 授予麦克风与辅助功能权限。",
|
||
"step2.t": "选引擎与润色",
|
||
"step2.b": "本地识别 + 内置润色零配置可用;也可填入自己的 API Key 接入任意兼容模型。",
|
||
"step3.t": "开口说话",
|
||
"step3.b": "切换到 OSGKeyboard 键盘,或按住 Option 键。润色好的文字自动插入光标处。",
|
||
"close.badge": "隐私优先",
|
||
"close.title": "你的声音,始终属于你",
|
||
"close.body": "默认在设备端识别,录音不上传。润色只发送转写文字,不记录日常击键。云端引擎需你主动开启,并适用所配置服务商的隐私条款。",
|
||
"close.cta": "查看隐私政策",
|
||
"footer.copy": "© OSGKeyboard · v0.5.3 · 源码可见",
|
||
"footer.source": "源代码",
|
||
"footer.privacy": "隐私",
|
||
"footer.license": "许可协议"
|
||
}
|
||
};
|
||
|
||
function applyLang(lang) {
|
||
const strings = copy[lang] || copy.zh;
|
||
document.documentElement.lang = lang === "zh" ? "zh-Hans" : "en";
|
||
document.querySelectorAll("[data-i18n]").forEach((el) => {
|
||
const value = strings[el.getAttribute("data-i18n")];
|
||
if (value == null) return;
|
||
el.textContent = value;
|
||
});
|
||
document.querySelectorAll(".lang-toggle button").forEach((btn) => {
|
||
btn.classList.toggle("active", btn.dataset.lang === lang);
|
||
});
|
||
try { localStorage.setItem("osg-lang", lang); } catch (_) {}
|
||
}
|
||
|
||
document.querySelectorAll(".lang-toggle button").forEach((btn) => {
|
||
btn.addEventListener("click", () => applyLang(btn.dataset.lang));
|
||
});
|
||
|
||
const saved = (() => { try { return localStorage.getItem("osg-lang"); } catch (_) { return null; } })();
|
||
applyLang(saved || "zh");
|
||
</script>
|
||
</body>
|
||
</html>
|