feat: add privacy mode, thinking levels, PWA support, and i18n
- Add privacy mode to hide IP and user preferences from AI requests - Add model thinking levels (low/medium/high) for context analysis depth - Add PWA support with service worker, manifest, and app icons - Add SettingsPanel for user preferences (theme, background, language) - Add i18n translations for en/zh/ja/ko/de/fr - Add Pinia store for centralized settings management - Update backend to support user preferences and thinking levels - Update config to use absolute API URLs
This commit is contained in:
+26
-6
@@ -16,16 +16,36 @@ async function getClientIP() {
|
||||
}
|
||||
}
|
||||
|
||||
import { useSettingsStore } from '../stores/settings'
|
||||
|
||||
export async function fetchSuggestion(prefix, suffix, signal, apiUrl = API_URL) {
|
||||
try {
|
||||
const settings = useSettingsStore()
|
||||
const clientIP = await getClientIP()
|
||||
const headers = { 'Content-Type': 'application/json' }
|
||||
if (clientIP) headers['X-Client-IP'] = clientIP
|
||||
|
||||
|
||||
// Only send IP if privacy mode is OFF
|
||||
if (clientIP && !settings.privacyMode) {
|
||||
headers['X-Client-IP'] = clientIP
|
||||
}
|
||||
|
||||
const body = {
|
||||
prefix,
|
||||
suffix,
|
||||
languageId: 'markdown',
|
||||
model_thinking: settings.modelThinking,
|
||||
privacy_mode: settings.privacyMode,
|
||||
user_preferences: {
|
||||
language: settings.language,
|
||||
currency: settings.currency,
|
||||
timezone: settings.detectedTimezone
|
||||
}
|
||||
}
|
||||
|
||||
const res = await fetch(apiUrl, {
|
||||
method: 'POST',
|
||||
headers,
|
||||
body: JSON.stringify({ prefix, suffix, languageId: 'markdown' }),
|
||||
body: JSON.stringify(body),
|
||||
signal
|
||||
})
|
||||
|
||||
@@ -45,10 +65,10 @@ export async function fetchSuggestion(prefix, suffix, signal, apiUrl = API_URL)
|
||||
const { done, value } = await reader.read()
|
||||
if (done) break
|
||||
buffer += new TextDecoder().decode(value)
|
||||
|
||||
|
||||
const lines = buffer.split('\n')
|
||||
buffer = lines.pop() || ''
|
||||
|
||||
|
||||
for (const line of lines) {
|
||||
if (!line.startsWith('data: ')) continue
|
||||
const jsonStr = line.slice(6).trim()
|
||||
@@ -64,7 +84,7 @@ export async function fetchSuggestion(prefix, suffix, signal, apiUrl = API_URL)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return text
|
||||
} catch (e) {
|
||||
if (e.name === 'AbortError') {
|
||||
|
||||
+6
-3
@@ -1,3 +1,6 @@
|
||||
export const DEBUG = import.meta.env.DEV
|
||||
export const API_URL = import.meta.env.VITE_API_URL || '/v1/completions'
|
||||
export const OCR_URL = import.meta.env.VITE_OCR_URL || '/v1/ocr'
|
||||
export const DEBUG = import.meta.env.DEV
|
||||
|
||||
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL || 'http://149.104.29.239:8001'
|
||||
|
||||
export const API_URL = import.meta.env.VITE_API_URL || `${API_BASE_URL}/v1/completions`
|
||||
export const OCR_URL = import.meta.env.VITE_OCR_URL || `${API_BASE_URL}/v1/ocr`
|
||||
|
||||
@@ -0,0 +1,248 @@
|
||||
export const translations = {
|
||||
en: {
|
||||
settings: 'Settings',
|
||||
close: 'Close',
|
||||
appearance: 'Appearance',
|
||||
theme: 'Theme',
|
||||
light: 'Light',
|
||||
dark: 'Dark',
|
||||
system: 'System',
|
||||
background: 'Background',
|
||||
default: 'Default',
|
||||
warm: 'Warm',
|
||||
reading: 'Reading Light',
|
||||
image: 'Custom Image',
|
||||
opacity: 'Opacity',
|
||||
modelIntelligence: 'Model Intelligence',
|
||||
thinkingLevel: 'Thinking Level',
|
||||
low: 'Low',
|
||||
medium: 'Medium',
|
||||
high: 'High',
|
||||
lowDesc: 'Direct completion (Fastest)',
|
||||
mediumDesc: 'Brief analysis before suggesting',
|
||||
highDesc: 'Deep, step-by-step analysis (Slowest)',
|
||||
debounceTime: 'Debounce Time',
|
||||
privacyPreferences: 'Privacy & Preferences',
|
||||
privacyMode: 'Privacy Mode',
|
||||
privacyDesc: 'Prevent sending IP and preferences to the AI',
|
||||
language: 'Language',
|
||||
auto: 'Auto Detect',
|
||||
currency: 'Currency',
|
||||
about: 'About Us',
|
||||
importMd: 'Import Markdown',
|
||||
exportMd: 'Export Markdown',
|
||||
uploadImg: 'Upload Image',
|
||||
enableAI: 'Enable AI',
|
||||
disableAI: 'Disable AI',
|
||||
insertUrl: 'Insert Image from URL',
|
||||
insert: 'Insert',
|
||||
cancel: 'Cancel',
|
||||
imgTooLarge: 'Image too large',
|
||||
docTooLarge: 'Document too large, AI disabled'
|
||||
},
|
||||
zh: {
|
||||
settings: '设置',
|
||||
close: '关闭',
|
||||
appearance: '外观',
|
||||
theme: '主题',
|
||||
light: '浅色',
|
||||
dark: '深色',
|
||||
system: '跟随系统',
|
||||
background: '背景',
|
||||
default: '默认',
|
||||
warm: '暖色调',
|
||||
reading: '读书灯',
|
||||
image: '自定义图片',
|
||||
opacity: '透明度',
|
||||
modelIntelligence: '模型智能',
|
||||
thinkingLevel: '思考程度',
|
||||
low: '低',
|
||||
medium: '中',
|
||||
high: '高',
|
||||
lowDesc: '直接补全(最快)',
|
||||
mediumDesc: '简要分析上下文后建议',
|
||||
highDesc: '深度逐步分析(最慢但质量最高)',
|
||||
debounceTime: '防抖时间',
|
||||
privacyPreferences: '隐私与偏好',
|
||||
privacyMode: '隐私模式',
|
||||
privacyDesc: '不向 AI 发送 IP 地址和偏好设置',
|
||||
language: '语言',
|
||||
auto: '自动检测',
|
||||
currency: '货币',
|
||||
about: '关于我们',
|
||||
importMd: '导入 Markdown',
|
||||
exportMd: '导出 Markdown',
|
||||
uploadImg: '上传图片',
|
||||
enableAI: '启用 AI',
|
||||
disableAI: '禁用 AI',
|
||||
insertUrl: '通过 URL 插入图片',
|
||||
insert: '插入',
|
||||
cancel: '取消',
|
||||
imgTooLarge: '图片过大',
|
||||
docTooLarge: '文档过大,AI已禁用'
|
||||
},
|
||||
ja: {
|
||||
settings: '設定',
|
||||
close: '閉じる',
|
||||
appearance: '外観',
|
||||
theme: 'テーマ',
|
||||
light: 'ライト',
|
||||
dark: 'ダーク',
|
||||
system: 'システム',
|
||||
background: '背景',
|
||||
default: 'デフォルト',
|
||||
warm: '暖色',
|
||||
reading: '読書灯',
|
||||
image: 'カスタム画像',
|
||||
opacity: '不透明度',
|
||||
modelIntelligence: 'モデル知能',
|
||||
thinkingLevel: '思考レベル',
|
||||
low: '低',
|
||||
medium: '中',
|
||||
high: '高',
|
||||
lowDesc: '直接補完(最速)',
|
||||
mediumDesc: '提案前に文脈を簡単に分析',
|
||||
highDesc: '深く段階的に分析(遅いが最高品質)',
|
||||
debounceTime: 'デバウンス時間',
|
||||
privacyPreferences: 'プライバシーと設定',
|
||||
privacyMode: 'プライバシーモード',
|
||||
privacyDesc: 'AIにIPアドレスと設定を送信しない',
|
||||
language: '言語',
|
||||
auto: '自動検出',
|
||||
currency: '通貨',
|
||||
about: '私たちについて',
|
||||
importMd: 'Markdownをインポート',
|
||||
exportMd: 'Markdownをエクスポート',
|
||||
uploadImg: '画像をアップロード',
|
||||
enableAI: 'AIを有効化',
|
||||
disableAI: 'AIを無効化',
|
||||
insertUrl: 'URLから画像を挿入',
|
||||
insert: '挿入',
|
||||
cancel: 'キャンセル',
|
||||
imgTooLarge: '画像が大きすぎます',
|
||||
docTooLarge: 'ドキュメントが大きすぎます、AI無効'
|
||||
},
|
||||
ko: {
|
||||
settings: '설정',
|
||||
close: '닫기',
|
||||
appearance: '외관',
|
||||
theme: '테마',
|
||||
light: '라이트',
|
||||
dark: '다크',
|
||||
system: '시스템',
|
||||
background: '배경',
|
||||
default: '기본',
|
||||
warm: '따뜻한 색',
|
||||
reading: '독서등',
|
||||
image: '사용자 지정 이미지',
|
||||
opacity: '불투명도',
|
||||
modelIntelligence: '모델 지능',
|
||||
thinkingLevel: '사고 수준',
|
||||
low: '낮음',
|
||||
medium: '중간',
|
||||
high: '높음',
|
||||
lowDesc: '직접 완성 (가장 빠름)',
|
||||
mediumDesc: '제안 전 문맥 간단 분석',
|
||||
highDesc: '심층 단계별 분석 (가장 느리지만 최고 품질)',
|
||||
debounceTime: '디바운스 시간',
|
||||
privacyPreferences: '개인정보 및 환경설정',
|
||||
privacyMode: '개인정보 모드',
|
||||
privacyDesc: 'AI에 IP 주소 및 설정 전송 안 함',
|
||||
language: '언어',
|
||||
auto: '자동 감지',
|
||||
currency: '통화',
|
||||
about: '회사 소개',
|
||||
importMd: 'Markdown 가져오기',
|
||||
exportMd: 'Markdown 내보내기',
|
||||
uploadImg: '이미지 업로드',
|
||||
enableAI: 'AI 활성화',
|
||||
disableAI: 'AI 비활성화',
|
||||
insertUrl: 'URL로 이미지 삽입',
|
||||
insert: '삽입',
|
||||
cancel: '취소',
|
||||
imgTooLarge: '이미지가 너무 큽니다',
|
||||
docTooLarge: '문서가 너무 큽니다, AI 비활성화됨'
|
||||
},
|
||||
de: {
|
||||
settings: 'Einstellungen',
|
||||
close: 'Schließen',
|
||||
appearance: 'Aussehen',
|
||||
theme: 'Thema',
|
||||
light: 'Hell',
|
||||
dark: 'Dunkel',
|
||||
system: 'System',
|
||||
background: 'Hintergrund',
|
||||
default: 'Standard',
|
||||
warm: 'Warm',
|
||||
reading: 'Leselicht',
|
||||
image: 'Eigenes Bild',
|
||||
opacity: 'Deckkraft',
|
||||
modelIntelligence: 'Modell-Intelligenz',
|
||||
thinkingLevel: 'Denkniveau',
|
||||
low: 'Niedrig',
|
||||
medium: 'Mittel',
|
||||
high: 'Hoch',
|
||||
lowDesc: 'Direkte Vervollständigung (Am schnellsten)',
|
||||
mediumDesc: 'Kurze Analyse vor Vorschlag',
|
||||
highDesc: 'Tiefe schrittweise Analyse (Langsam, aber höchste Qualität)',
|
||||
debounceTime: 'Entprellzeit',
|
||||
privacyPreferences: 'Datenschutz & Einstellungen',
|
||||
privacyMode: 'Datenschutzmodus',
|
||||
privacyDesc: 'Sende keine IP und Einstellungen an KI',
|
||||
language: 'Sprache',
|
||||
auto: 'Automatisch',
|
||||
currency: 'Währung',
|
||||
about: 'Über uns',
|
||||
importMd: 'Markdown importieren',
|
||||
exportMd: 'Markdown exportieren',
|
||||
uploadImg: 'Bild hochladen',
|
||||
enableAI: 'KI aktivieren',
|
||||
disableAI: 'KI deaktivieren',
|
||||
insertUrl: 'Bild per URL einfügen',
|
||||
insert: 'Einfügen',
|
||||
cancel: 'Abbrechen',
|
||||
imgTooLarge: 'Bild zu groß',
|
||||
docTooLarge: 'Dokument zu groß, KI deaktiviert'
|
||||
},
|
||||
fr: {
|
||||
settings: 'Paramètres',
|
||||
close: 'Fermer',
|
||||
appearance: 'Apparence',
|
||||
theme: 'Thème',
|
||||
light: 'Clair',
|
||||
dark: 'Sombre',
|
||||
system: 'Système',
|
||||
background: 'Arrière-plan',
|
||||
default: 'Défaut',
|
||||
warm: 'Chaud',
|
||||
reading: 'Lampe de lecture',
|
||||
image: 'Image personnalisée',
|
||||
opacity: 'Opacité',
|
||||
modelIntelligence: 'Intelligence du modèle',
|
||||
thinkingLevel: 'Niveau de réflexion',
|
||||
low: 'Bas',
|
||||
medium: 'Moyen',
|
||||
high: 'Haut',
|
||||
lowDesc: 'Complétion directe (Le plus rapide)',
|
||||
mediumDesc: 'Analyse brève avant suggestion',
|
||||
highDesc: 'Analyse approfondie étape par étape (Le plus lent)',
|
||||
debounceTime: 'Temps de rebond',
|
||||
privacyPreferences: 'Confidentialité et préférences',
|
||||
privacyMode: 'Mode confidentialité',
|
||||
privacyDesc: 'Ne pas envoyer IP et préférences à l\'IA',
|
||||
language: 'Langue',
|
||||
auto: 'Détection auto',
|
||||
currency: 'Devise',
|
||||
about: 'À propos de nous',
|
||||
importMd: 'Importer Markdown',
|
||||
exportMd: 'Exporter Markdown',
|
||||
uploadImg: 'Télécharger image',
|
||||
enableAI: 'Activer IA',
|
||||
disableAI: 'Désactiver IA',
|
||||
insertUrl: 'Insérer image via URL',
|
||||
insert: 'Insérer',
|
||||
cancel: 'Annuler',
|
||||
imgTooLarge: 'Image trop grande',
|
||||
docTooLarge: 'Document trop grand, IA désactivée'
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user