Skip to content

Commit

Permalink
feat: new translation api (#945)
Browse files Browse the repository at this point in the history
  • Loading branch information
sdjdd authored Nov 17, 2023
1 parent c4b9a02 commit dbeef5a
Show file tree
Hide file tree
Showing 6 changed files with 43 additions and 177 deletions.
1 change: 0 additions & 1 deletion api/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ apiRouter.use('/customer-services', require('./customerService/api'))
apiRouter.get('/debug/search', parseSearchingQ, (req, res) => {
res.json({ q: req.q, query: req.query })
})
apiRouter.use('/translate', require('./translate/api'))
apiRouter.use('/quick-replies', require('./quick-reply/api'))

const router = Router()
Expand Down
48 changes: 0 additions & 48 deletions api/translate/api.js

This file was deleted.

56 changes: 0 additions & 56 deletions api/translate/utils.js

This file was deleted.

73 changes: 4 additions & 69 deletions modules/Ticket/ReplyCard.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,76 +39,11 @@ function getTextNodes(root) {
return result
}

/**
* @param {string[]} texts
*/
async function translate(texts) {
if (texts.length === 0) {
return []
}
const idByText = {}
const dstBySrc = {}
const srcs = []
texts.forEach((text) => {
if (text.trim() === '') {
dstBySrc[text] = text
return
}
if (text in idByText) {
return
}
idByText[text] = srcs.length
srcs.push(text)
})
const { result: dsts } = await fetch(`/api/1/translate`, {
method: 'POST',
body: { text: srcs.join('\n') },
})
dsts.forEach((dst, id) => (dstBySrc[srcs[id]] = dst))
return texts.map((text) => dstBySrc[text])
}

export function BaiduTranslate({ enabled, children }) {
const { addNotification } = useContext(AppContext)
const $container = useRef()
const $texts = useRef()
const $task = useRef()

useEffect(() => {
if (enabled) {
if (!$texts.current) {
$texts.current = getTextNodes($container.current).map((node) => ({
node,
src: _.trim(node.nodeValue, '\n'),
dst: '',
}))
}
if (!$task.current) {
$task.current = translate($texts.current.map((text) => text.src)).then((results) => {
results.forEach((dst, index) => ($texts.current[index].dst = dst))
return
})
}
$task.current
.then(() => {
$texts.current.forEach(({ node, dst }) => {
node.replaceData(0, node.length, dst)
})
return
})
.catch((error) => {
$task.current = undefined
addNotification(error)
})
} else {
if ($texts.current) {
$texts.current.forEach(({ node, src }) => node.replaceData(0, node.length, src))
}
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [enabled])

return <div ref={$container}>{children}</div>
if (enabled) {
return <div>Translation not available</div>
}
return children
}
BaiduTranslate.propTypes = {
enabled: PropTypes.bool,
Expand Down
35 changes: 35 additions & 0 deletions next/api/src/controller/translate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { z } from 'zod';
import axios from 'axios';

import { Body, Controller, HttpError, Post } from '@/common/http';
import { ZodValidationPipe } from '@/common/pipe';

const translateSchema = z.object({
text: z.string(),
});

@Controller('translate')
export class TranslateController {
private fanyiToken = process.env.FANYI_TOKEN;

@Post()
async translate(
@Body(new ZodValidationPipe(translateSchema)) { text }: z.infer<typeof translateSchema>
) {
if (!this.fanyiToken) {
throw new HttpError(400, 'translation service is not configured');
}

const res = await axios.post(
'https://fanyi.leanapp.cn/',
{ text },
{
headers: {
'x-fanyi-token': this.fanyiToken,
},
}
);

return res.data;
}
}
7 changes: 4 additions & 3 deletions next/web/src/App/Admin/Tickets/Ticket/api1.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,12 +78,13 @@ async function translate(texts: string[]) {
if (filteredTexts.length === 0) {
return {};
}
const { data } = await http.post<{ result: string[] }>('/api/1/translate', {
const { data } = await http.post<{ text: string }>('/api/2/translate', {
text: filteredTexts.join('\n'),
});
const result = data.text.split('\n');
return filteredTexts.reduce<Record<string, string>>((map, text, i) => {
if (i < data.result.length) {
map[text] = data.result[i];
if (i < result.length) {
map[text] = result[i];
}
return map;
}, {});
Expand Down

0 comments on commit dbeef5a

Please sign in to comment.