Update from Vibe Studio

This commit is contained in:
Vibe Studio
2026-01-16 09:17:38 +00:00
parent 976704f9ec
commit 90e523b17e
2 changed files with 114 additions and 256 deletions

View File

@@ -1,29 +1,15 @@
export interface SpellCheckRequest {
user_input_text: string
auto_correct: boolean
custom_vocab: string[]
}
export interface DifyRequest { export interface DifyRequest {
inputs: { inputs: {
user_input_text: string user_input: string
auto_correct: boolean
custom_vocab: string[]
} }
query: string query: string
response_mode: string response_mode: string
} }
export function checkAndCorrectSpelling( export function checkAndCorrectSpelling(user_input: string) {
user_input_text: string,
auto_correct: boolean,
custom_vocab: string[]
) {
const requestBody: DifyRequest = { const requestBody: DifyRequest = {
inputs: { inputs: {
user_input_text, user_input
auto_correct,
custom_vocab
}, },
query: '1', query: '1',
response_mode: 'streaming' response_mode: 'streaming'
@@ -33,7 +19,7 @@ export function checkAndCorrectSpelling(
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'Authorization': 'Bearer app-Dmsx84IAGk7rVCko5MWptmK3' 'Authorization': 'Bearer app-8LtwQRbmrDRpiGFZqVg4SK3q'
}, },
body: JSON.stringify(requestBody) body: JSON.stringify(requestBody)
}) })

View File

