feat: add video OCR/ASR, DOCX/PDF export, input block and risk config updates

- Video pipeline: video file OCR via VLM plus audio track ASR, integrated
  into job_handlers with progress emit per phase. New media_utils.py for
  audio extraction from video files.
- Document export: richExport.js replaces inline docx builder; DOCX and PDF
  export buttons are now enabled in MilkdownEditor. File size limit raised to
  100 MB.
- Input block: new InputBlockCrepe.vue component with inputBlockPlugin.ts
  and inputBlock.js for custom user-input nodes in the editor.
- Risk config: added Vite dev server ports (5173) to CORS allowlist and
  increased OCR max input from 10 MB to 100 MB.
- TTS/ASR refactor: simplified tts_asr.py model loading and warmup logic.
- Test coverage: updated tests for llm, main endpoints, pro completions and
  web search modules.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
“ydy0615”
2026-06-18 16:32:31 +08:00
parent 4813196b0a
commit 356108e792
34 changed files with 1457 additions and 563 deletions
+25 -2
View File
@@ -56,6 +56,7 @@ import { hiddenTextInputPlugin, hiddenTextNode, hiddenTextRemark, hiddenTextView
import { fetchSuggestion, submitCompress, pollCompressStatus } from '../utils/api.js'
import { isDocumentVisible, getRecommendedDebounce, getRecommendedSyncInterval } from '../composables/useVisibility.js'
const COPILOT_TOGGLE_EVENT = 'llm-in-text:copilot-toggle'
const props = defineProps({
docType: { type: String, default: 'txt' },
docName: { type: String, default: 'document.txt' },
@@ -77,6 +78,7 @@ let crepe = null
let syncTimer = null
let syncingExternal = false
let compressPoller = null
let copilotToggleHandler = null
const handleCompress = () => {
if (compressState.value !== 'idle') return
@@ -233,8 +235,26 @@ onMounted(async () => {
crepe.editor.action((ctx) => {
const view = ctx.get(editorViewCtx)
setCopilotEnabled(view, true)
const enabled = typeof window !== 'undefined'
? window.__LLM_IN_TEXT_COPILOT_ENABLED__ !== false
: true
setCopilotEnabled(view, enabled)
if (!enabled) {
clearGhostSuggestion(view)
}
})
copilotToggleHandler = (event) => {
const enabled = Boolean(event?.detail?.enabled)
crepe?.editor?.action((ctx) => {
const view = ctx.get(editorViewCtx)
setCopilotEnabled(view, enabled)
if (!enabled) {
clearGhostSuggestion(view)
}
})
}
window.addEventListener(COPILOT_TOGGLE_EVENT, copilotToggleHandler)
})
onUnmounted(() => {
@@ -246,6 +266,10 @@ onUnmounted(() => {
compressPoller.stop()
compressPoller = null
}
if (copilotToggleHandler) {
window.removeEventListener(COPILOT_TOGGLE_EVENT, copilotToggleHandler)
copilotToggleHandler = null
}
if (crepe) {
crepe.editor.action((ctx) => {
const view = ctx.get(editorViewCtx)
@@ -444,4 +468,3 @@ onUnmounted(() => {
display: none !important;
}
</style>