Update code comments and translations

This commit is contained in:
smallstone 2023-12-21 16:40:23 +08:00
parent 8172d7c38b
commit 4c17f31391
6 changed files with 245 additions and 174 deletions

View File

@ -13,7 +13,7 @@
// 1. 打开设置 // 1. 打开设置
// 2. 启动 ask code 安装 // 2. 启动 ask code 安装
// 3. 设置 access key // 3. 设置 access key
- featureToggles - featureToggles // 判断有没有 ask code
- isDevChatInstalled // 判断 ask code 是否安装 - isDevChatInstalled // 判断 ask code 是否安装
- historyMessages // 页面的历史消息 - historyMessages // 页面的历史消息

View File

@ -307,7 +307,7 @@ class IdeaBridge {
this.resviesContext(res); this.resviesContext(res);
break; break;
case "getSetting/response": case "getSetting/response":
this.resviceSettings(res); // this.resviceSettings(res);
break; break;
case "listTopics/response": case "listTopics/response":
this.resviceTopicList(res); this.resviceTopicList(res);
@ -377,7 +377,6 @@ class IdeaBridge {
} }
resviceSettings(res) { resviceSettings(res) {
console.log("resviceSettings res: ", res);
// 用户设置的回调 // 用户设置的回调
const setting = res.payload.setting; const setting = res.payload.setting;

View File

@ -34,7 +34,7 @@ import Topic from "./Topic";
import { observer } from "mobx-react-lite"; import { observer } from "mobx-react-lite";
import { useMst } from "@/views/stores/RootStore"; import { useMst } from "@/views/stores/RootStore";
import { ChatContext } from "@/views/stores/InputStore"; import { ChatContext } from "@/views/stores/InputStore";
import { useTranslation } from "react-i18next"; import { Trans, useTranslation } from "react-i18next";
const useStyles = createStyles((theme) => ({ const useStyles = createStyles((theme) => ({
actionIcon: { actionIcon: {
@ -312,7 +312,7 @@ const InputMessage = observer((props: any) => {
color: theme.colors.gray[6], color: theme.colors.gray[6],
}} }}
> >
{description} <Trans>{description}</Trans>
</Text> </Text>
</Stack> </Stack>
</Flex> </Flex>

View File

@ -3,7 +3,7 @@ import React from "react";
import { observer } from "mobx-react-lite"; import { observer } from "mobx-react-lite";
import MessageMarkdown from "@/views/components/MessageMarkdown"; import MessageMarkdown from "@/views/components/MessageMarkdown";
import { useMst } from "@/views/stores/RootStore"; import { useMst } from "@/views/stores/RootStore";
import { useTranslation } from "react-i18next"; import { Trans, useTranslation } from "react-i18next";
interface IProps { interface IProps {
messageType: string; messageType: string;
@ -23,12 +23,22 @@ const useStyles = createStyles((theme, options: any) => ({
}, },
})); }));
const trasnlateKey = (children: string) => {
if (children && children.includes("You can configure DevChat from")) {
return "devchat.help";
}
return "";
};
const MessageBody = observer((props: IProps) => { const MessageBody = observer((props: IProps) => {
const { children, messageType, activeStep = false, messageDone } = props; const { children, messageType, activeStep = false, messageDone } = props;
const { chat } = useMst(); const { chat } = useMst();
const { classes } = useStyles({ const { classes } = useStyles({
chatPanelWidth: chat.chatPanelWidth, chatPanelWidth: chat.chatPanelWidth,
}); });
const { t } = useTranslation();
const transkey = trasnlateKey(children);
return messageType === "bot" ? ( return messageType === "bot" ? (
<MessageMarkdown <MessageMarkdown
className={classes.bodyWidth} className={classes.bodyWidth}

View File

@ -1,8 +1,8 @@
import { Button, Anchor, Stack, Group, Box, createStyles } from "@mantine/core"; import { Button, Anchor, Stack, Group, Box, createStyles } from "@mantine/core";
import React, { useEffect, useState } from "react"; import React, { useEffect, useMemo, useState } from "react";
import ReactMarkdown from "react-markdown"; import ReactMarkdown from "react-markdown";
import rehypeRaw from "rehype-raw"; import rehypeRaw from "rehype-raw";
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'; import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
import { okaidia } from "react-syntax-highlighter/dist/esm/styles/prism"; import { okaidia } from "react-syntax-highlighter/dist/esm/styles/prism";
import CodeButtons from "./CodeButtons"; import CodeButtons from "./CodeButtons";
import Step from "./Step"; import Step from "./Step";
@ -10,12 +10,12 @@ import LanguageCorner from "./LanguageCorner";
import { observer } from "mobx-react-lite"; import { observer } from "mobx-react-lite";
import { useMst } from "@/views/stores/RootStore"; import { useMst } from "@/views/stores/RootStore";
import { Message } from "@/views/stores/ChatStore"; import { Message } from "@/views/stores/ChatStore";
import messageUtil from '@/util/MessageUtil'; import messageUtil from "@/util/MessageUtil";
import {fromMarkdown} from 'mdast-util-from-markdown'; import { fromMarkdown } from "mdast-util-from-markdown";
import {visit} from 'unist-util-visit'; import { visit } from "unist-util-visit";
import ChatMark from "@/views/components/ChatMark"; import ChatMark from "@/views/components/ChatMark";
import { useSetState } from "@mantine/hooks"; import { useSetState } from "@mantine/hooks";
import { toMarkdown } from "mdast-util-to-markdown"; import { Trans, useTranslation } from "react-i18next";
const useStyles = createStyles((theme) => ({ const useStyles = createStyles((theme) => ({
link:{ link:{
@ -29,28 +29,30 @@ const useStyles = createStyles((theme) => ({
} }
} }
})); }));
interface MessageMarkdownProps extends React.ComponentProps<typeof ReactMarkdown> { interface MessageMarkdownProps
children: string, extends React.ComponentProps<typeof ReactMarkdown> {
className: string, children: string | any;
messageDone?: boolean, className: string;
activeStep?: boolean messageDone?: boolean;
temp?: boolean;
} }
type Step = { type Step = {
index: number, index: number;
content: string; content: string;
endsWithTripleBacktick: boolean; endsWithTripleBacktick: boolean;
}; };
function parseMetaData(string) { function parseMetaData(string) {
const regexp = /((?<k1>(?!=)\S+)=((?<v1>(["'`])(.*?)\5)|(?<v2>\S+)))|(?<k2>\S+)/g; const regexp =
const io = (string ?? '').matchAll(regexp); /((?<k1>(?!=)\S+)=((?<v1>(["'`])(.*?)\5)|(?<v2>\S+)))|(?<k2>\S+)/g;
const io = (string ?? "").matchAll(regexp);
return new Map( return new Map(
[...io] [...io]
.map((item) => item?.groups) .map((item) => item?.groups)
.map(({ k1, k2, v1, v2 }) => [k1 ?? k2, v1 ?? v2]), .map(({ k1, k2, v1, v2 }) => [k1 ?? k2, v1 ?? v2])
); );
} }
const MessageMarkdown = observer((props: MessageMarkdownProps) => { const MessageMarkdown = observer((props: MessageMarkdownProps) => {
@ -63,18 +65,18 @@ const MessageMarkdown = observer((props: MessageMarkdownProps) => {
const [chatmarkValues,setChatmarkValues] = useSetState({}); const [chatmarkValues,setChatmarkValues] = useSetState({});
const {classes} = useStyles(); const {classes} = useStyles();
const handleExplain = (value: string | undefined) => { const handleExplain = (value: string | undefined) => {
console.log(value); console.log(value);
switch (value) { switch (value) {
case "#ask_code": case "#ask_code":
chat.addMessages([ chat.addMessages([
Message.create({ Message.create({
type: 'user', type: "user",
message: 'Explain /ask-code' message: "Explain /ask-code",
}), }),
Message.create({ Message.create({
type: 'bot', type: "bot",
message: `***/ask-code*** message: `***/ask-code***
Ask anything about your codebase and get answers from our AI agent. Ask anything about your codebase and get answers from our AI agent.
@ -84,147 +86,198 @@ Sample questions:
- Why does the lead time for changes sometimes show as null? - Why does the lead time for changes sometimes show as null?
- How is store.findAllAccounts implemented? - How is store.findAllAccounts implemented?
- The recursive retriever currently drops any TextNodes and only queries the IndexNodes. It's a bug. How can we fix it? - The recursive retriever currently drops any TextNodes and only queries the IndexNodes. It's a bug. How can we fix it?
` `,
}), }),
]); ]);
break; break;
case '#code': case "#code":
chat.addMessages([ chat.addMessages([
Message.create({ Message.create({
type: 'user', type: "user",
message: 'Explain /code' message: "Explain /code",
}), }),
Message.create({ Message.create({
type: 'bot', type: "bot",
message: `***/code*** message: `***/code***
Use this DevChat workflow to request code writing. Please input your specific requirements and supply the appropriate context for implementation. You can select the relevant code or files and right-click to "Add to DevChat". If you find the context is still insufficient, you can enhance my understanding of your code by providing class/function definitions of the selected code. To do this, click the "+" button for the selected code and choose "symbol definitions". Please note, it may take a few seconds for this information to appear in DevChat. Use this DevChat workflow to request code writing. Please input your specific requirements and supply the appropriate context for implementation. You can select the relevant code or files and right-click to "Add to DevChat". If you find the context is still insufficient, you can enhance my understanding of your code by providing class/function definitions of the selected code. To do this, click the "+" button for the selected code and choose "symbol definitions". Please note, it may take a few seconds for this information to appear in DevChat.
` `,
}), }),
]); ]);
break; break;
case '#commit_message': case "#commit_message":
chat.addMessages([ chat.addMessages([
Message.create({ Message.create({
type: 'user', type: "user",
message: 'Explain /commit_message' message: "Explain /commit_message",
}), }),
Message.create({ Message.create({
type: 'bot', type: "bot",
message: `***/commit_message*** message: `***/commit_message***
Use this DevChat workflow to request a commit message. Generally, you don't need to type anything else, but please give me the output of \`git diff\`. Of course, you don't need to manually execute the command and copy & paste its output. Simply click the "+" button and select \`git diff —cached\` to include only the staged changes, or \`git diff HEAD\` to include all changes. Use this DevChat workflow to request a commit message. Generally, you don't need to type anything else, but please give me the output of \`git diff\`. Of course, you don't need to manually execute the command and copy & paste its output. Simply click the "+" button and select \`git diff —cached\` to include only the staged changes, or \`git diff HEAD\` to include all changes.
` `,
}), }),
]); ]);
break; break;
case '#release_note': case "#release_note":
chat.addMessages([ chat.addMessages([
Message.create({ Message.create({
type: 'user', type: "user",
message: 'Explain /release_note' message: "Explain /release_note",
}), }),
Message.create({ Message.create({
type: 'bot', type: "bot",
message: `***/release_note*** message: `***/release_note***
Generate a professionally written and formatted release note in markdown with this workflow. I just need some basic information about the commits for the release. Add this to the context by clicking the "+" button and selecting \`git_log_releasenote\`. If the scope of commits differs from the default command, you can also select \`<custom command>\` and input a command line such as \`git log 579398b^..HEAD --pretty=format:"%h - %B"\` to include the commit 579398b (inclusive) up to the latest. Generate a professionally written and formatted release note in markdown with this workflow. I just need some basic information about the commits for the release. Add this to the context by clicking the "+" button and selecting \`git_log_releasenote\`. If the scope of commits differs from the default command, you can also select \`<custom command>\` and input a command line such as \`git log 579398b^..HEAD --pretty=format:"%h - %B"\` to include the commit 579398b (inclusive) up to the latest.
` `,
}), }),
]); ]);
break; break;
case "#settings": case "#settings":
messageUtil.sendMessage({ command: 'doCommand', content: ['workbench.action.openSettings', 'DevChat'] }); messageUtil.sendMessage({
break; command: "doCommand",
} content: ["workbench.action.openSettings", "DevChat"],
chat.goScrollBottom();
};
const handleButton = (value: string | number | readonly string[] | undefined) => {
switch (value) {
case "settings": messageUtil.sendMessage({ command: 'doCommand', content: ['workbench.action.openSettings', 'DevChat'] }); break;
case "setting_openai_key": messageUtil.sendMessage({ command: 'doCommand', content: ['DevChat.AccessKey.OpenAI'] }); break;
case "setting_devchat_key": messageUtil.sendMessage({ command: 'doCommand', content: ['DevChat.AccessKey.DevChat'] }); break;
}
};
useEffect(()=>{
let previousNode:any = null;
let chatmarkCount = 0;
visit(tree, function (node) {
if (node.type === 'code') {
// set meta data as props
const metaData = parseMetaData(node.meta);
let props = {...metaData};
if(node.lang ==='chatmark' || node.lang ==='ChatMark'){
props['index'] = chatmarkCount;
} else if ((node.lang === 'yaml' || node.lang === 'YAML') && previousNode && previousNode.type === 'code' && previousNode.lang === 'chatmark') {
setChatmarkValues({[`chatmark-${previousNode.data.hProperties.index}`]:node.value});
}
node.data={
hProperties:{
...props
}
};
// record node and count data for next loop
previousNode = node;
if(node.lang ==='chatmark' || node.lang ==='ChatMark'){
chatmarkCount++;
}
}
}); });
},[children]); break;
}
chat.goScrollBottom();
};
const handleButton = (
value: string | number | readonly string[] | undefined
) => {
switch (value) {
case "settings":
messageUtil.sendMessage({
command: "doCommand",
content: ["workbench.action.openSettings", "DevChat"],
});
break;
case "setting_openai_key":
messageUtil.sendMessage({
command: "doCommand",
content: ["DevChat.AccessKey.OpenAI"],
});
break;
case "setting_devchat_key":
messageUtil.sendMessage({
command: "doCommand",
content: ["DevChat.AccessKey.DevChat"],
});
break;
}
};
return <ReactMarkdown useEffect(() => {
{...props} let previousNode: any = null;
remarkPlugins={[()=> (tree) =>{ let chatmarkCount = 0;
let stepCount = 0; visit(tree, function (node) {
let chatmarkCount = 0; if (node.type === "code") {
let previousNode:any = null; // set meta data as props
visit(tree, function (node) { const metaData = parseMetaData(node.meta);
if (node.type === 'code') { let props = { ...metaData };
// set meta data as props if (node.lang === "chatmark" || node.lang === "ChatMark") {
const metaData = parseMetaData(node.meta); props["index"] = chatmarkCount;
let props = {...metaData}; } else if (
if(node.lang ==='step' || node.lang ==='Step'){ (node.lang === "yaml" || node.lang === "YAML") &&
props['index'] = stepCount; previousNode &&
} else if(node.lang ==='chatmark' || node.lang ==='ChatMark'){ previousNode.type === "code" &&
props['id'] = `chatmark-${chatmarkCount}`; previousNode.lang === "chatmark"
props['index'] = chatmarkCount; ) {
} else if ((node.lang === 'yaml' || node.lang === 'YAML') && previousNode && previousNode.type === 'code' && previousNode.lang === 'chatmark') { setChatmarkValues({
props['hidden'] = true; [`chatmark-${previousNode.data.hProperties.index}`]: node.value,
} });
node.data={ }
hProperties:{ node.data = {
...props hProperties: {
} ...props,
}; },
// record node and count data for next loop };
previousNode = node; // record node and count data for next loop
if(node.lang ==='chatmark' || node.lang ==='ChatMark'){ previousNode = node;
chatmarkCount++; if (node.lang === "chatmark" || node.lang === "ChatMark") {
} chatmarkCount++;
if(node.lang ==='step' || node.lang ==='Step'){ }
stepCount++; }
} });
} }, [children]);
});
}]}
rehypePlugins={[rehypeRaw]} const trasnlateChildren = useMemo(() => {
components={{ if (i18n && i18n.language === "zh") {
code({ node, inline, className, children, index, ...props }) { // 目前只有中文需要单独翻译
if (children) {
if (children.includes("You can configure DevChat from")) {
return t("devchat.help");
}
// DevChat key is missing from your environment or settings
if (
children.includes("DevChat key is missing from your environment ")
) {
return t("devchat.setkey");
}
}
}
return children;
}, [children, i18n.language]);
const match = /language-(\w+)/.exec(className || ''); return (
const value = String(children).replace(/\n$/, ''); <ReactMarkdown
let lanugage = match && match[1]; {...props}
if (!lanugage) { remarkPlugins={[
lanugage = "unknow"; () => (tree) => {
} let stepCount = 1;
let chatmarkCount = 0;
let previousNode: any = null;
visit(tree, function (node) {
if (node.type === "code") {
// set meta data as props
const metaData = parseMetaData(node.meta);
let props = { ...metaData };
if (node.lang === "step" || node.lang === "Step") {
props["index"] = stepCount;
} else if (node.lang === "chatmark" || node.lang === "ChatMark") {
props["id"] = `chatmark-${chatmarkCount}`;
props["index"] = chatmarkCount;
} else if (
(node.lang === "yaml" || node.lang === "YAML") &&
previousNode &&
previousNode.type === "code" &&
previousNode.lang === "chatmark"
) {
props["hidden"] = true;
}
node.data = {
hProperties: {
...props,
},
};
// record node and count data for next loop
previousNode = node;
if (node.lang === "chatmark" || node.lang === "ChatMark") {
chatmarkCount++;
}
if (node.lang === "step" || node.lang === "Step") {
stepCount++;
}
}
});
},
]}
rehypePlugins={[rehypeRaw]}
components={{
code({ node, inline, className, children, index, ...props }) {
const match = /language-(\w+)/.exec(className || "");
const value = String(children).replace(/\n$/, "");
let lanugage = match && match[1];
if (!lanugage) {
lanugage = "unknow";
}
let wrapLongLines = false; let wrapLongLines = false;
if (lanugage === 'markdown' || lanugage === 'text') { if (lanugage === "markdown" || lanugage === "text") {
wrapLongLines = true; wrapLongLines = true;
} }
if (lanugage === 'step' || lanugage === 'Step') { if (lanugage === 'step' || lanugage === 'Step') {
const status = activeStep && Number(index) === codes.length - 1 && lastNode.type === 'code' ? "running" : "done"; const status = activeStep && Number(index) === codes.length - 1 && lastNode.type === 'code' ? "running" : "done";
@ -236,9 +289,9 @@ Generate a professionally written and formatted release note in markdown with th
return <ChatMark value={chatmarkValue} messageDone={messageDone}>{value}</ChatMark>; return <ChatMark value={chatmarkValue} messageDone={messageDone}>{value}</ChatMark>;
} }
if ((lanugage === 'yaml' || lanugage === 'YAML') && props.hidden) { if ((lanugage === "yaml" || lanugage === "YAML") && props.hidden) {
return <></>; return <></>;
} }
return !inline && lanugage ? ( return !inline && lanugage ? (
<div style={{ position: 'relative' }} className={classes.codeOverride}> <div style={{ position: 'relative' }} className={classes.codeOverride}>

View File

@ -7,5 +7,14 @@
"User": "用户", "User": "用户",
"Ask DevChat a question or type / for workflow": "向 DevChat 提问或输入 '/' 以查看工作流", "Ask DevChat a question or type / for workflow": "向 DevChat 提问或输入 '/' 以查看工作流",
"How do I use DevChat?": "如何使用 DevChat", "How do I use DevChat?": "如何使用 DevChat",
"balance": "您的余额为 {{formatedCurrency}},登录 <4>web.devchat.ai</4> 以获得更多 tokens" "balance": "您的余额为 {{formatedCurrency}},登录 <4>web.devchat.ai</4> 以获得更多 tokens",
"devchat.help": "你想写一些代码还是对这个项目有疑问?只需右键单击您选择的文件或代码片段,然后将它们添加到 DevChat 中。请随时问我任何问题,或者让我帮你编码。<br> <br> 不要忘记检查输入左侧的“+”按钮,以添加更多上下文。要查看可以在上下文中运行的工作流列表,只需键入“/”。提示愉快! <br> <br>首先,我可以为您做一些事情:<br> <br> [/code: 基于你的代码来写 prompt](#code) <br> [/commit_message: 根据代码更改编写提交消息](#commit_message) <br> <br> [/release_note: 根据您最近的提交来写提交说明](#release_note) <br> <br> [/ask-code: 询问任何关于您的代码库的信息,并从我们的人工智能代理那里获得答案](#ask_code) <br> <br>你可以点击[设置](#settings)来配置 DevChat",
"devchat.setkey": "您的环境或设置中缺少 DevChat key。请输入您的 DevChat key我会确保 DevChat 将会正常工作。<br> <br> <button value=\"setting_devchat_key\">设置 DevChat key</button>",
"Is DevChat Access Key ready?": "是否已准备好 DevChat Access Key",
"Ask questions about the current project's codebase, which requires proactive acquisition of additional context information to answer.": "询问关于当前项目代码库的问题,这需要主动获取额外的上下文信息来回答。",
"Generate code with a general template embedded into the prompt.": "使用嵌入到提示中的通用模板生成代码。",
"Generate code with a Python-specific template embedded into the prompt.": "使用嵌入到提示中的 Python 特定模板生成代码。",
"commit changes with commit message in english.": "使用英文提交更改。",
"Generate a commit message for the given git diff.": "为给定的 git diff 生成提交消息。",
"Generate a release note for the given commit log.": "为给定的提交日志生成发布说明。"
} }