@@ -1,75 +1,36 @@
import { useState } from 'react' import { useState, useEffect, useRef } from 'react'
import { Button, Card, Form, Input, message, Space, Switch } from 'antd' import { Button, Card, Form, Input, message, Typography } from 'antd'
import { checkAndCorrectSpelling } from '@/api/spellCheck' import { checkAndCorrectSpelling } from '@/api/spellCheck'
interface CorrectionResult { const { Title } = Typography
original: string
corrected: string
position: number
suggestions?: string[]
}
const SpellCheck = () => { const SpellCheck = () => {
const [form] = Form.useForm() const [form] = Form.useForm()
const [isGenerating, setIsGenerating] = useState(false) const [isGenerating, setIsGenerating] = useState(false)
const [correctionResults, setCorrectionResults] = useState<CorrectionResult[]>([]) const [generatedResult, setGeneratedResult] = useState('')
const [correctedText, setCorrectedText] = useState('') const textareaRef = useRef<any>(null)
const maxChars = 5000
const validateCustomVocab = (_: any, value: string) => { // 页面加载时自动聚焦
if (!value) { useEffect(() => {
return Promise.resolve() if (textareaRef.current) {
textareaRef.current.focus()
} }
try { }, [])
const parsed = JSON.parse(value)
if (!Array.isArray(parsed)) {
return Promise.reject(new Error('必须是JSON数组格式'))
}
if (!parsed.every(item => typeof item === 'string')) {
return Promise.reject(new Error('数组元素必须为字符串'))
}
return Promise.resolve()
} catch (error) {
return Promise.reject(new Error('JSON格式无效'))
}
}
const handleGenerate = async () => { const handleGenerate = async () => {
try { try {
const formValues = await form.validateFields() const formValues = await form.validateFields()
// 验证用户输入文本 // 验证用户输入文本
if (!formValues.user_input_text?.trim()) { if (!formValues.user_input?.trim()) {
message.warning('请输入需要检测错别字的文本') message.warning('请输入需要检测错别字的文本')
return return
} }
// 验证文本长度
if (formValues.user_input_text.length > maxChars) {
message.warning(`输入文本不能超过${maxChars}个字符`)
return
}
setIsGenerating(true) setIsGenerating(true)
setCorrectionResults([]) setGeneratedResult('')
setCorrectedText('')
let customVocabArray: string[] = [] const response = await checkAndCorrectSpelling(formValues.user_input)
if (formValues.custom_vocab) {
try {
customVocabArray = JSON.parse(formValues.custom_vocab)
} catch (error) {
message.error('自定义词汇库格式错误')
setIsGenerating(false)
return
}
}
const response = await checkAndCorrectSpelling(
formValues.user_input_text,
formValues.auto_correct || false,
customVocabArray
)
if (!response.ok) { if (!response.ok) {
const errorText = await response.text() const errorText = await response.text()
@@ -84,7 +45,6 @@ const SpellCheck = () => {
const decoder = new TextDecoder('utf-8') const decoder = new TextDecoder('utf-8')
let buffer = '' let buffer = ''
let fullContent = '' let fullContent = ''
let results: CorrectionResult[] = []
try { try {
while (true) { while (true) {
@@ -112,22 +72,7 @@ const SpellCheck = () => {
if (parsed.event === 'message' && parsed.answer) { if (parsed.event === 'message' && parsed.answer) {
fullContent += parsed.answer fullContent += parsed.answer
// 尝试解析JSON结果 setGeneratedResult(fullContent)
try {
results = JSON.parse(fullContent)
setCorrectionResults(results)
if (formValues.auto_correct) {
let corrected = formValues.user_input_text
results.forEach(item => {
if (item.corrected && item.original) {
corrected = corrected.replace(item.original, item.corrected)
}
})
setCorrectedText(corrected)
}
} catch (e) {
// 解析失败,继续等待
}
} else if (parsed.event === 'error') { } else if (parsed.event === 'error') {
throw new Error(parsed.message || 'Dify API 返回错误') throw new Error(parsed.message || 'Dify API 返回错误')
} }
@@ -140,24 +85,6 @@ const SpellCheck = () => {
} finally { } finally {
reader.releaseLock() reader.releaseLock()
} }
if (results.length === 0 && fullContent) {
try {
results = JSON.parse(fullContent)
setCorrectionResults(results)
if (formValues.auto_correct) {
let corrected = formValues.user_input_text
results.forEach(item => {
if (item.corrected && item.original) {
corrected = corrected.replace(item.original, item.corrected)
}
})
setCorrectedText(corrected)
}
} catch (e) {
message.warning('检测完成,但结果格式异常')
}
}
} catch (error) { } catch (error) {
console.error('检测错误:', error) console.error('检测错误:', error)
message.error(error instanceof Error ? error.message : '检测失败,请稍后重试') message.error(error instanceof Error ? error.message : '检测失败,请稍后重试')
@@ -168,173 +95,118 @@ const SpellCheck = () => {
const handleReset = () => { const handleReset = () => {
form.resetFields() form.resetFields()
setCorrectionResults([]) setGeneratedResult('')
setCorrectedText('')
message.info('已重置表单') message.info('已重置表单')
if (textareaRef.current) {
textareaRef.current.focus()
}
} }
const renderCorrectionResults = () => { const handleCopy = async () => {
if (isGenerating) { try {
return ( await navigator.clipboard.writeText(generatedResult)
<div style={{ textAlign: 'center', color: '#999', padding: '20px' }}> message.success('复制成功')
... } catch (error) {
</div> message.error('复制失败')
)
} }
if (correctionResults.length === 0) {
return (
<div style={{ textAlign: 'center', color: '#999' }}>
</div>
)
}
return (
<div style={{ display: 'flex', flexDirection: 'column', gap: '16px' }}>
{correctionResults.map((item, index) => (
<div
key={index}
style={{
padding: '12px',
backgroundColor: '#f5f5f5',
borderRadius: '6px',
border: '1px solid #d9d9d9'
}}
>
<div style={{ marginBottom: '8px', fontWeight: 'bold' }}>
{item.position}
</div>
<div style={{ display: 'flex', gap: '8px', alignItems: 'center' }}>
<span style={{ color: '#ff4d4f' }}>{item.original}</span>
<span></span>
<span style={{ color: '#52c41a' }}>{item.corrected}</span>
</div>
{item.suggestions && item.suggestions.length > 0 && (
<div style={{ marginTop: '8px', fontSize: '12px', color: '#666' }}>
{item.suggestions.join('、')}
</div>
)}
</div>
))}
</div>
)
} }
return ( return (
<div style={{ maxWidth: '900px', margin: '0 auto', padding: '20px' }}> <div className="spell-check-page" style={{ maxWidth: '800px', margin: '0 auto', padding: '20px' }}>
{/* 页面标题区 */} {/* 页面标题区 */}
<div style={{ textAlign: 'center', marginBottom: '40px' }}> <div style={{ textAlign: 'center', marginBottom: '30px' }}>
<h1 style={{ color: '#1890ff', fontSize: '32px', fontWeight: 'bold', margin: 0 }}> <Title level={2} style={{ color: '#1890ff', margin: 0 }}>
</h1> </Title>
</div> </div>
<Space direction="vertical" style={{ width: '100%' }} size="large"> {/* 参数输入区 */}
{/* 参数输入区 */} <Card style={{ marginBottom: '20px' }}>
<Card title="参数输入区"> <Form
<Form form={form} layout="vertical"> form={form}
<Form.Item layout="vertical"
name="user_input_text" initialValues={{ user_input: '' }}
label="用户输入文本" >
rules={[ <Form.Item
{ required: true, message: '请输入需要检测错别字的文本' }, name="user_input"
{ max: maxChars, message: `输入文本不能超过${maxChars}个字符` } label="需要检测的文本"
]} rules={[
> { required: true, message: '请输入需要检测错别字的文本' }
<Input.TextArea ]}
rows={8}
placeholder="请输入需要检测错别字的中文文本..."
maxLength={maxChars}
showCount
style={{ fontSize: '14px' }}
/>
</Form.Item>
<Form.Item name="auto_correct" label="是否自动替换" valuePropName="checked">
<Switch />
</Form.Item>
<Form.Item
name="custom_vocab"
label="自定义词汇库(可选)"
rules={[{ validator: validateCustomVocab }]}
>
<Input.TextArea
rows={4}
placeholder='请输入JSON格式词汇库["正确词1", "正确词2"]'
style={{ fontSize: '14px' }}
/>
<div className="form-helper-text" style={{ fontSize: '12px', color: '#666', marginTop: '4px' }}>
JSON数组
</div>
</Form.Item>
</Form>
</Card>
{/* 操作按钮区 */}
<div className="button-group" style={{ display: 'flex', justifyContent: 'center', gap: '16px' }}>
<Button
type="primary"
size="large"
onClick={handleGenerate}
loading={isGenerating}
style={{ minWidth: '120px', height: '40px', fontSize: '16px' }}
> >
<Input.TextArea
</Button> ref={textareaRef}
<Button rows={8}
size="large" placeholder="请输入需要检测错别字的中文文本..."
onClick={handleReset} style={{ fontSize: '14px' }}
disabled={isGenerating} />
style={{ minWidth: '120px', height: '40px', fontSize: '16px' }} </Form.Item>
> </Form>
</Card>
</Button>
</div>
{/* 内容展示区 */} {/* 操作按钮区 */}
<Card <div style={{ display: 'flex', justifyContent: 'center', gap: '16px', marginBottom: '30px' }}>
title="检测结果" <Button
type="primary"
size="large"
onClick={handleGenerate}
loading={isGenerating}
style={{ minWidth: '140px', height: '44px', fontSize: '16px' }}
>
</Button>
<Button
size="large"
onClick={handleReset}
disabled={isGenerating}
style={{ minWidth: '140px', height: '44px', fontSize: '16px' }}
>
</Button>
</div>
{/* 内容展示区 */}
<Card
title="检测结果"
style={{
display: generatedResult || isGenerating ? 'block' : 'none',
minHeight: '200px'
}}
>
<div
style={{ style={{
display: correctionResults.length > 0 || isGenerating ? 'block' : 'none' minHeight: '150px',
maxHeight: '60vh',
overflowY: 'auto',
padding: '20px',
backgroundColor: '#fafafa',
border: '1px solid #e8e8e8',
borderRadius: '6px',
fontSize: '14px',
lineHeight: '1.8',
whiteSpace: 'pre-wrap'
}} }}
> >
<div {isGenerating && !generatedResult ? (
style={{ <div style={{ textAlign: 'center', color: '#999', padding: '40px 0' }}>
minHeight: '150px', ...
maxHeight: '400px',
overflowY: 'auto',
padding: '15px',
backgroundColor: '#fafafa',
border: '1px solid #d9d9d9',
borderRadius: '4px'
}}
>
{renderCorrectionResults()}
</div>
</Card>
{correctedText && (
<Card title="纠正后的文本">
<div
style={{
minHeight: '120px',
padding: '15px',
backgroundColor: '#f6ffed',
border: '1px solid #b7eb8f',
borderRadius: '4px',
whiteSpace: 'pre-wrap',
wordWrap: 'break-word',
fontSize: '14px',
lineHeight: '1.6'
}}
>
{correctedText}
</div> </div>
</Card> ) : generatedResult ? (
)} <div>
</Space> {generatedResult}
<div style={{ marginTop: '20px', textAlign: 'center' }}>
<Button onClick={handleCopy} size="small">
</Button>
</div>
</div>
) : (
<div style={{ textAlign: 'center', color: '#999' }}>
</div>
)}
</div>
</Card>
</div> </div>
) )
} }