diff --git a/src/pages/home/index.tsx b/src/pages/home/index.tsx index a9178c5..728aab7 100644 --- a/src/pages/home/index.tsx +++ b/src/pages/home/index.tsx @@ -1,73 +1,371 @@ -import { Card, Row, Col, Typography, Space } from 'antd' -import { Link } from 'react-router-dom' -import { RobotOutlined, TranslationOutlined, FileTextOutlined, EditOutlined, SafetyCertificateOutlined } from '@ant-design/icons' +import { useState } from 'react' +import { Button, Card, Form, Input, message, Space, Typography } from 'antd' +import { reviewContract } from '@/api/contract-review' -const { Title, Paragraph } = Typography +const { Title, Paragraph, Text } = Typography -const cards = [ - { - title: '测试页面 1', - description: 'Dify AI Agent 集成示例', - icon: , - link: '/test1' - }, - { - title: '测试页面 2', - description: '功能开发中...', - icon: , - link: '/test2' - }, - { - title: '中英翻译器', - description: 'AI 驱动的翻译工具', - icon: , - link: '/zh-en-translator' - }, - { - title: '合同智能审核', - description: 'AI 驱动的合同智能审核系统,提供专业建议', - icon: , - link: '/contract-review' - }, - { - title: '错别字检测', - description: '智能检测和纠正中文文本中的错别字', - icon: , - link: '/spell-check' - }, - { - title: '错别字检测与修正系统', - description: '更智能的错别字检测与修正系统,支持分类和建议', - icon: , - link: '/spell-check-system' - } -] +const { TextArea } = Input const HomePage: React.FC = () => { + const [form] = Form.useForm() + const [loading, setLoading] = useState(false) + const [reviewResult, setReviewResult] = useState('') + const [currentInput, setCurrentInput] = useState('') + + const maxChars = 5000 + + // 简单的markdown处理函数 + const formatMarkdown = (text: string) => { + if (!text) return [] + + const lines = text.split('\n') + const elements: React.ReactNode[] = [] + let currentList: string[] = [] + let inTable = false + let tableHeaders: string[] = [] + let tableRows: string[][] = [] + + const flushList = () => { + if (currentList.length > 0) { + elements.push( +
    + {currentList.map((item, index) => ( +
  • {item}
  • + ))} +
+ ) + currentList = [] + } + } + + const flushTable = () => { + if (tableHeaders.length > 0) { + elements.push( +
+ + + + {tableHeaders.map((header, index) => ( + + ))} + + + + {tableRows.map((row, rowIndex) => ( + + {row.map((cell, cellIndex) => ( + + ))} + + ))} + +
+ {header} +
+ {cell} +
+
+ ) + tableHeaders = [] + tableRows = [] + inTable = false + } + } + + lines.forEach((line, index) => { + const trimmedLine = line.trim() + + // 处理标题 + if (trimmedLine.startsWith('# ')) { + flushList() + flushTable() + elements.push( + + {trimmedLine.substring(2)} + + ) + } else if (trimmedLine.startsWith('## ')) { + flushList() + flushTable() + elements.push( + + {trimmedLine.substring(3)} + + ) + } else if (trimmedLine.startsWith('### ')) { + flushList() + flushTable() + elements.push( + + {trimmedLine.substring(4)} + + ) + } + // 处理分割线 + else if (trimmedLine === '---') { + flushList() + flushTable() + elements.push( +
+ ) + } + // 处理列表项 + else if (trimmedLine.startsWith('- ') || trimmedLine.startsWith('* ')) { + flushTable() + currentList.push(trimmedLine.substring(2)) + } + // 处理表格 + else if (trimmedLine.includes('|') && !inTable) { + flushList() + inTable = true + tableHeaders = trimmedLine.split('|').map(h => h.trim()).filter(h => h) + } else if (trimmedLine.includes('|') && inTable && !trimmedLine.includes('---')) { + const row = trimmedLine.split('|').map(c => c.trim()).filter(c => c) + if (row.length > 0) { + tableRows.push(row) + } + } else if (trimmedLine.includes('|') && inTable && trimmedLine.includes('---')) { + // 跳过分隔行 + } + // 处理普通段落 + else if (trimmedLine) { + flushList() + flushTable() + + // 处理加粗文本 + const boldRegex = /\*\*(.*?)\*\*/g + const parts = trimmedLine.split(boldRegex) + + if (parts.length > 1) { + elements.push( + + {parts.map((part, partIndex) => + partIndex % 2 === 1 ? + {part} : + part + )} + + ) + } else { + elements.push( + + {trimmedLine} + + ) + } + } + }) + + // 清理剩余的内容 + flushList() + flushTable() + + return elements + } + + const handleReview = async () => { + try { + const contract_text = form.getFieldValue('contract_text') || '' + + if (!contract_text.trim()) { + message.warning('请输入合同片段内容') + return + } + + setLoading(true) + setReviewResult('') + + const response = await reviewContract(contract_text) + + if (!response.ok) { + const errorText = await response.text() + throw new Error(`审核请求失败: ${response.status} ${errorText}`) + } + + if (!response.body) { + throw new Error('响应体为空') + } + + const reader = response.body.getReader() + const decoder = new TextDecoder('utf-8') + let buffer = '' + let fullContent = '' + + try { + while (true) { + const { done, value } = await reader.read() + if (done) break + + buffer += decoder.decode(value, { stream: true }) + const lines = buffer.split('\n') + buffer = lines.pop() || '' + + for (const line of lines) { + const trimmedLine = line.trim() + if (!trimmedLine || trimmedLine === 'data: [DONE]') { + if (trimmedLine === 'data: [DONE]') { + message.success('审核完成') + setLoading(false) + return + } + continue + } + + if (trimmedLine.startsWith('data: ')) { + try { + const data = trimmedLine.slice(6) + const parsed = JSON.parse(data) + + if (parsed.event === 'message' && parsed.answer) { + fullContent += parsed.answer + setReviewResult(fullContent) + } else if (parsed.event === 'error') { + throw new Error(parsed.message || 'Dify API 返回错误') + } + } catch (parseError) { + console.warn('跳过无法解析的行:', trimmedLine) + } + } + } + } + } finally { + reader.releaseLock() + } + + if (fullContent) { + message.success('审核完成') + } else { + throw new Error('未收到审核结果') + } + } catch (error) { + console.error('审核错误:', error) + message.error(error instanceof Error ? error.message : '审核失败,请稍后重试') + } finally { + setLoading(false) + } + } + + const handleReset = () => { + form.resetFields() + setReviewResult('') + setCurrentInput('') + message.info('已重置内容') + } + + const handleReReview = () => { + handleReview() + } + return ( -
- 欢迎使用 AI 办公助手 - - 选择下方功能开始使用,或通过顶部导航访问其他页面。 +
+ 合同智能审核 + + 通过AI技术对合同片段进行智能审核,提供专业建议 - - {cards.map((card, index) => ( - - - - - {card.icon} - {card.title} - - {card.description} - - - - - - ))} - + + {/* 参数输入区 */} + +
+ + 合同片段文本 + maxChars ? '#ff4d4f' : '#999' }}> + {currentInput.length} / {maxChars} + +
+ } + rules={[ + { required: true, message: '请输入合同片段内容' }, + { max: maxChars, message: `输入内容不能超过${maxChars}个字符` } + ]} + > +