From f57b5710a00ac4512466424b66647b85d823e945 Mon Sep 17 00:00:00 2001 From: Zhang Minghan Date: Sun, 24 Sep 2023 09:20:37 +0800 Subject: [PATCH] fix generation context and prompt --- app/src/assets/generation.less | 6 ++---- app/src/i18n.ts | 6 +++--- app/src/routes/Generation.tsx | 38 ++++++++++++++++++++++++---------- app/src/routes/Home.tsx | 4 ++++ app/src/service.ts | 2 +- app/src/utils.ts | 12 ++++++++++- generation/api.go | 2 ++ generation/prompt.go | 2 +- 8 files changed, 51 insertions(+), 21 deletions(-) diff --git a/app/src/assets/generation.less b/app/src/assets/generation.less index ef8cbcb..d508acd 100644 --- a/app/src/assets/generation.less +++ b/app/src/assets/generation.less @@ -59,16 +59,14 @@ .message-box { width: 100%; height: max-content; + min-height: 120px; border-radius: var(--radius); border: 1px solid hsl(var(--border)); color: hsl(var(--text-secondary)); padding: 0.6rem 1rem; font-size: 10px; overflow: hidden; - white-space: pre-wrap; - overflow-wrap: break-word; - word-wrap: break-word; - word-break: break-all; + text-overflow: ellipsis; } .quota-box { diff --git a/app/src/i18n.ts b/app/src/i18n.ts index 026a363..82cf0bb 100644 --- a/app/src/i18n.ts +++ b/app/src/i18n.ts @@ -100,7 +100,7 @@ const resources = { "free-price": "Free Forever", pro: "Pro", "pro-price": "8 CNY/Month", - "free-gpt3": "GPT-3.5 Free Forever", + "free-gpt3": "GPT-3.5 (16k) Free Forever", "free-dalle": "5 free quotas per day", "free-web": "web searching feature", "free-conversation": "conversation storage", @@ -243,7 +243,7 @@ const resources = { "free-price": "永久免费", pro: "专业版", "pro-price": "8 元/月", - "free-gpt3": "GPT-3.5 永久免费", + "free-gpt3": "GPT-3.5 (16k) 永久免费", "free-dalle": "每日 5 次免费绘图", "free-web": "联网搜索功能", "free-conversation": "对话存储记录", @@ -391,7 +391,7 @@ const resources = { "free-price": "Бесплатно навсегда", pro: "Профессиональный", "pro-price": "8 CNY/месяц", - "free-gpt3": "GPT-3.5 бесплатно навсегда", + "free-gpt3": "GPT-3.5 (16k) бесплатно навсегда", "free-dalle": "5 бесплатных квот в день", "free-web": "веб-поиск", "free-conversation": "хранение разговоров", diff --git a/app/src/routes/Generation.tsx b/app/src/routes/Generation.tsx index f55c6b1..4f96e0e 100644 --- a/app/src/routes/Generation.tsx +++ b/app/src/routes/Generation.tsx @@ -1,5 +1,5 @@ import "../assets/generation.less"; -import { useSelector } from "react-redux"; +import {useDispatch, useSelector} from "react-redux"; import { selectAuthenticated } from "../store/auth.ts"; import { useTranslation } from "react-i18next"; import { Button } from "../components/ui/button.tsx"; @@ -11,7 +11,8 @@ import { useEffect, useRef, useState } from "react"; import SelectGroup from "../components/SelectGroup.tsx"; import {manager} from "../conversation/generation.ts"; import {useToast} from "../components/ui/use-toast.ts"; -import {handleLine} from "../utils.ts"; +import {handleGenerationData} from "../utils.ts"; +import {selectModel, setModel} from "../store/chat.ts"; type WrapperProps = { onSend?: (value: string, model: string) => boolean; @@ -19,14 +20,21 @@ type WrapperProps = { function Wrapper({ onSend }: WrapperProps) { const { t } = useTranslation(); + const dispatch = useDispatch(); const ref = useRef(null); const [ stayed, setStayed ] = useState(false); const [ hash, setHash ] = useState(""); const [ data, setData ] = useState(""); const [ quota, setQuota ] = useState(0); - const [model, setModel] = useState("GPT-3.5"); + const model = useSelector(selectModel); + const auth = useSelector(selectAuthenticated); + const { toast } = useToast(); + useEffect(() => { + if (auth && model === "GPT-3.5") dispatch(setModel("GPT-3.5-16k")); + }, [auth]); + function clear() { setData(""); setQuota(0); @@ -52,14 +60,14 @@ function Wrapper({ onSend }: WrapperProps) { setHash(hash); }) - function handleSend() { + function handleSend(model: string = "gpt-3.5-16k") { const target = ref.current as HTMLInputElement | null; if (!target) return; const value = target.value.trim(); if (!value.length) return; - if (onSend?.(value, model.toLowerCase())) { + if (onSend?.(value, model)) { setStayed(true); clear(); target.value = ""; @@ -68,13 +76,18 @@ function Wrapper({ onSend }: WrapperProps) { useEffect(() => { ref.current && (ref.current as HTMLInputElement).focus(); + ref.current && (ref.current as HTMLInputElement).removeEventListener("keydown", () => {}); ref.current && (ref.current as HTMLInputElement).addEventListener("keydown", (e) => { if (e.key === "Enter") { - handleSend(); + handleSend(model); } }); - }); + + return () => { + ref.current && (ref.current as HTMLInputElement).removeEventListener("keydown", () => {}); + } + }, [ref]); return (
{ @@ -85,7 +98,7 @@ function Wrapper({ onSend }: WrapperProps) { {quota}
}
-              { handleLine(data, 10) || t('generate.empty') }
+              { handleGenerationData(data) || t('generate.empty') }
             
{ hash.length > 0 && @@ -110,7 +123,7 @@ function Wrapper({ onSend }: WrapperProps) { size={`icon`} className={`action`} variant={`default`} - onClick={handleSend} + onClick={() => handleSend(model)} > @@ -119,7 +132,9 @@ function Wrapper({ onSend }: WrapperProps) { { + dispatch(setModel(value)); + }} /> @@ -147,7 +162,8 @@ function Generation() { { - return manager.generateWithBlock(prompt, model) + console.debug(`[generation] create generation request (prompt: ${prompt}, model: ${model.toLowerCase()})`); + return manager.generateWithBlock(prompt, model.toLowerCase()); }} /> diff --git a/app/src/routes/Home.tsx b/app/src/routes/Home.tsx index 4ce7e3e..51dbafe 100644 --- a/app/src/routes/Home.tsx +++ b/app/src/routes/Home.tsx @@ -286,6 +286,10 @@ function ChatWrapper() { const target = useRef(null); manager.setDispatch(dispatch); + useEffect(() => { + if (auth && model === "GPT-3.5") dispatch(setModel("GPT-3.5-16k")); + }, [auth]); + function clearFile() { clearEvent?.(); } diff --git a/app/src/service.ts b/app/src/service.ts index 6fa24e6..6ddd8c7 100644 --- a/app/src/service.ts +++ b/app/src/service.ts @@ -12,7 +12,7 @@ export const updateSW = registerSW({ }).then(async (resp) => { if (resp?.status === 200) { await registration.update(); - if (registration.onupdatefound) console.log("update found"); + if (registration.onupdatefound) console.debug("update found"); } }); }, diff --git a/app/src/utils.ts b/app/src/utils.ts index 31613ad..95947f8 100644 --- a/app/src/utils.ts +++ b/app/src/utils.ts @@ -197,12 +197,22 @@ export function useDraggableInput( }); } +export function escapeRegExp(str: string): string { + // convert \n to [enter], \t to [tab], \r to [return], \s to [space], \" to [quote], \' to [single-quote] + return str.replace(/\\n/g, "\n").replace(/\\t/g, "\t").replace(/\\r/g, "\r").replace(/\\s/g, " ").replace(/\\"/g, "\"").replace(/\\'/g, "'"); +} + export function handleLine(data: string, max_line: number, end?: boolean): string { const segment = data.split("\n"); const line = segment.length; if (line > max_line) { - return end ? segment.slice(line - max_line).join("\n") : segment.slice(0, max_line).join("\n"); + return (end ?? true) ? segment.slice(line - max_line).join("\n") : segment.slice(0, max_line).join("\n"); } else { return data; } } + +export function handleGenerationData(data: string): string { + data = data.replace(/{\s*"result":\s*{/g, "").trim().replace(/}\s*$/g, ""); + return handleLine(escapeRegExp(data), 6); +} diff --git a/generation/api.go b/generation/api.go index 8caed43..9e8fcd1 100644 --- a/generation/api.go +++ b/generation/api.go @@ -82,6 +82,7 @@ func GenerateAPI(c *gin.Context) { End: true, Error: "generation rate limit exceeded, the max generation rate is 30 per hour.", }) + return } useReverse := auth.CanEnableSubscription(db, cache, user) @@ -91,6 +92,7 @@ func GenerateAPI(c *gin.Context) { Quota: 0, End: true, }) + return } hash, err := CreateGenerationWithCache(form.Model, form.Prompt, useReverse, func(data string) { diff --git a/generation/prompt.go b/generation/prompt.go index 1d51f33..31713cb 100644 --- a/generation/prompt.go +++ b/generation/prompt.go @@ -19,7 +19,7 @@ func CreateGeneration(model string, prompt string, path string, enableReverse bo {Role: "user", Content: "python后端"}, {Role: "assistant", Content: "{\n \"result\": {\n \"app.py\": \"from flask import Flask\\n\\napp = Flask(__name__)\\n\\n\\n@app.route('/')\\ndef hello_world():\\n return 'Hello, World!'\\n\\n\\nif __name__ == '__main__':\\n app.run()\",\n \"requirements.txt\": \"flask\\n\",\n \"README.md\": \"# Python 后端\\n本项目是一个简单的python后端示例, 使用`flask`框架构建后端。\n你可以按照下列步骤运行此应用,flask将在本地服务器(默认是在http://127.0.0.1:5000/)上运行。当你在浏览器中访问该URL时,将看到显示Hello, World!的页面。\\n\\n这只是一个简单的项目,Flask还支持更多功能和路由规则,你可以提供更多的信息和需要进一步扩展和定制Flask应用。\\n\\n### 1. 初始化: \\n```shell\\npip install -r requirements.txt\\n```\\n### 2. 运行\\n```shell\\npython app.py\\n```\"\n }\n}"}, {Role: "user", Content: "golang fiber websocket项目"}, - {Role: "assistant", Content: "{\n \"result\": {\n \"main.go\": \"package main\\n\\nimport (\\n\\t\"log\\\"\\n\\n\\t\"github.com/gofiber/fiber/v2\\\"\\n\\t\"github.com/gofiber/websocket/v2\\\"\\n)\\n\\nfunc main() {\\n\\tapp := fiber.New()\\n\\n\\tapp.Get(\\\"/\\\", func(c *fiber.Ctx) error {\\n\\t\\treturn c.SendString(\\\"Hello, World!\\\")\\n\\t})\\n\\n\\tapp.Get(\\\"/ws\\\", websocket.New(func(c *websocket.Conn) {\\n\\t\\tfor {\\n\\t\\t\\tmt, message, err := c.ReadMessage()\\n\\t\\t\\tif err != nil {\\n\\t\\t\\t\\tlog.Println(\\\"read error:\\\", err)\\n\\t\\t\\t\\tbreak\\n\\t\\t\\t}\\n\\t\\t\\tlog.Printf(\\\"received: %s\\\", message)\\n\\t\\t\\terr = c.WriteMessage(mt, message)\\n\\t\\t\\tif err != nil {\\n\\t\\t\\t\\tlog.Println(\\\"write error:\\\", err)\\n\\t\\t\\t\\tbreak\\n\\t\\t\\t}\\n\\t\\t}\\n\\t}))\\n\\n\\tlog.Fatal(app.Listen(\\\":3000\\\"))\\n}\",\n \"go.mod\": \"module fiber-websocket\\n\\ngo 1.16\\n\\nrequire (\\n\\tgithub.com/gofiber/fiber/v2 v2.12.1\\n\\tgithub.com/gofiber/websocket/v2 v2.10.2\\n)\",\n \"README.md\": \"# Golang Fiber WebSocket项目\\n\\n这个项目是一个使用Golang和Fiber框架构建的WebSocket服务器示例。\\n\\n### 1. 初始化:\\n```shell\\ngo mod init fiber-websocket\\n```\\n\\n### 2. 安装依赖:\\n```shell\\ngo get github.com/gofiber/fiber/v2\\n``` \\n```shell\\ngo get github.com/gofiber/websocket/v2\\n```\\n\\n### 3. 创建main.go文件,将以下代码复制粘贴:\\n\\n```go\\npackage main\\n\\nimport (\\n\\t\\\"log\\\"\\n\\n\\t\\\"github.com/gofiber/fiber/v2\\\"\\n\\t\\\"github.com/gofiber/websocket/v2\\\"\\n)\\n\\nfunc main() {\\n\\tapp := fiber.New()\\n\\n\\tapp.Get(\\\"/\\\", func(c *fiber.Ctx) error {\\n\\t\\treturn c.SendString(\\\"Hello, World!\\\")\\n\\t})\\n\\n\\tapp.Get(\\\"/ws\\\", websocket.New(func(c *websocket.Conn) {\\n\\t\\tfor {\\n\\t\\t\\tmt, message, err := c.ReadMessage()\\n\\t\\t\\tif err != nil {\\n\\t\\t\\t\\tlog.Println(\\\"read error:\\\", err)\\n\\t\\t\\t\\tbreak\\n\\t\\t\\t}\\n\\t\\t\\tlog.Printf(\\\"received: %s\\\", message)\\n\\t\\t\\terr = c.WriteMessage(mt, message)\\n\\t\\t\\tif err != nil {\\n\\t\\t\\t\\tlog.Println(\\\"write error:\\\", err)\\n\\t\\t\\t\\tbreak\\n\\t\\t\\t}\\n\\t\\t}\\n\\t}))\\n\\n\\tlog.Fatal(app.Listen(\\\":3000\\\"))\\n}\\n```\\n\\n### 4. 运行应用程序:\\n```shell\\ngo run main.go\\n```\\n\\n应用程序将在本地服务器(默认是在http://localhost:3000)上运行。当你在浏览器中访问`http://localhost:3000`时,将看到显示\"Hello, World!\"的页面。你还可以访问`http://localhost:3000/ws`来测试WebSocket功能。\n\n这只是一个简单的示例,Fiber框架提供了更多的功能和路由规则,你可以在此基础上进行进一步扩展和定制。\n\n注意:在运行应用程序之前,请确保已经安装了Go语言开发环境。"}, + {Role: "assistant", Content: "{\n \"result\": {\n \"main.go\": \"package main\\n\\nimport (\\n\\t\"log\\\"\\n\\n\\t\"github.com/gofiber/fiber/v2\\\"\\n\\t\"github.com/gofiber/websocket/v2\\\"\\n)\\n\\nfunc main() {\\n\\tapp := fiber.New()\\n\\n\\tapp.Get(\\\"/\\\", func(c *fiber.Ctx) error {\\n\\t\\treturn c.SendString(\\\"Hello, World!\\\")\\n\\t})\\n\\n\\tapp.Get(\\\"/ws\\\", websocket.New(func(c *websocket.Conn) {\\n\\t\\tfor {\\n\\t\\t\\tmt, message, err := c.ReadMessage()\\n\\t\\t\\tif err != nil {\\n\\t\\t\\t\\tlog.Println(\\\"read error:\\\", err)\\n\\t\\t\\t\\tbreak\\n\\t\\t\\t}\\n\\t\\t\\tlog.Printf(\\\"received: %s\\\", message)\\n\\t\\t\\terr = c.WriteMessage(mt, message)\\n\\t\\t\\tif err != nil {\\n\\t\\t\\t\\tlog.Println(\\\"write error:\\\", err)\\n\\t\\t\\t\\tbreak\\n\\t\\t\\t}\\n\\t\\t}\\n\\t}))\\n\\n\\tlog.Fatal(app.Listen(\\\":3000\\\"))\\n}\",\n \"go.mod\": \"module fiber-websocket\\n\\ngo 1.16\\n\\nrequire (\\n\\tgithub.com/gofiber/fiber/v2 v2.12.1\\n\\tgithub.com/gofiber/websocket/v2 v2.10.2\\n)\",\n \"README.md\": \"# Golang Fiber WebSocket项目\\n\\n这个项目是一个使用 Golang 和 Fiber 框架构建的 WebSocket 服务器示例。\\n\\n### 运行应用程序:\\n```shell\\ngo run main.go\\n```\\n\\n应用程序将在本地服务器(默认是在http://localhost:3000)上运行。当你在浏览器中访问`http://localhost:3000`时,将看到显示\"Hello, World!\"的页面。你还可以访问`http://localhost:3000/ws`来测试 WebSocket 连接。\n\n注意:在运行应用程序之前,请确保已经安装了Go语言开发环境。\"\n }\n}"}, {Role: "user", Content: prompt}, }, -1, func(data string) { hook(data)