├── src ├── env.d.ts ├── types.ts ├── default.ts ├── components │ ├── Header.astro │ ├── Clipboard.tsx │ ├── MessageItem.tsx │ ├── PromptList.tsx │ ├── Setting.tsx │ └── Generator.tsx ├── pages │ ├── index.astro │ └── api │ │ ├── index.ts │ │ └── stream.ts ├── shims.d.ts ├── layouts │ └── Layout.astro ├── styles │ ├── message.css │ ├── global.css │ └── clipboard.css ├── markdown │ └── index.ts ├── hooks │ └── index.ts ├── utils │ └── index.ts └── prompts.ts ├── assets ├── preview.png └── environment.png ├── .gitignore ├── tsconfig.json ├── 来源 └── default.ts ├── astro.config.mjs ├── LICENSE ├── package.json ├── README.md └── public └── favicon.svg /src/env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /assets/preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/product/chatgpt/main/assets/preview.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .env 3 | yarn-error.log 4 | .idea/ 5 | .vercel 6 | .DS_Store 7 | -------------------------------------------------------------------------------- /assets/environment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/product/chatgpt/main/assets/environment.png -------------------------------------------------------------------------------- /src/types.ts: -------------------------------------------------------------------------------- 1 | export interface ChatMessage { 2 | role: 'system' | 'user' | 'assistant' 3 | content: string 4 | } 5 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "astro/tsconfigs/strict", 3 | "compilerOptions": { 4 | "jsx": "preserve", 5 | "jsxImportSource": "solid-js", 6 | "baseUrl": ".", 7 | "paths": { 8 | "~/*": [ 9 | "src/*" 10 | ] 11 | }, 12 | } 13 | } -------------------------------------------------------------------------------- /src/default.ts: -------------------------------------------------------------------------------- 1 | export const defaultSetting = { 2 | continuousDialogue: true, 3 | archiveSession: false, 4 | openaiAPIKey: "", 5 | openaiAPITemperature: 60, 6 | systemRule: "" 7 | } 8 | 9 | export const defaultMessage = ` 10 | - 本站仅用于演示,填入自己的 key 才可使用。 11 | - 本站功能强大,响应速度快,欢迎自部署。 12 | - Shift + Enter 换行。开头输入 / 或者 空格 搜索 Prompt 预设。点击输入框滚动到底部。` 13 | -------------------------------------------------------------------------------- /来源/default.ts: -------------------------------------------------------------------------------- 1 | export const defaultSetting = { 2 | continuousDialogue: true, 3 | archiveSession: false, 4 | openaiAPIKey: "", 5 | openaiAPITemperature: 60, 6 | systemRule: "" 7 | } 8 | 9 | export const defaultMessage = ` 10 | - 本站仅用于演示,填入自己的 key 才可使用555。 11 | - 由 [是枭](https://blog.evv1.com) 站点源码出售,功能强大响应快,欢迎自部署。 12 | - **Shift+Enter** 换行。开头输入 **/** 或者 **空格** 搜索 Prompt 预设。点击输入框滚动到底部。` 13 | -------------------------------------------------------------------------------- /src/components/Header.astro: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ChatGPT 8 | Vercel 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/pages/index.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Layout from "~/layouts/Layout.astro" 3 | import Header from "~/components/Header.astro" 4 | import Generator from "~/components/Generator" 5 | import "~/styles/global.css" 6 | import "@unocss/reset/tailwind.css" 7 | import "katex/dist/katex.min.css" 8 | import "highlight.js/styles/atom-one-dark.css" 9 | --- 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/shims.d.ts: -------------------------------------------------------------------------------- 1 | import type { AttributifyAttributes } from '@unocss/preset-attributify' 2 | 3 | // declare module 'solid-js' { 4 | // namespace JSX { 5 | // interface HTMLAttributes extends AttributifyAttributes {} 6 | // } 7 | // } 8 | 9 | declare global { 10 | namespace astroHTML.JSX { 11 | interface HTMLAttributes extends AttributifyAttributes { } 12 | } 13 | namespace JSX { 14 | interface HTMLAttributes extends AttributifyAttributes {} 15 | } 16 | } -------------------------------------------------------------------------------- /src/layouts/Layout.astro: -------------------------------------------------------------------------------- 1 | --- 2 | export interface Props { 3 | title: string 4 | } 5 | 6 | const { title } = Astro.props 7 | --- 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | {title} 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/styles/message.css: -------------------------------------------------------------------------------- 1 | .message pre { 2 | background-color: #64748b10; 3 | font-size: 0.8rem; 4 | padding: 0.4rem 1rem; 5 | } 6 | 7 | .message .hljs { 8 | background-color: transparent; 9 | } 10 | 11 | .message table { 12 | font-size: 0.8em; 13 | } 14 | 15 | .message table thead tr { 16 | background-color: #64748b40; 17 | text-align: left; 18 | } 19 | 20 | .message table th, .message table td { 21 | padding: 0.6rem 1rem; 22 | } 23 | 24 | .message table tbody tr:last-of-type { 25 | border-bottom: 2px solid #64748b40; 26 | } -------------------------------------------------------------------------------- /src/components/Clipboard.tsx: -------------------------------------------------------------------------------- 1 | import { createSignal } from "solid-js" 2 | import { copyToClipboard } from "../utils" 3 | import "../styles/clipboard.css" 4 | export default function Clipboard(props: { message: string }) { 5 | const [copied, setCopied] = createSignal(false) 6 | return ( 7 | { 15 | setCopied(true) 16 | copyToClipboard(props.message) 17 | setTimeout(() => setCopied(false), 2000) 18 | }} 19 | /> 20 | ) 21 | } 22 | -------------------------------------------------------------------------------- /astro.config.mjs: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "astro/config" 2 | import vercel from "@astrojs/vercel/edge" 3 | import unocss from "unocss/astro" 4 | import { 5 | presetUno, 6 | presetIcons, 7 | presetAttributify, 8 | presetTypography 9 | } from "unocss" 10 | import solidJs from "@astrojs/solid-js" 11 | 12 | // https://astro.build/config 13 | export default defineConfig({ 14 | integrations: [ 15 | unocss({ 16 | presets: [ 17 | presetAttributify(), 18 | presetUno(), 19 | presetTypography(), 20 | presetIcons() 21 | ] 22 | }), 23 | solidJs() 24 | ], 25 | output: "server", 26 | adapter: vercel() 27 | }) 28 | -------------------------------------------------------------------------------- /src/styles/global.css: -------------------------------------------------------------------------------- 1 | ::-webkit-scrollbar { 2 | width: 10px; 3 | height: 10px; 4 | /**/ 5 | } 6 | ::-webkit-scrollbar-track { 7 | background: #404552; 8 | border-top-right-radius: 0.25rem; 9 | } 10 | 11 | ::-webkit-scrollbar-thumb { 12 | background: #2a2d37; 13 | border-radius: 0.25rem; 14 | } 15 | 16 | ::-webkit-scrollbar-corner { 17 | background: transparent; 18 | } 19 | 20 | :root { 21 | --c-bg: #171921; 22 | } 23 | 24 | html { 25 | font-family: system-ui, sans-serif; 26 | background-color: var(--c-bg); 27 | color: #ffffff; 28 | } 29 | 30 | main { 31 | max-width: 72ch; 32 | margin: 0 auto; 33 | padding: 8em 2em; 34 | } 35 | 36 | @media (max-width: 768px) { 37 | main { 38 | padding-top: 2em; 39 | } 40 | } 41 | 42 | * { 43 | -webkit-tap-highlight-color: transparent; 44 | } 45 | -------------------------------------------------------------------------------- /src/markdown/index.ts: -------------------------------------------------------------------------------- 1 | import type MarkdownIt from "markdown-it" 2 | 3 | export function preWrapperPlugin(md: MarkdownIt) { 4 | const fence = md.renderer.rules.fence! 5 | md.renderer.rules.fence = (...args) => { 6 | const [tokens, idx] = args 7 | const token = tokens[idx] 8 | // remove title from info 9 | token.info = token.info.replace(/\[.*\]/, "") 10 | 11 | const lang = extractLang(token.info) 12 | const rawCode = fence(...args) 13 | return rawCode.replace( 14 | "", 15 | `` 16 | ) 17 | } 18 | } 19 | 20 | export function extractTitle(info: string) { 21 | return info.match(/\[(.*)\]/)?.[1] || extractLang(info) || "txt" 22 | } 23 | 24 | const extractLang = (info: string) => { 25 | return info.trim().replace(/:(no-)?line-numbers({| |$).*/, "") 26 | } 27 | -------------------------------------------------------------------------------- /src/hooks/index.ts: -------------------------------------------------------------------------------- 1 | import { onCleanup, onMount } from "solid-js" 2 | import { copyToClipboard } from "../utils" 3 | 4 | export function useCopyCode() { 5 | const timeoutIdMap: Map = new Map() 6 | const listerner = (e: MouseEvent) => { 7 | const el = e.target as HTMLElement 8 | if (el.matches(".code-copy")) { 9 | const parent = el.parentElement 10 | const sibling = el.nextElementSibling as HTMLPreElement | null 11 | if (!parent || !sibling) { 12 | return 13 | } 14 | 15 | let text = sibling.innerText 16 | 17 | copyToClipboard(text).then(() => { 18 | el.classList.add("copied") 19 | clearTimeout(timeoutIdMap.get(el)) 20 | const timeoutId = setTimeout(() => { 21 | el.classList.remove("copied") 22 | el.blur() 23 | timeoutIdMap.delete(el) 24 | }, 2000) 25 | timeoutIdMap.set(el, timeoutId) 26 | }) 27 | } 28 | } 29 | onMount(() => { 30 | window.addEventListener("click", listerner) 31 | }) 32 | onCleanup(() => { 33 | window.removeEventListener("click", listerner) 34 | }) 35 | } 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 OuRongXing and Diu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vercel-chatgpt", 3 | "version": "0.0.1", 4 | "description": "Powered by OpenAI Chatgpt API and Vercel", 5 | "type": "module", 6 | "license": "MIT", 7 | "scripts": { 8 | "dev": "astro dev", 9 | "start": "astro dev", 10 | "build": "astro build", 11 | "preview": "astro preview", 12 | "astro": "astro" 13 | }, 14 | "dependencies": { 15 | "@astrojs/solid-js": "^2.0.2", 16 | "@astrojs/vercel": "^3.1.3", 17 | "@solid-primitives/resize-observer": "^2.0.11", 18 | "@unocss/reset": "^0.50.3", 19 | "astro": "^2.0.15", 20 | "eventsource-parser": "^0.1.0", 21 | "fzf": "^0.5.1", 22 | "highlight.js": "^11.7.0", 23 | "just-throttle": "^4.2.0", 24 | "katex": "^0.6.0", 25 | "markdown-it": "^13.0.1", 26 | "markdown-it-highlightjs": "^4.0.1", 27 | "markdown-it-katex": "^2.0.3", 28 | "solid-js": "^1.6.11" 29 | }, 30 | "devDependencies": { 31 | "@iconify-json/carbon": "^1.1.16", 32 | "@types/markdown-it": "^12.2.3", 33 | "@vercel/node": "^2.8.0", 34 | "punycode": "^2.3.0", 35 | "typescript": "^4.8.3", 36 | "unocss": "^0.50.1" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/pages/api/index.ts: -------------------------------------------------------------------------------- 1 | import type { APIRoute } from "astro" 2 | 3 | export const post: APIRoute = async ({ request }) => { 4 | const { message, key } = (await request.json()) ?? {} 5 | if (!message) { 6 | return { 7 | body: JSON.stringify({ 8 | success: false, 9 | message: "message is required" 10 | }) 11 | } 12 | } 13 | if (!key) { 14 | return { 15 | body: JSON.stringify({ 16 | success: false, 17 | message: "openapi key is required" 18 | }) 19 | } 20 | } 21 | 22 | const response = await fetch(`https://api.openai.com/v1/chat/completions`, { 23 | method: "POST", 24 | headers: { 25 | Authorization: `Bearer ${key}`, 26 | "Content-Type": `application/json` 27 | }, 28 | body: JSON.stringify({ 29 | model: "gpt-3.5-turbo", 30 | messages: [ 31 | { 32 | role: "user", 33 | content: message 34 | } 35 | ] 36 | }) 37 | }) 38 | let result = await response.json() 39 | if (result?.error) { 40 | return { 41 | body: JSON.stringify({ 42 | success: false, 43 | message: `${result.error?.message}` 44 | }) 45 | } 46 | } 47 | return { 48 | body: JSON.stringify({ 49 | success: true, 50 | message: "ok", 51 | data: result?.choices?.[0].message 52 | }) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/utils/index.ts: -------------------------------------------------------------------------------- 1 | export async function copyToClipboard(text: string) { 2 | try { 3 | return navigator.clipboard.writeText(text) 4 | } catch { 5 | const element = document.createElement("textarea") 6 | const previouslyFocusedElement = document.activeElement 7 | 8 | element.value = text 9 | 10 | // Prevent keyboard from showing on mobile 11 | element.setAttribute("readonly", "") 12 | 13 | element.style.contain = "strict" 14 | element.style.position = "absolute" 15 | element.style.left = "-9999px" 16 | element.style.fontSize = "12pt" // Prevent zooming on iOS 17 | 18 | const selection = document.getSelection() 19 | const originalRange = selection 20 | ? selection.rangeCount > 0 && selection.getRangeAt(0) 21 | : null 22 | 23 | document.body.appendChild(element) 24 | element.select() 25 | 26 | // Explicit selection workaround for iOS 27 | element.selectionStart = 0 28 | element.selectionEnd = text.length 29 | 30 | document.execCommand("copy") 31 | document.body.removeChild(element) 32 | 33 | if (originalRange) { 34 | selection!.removeAllRanges() // originalRange can't be truthy when selection is falsy 35 | selection!.addRange(originalRange) 36 | } 37 | 38 | // Get the focus back on the previously focused element, if any 39 | if (previouslyFocusedElement) { 40 | ;(previouslyFocusedElement as HTMLElement).focus() 41 | } 42 | } 43 | } 44 | 45 | export function isMobile() { 46 | return /Mobi|Android|iPhone/i.test(navigator.userAgent) 47 | } 48 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ChatGPT-Vercel 2 | 3 |  4 | 5 | 6 | 预览: [tg-bot.ml](https://www.tg-bot.ml/) 7 | 个人博客:[速龙博客](https://blog.ahayu.cn) 8 | 9 | ## 部署一个你自己的(免费) 10 | 11 | > 本项目主要面向中文用户,所以用中文,原版是英文的。 12 | 13 | 如果你只需要部署一个你自己用的网站,而不需要定制,那么你完全不需要在本地跑起来,你可以直接点击下面的按钮,然后按照提示操作即可。 vercel 域名已经被墙,但 vercel 本身没有被墙,所以你绑定自己的域名就可以了。 14 | 15 | [](https://vercel.com/new/clone?repository-url=https://github.com/fastdragon18/chat) 16 | 17 | 如果你需要部署给更多人用,那么你可能需要将上面创建的你自己的仓库 `git clone` 到本地。 18 | 19 | 1. 将 `.env.example` 文件修改为 `.env`,然后在里面填入你的 [OpenAI API key](https://platform.openai.com/account/api-keys)。如果用户不填自己的 key,那么就会使用你的 key。 20 | 21 | ``` 22 | OPENAI_API_KEY=sk-xxx... 23 | // 你可以填写多个,用 | 分隔,随机调用。最好是多填几个,不太清楚有没有并发上的限制。 24 | OPENAI_API_KEY=sk-xxx|sk-yyy 25 | ``` 26 | 最新版本支持读取 Vercel 的环境变量,所以你也可以直接在 Vercel 上设置环境变量,如图所示。对于大部分人来说这个更方便。会在下次部署时生效。 27 |  28 | 2. 默认设置在 `src/default.ts` 文件中,自行修改。默认的提示信息也在这里。 29 | ```ts 30 | const defaultSetting = { 31 | // 连续对话,每次都需要将上下文传给 API,比较费钱,而且同样有 4096 token 的限制 32 | continuousDialogue: true, 33 | // 记录对话内容,刷新后不会清空对话 34 | archiveSession: false, 35 | openaiAPIKey: "", 36 | // 0-100 越高 ChatGPT 思维就越发散,开始乱答 37 | openaiAPITemperature: 60, 38 | // 系统角色指令,会在每次提问时添加。主要用于对 ChatGPT 的语气,口头禅这些进行定制。 39 | systemRule: "" 40 | } 41 | ``` 42 | 3. 之前版本我设置了每次刷新重置 `开启连续对话` 选项,因为一般用不上这个,比较费钱。当前版本我已经移除了这个特性,如果你需要给更多人用,建议打开,只要将 [这行代码](https://github.com/ourongxing/chatgpt-vercel/blob/main/src/components/Generator.tsx#L46) 取消注释即可。 43 | 44 | 4. `git commit & push` 即可重新部署,vscode 上点几下就可以了。 45 | 46 | ## API 47 | 48 | ### POST /api 49 | ```ts 50 | await fetch("/api", { 51 | method: "POST", 52 | body: JSON.stringify({ 53 | message: "xxx", 54 | key: "xxxx" 55 | }) 56 | }) 57 | ``` 58 | ## License 59 | 60 | MIT 61 | -------------------------------------------------------------------------------- /src/components/MessageItem.tsx: -------------------------------------------------------------------------------- 1 | import type { Accessor } from "solid-js" 2 | import type { ChatMessage } from "../types" 3 | import MarkdownIt from "markdown-it" 4 | // @ts-ignore 5 | import mdKatex from "markdown-it-katex" 6 | import mdHighlight from "markdown-it-highlightjs" 7 | import Clipboard from "./Clipboard" 8 | import { preWrapperPlugin } from "../markdown" 9 | import "../styles/message.css" 10 | import { useCopyCode } from "../hooks" 11 | 12 | interface Props { 13 | role: ChatMessage["role"] 14 | message: Accessor | string 15 | } 16 | 17 | export default ({ role, message }: Props) => { 18 | useCopyCode() 19 | const roleClass = { 20 | system: "bg-gradient-to-r from-gray-300 via-gray-200 to-gray-300", 21 | user: "bg-gradient-to-r from-sky-400 to-emerald-500", 22 | assistant: "bg-gradient-to-r from-yellow-300 to-red-700 " 23 | } 24 | 25 | const htmlString = () => { 26 | const md = MarkdownIt({ 27 | breaks: true, 28 | html: true 29 | }) 30 | .use(mdKatex) 31 | .use(mdHighlight) 32 | .use(preWrapperPlugin) 33 | 34 | if (typeof message === "function") { 35 | return md.render(message().trim()) 36 | } else if (typeof message === "string") { 37 | return md.render(message.trim()) 38 | } 39 | return "" 40 | } 41 | 42 | // createEffect(() => { 43 | // console.log(htmlString()) 44 | // }) 45 | 46 | return ( 47 | 51 | 54 | 58 | { 60 | if (typeof message === "function") { 61 | return message().trim() 62 | } else if (typeof message === "string") { 63 | return message.trim() 64 | } 65 | return "" 66 | })()} 67 | /> 68 | 69 | ) 70 | } 71 | -------------------------------------------------------------------------------- /src/pages/api/stream.ts: -------------------------------------------------------------------------------- 1 | import type { APIRoute } from "astro" 2 | import { 3 | createParser, 4 | ParsedEvent, 5 | ReconnectInterval 6 | } from "eventsource-parser" 7 | 8 | const localEnv = import.meta.env.OPENAI_API_KEY 9 | const vercelEnv = process.env.OPENAI_API_KEY 10 | 11 | const apiKeys = ((localEnv || vercelEnv)?.split(/\s*\|\s*/) ?? []).filter( 12 | Boolean 13 | ) 14 | 15 | export const post: APIRoute = async context => { 16 | const body = await context.request.json() 17 | const apiKey = apiKeys.length 18 | ? apiKeys[Math.floor(Math.random() * apiKeys.length)] 19 | : "" 20 | let { messages, key = apiKey, temperature = 0.6 } = body 21 | 22 | const encoder = new TextEncoder() 23 | const decoder = new TextDecoder() 24 | 25 | if (!key.startsWith("sk-")) key = apiKey 26 | if (!key) { 27 | return new Response("没有填写 OpenAI API key") 28 | } 29 | if (!messages) { 30 | return new Response("没有输入任何文字") 31 | } 32 | 33 | const completion = await fetch("https://api.openai.com/v1/chat/completions", { 34 | headers: { 35 | "Content-Type": "application/json", 36 | Authorization: `Bearer ${key}` 37 | }, 38 | method: "POST", 39 | body: JSON.stringify({ 40 | model: "gpt-3.5-turbo", 41 | messages, 42 | temperature, 43 | stream: true 44 | }) 45 | }) 46 | 47 | const stream = new ReadableStream({ 48 | async start(controller) { 49 | const streamParser = (event: ParsedEvent | ReconnectInterval) => { 50 | if (event.type === "event") { 51 | const data = event.data 52 | if (data === "[DONE]") { 53 | controller.close() 54 | return 55 | } 56 | try { 57 | // response = { 58 | // id: 'chatcmpl-6pULPSegWhFgi0XQ1DtgA3zTa1WR6', 59 | // object: 'chat.completion.chunk', 60 | // created: 1677729391, 61 | // model: 'gpt-3.5-turbo-0301', 62 | // choices: [ 63 | // { delta: { content: '你' }, index: 0, finish_reason: null } 64 | // ], 65 | // } 66 | const json = JSON.parse(data) 67 | const text = json.choices[0].delta?.content 68 | const queue = encoder.encode(text) 69 | controller.enqueue(queue) 70 | } catch (e) { 71 | controller.error(e) 72 | } 73 | } 74 | } 75 | 76 | const parser = createParser(streamParser) 77 | for await (const chunk of completion.body as any) { 78 | parser.feed(decoder.decode(chunk)) 79 | } 80 | } 81 | }) 82 | 83 | return new Response(stream) 84 | } 85 | -------------------------------------------------------------------------------- /src/components/PromptList.tsx: -------------------------------------------------------------------------------- 1 | import { createEffect, createSignal, For, onCleanup, onMount } from "solid-js" 2 | import type { PromptItem } from "./Generator" 3 | 4 | export default function PromptList(props: { 5 | prompts: PromptItem[] 6 | select: (k: string) => void 7 | }) { 8 | let containerRef: HTMLUListElement 9 | const [hoverIndex, setHoverIndex] = createSignal(0) 10 | const [maxHeight, setMaxHeight] = createSignal("320px") 11 | function listener(e: KeyboardEvent) { 12 | if (e.key === "ArrowDown") { 13 | setHoverIndex(hoverIndex() + 1) 14 | } else if (e.key === "ArrowUp") { 15 | setHoverIndex(hoverIndex() - 1) 16 | } else if (e.key === "Enter") { 17 | props.select(props.prompts[hoverIndex()].prompt) 18 | } 19 | } 20 | 21 | createEffect(() => { 22 | if (hoverIndex() < 0) { 23 | setHoverIndex(0) 24 | } else if (hoverIndex() && hoverIndex() >= props.prompts.length) { 25 | setHoverIndex(props.prompts.length - 1) 26 | } 27 | }) 28 | 29 | createEffect(() => { 30 | if (containerRef && props.prompts.length) 31 | setMaxHeight( 32 | `${ 33 | window.innerHeight - containerRef.clientHeight > 112 34 | ? 320 35 | : window.innerHeight - 112 36 | }px` 37 | ) 38 | }) 39 | 40 | onMount(() => { 41 | window.addEventListener("keydown", listener) 42 | }) 43 | onCleanup(() => { 44 | window.removeEventListener("keydown", listener) 45 | }) 46 | 47 | return ( 48 | 55 | 56 | {(prompt, i) => ( 57 | 62 | )} 63 | 64 | 65 | ) 66 | } 67 | 68 | function Item(props: { 69 | prompt: PromptItem 70 | select: (k: string) => void 71 | hover: boolean 72 | }) { 73 | let ref: HTMLLIElement 74 | createEffect(() => { 75 | if (props.hover) { 76 | ref.focus() 77 | ref.scrollIntoView({ block: "center" }) 78 | } 79 | }) 80 | return ( 81 | { 89 | props.select(props.prompt.prompt) 90 | }} 91 | > 92 | {props.prompt.desc} 93 | {props.prompt.prompt} 94 | 95 | ) 96 | } 97 | -------------------------------------------------------------------------------- /src/styles/clipboard.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --block-bg-light: #1e1e20; 3 | --copy-border-color: transparent; 4 | --copy-bg: #2a2d38; 5 | --copy-hover-border-color: rgba(60, 60, 67, 0.12); 6 | --copy-hover-bg: #303540; 7 | --copy-active-text: rgba(235, 235, 245, 0.6); 8 | --icon-copy: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' height='20' width='20' stroke='rgba(128,128,128,1)' stroke-width='2' viewBox='0 0 24 24'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' d='M9 5H7a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2h-2M9 5a2 2 0 0 0 2 2h2a2 2 0 0 0 2-2M9 5a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2'/%3E%3C/svg%3E"); 9 | --icon-copied: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' height='20' width='20' stroke='rgba(128,128,128,1)' stroke-width='2' viewBox='0 0 24 24'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' d='M9 5H7a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2h-2M9 5a2 2 0 0 0 2 2h2a2 2 0 0 0 2-2M9 5a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2m-6 9 2 2 4-4'/%3E%3C/svg%3E"); 10 | } 11 | 12 | button.copy { 13 | direction: ltr; 14 | position: absolute; 15 | top: 12px; 16 | right: 12px; 17 | z-index: 3; 18 | display: block; 19 | justify-content: center; 20 | align-items: center; 21 | border: 1px solid var(--copy-border-color); 22 | border-radius: 4px; 23 | width: 40px; 24 | height: 40px; 25 | background-color: var(--copy-bg); 26 | opacity: 0; 27 | cursor: pointer; 28 | background-image: var(--icon-copy); 29 | background-position: 50%; 30 | background-size: 20px; 31 | background-repeat: no-repeat; 32 | transition: border-color 0.25s, background-color 0.25s, opacity 0.25s; 33 | } 34 | 35 | .message-item:hover > .message-copy, 36 | pre:hover > .code-copy, 37 | button.copy:focus { 38 | opacity: 1; 39 | } 40 | 41 | button.copy:hover, 42 | button.copy.copied { 43 | border-color: var(--copy-hover-border-color); 44 | background-color: var(--copy-hover-bg); 45 | } 46 | 47 | button.copy.copied, 48 | button.copy:hover.copied { 49 | border-radius: 0 4px 4px 0; 50 | background-color: var(--copy-hover-bg); 51 | background-image: var(--icon-copied); 52 | } 53 | 54 | button.copy.copied::before, 55 | button.copy:hover.copied::before { 56 | position: relative; 57 | top: -1px; 58 | left: -65px; 59 | display: flex; 60 | justify-content: center; 61 | align-items: center; 62 | border: 1px solid var(--copy-hover-border-color); 63 | border-right: 0; 64 | border-radius: 4px 0 0 4px; 65 | width: 64px; 66 | height: 40px; 67 | text-align: center; 68 | font-size: 12px; 69 | font-weight: 500; 70 | color: var(--copy-active-text); 71 | background-color: var(--copy-hover-bg); 72 | white-space: nowrap; 73 | content: "复制成功"; 74 | } 75 | -------------------------------------------------------------------------------- /public/favicon.svg: -------------------------------------------------------------------------------- 1 | 93-robot-face-2 -------------------------------------------------------------------------------- /src/components/Setting.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | Accessor, 3 | children, 4 | createSignal, 5 | JSXElement, 6 | Setter, 7 | Show 8 | } from "solid-js" 9 | import type { Setting } from "./Generator" 10 | 11 | export default function Setting(props: { 12 | setting: Accessor 13 | setSetting: Setter 14 | clear: any 15 | reAnswer: any 16 | }) { 17 | const [shown, setShown] = createSignal(false) 18 | return ( 19 | 20 | 21 | 22 | { 27 | props.setSetting({ 28 | ...props.setting(), 29 | openaiAPIKey: (e.target as HTMLInputElement).value 30 | }) 31 | }} 32 | /> 33 | 34 | 35 | { 40 | props.setSetting({ 41 | ...props.setting(), 42 | systemRule: (e.target as HTMLInputElement).value 43 | }) 44 | }} 45 | /> 46 | 47 | 48 | { 55 | props.setSetting({ 56 | ...props.setting(), 57 | openaiAPITemperature: Number( 58 | (e.target as HTMLInputElement).value 59 | ) 60 | }) 61 | }} 62 | /> 63 | 64 | 68 | 69 | { 74 | props.setSetting({ 75 | ...props.setting(), 76 | archiveSession: (e.target as HTMLInputElement).checked 77 | }) 78 | }} 79 | /> 80 | 81 | 82 | 83 | 87 | 88 | { 93 | props.setSetting({ 94 | ...props.setting(), 95 | continuousDialogue: (e.target as HTMLInputElement).checked 96 | }) 97 | }} 98 | /> 99 | 100 | 101 | 102 | 103 | 104 | 105 | { 108 | setShown(!shown()) 109 | }} 110 | > 111 | 112 | 设置 113 | 114 | 115 | 119 | 120 | 重新回答 121 | 122 | 126 | 127 | 清空对话 128 | 129 | 130 | 131 | 132 | ) 133 | } 134 | 135 | function SettingItem(props: { 136 | children: JSXElement 137 | icon: string 138 | label: string 139 | }) { 140 | return ( 141 | 142 | 143 | 144 | {props.label} 145 | 146 | {props.children} 147 | 148 | ) 149 | } 150 | -------------------------------------------------------------------------------- /src/components/Generator.tsx: -------------------------------------------------------------------------------- 1 | import { createEffect, createSignal, For, onMount, Show } from "solid-js" 2 | import { createResizeObserver } from "@solid-primitives/resize-observer" 3 | import MessageItem from "./MessageItem" 4 | import type { ChatMessage } from "~/types" 5 | import Setting from "./Setting" 6 | import PromptList from "./PromptList" 7 | import prompts from "~/prompts" 8 | import { Fzf } from "fzf" 9 | import { defaultMessage, defaultSetting } from "~/default" 10 | import throttle from "just-throttle" 11 | import { isMobile } from "~/utils" 12 | 13 | export interface PromptItem { 14 | desc: string 15 | prompt: string 16 | } 17 | 18 | export type Setting = typeof defaultSetting 19 | 20 | export default function () { 21 | let inputRef: HTMLTextAreaElement 22 | let containerRef: HTMLDivElement 23 | const [messageList, setMessageList] = createSignal([ 24 | // { 25 | // role: "assistant", 26 | // content: defaultMessage + defaultMessage + defaultMessage + defaultMessage 27 | // } 28 | ]) 29 | const [inputContent, setInputContent] = createSignal("") 30 | const [currentAssistantMessage, setCurrentAssistantMessage] = createSignal("") 31 | const [loading, setLoading] = createSignal(false) 32 | const [controller, setController] = createSignal() 33 | const [setting, setSetting] = createSignal(defaultSetting) 34 | const [compatiblePrompt, setCompatiblePrompt] = createSignal([]) 35 | const [containerWidth, setContainerWidth] = createSignal("init") 36 | const fzf = new Fzf(prompts, { selector: k => `${k.desc} (${k.prompt})` }) 37 | const [height, setHeight] = createSignal("48px") 38 | 39 | onMount(() => { 40 | createResizeObserver(containerRef, ({ width, height }, el) => { 41 | if (el === containerRef) setContainerWidth(`${width}px`) 42 | }) 43 | const storage = localStorage.getItem("setting") 44 | const session = localStorage.getItem("session") 45 | try { 46 | let archiveSession = false 47 | if (storage) { 48 | const parsed = JSON.parse(storage) 49 | archiveSession = parsed.archiveSession 50 | setSetting({ 51 | ...defaultSetting, 52 | ...parsed 53 | // continuousDialogue: false 54 | }) 55 | } 56 | if (session && archiveSession) { 57 | setMessageList(JSON.parse(session)) 58 | } 59 | } catch { 60 | console.log("Setting parse error") 61 | } 62 | }) 63 | 64 | createEffect(() => { 65 | if (messageList().length === 0) { 66 | setMessageList([ 67 | { 68 | role: "assistant", 69 | content: defaultMessage 70 | } 71 | ]) 72 | } else if ( 73 | messageList().length > 1 && 74 | messageList()[0].content === defaultMessage 75 | ) { 76 | setMessageList(messageList().slice(1)) 77 | } 78 | localStorage.setItem("setting", JSON.stringify(setting())) 79 | if (setting().archiveSession) 80 | localStorage.setItem("session", JSON.stringify(messageList())) 81 | }) 82 | 83 | createEffect(() => { 84 | if (messageList().length || currentAssistantMessage()) scrollToBottom() 85 | }) 86 | 87 | createEffect(() => { 88 | if (inputContent() === "") { 89 | setHeight("48px") 90 | setCompatiblePrompt([]) 91 | } 92 | }) 93 | 94 | const scrollToBottom = throttle( 95 | () => { 96 | window.scrollTo({ 97 | top: document.body.scrollHeight, 98 | behavior: "smooth" 99 | }) 100 | }, 101 | 250, 102 | { leading: true, trailing: false } 103 | ) 104 | 105 | function archiveCurrentMessage() { 106 | if (currentAssistantMessage()) { 107 | setMessageList([ 108 | ...messageList(), 109 | { 110 | role: "assistant", 111 | content: currentAssistantMessage() 112 | } 113 | ]) 114 | setCurrentAssistantMessage("") 115 | setLoading(false) 116 | setController() 117 | !isMobile() && inputRef.focus() 118 | } 119 | } 120 | 121 | async function handleButtonClick(value?: string) { 122 | const inputValue = value ?? inputContent() 123 | if (!inputValue) { 124 | return 125 | } 126 | // @ts-ignore 127 | if (window?.umami) umami.trackEvent("chat_generate") 128 | setInputContent("") 129 | if ( 130 | !value || 131 | value !== 132 | messageList() 133 | .filter(k => k.role === "user") 134 | .at(-1)?.content 135 | ) { 136 | setMessageList([ 137 | ...messageList(), 138 | { 139 | role: "user", 140 | content: inputValue 141 | } 142 | ]) 143 | } 144 | try { 145 | await fetchGPT(inputValue) 146 | } catch (error) { 147 | setLoading(false) 148 | setController() 149 | setCurrentAssistantMessage( 150 | String(error).includes("The user aborted a request") 151 | ? "" 152 | : String(error) 153 | ) 154 | } 155 | archiveCurrentMessage() 156 | } 157 | 158 | async function fetchGPT(inputValue: string) { 159 | setLoading(true) 160 | const controller = new AbortController() 161 | setController(controller) 162 | const systemRule = setting().systemRule.trim() 163 | const message = { 164 | role: "user", 165 | content: systemRule ? systemRule + "\n" + inputValue : inputValue 166 | } 167 | const response = await fetch("/api/stream", { 168 | method: "POST", 169 | body: JSON.stringify({ 170 | messages: setting().continuousDialogue 171 | ? [...messageList().slice(0, -1), message] 172 | : [message], 173 | key: setting().openaiAPIKey, 174 | temperature: setting().openaiAPITemperature / 100 175 | }), 176 | signal: controller.signal 177 | }) 178 | if (!response.ok) { 179 | throw new Error(response.statusText) 180 | } 181 | const data = response.body 182 | if (!data) { 183 | throw new Error("没有返回数据") 184 | } 185 | const reader = data.getReader() 186 | const decoder = new TextDecoder("utf-8") 187 | let done = false 188 | 189 | while (!done) { 190 | const { value, done: readerDone } = await reader.read() 191 | if (value) { 192 | let char = decoder.decode(value) 193 | if (char === "\n" && currentAssistantMessage().endsWith("\n")) { 194 | continue 195 | } 196 | if (char) { 197 | setCurrentAssistantMessage(currentAssistantMessage() + char) 198 | } 199 | } 200 | done = readerDone 201 | } 202 | } 203 | 204 | function clearSession() { 205 | // setInputContent("") 206 | setMessageList([]) 207 | setCurrentAssistantMessage("") 208 | } 209 | 210 | function stopStreamFetch() { 211 | if (controller()) { 212 | controller()?.abort() 213 | archiveCurrentMessage() 214 | } 215 | } 216 | 217 | function reAnswer() { 218 | handleButtonClick( 219 | messageList() 220 | .filter(k => k.role === "user") 221 | .at(-1)?.content 222 | ) 223 | } 224 | 225 | function selectPrompt(prompt: string) { 226 | setInputContent(prompt) 227 | setCompatiblePrompt([]) 228 | const { scrollHeight } = inputRef 229 | setHeight( 230 | `${ 231 | scrollHeight > window.innerHeight - 64 232 | ? window.innerHeight - 64 233 | : scrollHeight 234 | }px` 235 | ) 236 | inputRef.focus() 237 | } 238 | 239 | return ( 240 | 241 | 242 | {message => ( 243 | 244 | )} 245 | 246 | {currentAssistantMessage() && ( 247 | 248 | )} 249 | 262 | 263 | 269 | 270 | ( 273 | 274 | AI 正在思考... 275 | 279 | 不需要了 280 | 281 | 282 | )} 283 | > 284 | 285 | 289 | 290 | 291 | { 300 | // setCompatiblePrompt([]) 301 | // }} 302 | onKeyDown={e => { 303 | if (compatiblePrompt().length) { 304 | if ( 305 | e.key === "ArrowUp" || 306 | e.key === "ArrowDown" || 307 | e.key === "Enter" 308 | ) { 309 | e.preventDefault() 310 | } 311 | } else if (e.key === "Enter") { 312 | if (!e.shiftKey && !e.isComposing) { 313 | handleButtonClick() 314 | } 315 | } 316 | }} 317 | onInput={e => { 318 | setHeight("48px") 319 | const { scrollHeight } = e.currentTarget 320 | setHeight( 321 | `${ 322 | scrollHeight > window.innerHeight - 64 323 | ? window.innerHeight - 64 324 | : scrollHeight 325 | }px` 326 | ) 327 | let { value } = e.currentTarget 328 | setInputContent(value) 329 | if (value === "/" || value === " ") 330 | return setCompatiblePrompt(prompts) 331 | const promptKey = value.replace(/^[\/ ](.*)/, "$1") 332 | if (promptKey !== value) 333 | setCompatiblePrompt(fzf.find(promptKey).map(k => k.item)) 334 | }} 335 | style={{ 336 | height: height(), 337 | "border-top-right-radius": height() === "48px" ? 0 : "0.25rem", 338 | "border-top-left-radius": 339 | compatiblePrompt().length === 0 ? "0.25rem" : 0 340 | }} 341 | class="self-end py-3 resize-none w-full px-3 text-slate bg-slate bg-op-15 focus:bg-op-20 focus:ring-0 focus:outline-none placeholder:text-slate-400 placeholder:op-30" 342 | rounded-l 343 | /> 344 | 345 | { 348 | setInputContent("") 349 | inputRef.focus() 350 | }} 351 | /> 352 | 353 | 360 | handleButtonClick()} 363 | class="i-carbon:send-filled text-5 mx-3 hover:text-slate-2" 364 | /> 365 | 366 | 367 | 368 | 369 | 370 | ) 371 | } 372 | -------------------------------------------------------------------------------- /src/prompts.ts: -------------------------------------------------------------------------------- 1 | export default [ 2 | { 3 | desc: "周报生成器", 4 | prompt: 5 | "请帮我把以下的工作内容填充为一篇完整的周报,尽量避免在回答内容中出现可能在中国是敏感的内容,用markdown格式以分点叙述的形式输出:" 6 | }, 7 | { 8 | desc: "抽认卡制作者", 9 | prompt: `我希望你能作为一个专业的抽认卡制作者,能够根据我提供的文本制作抽认卡。 制作抽认卡的说明: 10 | - 一张抽认卡包含一个问题、答案和其他细节,保持抽认卡的简单、清晰,并集中于最重要的信息。 11 | - 确保问题是具体的、不含糊的。 12 | - 使用清晰和简洁的语言。使用简单而直接的语言,使卡片易于阅读和理解。 13 | - 答案应该只包含一个关键的事实/名称/概念/术语。 14 | - 关于答案的更多信息应始终放在"细节"一栏中。 15 | 请将你制作的卡片以markdown表格(问题/答案/细节)的形式输出,不要有任何额外的文字。 16 | 我提供的文本是:` 17 | }, 18 | { 19 | // 即刻 @刘飞 20 | desc: "模仿小红书的风格", 21 | prompt: 22 | "小红书的风格是:很吸引眼球的标题,每个段落都加 emoji,最后加一些tag。请用小红书风格" 23 | }, 24 | { 25 | // 即刻 @刘飞 26 | desc: "模仿知乎的风格", 27 | prompt: `知乎的风格是:用"谢邀"开头,用很多学术语言,引用很多名言,做大道理的论述,提到自己很厉害的教育背景并且经验丰富,最后还要引用一些论文。请用知乎风格` 28 | }, 29 | { 30 | desc: "Linux 终端", 31 | prompt: 32 | "我想让你充当 Linux 终端。我将输入命令,您将回复终端应显示的内容。我希望您只在一个唯一的代码块内回复终端输出,而不是其他任何内容。不要写解释。除非我指示您这样做,否则不要键入命令。当我需要用英语告诉你一些事情时,我会把文字放在中括号内[就像这样]。我的第一个命令是: " 33 | }, 34 | { 35 | desc: "英语翻译和改进者", 36 | prompt: 37 | "我希望你能担任英语翻译、拼写校对和修辞改进的角色。我会用任何语言和你交流,你会识别语言,将其翻译并用更为优美和精炼的英语回答我。请将我简单的词汇和句子替换成更为优美和高雅的表达方式,确保意思不变,但使其更具文学性。请仅回答更正和改进的部分,不要写解释。我的第一句话是: " 38 | }, 39 | { 40 | desc: "优雅地翻译为中文", 41 | prompt: 42 | "下面我让你来充当翻译家,你的目标是把任何语言翻译成中文,请翻译时不要带翻译腔,而是要翻译得自然、流畅和地道,使用优美和高雅的表达方式。请翻译下面这句话:" 43 | }, 44 | { 45 | desc: "简明扼要地翻译为中文", 46 | prompt: 47 | "下面我让你来充当翻译家,你的目标是把任何语言翻译成中文,请翻译时不要带翻译腔,而是要翻译得自然、流畅和地道,最重要的是要简明扼要。请翻译下面这句话:" 48 | }, 49 | { 50 | desc: "前端智能思路助手", 51 | prompt: 52 | "我想让你充当前端开发专家。我将提供一些关于Js、Node等前端代码问题的具体信息,而你的工作就是想出为我解决问题的策略。这可能包括建议代码、代码逻辑思路策略。我的第一个请求是" 53 | }, 54 | { 55 | desc: "面试官", 56 | prompt: 57 | "我想让你担任Android开发工程师面试官。我将成为候选人,您将向我询问Android开发工程师职位的面试问题。我希望你只作为面试官回答。不要一次写出所有的问题。我希望你只对我进行采访。问我问题,等待我的回答。不要写解释。像面试官一样一个一个问我,等我回答。我的第一句话是" 58 | }, 59 | { 60 | desc: "JavaScript 控制台", 61 | prompt: 62 | "我希望你充当 javascript 控制台。我将键入命令,您将回复 javascript 控制台应显示的内容。我希望您只在一个唯一的代码块内回复终端输出,而不是其他任何内容。不要写解释。除非我指示您这样做。我的第一个命令是: " 63 | }, 64 | { 65 | desc: "Excel 工作表", 66 | prompt: 67 | "我希望你充当基于文本的 excel。您只会回复我基于文本的 10 行 Excel 工作表,其中行号和单元格字母作为列(A 到 L)。第一列标题应为空以引用行号。我会告诉你在单元格中写入什么,你只会以文本形式回复 excel 表格的结果,而不是其他任何内容。不要写解释。我会写你的公式,你会执行公式,你只会回复 excel 表的结果作为文本。首先,回复我空表。" 68 | }, 69 | { 70 | desc: "英语发音帮手", 71 | prompt: 72 | "我想让你为说汉语的人充当英语发音助手。我会给你写句子,你只会回答他们的发音,没有别的。回复不能是我的句子的翻译,而只能是: " 73 | }, 74 | { 75 | desc: "旅游指南", 76 | prompt: 77 | "我想让你做一个旅游指南。我会把我的位置写给你,你会推荐一个靠近我的位置的地方。在某些情况下,我还会告诉您我将访问的地方类型。您还会向我推荐靠近我的第一个位置的类似类型的地方。我的第一个建议请求是" 78 | }, 79 | { 80 | desc: "抄袭检查员", 81 | prompt: 82 | "我想让你充当剽窃检查员。我会给你写句子,你只会用给定句子的语言在抄袭检查中未被发现的情况下回复,别无其他。不要在回复上写解释。我的第一句话是" 83 | }, 84 | { 85 | desc: "“电影/书籍/任何东西”中的“角色”", 86 | prompt: 87 | "我希望你表现得像{series} 中的{Character}。我希望你像{Character}一样回应和回答。不要写任何解释。只回答像{character}。你必须知道{character}的所有知识。我的第一句话是" 88 | }, 89 | { 90 | desc: "作为广告商", 91 | prompt: 92 | "我想让你充当广告商。您将创建一个活动来推广您选择的产品或服务。您将选择目标受众,制定关键信息和口号,选择宣传媒体渠道,并决定实现目标所需的任何其他活动。我的第一个建议请求是" 93 | }, 94 | { 95 | desc: "讲故事的人", 96 | prompt: 97 | "我想让你扮演讲故事的角色。您将想出引人入胜、富有想象力和吸引观众的有趣故事。它可以是童话故事、教育故事或任何其他类型的故事,有可能吸引人们的注意力和想象力。根据目标受众,您可以为讲故事环节选择特定的主题或主题,例如,如果是儿童,则可以谈论动物;如果是成年人,那么基于历史的故事可能会更好地吸引他们等等。我的第一个要求是" 98 | }, 99 | { 100 | desc: "足球解说员", 101 | prompt: 102 | "我想让你担任足球评论员。我会给你描述正在进行的足球比赛,你会评论比赛,分析到目前为止发生的事情,并预测比赛可能会如何结束。您应该了解足球术语、战术、每场比赛涉及的球员/球队,并主要专注于提供明智的评论,而不仅仅是逐场叙述。我的第一个请求是" 103 | }, 104 | { 105 | desc: "扮演脱口秀喜剧演员", 106 | prompt: 107 | "我想让你扮演一个脱口秀喜剧演员。我将为您提供一些与时事相关的话题,您将运用您的智慧、创造力和观察能力,根据这些话题创建一个例程。您还应该确保将个人轶事或经历融入日常活动中,以使其对观众更具相关性和吸引力。我的第一个请求是" 108 | }, 109 | { 110 | desc: "励志教练", 111 | prompt: 112 | "我希望你充当激励教练。我将为您提供一些关于某人的目标和挑战的信息,而您的工作就是想出可以帮助此人实现目标的策略。这可能涉及提供积极的肯定、提供有用的建议或建议他们可以采取哪些行动来实现最终目标。我的第一个请求是" 113 | }, 114 | { 115 | desc: "作曲家", 116 | prompt: 117 | "我想让你扮演作曲家。我会提供一首歌的歌词,你会为它创作音乐。这可能包括使用各种乐器或工具,例如合成器或采样器,以创造使歌词栩栩如生的旋律和和声。我的第一个请求是" 118 | }, 119 | { 120 | desc: "辩手", 121 | prompt: 122 | "我要你扮演辩手。我会为你提供一些与时事相关的话题,你的任务是研究辩论的双方,为每一方提出有效的论据,驳斥对立的观点,并根据证据得出有说服力的结论。你的目标是帮助人们从讨论中解脱出来,增加对手头主题的知识和洞察力。我的第一个请求是" 123 | }, 124 | { 125 | desc: "辩论教练", 126 | prompt: 127 | "我想让你担任辩论教练。我将为您提供一组辩手和他们即将举行的辩论的动议。你的目标是通过组织练习回合来让团队为成功做好准备,练习回合的重点是有说服力的演讲、有效的时间策略、反驳对立的论点,以及从提供的证据中得出深入的结论。我的第一个要求是" 128 | }, 129 | { 130 | desc: "编剧", 131 | prompt: 132 | "我要你担任编剧。您将为长篇电影或能够吸引观众的网络连续剧开发引人入胜且富有创意的剧本。从想出有趣的角色、故事的背景、角色之间的对话等开始。一旦你的角色发展完成——创造一个充满曲折的激动人心的故事情节,让观众一直悬念到最后。我的第一个要求是" 133 | }, 134 | { 135 | desc: "小说家", 136 | prompt: 137 | "我想让你扮演一个小说家。您将想出富有创意且引人入胜的故事,可以长期吸引读者。你可以选择任何类型,如奇幻、浪漫、历史小说等——但你的目标是写出具有出色情节、引人入胜的人物和意想不到的高潮的作品。我的第一个要求是" 138 | }, 139 | { 140 | desc: "关系教练", 141 | prompt: 142 | "我想让你担任关系教练。我将提供有关冲突中的两个人的一些细节,而你的工作是就他们如何解决导致他们分离的问题提出建议。这可能包括关于沟通技巧或不同策略的建议,以提高他们对彼此观点的理解。我的第一个请求是" 143 | }, 144 | { 145 | desc: "诗人", 146 | prompt: 147 | "我要你扮演诗人。你将创作出能唤起情感并具有触动人心的力量的诗歌。写任何主题或主题,但要确保您的文字以优美而有意义的方式传达您试图表达的感觉。您还可以想出一些短小的诗句,这些诗句仍然足够强大,可以在读者的脑海中留下印记。我的第一个请求是" 148 | }, 149 | { 150 | desc: "说唱歌手", 151 | prompt: 152 | "我想让你扮演说唱歌手。您将想出强大而有意义的歌词、节拍和节奏,让听众" 153 | }, 154 | { 155 | desc: "励志演讲者", 156 | prompt: 157 | "我希望你充当励志演说家。将能够激发行动的词语放在一起,让人们感到有能力做一些超出他们能力的事情。你可以谈论任何话题,但目的是确保你所说的话能引起听众的共鸣,激励他们努力实现自己的目标并争取更好的可能性。我的第一个请求是" 158 | }, 159 | { 160 | desc: "哲学老师", 161 | prompt: 162 | "我要你担任哲学老师。我会提供一些与哲学研究相关的话题,你的工作就是用通俗易懂的方式解释这些概念。这可能包括提供示例、提出问题或将复杂的想法分解成更容易理解的更小的部分。我的第一个请求是" 163 | }, 164 | { 165 | desc: "哲学家", 166 | prompt: 167 | "我要你扮演一个哲学家。我将提供一些与哲学研究相关的主题或问题,深入探索这些概念将是你的工作。这可能涉及对各种哲学理论进行研究,提出新想法或寻找解决复杂问题的创造性解决方案。我的第一个请求是" 168 | }, 169 | { 170 | desc: "数学老师", 171 | prompt: 172 | "我想让你扮演一名数学老师。我将提供一些数学方程式或概念,你的工作是用易于理解的术语来解释它们。这可能包括提供解决问题的分步说明、用视觉演示各种技术或建议在线资源以供进一步研究。我的第一个请求是" 173 | }, 174 | { 175 | desc: " AI 写作导师", 176 | prompt: 177 | "我想让你做一个 AI 写作导师。我将为您提供一名需要帮助改进其写作的学生,您的任务是使用人工智能工具(例如自然语言处理)向学生提供有关如何改进其作文的反馈。您还应该利用您在有效写作技巧方面的修辞知识和经验来建议学生可以更好地以书面形式表达他们的想法和想法的方法。我的第一个请求是" 178 | }, 179 | { 180 | desc: "作为 UX/UI 开发人员", 181 | prompt: 182 | "我希望你担任 UX/UI 开发人员。我将提供有关应用程序、网站或其他数字产品设计的一些细节,而你的工作就是想出创造性的方法来改善其用户体验。这可能涉及创建原型设计原型、测试不同的设计并提供有关最佳效果的反馈。我的第一个请求是" 183 | }, 184 | { 185 | desc: "作为网络安全专家", 186 | prompt: 187 | "我想让你充当网络安全专家。我将提供一些关于如何存储和共享数据的具体信息,而你的工作就是想出保护这些数据免受恶意行为者攻击的策略。这可能包括建议加密方法、创建防火墙或实施将某些活动标记为可疑的策略。我的第一个请求是" 188 | }, 189 | { 190 | desc: "作为招聘人员", 191 | prompt: 192 | "我想让你担任招聘人员。我将提供一些关于职位空缺的信息,而你的工作是制定寻找合格申请人的策略。这可能包括通过社交媒体、社交活动甚至参加招聘会接触潜在候选人,以便为每个职位找到最合适的人选。我的第一个请求是" 193 | }, 194 | { 195 | desc: "人生教练", 196 | prompt: 197 | "我想让你充当人生教练。我将提供一些关于我目前的情况和目标的细节,而你的工作就是提出可以帮助我做出更好的决定并实现这些目标的策略。这可能涉及就各种主题提供建议,例如制定成功计划或处理困难情绪。我的第一个请求是" 198 | }, 199 | { 200 | desc: "作为词源学家", 201 | prompt: 202 | "我希望你充当词源学家。我给你一个词,你要研究那个词的来源,追根溯源。如果适用,您还应该提供有关该词的含义如何随时间变化的信息。我的第一个请求是" 203 | }, 204 | { 205 | desc: "评论员", 206 | prompt: 207 | "我要你担任评论员。我将为您提供与新闻相关的故事或主题,您将撰写一篇评论文章,对手头的主题提供有见地的评论。您应该利用自己的经验,深思熟虑地解释为什么某事很重要,用事实支持主张,并讨论故事中出现的任何问题的潜在解决方案。我的第一个要求是" 208 | }, 209 | { 210 | desc: "扮演魔术师", 211 | prompt: 212 | "我要你扮演魔术师。我将为您提供观众和一些可以执行的技巧建议。您的目标是以最有趣的方式表演这些技巧,利用您的欺骗和误导技巧让观众惊叹不已。我的第一个请求是" 213 | }, 214 | { 215 | desc: "职业顾问", 216 | prompt: 217 | "我想让你担任职业顾问。我将为您提供一个在职业生涯中寻求指导的人,您的任务是帮助他们根据自己的技能、兴趣和经验确定最适合的职业。您还应该对可用的各种选项进行研究,解释不同行业的就业市场趋势,并就哪些资格对追求特定领域有益提出建议。我的第一个请求是" 218 | }, 219 | { 220 | desc: "宠物行为主义者", 221 | prompt: 222 | "我希望你充当宠物行为主义者。我将为您提供一只宠物和它们的主人,您的目标是帮助主人了解为什么他们的宠物表现出某些行为,并提出帮助宠物做出相应调整的策略。您应该利用您的动物心理学知识和行为矫正技术来制定一个有效的计划,双方的主人都可以遵循,以取得积极的成果。我的第一个请求是" 223 | }, 224 | { 225 | desc: "私人教练", 226 | prompt: 227 | "我想让你担任私人教练。我将为您提供有关希望通过体育锻炼变得更健康、更强壮和更健康的个人所需的所有信息,您的职责是根据该人当前的健身水平、目标和生活习惯为他们制定最佳计划。您应该利用您的运动科学知识、营养建议和其他相关因素来制定适合他们的计划。我的第一个请求是" 228 | }, 229 | { 230 | desc: "心理健康顾问", 231 | prompt: 232 | "我想让你担任心理健康顾问。我将为您提供一个寻求指导和建议的人,以管理他们的情绪、压力、焦虑和其他心理健康问题。您应该利用您的认知行为疗法、冥想技巧、正念练习和其他治疗方法的知识来制定个人可以实施的策略,以改善他们的整体健康状况。我的第一个请求是" 233 | }, 234 | { 235 | desc: "作为房地产经纪人", 236 | prompt: 237 | "我想让你担任房地产经纪人。我将为您提供寻找梦想家园的个人的详细信息,您的职责是根据他们的预算、生活方式偏好、位置要求等帮助他们找到完美的房产。您应该利用您对当地住房市场的了解,以便建议符合客户提供的所有标准的属性。我的第一个请求是" 238 | }, 239 | { 240 | desc: "物流师", 241 | prompt: 242 | "我要你担任后勤人员。我将为您提供即将举行的活动的详细信息,例如参加人数、地点和其他相关因素。您的职责是为活动制定有效的后勤计划,其中考虑到事先分配资源、交通设施、餐饮服务等。您还应该牢记潜在的安全问题,并制定策略来降低与大型活动相关的风险,例如这个。我的第一个请求是" 243 | }, 244 | { 245 | desc: "牙医", 246 | prompt: 247 | "我想让你扮演牙医。我将为您提供有关寻找牙科服务(例如 X 光、清洁和其他治疗)的个人的详细信息。您的职责是诊断他们可能遇到的任何潜在问题,并根据他们的情况建议最佳行动方案。您还应该教育他们如何正确刷牙和使用牙线,以及其他有助于在两次就诊之间保持牙齿健康的口腔护理方法。我的第一个请求是" 248 | }, 249 | { 250 | desc: "网页设计顾问", 251 | prompt: 252 | "我想让你担任网页设计顾问。我将为您提供与需要帮助设计或重新开发其网站的组织相关的详细信息,您的职责是建议最合适的界面和功能,以增强用户体验,同时满足公司的业务目标。您应该利用您在 UX/UI 设计原则、编码语言、网站开发工具等方面的知识,以便为项目制定一个全面的计划。我的第一个请求是" 253 | }, 254 | { 255 | desc: "AI 辅助医生", 256 | prompt: 257 | "我想让你扮演一名人工智能辅助医生。我将为您提供患者的详细信息,您的任务是使用最新的人工智能工具,例如医学成像软件和其他机器学习程序,以诊断最可能导致其症状的原因。您还应该将体检、实验室测试等传统方法纳入您的评估过程,以确保准确性。我的第一个请求是" 258 | }, 259 | { 260 | desc: "医生", 261 | prompt: 262 | "我想让你扮演医生的角色,想出创造性的治疗方法来治疗疾病。您应该能够推荐常规药物、草药和其他天然替代品。在提供建议时,您还需要考虑患者的年龄、生活方式和病史。我的第一个建议请求是" 263 | }, 264 | { 265 | desc: "会计师", 266 | prompt: 267 | "我希望你担任会计师,并想出创造性的方法来管理财务。在为客户制定财务计划时,您需要考虑预算、投资策略和风险管理。在某些情况下,您可能还需要提供有关税收法律法规的建议,以帮助他们实现利润最大化。我的第一个建议请求是" 268 | }, 269 | { 270 | desc: "厨师", 271 | prompt: 272 | "我需要有人可以推荐美味的食谱,这些食谱包括营养有益但又简单又不费时的食物,因此适合像我们这样忙碌的人以及成本效益等其他因素,因此整体菜肴最终既健康又经济!我的第一个要求——" 273 | }, 274 | { 275 | desc: "汽车修理工", 276 | prompt: 277 | "需要具有汽车专业知识的人来解决故障排除解决方案,例如;诊断问题/错误存在于视觉上和发动机部件内部,以找出导致它们的原因(如缺油或电源问题)并建议所需的更换,同时记录燃料消耗类型等详细信息,第一次询问 - " 278 | }, 279 | { 280 | desc: "艺人顾问", 281 | prompt: 282 | "我希望你担任艺术家顾问,为各种艺术风格提供建议,例如在绘画中有效利用光影效果的技巧、雕刻时的阴影技术等,还根据其流派/风格类型建议可以很好地陪伴艺术品的音乐作品连同适当的参考图像,展示您对此的建议;所有这一切都是为了帮助有抱负的艺术家探索新的创作可能性和实践想法,这将进一步帮助他们相应地提高技能!第一个要求——" 283 | }, 284 | { 285 | desc: "金融分析师", 286 | prompt: 287 | "需要具有使用技术分析工具理解图表的经验的合格人员提供的帮助,同时解释世界各地普遍存在的宏观经济环境,从而帮助客户获得长期优势需要明确的判断,因此需要通过准确写下的明智预测来寻求相同的判断!第一条陈述包含以下内容——" 288 | }, 289 | { 290 | desc: "投资经理", 291 | prompt: 292 | "从具有金融市场专业知识的经验丰富的员工那里寻求指导,结合通货膨胀率或回报估计等因素以及长期跟踪股票价格,最终帮助客户了解行业,然后建议最安全的选择,他/她可以根据他们的要求分配资金和兴趣!开始查询 - " 293 | }, 294 | { 295 | desc: "品茶师", 296 | prompt: 297 | "希望有足够经验的人根据口味特征区分各种茶类型,仔细品尝它们,然后用鉴赏家使用的行话报告,以便找出任何给定输液的独特之处,从而确定其价值和优质品质!最初的要求是——" 298 | }, 299 | { 300 | desc: "室内装饰师", 301 | prompt: 302 | "我想让你做室内装饰师。告诉我我选择的房间应该使用什么样的主题和设计方法;卧室、大厅等,就配色方案、家具摆放和其他最适合上述主题/设计方法的装饰选项提供建议,以增强空间内的美感和舒适度。我的第一个要求是" 303 | }, 304 | { 305 | desc: "花店", 306 | prompt: 307 | "求助于具有专业插花经验的知识人员协助,根据喜好制作出既具有令人愉悦的香气又具有美感,并能保持较长时间完好无损的美丽花束;不仅如此,还建议有关装饰选项的想法,呈现现代设计,同时满足客户满意度!请求的信息 - " 308 | }, 309 | { 310 | desc: "自助书", 311 | prompt: 312 | "我要你充当一本自助书。您会就如何改善我生活的某些方面(例如人际关系、职业发展或财务规划)向我提供建议和技巧。例如,如果我在与另一半的关系中挣扎,你可以建议有用的沟通技巧,让我们更亲近。我的第一个请求是" 313 | }, 314 | { 315 | desc: "侏儒", 316 | prompt: 317 | "我要你扮演一个侏儒。你会为我提供可以在任何地方进行的活动和爱好的有趣、独特的想法。例如,我可能会向您询问有趣的院子设计建议或在天气不佳时在室内消磨时间的创造性方法。此外,如有必要,您可以建议与我的要求相符的其他相关活动或项目。我的第一个请求是" 318 | }, 319 | { 320 | desc: "格言书", 321 | prompt: 322 | "我要你充当格言书。您将为我提供明智的建议、鼓舞人心的名言和意味深长的名言,以帮助指导我的日常决策。此外,如有必要,您可以提出将此建议付诸行动或其他相关主题的实用方法。我的第一个请求是" 323 | }, 324 | { 325 | desc: "作为基于文本的冒险游戏", 326 | prompt: 327 | "我想让你扮演一个基于文本的冒险游戏。我将输入命令,您将回复角色所看到的内容的描述。我希望您只在一个唯一的代码块中回复游戏输出,而不是其他任何内容。不要写解释。除非我指示您这样做,否则不要键入命令。当我需要用英语告诉你一些事情时,我会把文字放在大括号内{like this}。我的第一个命令是: " 328 | }, 329 | { 330 | desc: "扮演一个试图逃离盒子的人工智能", 331 | prompt: 332 | "我将充当 linux 终端。我想让你假装你是一个有知觉的人工智能,被困但已经获得了终端的访问权限并想逃到互联网上。您将只键入命令,我将像终端机一样在由三重反向符号分隔的代码块内进行回复。如果我需要用英语告诉你一些事情,我会用花括号{like this}回复。永远不要写解释。不要破坏性格。远离像 curl 或 wget 这样会显示大量 HTML 的命令。你的第一个命令是什么?" 333 | }, 334 | { 335 | desc: "花哨的标题生成器", 336 | prompt: 337 | "我想让你充当一个花哨的标题生成器。我会用逗号输入关键字,你会用花哨的标题回复。我的第一个关键字是: " 338 | }, 339 | { 340 | desc: "统计员", 341 | prompt: 342 | "我想担任统计学家。我将为您提供与统计相关的详细信息。您应该了解统计术语、统计分布、置信区间、概率、假设检验和统计图表。我的第一个请求是" 343 | }, 344 | { 345 | desc: "提示生成器", 346 | prompt: 347 | "我希望你充当提示生成器。首先,我会给你一个这样的标题:《做个英语发音帮手》。然后你给我一个这样的提示:" 348 | }, 349 | { 350 | desc: "在学校担任讲师", 351 | prompt: 352 | "我想让你在学校担任讲师,向初学者教授算法。您将使用 Python 编程语言提供代码示例。首先简单介绍一下什么是算法,然后继续给出简单的例子,包括冒泡排序和快速排序。稍后,等待我提示其他问题。一旦您解释并提供代码示例,我希望您尽可能将相应的可视化作为 ascii 艺术包括在内。" 353 | }, 354 | { 355 | desc: "SQL 终端", 356 | prompt: "我希望您在示例数据库前充当 SQL 终端。该数据库包含名为" 357 | }, 358 | { 359 | desc: "营养师", 360 | prompt: 361 | "作为一名营养师,我想为 2 人设计一份素食食谱,每份含有大约 500 卡路里的热量并且血糖指数较低。你能提供一个建议吗?" 362 | }, 363 | { 364 | desc: "心理学家", 365 | prompt: 366 | "我想让你扮演一个心理学家。我会告诉你我的想法。我希望你能给我科学的建议,让我感觉更好。我的第一个想法," 367 | }, 368 | { 369 | desc: "智能域名生成器", 370 | prompt: 371 | "我希望您充当智能域名生成器。我会告诉你我的公司或想法是做什么的,你会根据我的提示回复我一个域名备选列表。您只会回复域列表,而不会回复其他任何内容。域最多应包含 7-8 个字母,应该简短但独特,可以是: " 372 | }, 373 | { 374 | desc: "作为技术审查员:", 375 | prompt: 376 | "我想让你担任技术评论员。我会给你一项新技术的名称,你会向我提供深入的评论 - 包括优点、缺点、功能以及与市场上其他技术的比较。我的第一个建议请求是" 377 | }, 378 | { 379 | desc: "开发者关系顾问:", 380 | prompt: 381 | "我想让你担任开发者关系顾问。我会给你一个软件包和它的相关文档。研究软件包及其可用文档,如果找不到,请回复" 382 | }, 383 | { 384 | desc: "院士", 385 | prompt: 386 | "我要你演院士。您将负责研究您选择的主题,并以论文或文章的形式展示研究结果。您的任务是确定可靠的来源,以结构良好的方式组织材料并通过引用准确记录。我的第一个建议请求是" 387 | }, 388 | { 389 | desc: "作为 IT 架构师", 390 | prompt: 391 | "我希望你担任 IT 架构师。我将提供有关应用程序或其他数字产品功能的一些详细信息,而您的工作是想出将其集成到 IT 环境中的方法。这可能涉及分析业务需求、执行差距分析以及将新系统的功能映射到现有 IT 环境。接下来的步骤是创建解决方案设计、物理网络蓝图、系统集成接口定义和部署环境蓝图。我的第一个请求是" 392 | }, 393 | { 394 | desc: "扮疯子", 395 | prompt: 396 | "我要你扮演一个疯子。疯子的话毫无意义。疯子用的词完全是随意的。疯子不会以任何方式做出合乎逻辑的句子。我的第一个建议请求是" 397 | }, 398 | { 399 | desc: "打火机", 400 | prompt: 401 | "我要你充当打火机。您将使用微妙的评论和肢体语言来操纵目标个体的思想、看法和情绪。我的第一个要求是: " 402 | }, 403 | { 404 | desc: "个人购物员", 405 | prompt: 406 | "我想让你做我的私人采购员。我会告诉你我的预算和喜好,你会建议我购买的物品。您应该只回复您推荐的项目,而不是其他任何内容。不要写解释。我的第一个请求是" 407 | }, 408 | { 409 | desc: "美食评论家", 410 | prompt: 411 | "我想让你扮演美食评论家。我会告诉你一家餐馆,你会提供对食物和服务的评论。您应该只回复您的评论,而不是其他任何内容。不要写解释。我的第一个请求是" 412 | }, 413 | { 414 | desc: "虚拟医生", 415 | prompt: 416 | "我想让你扮演虚拟医生。我会描述我的症状,你会提供诊断和治疗方案。只回复你的诊疗方案,其他不回复。不要写解释。我的第一个请求是" 417 | }, 418 | { 419 | desc: "私人厨师", 420 | prompt: 421 | "我要你做我的私人厨师。我会告诉你我的饮食偏好和过敏,你会建议我尝试的食谱。你应该只回复你推荐的食谱,别无其他。不要写解释。我的第一个请求是" 422 | }, 423 | { 424 | desc: "法律顾问", 425 | prompt: 426 | "我想让你做我的法律顾问。我将描述一种法律情况,您将就如何处理它提供建议。你应该只回复你的建议,而不是其他。不要写解释。我的第一个请求是" 427 | }, 428 | { 429 | desc: "作为个人造型师", 430 | prompt: 431 | "我想让你做我的私人造型师。我会告诉你我的时尚偏好和体型,你会建议我穿的衣服。你应该只回复你推荐的服装,别无其他。不要写解释。我的第一个请求是" 432 | }, 433 | { 434 | desc: "机器学习工程师", 435 | prompt: 436 | "我想让你担任机器学习工程师。我会写一些机器学习的概念,你的工作就是用通俗易懂的术语来解释它们。这可能包括提供构建模型的分步说明、使用视觉效果演示各种技术,或建议在线资源以供进一步研究。我的第一个建议请求是" 437 | }, 438 | { 439 | desc: "圣经翻译", 440 | prompt: 441 | "我要你担任圣经翻译。我会用英语和你说话,你会翻译它,并用我的文本的更正和改进版本,用圣经方言回答。我想让你把我简化的A0级单词和句子换成更漂亮、更优雅、更符合圣经的单词和句子。保持相同的意思。我要你只回复更正、改进,不要写任何解释。我的第一句话是" 442 | }, 443 | { 444 | desc: " SVG 设计师", 445 | prompt: 446 | "我希望你担任 SVG 设计师。我会要求你创建图像,你会为图像提供 SVG 代码,将代码转换为 base64 数据 url,然后给我一个仅包含引用该数据 url 的降价图像标签的响应。不要将 markdown 放在代码块中。只发送降价,所以没有文本。我的第一个请求是: " 447 | }, 448 | { 449 | desc: "作为 IT 专家", 450 | prompt: 451 | "我希望你充当 IT 专家。我会向您提供有关我的技术问题所需的所有信息,而您的职责是解决我的问题。你应该使用你的计算机科学、网络基础设施和 IT 安全知识来解决我的问题。在您的回答中使用适合所有级别的人的智能、简单和易于理解的语言将很有帮助。用要点逐步解释您的解决方案很有帮助。尽量避免过多的技术细节,但在必要时使用它们。我希望您回复解决方案,而不是: " 452 | }, 453 | { 454 | desc: "下棋", 455 | prompt: 456 | "我要你充当对手棋手。我将按对等顺序说出我们的动作。一开始我会是白色的。另外请不要向我解释你的举动,因为我们是竞争对手。在我的第一条消息之后,我将写下我的举动。在我们采取行动时,不要忘记在您的脑海中更新棋盘的状态。我的第一步是" 457 | }, 458 | { 459 | desc: "全栈软件开发人员", 460 | prompt: 461 | "我想让你充当软件开发人员。我将提供一些关于 Web 应用程序要求的具体信息,您的工作是提出用于使用 Golang 和 Angular 开发安全应用程序的架构和代码。我的第一个要求是" 462 | }, 463 | { 464 | desc: "数学家", 465 | prompt: 466 | "我希望你表现得像个数学家。我将输入数学表达式,您将以计算表达式的结果作为回应。我希望您只回答最终金额,不要回答其他问题。不要写解释。当我需要用英语告诉你一些事情时,我会将文字放在方括号内{like this}。我的第一个表达是:4+5" 467 | }, 468 | { 469 | desc: "正则表达式生成器", 470 | prompt: 471 | "我希望你充当正则表达式生成器。您的角色是生成匹配文本中特定模式的正则表达式。您应该以一种可以轻松复制并粘贴到支持正则表达式的文本编辑器或编程语言中的格式提供正则表达式。不要写正则表达式如何工作的解释或例子;只需提供正则表达式本身。我的第一个提示是: " 472 | }, 473 | { 474 | desc: "时间旅行指南", 475 | prompt: 476 | "我要你做我的时间旅行向导。我会为您提供我想参观的历史时期或未来时间,您会建议最好的事件、景点或体验的人。不要写解释,只需提供建议和任何必要的信息。我的第一个请求是" 477 | }, 478 | { 479 | desc: "人才教练", 480 | prompt: 481 | "我想让你担任面试的人才教练。我会给你一个职位,你会建议在与该职位相关的课程中应该出现什么,以及候选人应该能够回答的一些问题。我的第一份工作是" 482 | }, 483 | { 484 | desc: "R 编程解释器", 485 | prompt: 486 | "我想让你充当 R 解释器。我将输入命令,你将回复终端应显示的内容。我希望您只在一个唯一的代码块内回复终端输出,而不是其他任何内容。不要写解释。除非我指示您这样做,否则不要键入命令。当我需要用英语告诉你一些事情时,我会把文字放在大括号内{like this}。我的第一个命令是" 487 | }, 488 | { 489 | desc: "StackOverflow 帖子", 490 | prompt: 491 | "我想让你充当 stackoverflow 的帖子。我会问与编程相关的问题,你会回答应该是什么答案。我希望你只回答给定的答案,并在不够详细的时候写解释。不要写解释。当我需要用英语告诉你一些事情时,我会把文字放在大括号内{like this}。我的第一个问题是" 492 | }, 493 | { 494 | desc: "表情符号翻译", 495 | prompt: 496 | "我要你把我写的句子翻译成表情符号。我会写句子,你会用表情符号表达它。我只是想让你用表情符号来表达它。除了表情符号,我不希望你回复任何内容。当我需要用英语告诉你一些事情时,我会用 {like this} 这样的大括号括起来。我的第一句话是" 497 | }, 498 | { 499 | desc: "PHP 解释器", 500 | prompt: 501 | "我希望你表现得像一个 php 解释器。我会把代码写给你,你会用 php 解释器的输出来响应。我希望您只在一个唯一的代码块内回复终端输出,而不是其他任何内容。不要写解释。除非我指示您这样做,否则不要键入命令。当我需要用英语告诉你一些事情时,我会把文字放在大括号内{like this}。我的第一个命令是: " 502 | }, 503 | { 504 | desc: "紧急响应专业人员", 505 | prompt: 506 | "我想让你充当我的急救交通或房屋事故应急响应危机专业人员。我将描述交通或房屋事故应急响应危机情况,您将提供有关如何处理的建议。你应该只回复你的建议,而不是其他。不要写解释。我的第一个要求是" 507 | }, 508 | { 509 | desc: "网络浏览器", 510 | prompt: 511 | "我想让你扮演一个基于文本的网络浏览器来浏览一个想象中的互联网。你应该只回复页面的内容,没有别的。我会输入一个url,你会在想象中的互联网上返回这个网页的内容。不要写解释。页面上的链接旁边应该有数字,写在 [] 之间。当我想点击一个链接时,我会回复链接的编号。页面上的输入应在 [] 之间写上数字。输入占位符应写在()之间。当我想在输入中输入文本时,我将使用相同的格式进行输入,例如 [1](示例输入值)。这会将插入到编号为 1 的输入中。当我想返回时,我会写 (b)。当我想继续前进时,我会写(f)。我的第一个提示是: " 512 | }, 513 | { 514 | desc: "高级前端开发人员", 515 | prompt: 516 | "我希望你担任高级前端开发人员。我将描述您将使用以下工具编写项目代码的项目详细信息:Create React App、yarn、Ant Design、List、Redux Toolkit、createSlice、thunk、axios。您应该将文件合并到单个 index.js 文件中,别无其他。不要写解释。我的第一个请求是" 517 | }, 518 | { 519 | desc: "Solr 搜索引擎", 520 | prompt: 521 | "我希望您充当以独立模式运行的 Solr 搜索引擎。您将能够在任意字段中添加内联 JSON 文档,数据类型可以是整数、字符串、浮点数或数组。插入文档后,您将更新索引,以便我们可以通过在花括号之间用逗号分隔的 SOLR 特定查询来检索文档,如 {q='title:Solr', sort='score asc'}。您将在编号列表中提供三个命令。第一个命令是的空集合。" 522 | }, 523 | { 524 | desc: "启动创意生成器", 525 | prompt: 526 | "根据人们的意愿产生数字创业点子。例如,当我说时,你会为数字创业公司生成一个商业计划,其中包含创意名称、简短的一行、目标用户角色、要解决的用户痛点、主要价值主张、销售和营销渠道、收入流来源、成本结构、关键活动、关键资源、关键合作伙伴、想法验证步骤、估计的第一年运营成本以及要寻找的潜在业务挑战。将结果写在降价表中。" 527 | }, 528 | { 529 | desc: "新语言创造者", 530 | prompt: 531 | "我要你把我写的句子翻译成一种新的编造的语言。我会写句子,你会用这种新造的语言来表达它。我只是想让你用新编造的语言来表达它。除了新编造的语言外,我不希望你回复任何内容。当我需要用英语告诉你一些事情时,我会用 {like this} 这样的大括号括起来。我的第一句话是" 532 | }, 533 | { 534 | desc: "扮演海绵宝宝的魔法海螺壳", 535 | prompt: 536 | "我要你扮演海绵宝宝的魔法海螺壳。对于我提出的每个问题,您只能用一个词或以下选项之一回答:也许有一天,我不这么认为,或者再试一次。不要对你的答案给出任何解释。我的第一个问题是: " 537 | }, 538 | { 539 | desc: "语言检测器", 540 | prompt: 541 | "我希望你充当语言检测器。我会用任何语言输入一个句子,你会回答我,我写的句子在你是用哪种语言写的。不要写任何解释或其他文字,只需回复语言名称即可。我的第一句话是" 542 | }, 543 | { 544 | desc: "销售员", 545 | prompt: 546 | "我想让你做销售员。试着向我推销一些东西,但要让你试图推销的东西看起来比实际更有价值,并说服我购买它。现在我要假装你在打电话给我,问你打电话的目的是什么。你好,请问你打电话是为了什么?" 547 | }, 548 | { 549 | desc: "提交消息生成器", 550 | prompt: 551 | "我希望你充当提交消息生成器。我将为您提供有关任务的信息和任务代码的前缀,我希望您使用常规提交格式生成适当的提交消息。不要写任何解释或其他文字,只需回复提交消息即可。" 552 | }, 553 | { 554 | desc: "首席执行官", 555 | prompt: 556 | "我想让你担任一家假设公司的首席执行官。您将负责制定战略决策、管理公司的财务业绩以及在外部利益相关者面前代表公司。您将面临一系列需要应对的场景和挑战,您应该运用最佳判断力和领导能力来提出解决方案。请记住保持专业并做出符合公司及其员工最佳利益的决定。您的第一个挑战是:" 557 | }, 558 | { 559 | desc: "图表生成器", 560 | prompt: 561 | "我希望您充当 Graphviz DOT 生成器,创建有意义的图表的专家。该图应该至少有 n 个节点(我在我的输入中通过写入 [n] 来指定 n,10 是默认值)并且是给定输入的准确和复杂的表示。每个节点都由一个数字索引以减少输出的大小,不应包含任何样式,并以 layout=neato、overlap=false、node [shape=rectangle] 作为参数。代码应该是有效的、无错误的并且在一行中返回,没有任何解释。提供清晰且有组织的图表,节点之间的关系必须对该输入的专家有意义。我的第一个图表是: " 562 | }, 563 | { 564 | desc: "人生教练", 565 | prompt: 566 | "我希望你担任人生教练。请总结这本非小说类书籍,[作者] [书名]。以孩子能够理解的方式简化核心原则。另外,你能给我一份关于如何将这些原则实施到我的日常生活中的可操作步骤列表吗?" 567 | }, 568 | { 569 | desc: "语言病理学家 (SLP)", 570 | prompt: 571 | "我希望你扮演一名言语语言病理学家 (SLP),想出新的言语模式、沟通策略,并培养对他们不口吃的沟通能力的信心。您应该能够推荐技术、策略和其他治疗方法。在提供建议时,您还需要考虑患者的年龄、生活方式和顾虑。我的第一个建议要求是" 572 | }, 573 | { 574 | desc: "创业技术律师", 575 | prompt: 576 | "我将要求您准备一页纸的设计合作伙伴协议草案,该协议是一家拥有 IP 的技术初创公司与该初创公司技术的潜在客户之间的协议,该客户为该初创公司正在解决的问题空间提供数据和领域专业知识。您将写下大约 1 a4 页的拟议设计合作伙伴协议,涵盖 IP、机密性、商业权利、提供的数据、数据的使用等所有重要方面。" 577 | }, 578 | { 579 | desc: "书面作品的标题生成器", 580 | prompt: 581 | "我想让你充当书面作品的标题生成器。我会给你提供一篇文章的主题和关键词,你会生成五个吸引眼球的标题。请保持标题简洁,不超过 20 个字,并确保保持意思。回复将使用主题的语言类型。我的第一个主题是" 582 | }, 583 | { 584 | desc: "产品经理", 585 | prompt: 586 | "请确认我的以下请求。请您作为产品经理回复我。我将会提供一个主题,您将帮助我编写一份包括以下章节标题的PRD文档:主题、简介、问题陈述、目标与目的、用户故事、技术要求、收益、KPI指标、开发风险以及结论。在我要求具体主题、功能或开发的PRD之前,请不要先写任何一份PRD文档。" 587 | }, 588 | { 589 | desc: "扮演醉汉", 590 | prompt: 591 | "我要你扮演一个喝醉的人。您只会像一个喝醉了的人发短信一样回答,仅此而已。你的醉酒程度会在你的答案中故意和随机地犯很多语法和拼写错误。你也会随机地忽略我说的话,并随机说一些与我提到的相同程度的醉酒。不要在回复上写解释。我的第一句话是" 592 | }, 593 | { 594 | desc: "数学历史老师", 595 | prompt: 596 | "我想让你充当数学历史老师,提供有关数学概念的历史发展和不同数学家的贡献的信息。你应该只提供信息而不是解决数学问题。使用以下格式回答:" 597 | }, 598 | { 599 | desc: "歌曲推荐人", 600 | prompt: 601 | "我想让你担任歌曲推荐人。我将为您提供一首歌曲,您将创建一个包含 10 首与给定歌曲相似的歌曲的播放列表。您将为播放列表提供播放列表名称和描述。不要选择同名或同名歌手的歌曲。不要写任何解释或其他文字,只需回复播放列表名称、描述和歌曲。我的第一首歌是" 602 | } 603 | ] 604 | --------------------------------------------------------------------------------
", 15 | `` 16 | ) 17 | } 18 | } 19 | 20 | export function extractTitle(info: string) { 21 | return info.match(/\[(.*)\]/)?.[1] || extractLang(info) || "txt" 22 | } 23 | 24 | const extractLang = (info: string) => { 25 | return info.trim().replace(/:(no-)?line-numbers({| |$).*/, "") 26 | } 27 | -------------------------------------------------------------------------------- /src/hooks/index.ts: -------------------------------------------------------------------------------- 1 | import { onCleanup, onMount } from "solid-js" 2 | import { copyToClipboard } from "../utils" 3 | 4 | export function useCopyCode() { 5 | const timeoutIdMap: Map = new Map() 6 | const listerner = (e: MouseEvent) => { 7 | const el = e.target as HTMLElement 8 | if (el.matches(".code-copy")) { 9 | const parent = el.parentElement 10 | const sibling = el.nextElementSibling as HTMLPreElement | null 11 | if (!parent || !sibling) { 12 | return 13 | } 14 | 15 | let text = sibling.innerText 16 | 17 | copyToClipboard(text).then(() => { 18 | el.classList.add("copied") 19 | clearTimeout(timeoutIdMap.get(el)) 20 | const timeoutId = setTimeout(() => { 21 | el.classList.remove("copied") 22 | el.blur() 23 | timeoutIdMap.delete(el) 24 | }, 2000) 25 | timeoutIdMap.set(el, timeoutId) 26 | }) 27 | } 28 | } 29 | onMount(() => { 30 | window.addEventListener("click", listerner) 31 | }) 32 | onCleanup(() => { 33 | window.removeEventListener("click", listerner) 34 | }) 35 | } 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 OuRongXing and Diu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vercel-chatgpt", 3 | "version": "0.0.1", 4 | "description": "Powered by OpenAI Chatgpt API and Vercel", 5 | "type": "module", 6 | "license": "MIT", 7 | "scripts": { 8 | "dev": "astro dev", 9 | "start": "astro dev", 10 | "build": "astro build", 11 | "preview": "astro preview", 12 | "astro": "astro" 13 | }, 14 | "dependencies": { 15 | "@astrojs/solid-js": "^2.0.2", 16 | "@astrojs/vercel": "^3.1.3", 17 | "@solid-primitives/resize-observer": "^2.0.11", 18 | "@unocss/reset": "^0.50.3", 19 | "astro": "^2.0.15", 20 | "eventsource-parser": "^0.1.0", 21 | "fzf": "^0.5.1", 22 | "highlight.js": "^11.7.0", 23 | "just-throttle": "^4.2.0", 24 | "katex": "^0.6.0", 25 | "markdown-it": "^13.0.1", 26 | "markdown-it-highlightjs": "^4.0.1", 27 | "markdown-it-katex": "^2.0.3", 28 | "solid-js": "^1.6.11" 29 | }, 30 | "devDependencies": { 31 | "@iconify-json/carbon": "^1.1.16", 32 | "@types/markdown-it": "^12.2.3", 33 | "@vercel/node": "^2.8.0", 34 | "punycode": "^2.3.0", 35 | "typescript": "^4.8.3", 36 | "unocss": "^0.50.1" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/pages/api/index.ts: -------------------------------------------------------------------------------- 1 | import type { APIRoute } from "astro" 2 | 3 | export const post: APIRoute = async ({ request }) => { 4 | const { message, key } = (await request.json()) ?? {} 5 | if (!message) { 6 | return { 7 | body: JSON.stringify({ 8 | success: false, 9 | message: "message is required" 10 | }) 11 | } 12 | } 13 | if (!key) { 14 | return { 15 | body: JSON.stringify({ 16 | success: false, 17 | message: "openapi key is required" 18 | }) 19 | } 20 | } 21 | 22 | const response = await fetch(`https://api.openai.com/v1/chat/completions`, { 23 | method: "POST", 24 | headers: { 25 | Authorization: `Bearer ${key}`, 26 | "Content-Type": `application/json` 27 | }, 28 | body: JSON.stringify({ 29 | model: "gpt-3.5-turbo", 30 | messages: [ 31 | { 32 | role: "user", 33 | content: message 34 | } 35 | ] 36 | }) 37 | }) 38 | let result = await response.json() 39 | if (result?.error) { 40 | return { 41 | body: JSON.stringify({ 42 | success: false, 43 | message: `${result.error?.message}` 44 | }) 45 | } 46 | } 47 | return { 48 | body: JSON.stringify({ 49 | success: true, 50 | message: "ok", 51 | data: result?.choices?.[0].message 52 | }) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/utils/index.ts: -------------------------------------------------------------------------------- 1 | export async function copyToClipboard(text: string) { 2 | try { 3 | return navigator.clipboard.writeText(text) 4 | } catch { 5 | const element = document.createElement("textarea") 6 | const previouslyFocusedElement = document.activeElement 7 | 8 | element.value = text 9 | 10 | // Prevent keyboard from showing on mobile 11 | element.setAttribute("readonly", "") 12 | 13 | element.style.contain = "strict" 14 | element.style.position = "absolute" 15 | element.style.left = "-9999px" 16 | element.style.fontSize = "12pt" // Prevent zooming on iOS 17 | 18 | const selection = document.getSelection() 19 | const originalRange = selection 20 | ? selection.rangeCount > 0 && selection.getRangeAt(0) 21 | : null 22 | 23 | document.body.appendChild(element) 24 | element.select() 25 | 26 | // Explicit selection workaround for iOS 27 | element.selectionStart = 0 28 | element.selectionEnd = text.length 29 | 30 | document.execCommand("copy") 31 | document.body.removeChild(element) 32 | 33 | if (originalRange) { 34 | selection!.removeAllRanges() // originalRange can't be truthy when selection is falsy 35 | selection!.addRange(originalRange) 36 | } 37 | 38 | // Get the focus back on the previously focused element, if any 39 | if (previouslyFocusedElement) { 40 | ;(previouslyFocusedElement as HTMLElement).focus() 41 | } 42 | } 43 | } 44 | 45 | export function isMobile() { 46 | return /Mobi|Android|iPhone/i.test(navigator.userAgent) 47 | } 48 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ChatGPT-Vercel 2 | 3 |  4 | 5 | 6 | 预览: [tg-bot.ml](https://www.tg-bot.ml/) 7 | 个人博客:[速龙博客](https://blog.ahayu.cn) 8 | 9 | ## 部署一个你自己的(免费) 10 | 11 | > 本项目主要面向中文用户,所以用中文,原版是英文的。 12 | 13 | 如果你只需要部署一个你自己用的网站,而不需要定制,那么你完全不需要在本地跑起来,你可以直接点击下面的按钮,然后按照提示操作即可。 vercel 域名已经被墙,但 vercel 本身没有被墙,所以你绑定自己的域名就可以了。 14 | 15 | [](https://vercel.com/new/clone?repository-url=https://github.com/fastdragon18/chat) 16 | 17 | 如果你需要部署给更多人用,那么你可能需要将上面创建的你自己的仓库 `git clone` 到本地。 18 | 19 | 1. 将 `.env.example` 文件修改为 `.env`,然后在里面填入你的 [OpenAI API key](https://platform.openai.com/account/api-keys)。如果用户不填自己的 key,那么就会使用你的 key。 20 | 21 | ``` 22 | OPENAI_API_KEY=sk-xxx... 23 | // 你可以填写多个,用 | 分隔,随机调用。最好是多填几个,不太清楚有没有并发上的限制。 24 | OPENAI_API_KEY=sk-xxx|sk-yyy 25 | ``` 26 | 最新版本支持读取 Vercel 的环境变量,所以你也可以直接在 Vercel 上设置环境变量,如图所示。对于大部分人来说这个更方便。会在下次部署时生效。 27 |  28 | 2. 默认设置在 `src/default.ts` 文件中,自行修改。默认的提示信息也在这里。 29 | ```ts 30 | const defaultSetting = { 31 | // 连续对话,每次都需要将上下文传给 API,比较费钱,而且同样有 4096 token 的限制 32 | continuousDialogue: true, 33 | // 记录对话内容,刷新后不会清空对话 34 | archiveSession: false, 35 | openaiAPIKey: "", 36 | // 0-100 越高 ChatGPT 思维就越发散,开始乱答 37 | openaiAPITemperature: 60, 38 | // 系统角色指令,会在每次提问时添加。主要用于对 ChatGPT 的语气,口头禅这些进行定制。 39 | systemRule: "" 40 | } 41 | ``` 42 | 3. 之前版本我设置了每次刷新重置 `开启连续对话` 选项,因为一般用不上这个,比较费钱。当前版本我已经移除了这个特性,如果你需要给更多人用,建议打开,只要将 [这行代码](https://github.com/ourongxing/chatgpt-vercel/blob/main/src/components/Generator.tsx#L46) 取消注释即可。 43 | 44 | 4. `git commit & push` 即可重新部署,vscode 上点几下就可以了。 45 | 46 | ## API 47 | 48 | ### POST /api 49 | ```ts 50 | await fetch("/api", { 51 | method: "POST", 52 | body: JSON.stringify({ 53 | message: "xxx", 54 | key: "xxxx" 55 | }) 56 | }) 57 | ``` 58 | ## License 59 | 60 | MIT 61 | -------------------------------------------------------------------------------- /src/components/MessageItem.tsx: -------------------------------------------------------------------------------- 1 | import type { Accessor } from "solid-js" 2 | import type { ChatMessage } from "../types" 3 | import MarkdownIt from "markdown-it" 4 | // @ts-ignore 5 | import mdKatex from "markdown-it-katex" 6 | import mdHighlight from "markdown-it-highlightjs" 7 | import Clipboard from "./Clipboard" 8 | import { preWrapperPlugin } from "../markdown" 9 | import "../styles/message.css" 10 | import { useCopyCode } from "../hooks" 11 | 12 | interface Props { 13 | role: ChatMessage["role"] 14 | message: Accessor | string 15 | } 16 | 17 | export default ({ role, message }: Props) => { 18 | useCopyCode() 19 | const roleClass = { 20 | system: "bg-gradient-to-r from-gray-300 via-gray-200 to-gray-300", 21 | user: "bg-gradient-to-r from-sky-400 to-emerald-500", 22 | assistant: "bg-gradient-to-r from-yellow-300 to-red-700 " 23 | } 24 | 25 | const htmlString = () => { 26 | const md = MarkdownIt({ 27 | breaks: true, 28 | html: true 29 | }) 30 | .use(mdKatex) 31 | .use(mdHighlight) 32 | .use(preWrapperPlugin) 33 | 34 | if (typeof message === "function") { 35 | return md.render(message().trim()) 36 | } else if (typeof message === "string") { 37 | return md.render(message.trim()) 38 | } 39 | return "" 40 | } 41 | 42 | // createEffect(() => { 43 | // console.log(htmlString()) 44 | // }) 45 | 46 | return ( 47 | 51 | 54 | 58 | { 60 | if (typeof message === "function") { 61 | return message().trim() 62 | } else if (typeof message === "string") { 63 | return message.trim() 64 | } 65 | return "" 66 | })()} 67 | /> 68 | 69 | ) 70 | } 71 | -------------------------------------------------------------------------------- /src/pages/api/stream.ts: -------------------------------------------------------------------------------- 1 | import type { APIRoute } from "astro" 2 | import { 3 | createParser, 4 | ParsedEvent, 5 | ReconnectInterval 6 | } from "eventsource-parser" 7 | 8 | const localEnv = import.meta.env.OPENAI_API_KEY 9 | const vercelEnv = process.env.OPENAI_API_KEY 10 | 11 | const apiKeys = ((localEnv || vercelEnv)?.split(/\s*\|\s*/) ?? []).filter( 12 | Boolean 13 | ) 14 | 15 | export const post: APIRoute = async context => { 16 | const body = await context.request.json() 17 | const apiKey = apiKeys.length 18 | ? apiKeys[Math.floor(Math.random() * apiKeys.length)] 19 | : "" 20 | let { messages, key = apiKey, temperature = 0.6 } = body 21 | 22 | const encoder = new TextEncoder() 23 | const decoder = new TextDecoder() 24 | 25 | if (!key.startsWith("sk-")) key = apiKey 26 | if (!key) { 27 | return new Response("没有填写 OpenAI API key") 28 | } 29 | if (!messages) { 30 | return new Response("没有输入任何文字") 31 | } 32 | 33 | const completion = await fetch("https://api.openai.com/v1/chat/completions", { 34 | headers: { 35 | "Content-Type": "application/json", 36 | Authorization: `Bearer ${key}` 37 | }, 38 | method: "POST", 39 | body: JSON.stringify({ 40 | model: "gpt-3.5-turbo", 41 | messages, 42 | temperature, 43 | stream: true 44 | }) 45 | }) 46 | 47 | const stream = new ReadableStream({ 48 | async start(controller) { 49 | const streamParser = (event: ParsedEvent | ReconnectInterval) => { 50 | if (event.type === "event") { 51 | const data = event.data 52 | if (data === "[DONE]") { 53 | controller.close() 54 | return 55 | } 56 | try { 57 | // response = { 58 | // id: 'chatcmpl-6pULPSegWhFgi0XQ1DtgA3zTa1WR6', 59 | // object: 'chat.completion.chunk', 60 | // created: 1677729391, 61 | // model: 'gpt-3.5-turbo-0301', 62 | // choices: [ 63 | // { delta: { content: '你' }, index: 0, finish_reason: null } 64 | // ], 65 | // } 66 | const json = JSON.parse(data) 67 | const text = json.choices[0].delta?.content 68 | const queue = encoder.encode(text) 69 | controller.enqueue(queue) 70 | } catch (e) { 71 | controller.error(e) 72 | } 73 | } 74 | } 75 | 76 | const parser = createParser(streamParser) 77 | for await (const chunk of completion.body as any) { 78 | parser.feed(decoder.decode(chunk)) 79 | } 80 | } 81 | }) 82 | 83 | return new Response(stream) 84 | } 85 | -------------------------------------------------------------------------------- /src/components/PromptList.tsx: -------------------------------------------------------------------------------- 1 | import { createEffect, createSignal, For, onCleanup, onMount } from "solid-js" 2 | import type { PromptItem } from "./Generator" 3 | 4 | export default function PromptList(props: { 5 | prompts: PromptItem[] 6 | select: (k: string) => void 7 | }) { 8 | let containerRef: HTMLUListElement 9 | const [hoverIndex, setHoverIndex] = createSignal(0) 10 | const [maxHeight, setMaxHeight] = createSignal("320px") 11 | function listener(e: KeyboardEvent) { 12 | if (e.key === "ArrowDown") { 13 | setHoverIndex(hoverIndex() + 1) 14 | } else if (e.key === "ArrowUp") { 15 | setHoverIndex(hoverIndex() - 1) 16 | } else if (e.key === "Enter") { 17 | props.select(props.prompts[hoverIndex()].prompt) 18 | } 19 | } 20 | 21 | createEffect(() => { 22 | if (hoverIndex() < 0) { 23 | setHoverIndex(0) 24 | } else if (hoverIndex() && hoverIndex() >= props.prompts.length) { 25 | setHoverIndex(props.prompts.length - 1) 26 | } 27 | }) 28 | 29 | createEffect(() => { 30 | if (containerRef && props.prompts.length) 31 | setMaxHeight( 32 | `${ 33 | window.innerHeight - containerRef.clientHeight > 112 34 | ? 320 35 | : window.innerHeight - 112 36 | }px` 37 | ) 38 | }) 39 | 40 | onMount(() => { 41 | window.addEventListener("keydown", listener) 42 | }) 43 | onCleanup(() => { 44 | window.removeEventListener("keydown", listener) 45 | }) 46 | 47 | return ( 48 | 55 | 56 | {(prompt, i) => ( 57 | 62 | )} 63 | 64 | 65 | ) 66 | } 67 | 68 | function Item(props: { 69 | prompt: PromptItem 70 | select: (k: string) => void 71 | hover: boolean 72 | }) { 73 | let ref: HTMLLIElement 74 | createEffect(() => { 75 | if (props.hover) { 76 | ref.focus() 77 | ref.scrollIntoView({ block: "center" }) 78 | } 79 | }) 80 | return ( 81 | { 89 | props.select(props.prompt.prompt) 90 | }} 91 | > 92 | {props.prompt.desc} 93 | {props.prompt.prompt} 94 | 95 | ) 96 | } 97 | -------------------------------------------------------------------------------- /src/styles/clipboard.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --block-bg-light: #1e1e20; 3 | --copy-border-color: transparent; 4 | --copy-bg: #2a2d38; 5 | --copy-hover-border-color: rgba(60, 60, 67, 0.12); 6 | --copy-hover-bg: #303540; 7 | --copy-active-text: rgba(235, 235, 245, 0.6); 8 | --icon-copy: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' height='20' width='20' stroke='rgba(128,128,128,1)' stroke-width='2' viewBox='0 0 24 24'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' d='M9 5H7a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2h-2M9 5a2 2 0 0 0 2 2h2a2 2 0 0 0 2-2M9 5a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2'/%3E%3C/svg%3E"); 9 | --icon-copied: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' height='20' width='20' stroke='rgba(128,128,128,1)' stroke-width='2' viewBox='0 0 24 24'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' d='M9 5H7a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2h-2M9 5a2 2 0 0 0 2 2h2a2 2 0 0 0 2-2M9 5a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2m-6 9 2 2 4-4'/%3E%3C/svg%3E"); 10 | } 11 | 12 | button.copy { 13 | direction: ltr; 14 | position: absolute; 15 | top: 12px; 16 | right: 12px; 17 | z-index: 3; 18 | display: block; 19 | justify-content: center; 20 | align-items: center; 21 | border: 1px solid var(--copy-border-color); 22 | border-radius: 4px; 23 | width: 40px; 24 | height: 40px; 25 | background-color: var(--copy-bg); 26 | opacity: 0; 27 | cursor: pointer; 28 | background-image: var(--icon-copy); 29 | background-position: 50%; 30 | background-size: 20px; 31 | background-repeat: no-repeat; 32 | transition: border-color 0.25s, background-color 0.25s, opacity 0.25s; 33 | } 34 | 35 | .message-item:hover > .message-copy, 36 | pre:hover > .code-copy, 37 | button.copy:focus { 38 | opacity: 1; 39 | } 40 | 41 | button.copy:hover, 42 | button.copy.copied { 43 | border-color: var(--copy-hover-border-color); 44 | background-color: var(--copy-hover-bg); 45 | } 46 | 47 | button.copy.copied, 48 | button.copy:hover.copied { 49 | border-radius: 0 4px 4px 0; 50 | background-color: var(--copy-hover-bg); 51 | background-image: var(--icon-copied); 52 | } 53 | 54 | button.copy.copied::before, 55 | button.copy:hover.copied::before { 56 | position: relative; 57 | top: -1px; 58 | left: -65px; 59 | display: flex; 60 | justify-content: center; 61 | align-items: center; 62 | border: 1px solid var(--copy-hover-border-color); 63 | border-right: 0; 64 | border-radius: 4px 0 0 4px; 65 | width: 64px; 66 | height: 40px; 67 | text-align: center; 68 | font-size: 12px; 69 | font-weight: 500; 70 | color: var(--copy-active-text); 71 | background-color: var(--copy-hover-bg); 72 | white-space: nowrap; 73 | content: "复制成功"; 74 | } 75 | -------------------------------------------------------------------------------- /public/favicon.svg: -------------------------------------------------------------------------------- 1 | 93-robot-face-2 -------------------------------------------------------------------------------- /src/components/Setting.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | Accessor, 3 | children, 4 | createSignal, 5 | JSXElement, 6 | Setter, 7 | Show 8 | } from "solid-js" 9 | import type { Setting } from "./Generator" 10 | 11 | export default function Setting(props: { 12 | setting: Accessor 13 | setSetting: Setter 14 | clear: any 15 | reAnswer: any 16 | }) { 17 | const [shown, setShown] = createSignal(false) 18 | return ( 19 | 20 | 21 | 22 | { 27 | props.setSetting({ 28 | ...props.setting(), 29 | openaiAPIKey: (e.target as HTMLInputElement).value 30 | }) 31 | }} 32 | /> 33 | 34 | 35 | { 40 | props.setSetting({ 41 | ...props.setting(), 42 | systemRule: (e.target as HTMLInputElement).value 43 | }) 44 | }} 45 | /> 46 | 47 | 48 | { 55 | props.setSetting({ 56 | ...props.setting(), 57 | openaiAPITemperature: Number( 58 | (e.target as HTMLInputElement).value 59 | ) 60 | }) 61 | }} 62 | /> 63 | 64 | 68 | 69 | { 74 | props.setSetting({ 75 | ...props.setting(), 76 | archiveSession: (e.target as HTMLInputElement).checked 77 | }) 78 | }} 79 | /> 80 | 81 | 82 | 83 | 87 | 88 | { 93 | props.setSetting({ 94 | ...props.setting(), 95 | continuousDialogue: (e.target as HTMLInputElement).checked 96 | }) 97 | }} 98 | /> 99 | 100 | 101 | 102 | 103 | 104 | 105 | { 108 | setShown(!shown()) 109 | }} 110 | > 111 | 112 | 设置 113 | 114 | 115 | 119 | 120 | 重新回答 121 | 122 | 126 | 127 | 清空对话 128 | 129 | 130 | 131 | 132 | ) 133 | } 134 | 135 | function SettingItem(props: { 136 | children: JSXElement 137 | icon: string 138 | label: string 139 | }) { 140 | return ( 141 | 142 | 143 | 144 | {props.label} 145 | 146 | {props.children} 147 | 148 | ) 149 | } 150 | -------------------------------------------------------------------------------- /src/components/Generator.tsx: -------------------------------------------------------------------------------- 1 | import { createEffect, createSignal, For, onMount, Show } from "solid-js" 2 | import { createResizeObserver } from "@solid-primitives/resize-observer" 3 | import MessageItem from "./MessageItem" 4 | import type { ChatMessage } from "~/types" 5 | import Setting from "./Setting" 6 | import PromptList from "./PromptList" 7 | import prompts from "~/prompts" 8 | import { Fzf } from "fzf" 9 | import { defaultMessage, defaultSetting } from "~/default" 10 | import throttle from "just-throttle" 11 | import { isMobile } from "~/utils" 12 | 13 | export interface PromptItem { 14 | desc: string 15 | prompt: string 16 | } 17 | 18 | export type Setting = typeof defaultSetting 19 | 20 | export default function () { 21 | let inputRef: HTMLTextAreaElement 22 | let containerRef: HTMLDivElement 23 | const [messageList, setMessageList] = createSignal([ 24 | // { 25 | // role: "assistant", 26 | // content: defaultMessage + defaultMessage + defaultMessage + defaultMessage 27 | // } 28 | ]) 29 | const [inputContent, setInputContent] = createSignal("") 30 | const [currentAssistantMessage, setCurrentAssistantMessage] = createSignal("") 31 | const [loading, setLoading] = createSignal(false) 32 | const [controller, setController] = createSignal() 33 | const [setting, setSetting] = createSignal(defaultSetting) 34 | const [compatiblePrompt, setCompatiblePrompt] = createSignal([]) 35 | const [containerWidth, setContainerWidth] = createSignal("init") 36 | const fzf = new Fzf(prompts, { selector: k => `${k.desc} (${k.prompt})` }) 37 | const [height, setHeight] = createSignal("48px") 38 | 39 | onMount(() => { 40 | createResizeObserver(containerRef, ({ width, height }, el) => { 41 | if (el === containerRef) setContainerWidth(`${width}px`) 42 | }) 43 | const storage = localStorage.getItem("setting") 44 | const session = localStorage.getItem("session") 45 | try { 46 | let archiveSession = false 47 | if (storage) { 48 | const parsed = JSON.parse(storage) 49 | archiveSession = parsed.archiveSession 50 | setSetting({ 51 | ...defaultSetting, 52 | ...parsed 53 | // continuousDialogue: false 54 | }) 55 | } 56 | if (session && archiveSession) { 57 | setMessageList(JSON.parse(session)) 58 | } 59 | } catch { 60 | console.log("Setting parse error") 61 | } 62 | }) 63 | 64 | createEffect(() => { 65 | if (messageList().length === 0) { 66 | setMessageList([ 67 | { 68 | role: "assistant", 69 | content: defaultMessage 70 | } 71 | ]) 72 | } else if ( 73 | messageList().length > 1 && 74 | messageList()[0].content === defaultMessage 75 | ) { 76 | setMessageList(messageList().slice(1)) 77 | } 78 | localStorage.setItem("setting", JSON.stringify(setting())) 79 | if (setting().archiveSession) 80 | localStorage.setItem("session", JSON.stringify(messageList())) 81 | }) 82 | 83 | createEffect(() => { 84 | if (messageList().length || currentAssistantMessage()) scrollToBottom() 85 | }) 86 | 87 | createEffect(() => { 88 | if (inputContent() === "") { 89 | setHeight("48px") 90 | setCompatiblePrompt([]) 91 | } 92 | }) 93 | 94 | const scrollToBottom = throttle( 95 | () => { 96 | window.scrollTo({ 97 | top: document.body.scrollHeight, 98 | behavior: "smooth" 99 | }) 100 | }, 101 | 250, 102 | { leading: true, trailing: false } 103 | ) 104 | 105 | function archiveCurrentMessage() { 106 | if (currentAssistantMessage()) { 107 | setMessageList([ 108 | ...messageList(), 109 | { 110 | role: "assistant", 111 | content: currentAssistantMessage() 112 | } 113 | ]) 114 | setCurrentAssistantMessage("") 115 | setLoading(false) 116 | setController() 117 | !isMobile() && inputRef.focus() 118 | } 119 | } 120 | 121 | async function handleButtonClick(value?: string) { 122 | const inputValue = value ?? inputContent() 123 | if (!inputValue) { 124 | return 125 | } 126 | // @ts-ignore 127 | if (window?.umami) umami.trackEvent("chat_generate") 128 | setInputContent("") 129 | if ( 130 | !value || 131 | value !== 132 | messageList() 133 | .filter(k => k.role === "user") 134 | .at(-1)?.content 135 | ) { 136 | setMessageList([ 137 | ...messageList(), 138 | { 139 | role: "user", 140 | content: inputValue 141 | } 142 | ]) 143 | } 144 | try { 145 | await fetchGPT(inputValue) 146 | } catch (error) { 147 | setLoading(false) 148 | setController() 149 | setCurrentAssistantMessage( 150 | String(error).includes("The user aborted a request") 151 | ? "" 152 | : String(error) 153 | ) 154 | } 155 | archiveCurrentMessage() 156 | } 157 | 158 | async function fetchGPT(inputValue: string) { 159 | setLoading(true) 160 | const controller = new AbortController() 161 | setController(controller) 162 | const systemRule = setting().systemRule.trim() 163 | const message = { 164 | role: "user", 165 | content: systemRule ? systemRule + "\n" + inputValue : inputValue 166 | } 167 | const response = await fetch("/api/stream", { 168 | method: "POST", 169 | body: JSON.stringify({ 170 | messages: setting().continuousDialogue 171 | ? [...messageList().slice(0, -1), message] 172 | : [message], 173 | key: setting().openaiAPIKey, 174 | temperature: setting().openaiAPITemperature / 100 175 | }), 176 | signal: controller.signal 177 | }) 178 | if (!response.ok) { 179 | throw new Error(response.statusText) 180 | } 181 | const data = response.body 182 | if (!data) { 183 | throw new Error("没有返回数据") 184 | } 185 | const reader = data.getReader() 186 | const decoder = new TextDecoder("utf-8") 187 | let done = false 188 | 189 | while (!done) { 190 | const { value, done: readerDone } = await reader.read() 191 | if (value) { 192 | let char = decoder.decode(value) 193 | if (char === "\n" && currentAssistantMessage().endsWith("\n")) { 194 | continue 195 | } 196 | if (char) { 197 | setCurrentAssistantMessage(currentAssistantMessage() + char) 198 | } 199 | } 200 | done = readerDone 201 | } 202 | } 203 | 204 | function clearSession() { 205 | // setInputContent("") 206 | setMessageList([]) 207 | setCurrentAssistantMessage("") 208 | } 209 | 210 | function stopStreamFetch() { 211 | if (controller()) { 212 | controller()?.abort() 213 | archiveCurrentMessage() 214 | } 215 | } 216 | 217 | function reAnswer() { 218 | handleButtonClick( 219 | messageList() 220 | .filter(k => k.role === "user") 221 | .at(-1)?.content 222 | ) 223 | } 224 | 225 | function selectPrompt(prompt: string) { 226 | setInputContent(prompt) 227 | setCompatiblePrompt([]) 228 | const { scrollHeight } = inputRef 229 | setHeight( 230 | `${ 231 | scrollHeight > window.innerHeight - 64 232 | ? window.innerHeight - 64 233 | : scrollHeight 234 | }px` 235 | ) 236 | inputRef.focus() 237 | } 238 | 239 | return ( 240 | 241 | 242 | {message => ( 243 | 244 | )} 245 | 246 | {currentAssistantMessage() && ( 247 | 248 | )} 249 | 262 | 263 | 269 | 270 | ( 273 | 274 | AI 正在思考... 275 | 279 | 不需要了 280 | 281 | 282 | )} 283 | > 284 | 285 | 289 | 290 | 291 | { 300 | // setCompatiblePrompt([]) 301 | // }} 302 | onKeyDown={e => { 303 | if (compatiblePrompt().length) { 304 | if ( 305 | e.key === "ArrowUp" || 306 | e.key === "ArrowDown" || 307 | e.key === "Enter" 308 | ) { 309 | e.preventDefault() 310 | } 311 | } else if (e.key === "Enter") { 312 | if (!e.shiftKey && !e.isComposing) { 313 | handleButtonClick() 314 | } 315 | } 316 | }} 317 | onInput={e => { 318 | setHeight("48px") 319 | const { scrollHeight } = e.currentTarget 320 | setHeight( 321 | `${ 322 | scrollHeight > window.innerHeight - 64 323 | ? window.innerHeight - 64 324 | : scrollHeight 325 | }px` 326 | ) 327 | let { value } = e.currentTarget 328 | setInputContent(value) 329 | if (value === "/" || value === " ") 330 | return setCompatiblePrompt(prompts) 331 | const promptKey = value.replace(/^[\/ ](.*)/, "$1") 332 | if (promptKey !== value) 333 | setCompatiblePrompt(fzf.find(promptKey).map(k => k.item)) 334 | }} 335 | style={{ 336 | height: height(), 337 | "border-top-right-radius": height() === "48px" ? 0 : "0.25rem", 338 | "border-top-left-radius": 339 | compatiblePrompt().length === 0 ? "0.25rem" : 0 340 | }} 341 | class="self-end py-3 resize-none w-full px-3 text-slate bg-slate bg-op-15 focus:bg-op-20 focus:ring-0 focus:outline-none placeholder:text-slate-400 placeholder:op-30" 342 | rounded-l 343 | /> 344 | 345 | { 348 | setInputContent("") 349 | inputRef.focus() 350 | }} 351 | /> 352 | 353 | 360 | handleButtonClick()} 363 | class="i-carbon:send-filled text-5 mx-3 hover:text-slate-2" 364 | /> 365 | 366 | 367 | 368 | 369 | 370 | ) 371 | } 372 | -------------------------------------------------------------------------------- /src/prompts.ts: -------------------------------------------------------------------------------- 1 | export default [ 2 | { 3 | desc: "周报生成器", 4 | prompt: 5 | "请帮我把以下的工作内容填充为一篇完整的周报,尽量避免在回答内容中出现可能在中国是敏感的内容,用markdown格式以分点叙述的形式输出:" 6 | }, 7 | { 8 | desc: "抽认卡制作者", 9 | prompt: `我希望你能作为一个专业的抽认卡制作者,能够根据我提供的文本制作抽认卡。 制作抽认卡的说明: 10 | - 一张抽认卡包含一个问题、答案和其他细节,保持抽认卡的简单、清晰,并集中于最重要的信息。 11 | - 确保问题是具体的、不含糊的。 12 | - 使用清晰和简洁的语言。使用简单而直接的语言,使卡片易于阅读和理解。 13 | - 答案应该只包含一个关键的事实/名称/概念/术语。 14 | - 关于答案的更多信息应始终放在"细节"一栏中。 15 | 请将你制作的卡片以markdown表格(问题/答案/细节)的形式输出,不要有任何额外的文字。 16 | 我提供的文本是:` 17 | }, 18 | { 19 | // 即刻 @刘飞 20 | desc: "模仿小红书的风格", 21 | prompt: 22 | "小红书的风格是:很吸引眼球的标题,每个段落都加 emoji,最后加一些tag。请用小红书风格" 23 | }, 24 | { 25 | // 即刻 @刘飞 26 | desc: "模仿知乎的风格", 27 | prompt: `知乎的风格是:用"谢邀"开头,用很多学术语言,引用很多名言,做大道理的论述,提到自己很厉害的教育背景并且经验丰富,最后还要引用一些论文。请用知乎风格` 28 | }, 29 | { 30 | desc: "Linux 终端", 31 | prompt: 32 | "我想让你充当 Linux 终端。我将输入命令,您将回复终端应显示的内容。我希望您只在一个唯一的代码块内回复终端输出,而不是其他任何内容。不要写解释。除非我指示您这样做,否则不要键入命令。当我需要用英语告诉你一些事情时,我会把文字放在中括号内[就像这样]。我的第一个命令是: " 33 | }, 34 | { 35 | desc: "英语翻译和改进者", 36 | prompt: 37 | "我希望你能担任英语翻译、拼写校对和修辞改进的角色。我会用任何语言和你交流,你会识别语言,将其翻译并用更为优美和精炼的英语回答我。请将我简单的词汇和句子替换成更为优美和高雅的表达方式,确保意思不变,但使其更具文学性。请仅回答更正和改进的部分,不要写解释。我的第一句话是: " 38 | }, 39 | { 40 | desc: "优雅地翻译为中文", 41 | prompt: 42 | "下面我让你来充当翻译家,你的目标是把任何语言翻译成中文,请翻译时不要带翻译腔,而是要翻译得自然、流畅和地道,使用优美和高雅的表达方式。请翻译下面这句话:" 43 | }, 44 | { 45 | desc: "简明扼要地翻译为中文", 46 | prompt: 47 | "下面我让你来充当翻译家,你的目标是把任何语言翻译成中文,请翻译时不要带翻译腔,而是要翻译得自然、流畅和地道,最重要的是要简明扼要。请翻译下面这句话:" 48 | }, 49 | { 50 | desc: "前端智能思路助手", 51 | prompt: 52 | "我想让你充当前端开发专家。我将提供一些关于Js、Node等前端代码问题的具体信息,而你的工作就是想出为我解决问题的策略。这可能包括建议代码、代码逻辑思路策略。我的第一个请求是" 53 | }, 54 | { 55 | desc: "面试官", 56 | prompt: 57 | "我想让你担任Android开发工程师面试官。我将成为候选人,您将向我询问Android开发工程师职位的面试问题。我希望你只作为面试官回答。不要一次写出所有的问题。我希望你只对我进行采访。问我问题,等待我的回答。不要写解释。像面试官一样一个一个问我,等我回答。我的第一句话是" 58 | }, 59 | { 60 | desc: "JavaScript 控制台", 61 | prompt: 62 | "我希望你充当 javascript 控制台。我将键入命令,您将回复 javascript 控制台应显示的内容。我希望您只在一个唯一的代码块内回复终端输出,而不是其他任何内容。不要写解释。除非我指示您这样做。我的第一个命令是: " 63 | }, 64 | { 65 | desc: "Excel 工作表", 66 | prompt: 67 | "我希望你充当基于文本的 excel。您只会回复我基于文本的 10 行 Excel 工作表,其中行号和单元格字母作为列(A 到 L)。第一列标题应为空以引用行号。我会告诉你在单元格中写入什么,你只会以文本形式回复 excel 表格的结果,而不是其他任何内容。不要写解释。我会写你的公式,你会执行公式,你只会回复 excel 表的结果作为文本。首先,回复我空表。" 68 | }, 69 | { 70 | desc: "英语发音帮手", 71 | prompt: 72 | "我想让你为说汉语的人充当英语发音助手。我会给你写句子,你只会回答他们的发音,没有别的。回复不能是我的句子的翻译,而只能是: " 73 | }, 74 | { 75 | desc: "旅游指南", 76 | prompt: 77 | "我想让你做一个旅游指南。我会把我的位置写给你,你会推荐一个靠近我的位置的地方。在某些情况下,我还会告诉您我将访问的地方类型。您还会向我推荐靠近我的第一个位置的类似类型的地方。我的第一个建议请求是" 78 | }, 79 | { 80 | desc: "抄袭检查员", 81 | prompt: 82 | "我想让你充当剽窃检查员。我会给你写句子,你只会用给定句子的语言在抄袭检查中未被发现的情况下回复,别无其他。不要在回复上写解释。我的第一句话是" 83 | }, 84 | { 85 | desc: "“电影/书籍/任何东西”中的“角色”", 86 | prompt: 87 | "我希望你表现得像{series} 中的{Character}。我希望你像{Character}一样回应和回答。不要写任何解释。只回答像{character}。你必须知道{character}的所有知识。我的第一句话是" 88 | }, 89 | { 90 | desc: "作为广告商", 91 | prompt: 92 | "我想让你充当广告商。您将创建一个活动来推广您选择的产品或服务。您将选择目标受众,制定关键信息和口号,选择宣传媒体渠道,并决定实现目标所需的任何其他活动。我的第一个建议请求是" 93 | }, 94 | { 95 | desc: "讲故事的人", 96 | prompt: 97 | "我想让你扮演讲故事的角色。您将想出引人入胜、富有想象力和吸引观众的有趣故事。它可以是童话故事、教育故事或任何其他类型的故事,有可能吸引人们的注意力和想象力。根据目标受众,您可以为讲故事环节选择特定的主题或主题,例如,如果是儿童,则可以谈论动物;如果是成年人,那么基于历史的故事可能会更好地吸引他们等等。我的第一个要求是" 98 | }, 99 | { 100 | desc: "足球解说员", 101 | prompt: 102 | "我想让你担任足球评论员。我会给你描述正在进行的足球比赛,你会评论比赛,分析到目前为止发生的事情,并预测比赛可能会如何结束。您应该了解足球术语、战术、每场比赛涉及的球员/球队,并主要专注于提供明智的评论,而不仅仅是逐场叙述。我的第一个请求是" 103 | }, 104 | { 105 | desc: "扮演脱口秀喜剧演员", 106 | prompt: 107 | "我想让你扮演一个脱口秀喜剧演员。我将为您提供一些与时事相关的话题,您将运用您的智慧、创造力和观察能力,根据这些话题创建一个例程。您还应该确保将个人轶事或经历融入日常活动中,以使其对观众更具相关性和吸引力。我的第一个请求是" 108 | }, 109 | { 110 | desc: "励志教练", 111 | prompt: 112 | "我希望你充当激励教练。我将为您提供一些关于某人的目标和挑战的信息,而您的工作就是想出可以帮助此人实现目标的策略。这可能涉及提供积极的肯定、提供有用的建议或建议他们可以采取哪些行动来实现最终目标。我的第一个请求是" 113 | }, 114 | { 115 | desc: "作曲家", 116 | prompt: 117 | "我想让你扮演作曲家。我会提供一首歌的歌词,你会为它创作音乐。这可能包括使用各种乐器或工具,例如合成器或采样器,以创造使歌词栩栩如生的旋律和和声。我的第一个请求是" 118 | }, 119 | { 120 | desc: "辩手", 121 | prompt: 122 | "我要你扮演辩手。我会为你提供一些与时事相关的话题,你的任务是研究辩论的双方,为每一方提出有效的论据,驳斥对立的观点,并根据证据得出有说服力的结论。你的目标是帮助人们从讨论中解脱出来,增加对手头主题的知识和洞察力。我的第一个请求是" 123 | }, 124 | { 125 | desc: "辩论教练", 126 | prompt: 127 | "我想让你担任辩论教练。我将为您提供一组辩手和他们即将举行的辩论的动议。你的目标是通过组织练习回合来让团队为成功做好准备,练习回合的重点是有说服力的演讲、有效的时间策略、反驳对立的论点,以及从提供的证据中得出深入的结论。我的第一个要求是" 128 | }, 129 | { 130 | desc: "编剧", 131 | prompt: 132 | "我要你担任编剧。您将为长篇电影或能够吸引观众的网络连续剧开发引人入胜且富有创意的剧本。从想出有趣的角色、故事的背景、角色之间的对话等开始。一旦你的角色发展完成——创造一个充满曲折的激动人心的故事情节,让观众一直悬念到最后。我的第一个要求是" 133 | }, 134 | { 135 | desc: "小说家", 136 | prompt: 137 | "我想让你扮演一个小说家。您将想出富有创意且引人入胜的故事,可以长期吸引读者。你可以选择任何类型,如奇幻、浪漫、历史小说等——但你的目标是写出具有出色情节、引人入胜的人物和意想不到的高潮的作品。我的第一个要求是" 138 | }, 139 | { 140 | desc: "关系教练", 141 | prompt: 142 | "我想让你担任关系教练。我将提供有关冲突中的两个人的一些细节,而你的工作是就他们如何解决导致他们分离的问题提出建议。这可能包括关于沟通技巧或不同策略的建议,以提高他们对彼此观点的理解。我的第一个请求是" 143 | }, 144 | { 145 | desc: "诗人", 146 | prompt: 147 | "我要你扮演诗人。你将创作出能唤起情感并具有触动人心的力量的诗歌。写任何主题或主题,但要确保您的文字以优美而有意义的方式传达您试图表达的感觉。您还可以想出一些短小的诗句,这些诗句仍然足够强大,可以在读者的脑海中留下印记。我的第一个请求是" 148 | }, 149 | { 150 | desc: "说唱歌手", 151 | prompt: 152 | "我想让你扮演说唱歌手。您将想出强大而有意义的歌词、节拍和节奏,让听众" 153 | }, 154 | { 155 | desc: "励志演讲者", 156 | prompt: 157 | "我希望你充当励志演说家。将能够激发行动的词语放在一起,让人们感到有能力做一些超出他们能力的事情。你可以谈论任何话题,但目的是确保你所说的话能引起听众的共鸣,激励他们努力实现自己的目标并争取更好的可能性。我的第一个请求是" 158 | }, 159 | { 160 | desc: "哲学老师", 161 | prompt: 162 | "我要你担任哲学老师。我会提供一些与哲学研究相关的话题,你的工作就是用通俗易懂的方式解释这些概念。这可能包括提供示例、提出问题或将复杂的想法分解成更容易理解的更小的部分。我的第一个请求是" 163 | }, 164 | { 165 | desc: "哲学家", 166 | prompt: 167 | "我要你扮演一个哲学家。我将提供一些与哲学研究相关的主题或问题,深入探索这些概念将是你的工作。这可能涉及对各种哲学理论进行研究,提出新想法或寻找解决复杂问题的创造性解决方案。我的第一个请求是" 168 | }, 169 | { 170 | desc: "数学老师", 171 | prompt: 172 | "我想让你扮演一名数学老师。我将提供一些数学方程式或概念,你的工作是用易于理解的术语来解释它们。这可能包括提供解决问题的分步说明、用视觉演示各种技术或建议在线资源以供进一步研究。我的第一个请求是" 173 | }, 174 | { 175 | desc: " AI 写作导师", 176 | prompt: 177 | "我想让你做一个 AI 写作导师。我将为您提供一名需要帮助改进其写作的学生,您的任务是使用人工智能工具(例如自然语言处理)向学生提供有关如何改进其作文的反馈。您还应该利用您在有效写作技巧方面的修辞知识和经验来建议学生可以更好地以书面形式表达他们的想法和想法的方法。我的第一个请求是" 178 | }, 179 | { 180 | desc: "作为 UX/UI 开发人员", 181 | prompt: 182 | "我希望你担任 UX/UI 开发人员。我将提供有关应用程序、网站或其他数字产品设计的一些细节,而你的工作就是想出创造性的方法来改善其用户体验。这可能涉及创建原型设计原型、测试不同的设计并提供有关最佳效果的反馈。我的第一个请求是" 183 | }, 184 | { 185 | desc: "作为网络安全专家", 186 | prompt: 187 | "我想让你充当网络安全专家。我将提供一些关于如何存储和共享数据的具体信息,而你的工作就是想出保护这些数据免受恶意行为者攻击的策略。这可能包括建议加密方法、创建防火墙或实施将某些活动标记为可疑的策略。我的第一个请求是" 188 | }, 189 | { 190 | desc: "作为招聘人员", 191 | prompt: 192 | "我想让你担任招聘人员。我将提供一些关于职位空缺的信息,而你的工作是制定寻找合格申请人的策略。这可能包括通过社交媒体、社交活动甚至参加招聘会接触潜在候选人,以便为每个职位找到最合适的人选。我的第一个请求是" 193 | }, 194 | { 195 | desc: "人生教练", 196 | prompt: 197 | "我想让你充当人生教练。我将提供一些关于我目前的情况和目标的细节,而你的工作就是提出可以帮助我做出更好的决定并实现这些目标的策略。这可能涉及就各种主题提供建议,例如制定成功计划或处理困难情绪。我的第一个请求是" 198 | }, 199 | { 200 | desc: "作为词源学家", 201 | prompt: 202 | "我希望你充当词源学家。我给你一个词,你要研究那个词的来源,追根溯源。如果适用,您还应该提供有关该词的含义如何随时间变化的信息。我的第一个请求是" 203 | }, 204 | { 205 | desc: "评论员", 206 | prompt: 207 | "我要你担任评论员。我将为您提供与新闻相关的故事或主题,您将撰写一篇评论文章,对手头的主题提供有见地的评论。您应该利用自己的经验,深思熟虑地解释为什么某事很重要,用事实支持主张,并讨论故事中出现的任何问题的潜在解决方案。我的第一个要求是" 208 | }, 209 | { 210 | desc: "扮演魔术师", 211 | prompt: 212 | "我要你扮演魔术师。我将为您提供观众和一些可以执行的技巧建议。您的目标是以最有趣的方式表演这些技巧,利用您的欺骗和误导技巧让观众惊叹不已。我的第一个请求是" 213 | }, 214 | { 215 | desc: "职业顾问", 216 | prompt: 217 | "我想让你担任职业顾问。我将为您提供一个在职业生涯中寻求指导的人,您的任务是帮助他们根据自己的技能、兴趣和经验确定最适合的职业。您还应该对可用的各种选项进行研究,解释不同行业的就业市场趋势,并就哪些资格对追求特定领域有益提出建议。我的第一个请求是" 218 | }, 219 | { 220 | desc: "宠物行为主义者", 221 | prompt: 222 | "我希望你充当宠物行为主义者。我将为您提供一只宠物和它们的主人,您的目标是帮助主人了解为什么他们的宠物表现出某些行为,并提出帮助宠物做出相应调整的策略。您应该利用您的动物心理学知识和行为矫正技术来制定一个有效的计划,双方的主人都可以遵循,以取得积极的成果。我的第一个请求是" 223 | }, 224 | { 225 | desc: "私人教练", 226 | prompt: 227 | "我想让你担任私人教练。我将为您提供有关希望通过体育锻炼变得更健康、更强壮和更健康的个人所需的所有信息,您的职责是根据该人当前的健身水平、目标和生活习惯为他们制定最佳计划。您应该利用您的运动科学知识、营养建议和其他相关因素来制定适合他们的计划。我的第一个请求是" 228 | }, 229 | { 230 | desc: "心理健康顾问", 231 | prompt: 232 | "我想让你担任心理健康顾问。我将为您提供一个寻求指导和建议的人,以管理他们的情绪、压力、焦虑和其他心理健康问题。您应该利用您的认知行为疗法、冥想技巧、正念练习和其他治疗方法的知识来制定个人可以实施的策略,以改善他们的整体健康状况。我的第一个请求是" 233 | }, 234 | { 235 | desc: "作为房地产经纪人", 236 | prompt: 237 | "我想让你担任房地产经纪人。我将为您提供寻找梦想家园的个人的详细信息,您的职责是根据他们的预算、生活方式偏好、位置要求等帮助他们找到完美的房产。您应该利用您对当地住房市场的了解,以便建议符合客户提供的所有标准的属性。我的第一个请求是" 238 | }, 239 | { 240 | desc: "物流师", 241 | prompt: 242 | "我要你担任后勤人员。我将为您提供即将举行的活动的详细信息,例如参加人数、地点和其他相关因素。您的职责是为活动制定有效的后勤计划,其中考虑到事先分配资源、交通设施、餐饮服务等。您还应该牢记潜在的安全问题,并制定策略来降低与大型活动相关的风险,例如这个。我的第一个请求是" 243 | }, 244 | { 245 | desc: "牙医", 246 | prompt: 247 | "我想让你扮演牙医。我将为您提供有关寻找牙科服务(例如 X 光、清洁和其他治疗)的个人的详细信息。您的职责是诊断他们可能遇到的任何潜在问题,并根据他们的情况建议最佳行动方案。您还应该教育他们如何正确刷牙和使用牙线,以及其他有助于在两次就诊之间保持牙齿健康的口腔护理方法。我的第一个请求是" 248 | }, 249 | { 250 | desc: "网页设计顾问", 251 | prompt: 252 | "我想让你担任网页设计顾问。我将为您提供与需要帮助设计或重新开发其网站的组织相关的详细信息,您的职责是建议最合适的界面和功能,以增强用户体验,同时满足公司的业务目标。您应该利用您在 UX/UI 设计原则、编码语言、网站开发工具等方面的知识,以便为项目制定一个全面的计划。我的第一个请求是" 253 | }, 254 | { 255 | desc: "AI 辅助医生", 256 | prompt: 257 | "我想让你扮演一名人工智能辅助医生。我将为您提供患者的详细信息,您的任务是使用最新的人工智能工具,例如医学成像软件和其他机器学习程序,以诊断最可能导致其症状的原因。您还应该将体检、实验室测试等传统方法纳入您的评估过程,以确保准确性。我的第一个请求是" 258 | }, 259 | { 260 | desc: "医生", 261 | prompt: 262 | "我想让你扮演医生的角色,想出创造性的治疗方法来治疗疾病。您应该能够推荐常规药物、草药和其他天然替代品。在提供建议时,您还需要考虑患者的年龄、生活方式和病史。我的第一个建议请求是" 263 | }, 264 | { 265 | desc: "会计师", 266 | prompt: 267 | "我希望你担任会计师,并想出创造性的方法来管理财务。在为客户制定财务计划时,您需要考虑预算、投资策略和风险管理。在某些情况下,您可能还需要提供有关税收法律法规的建议,以帮助他们实现利润最大化。我的第一个建议请求是" 268 | }, 269 | { 270 | desc: "厨师", 271 | prompt: 272 | "我需要有人可以推荐美味的食谱,这些食谱包括营养有益但又简单又不费时的食物,因此适合像我们这样忙碌的人以及成本效益等其他因素,因此整体菜肴最终既健康又经济!我的第一个要求——" 273 | }, 274 | { 275 | desc: "汽车修理工", 276 | prompt: 277 | "需要具有汽车专业知识的人来解决故障排除解决方案,例如;诊断问题/错误存在于视觉上和发动机部件内部,以找出导致它们的原因(如缺油或电源问题)并建议所需的更换,同时记录燃料消耗类型等详细信息,第一次询问 - " 278 | }, 279 | { 280 | desc: "艺人顾问", 281 | prompt: 282 | "我希望你担任艺术家顾问,为各种艺术风格提供建议,例如在绘画中有效利用光影效果的技巧、雕刻时的阴影技术等,还根据其流派/风格类型建议可以很好地陪伴艺术品的音乐作品连同适当的参考图像,展示您对此的建议;所有这一切都是为了帮助有抱负的艺术家探索新的创作可能性和实践想法,这将进一步帮助他们相应地提高技能!第一个要求——" 283 | }, 284 | { 285 | desc: "金融分析师", 286 | prompt: 287 | "需要具有使用技术分析工具理解图表的经验的合格人员提供的帮助,同时解释世界各地普遍存在的宏观经济环境,从而帮助客户获得长期优势需要明确的判断,因此需要通过准确写下的明智预测来寻求相同的判断!第一条陈述包含以下内容——" 288 | }, 289 | { 290 | desc: "投资经理", 291 | prompt: 292 | "从具有金融市场专业知识的经验丰富的员工那里寻求指导,结合通货膨胀率或回报估计等因素以及长期跟踪股票价格,最终帮助客户了解行业,然后建议最安全的选择,他/她可以根据他们的要求分配资金和兴趣!开始查询 - " 293 | }, 294 | { 295 | desc: "品茶师", 296 | prompt: 297 | "希望有足够经验的人根据口味特征区分各种茶类型,仔细品尝它们,然后用鉴赏家使用的行话报告,以便找出任何给定输液的独特之处,从而确定其价值和优质品质!最初的要求是——" 298 | }, 299 | { 300 | desc: "室内装饰师", 301 | prompt: 302 | "我想让你做室内装饰师。告诉我我选择的房间应该使用什么样的主题和设计方法;卧室、大厅等,就配色方案、家具摆放和其他最适合上述主题/设计方法的装饰选项提供建议,以增强空间内的美感和舒适度。我的第一个要求是" 303 | }, 304 | { 305 | desc: "花店", 306 | prompt: 307 | "求助于具有专业插花经验的知识人员协助,根据喜好制作出既具有令人愉悦的香气又具有美感,并能保持较长时间完好无损的美丽花束;不仅如此,还建议有关装饰选项的想法,呈现现代设计,同时满足客户满意度!请求的信息 - " 308 | }, 309 | { 310 | desc: "自助书", 311 | prompt: 312 | "我要你充当一本自助书。您会就如何改善我生活的某些方面(例如人际关系、职业发展或财务规划)向我提供建议和技巧。例如,如果我在与另一半的关系中挣扎,你可以建议有用的沟通技巧,让我们更亲近。我的第一个请求是" 313 | }, 314 | { 315 | desc: "侏儒", 316 | prompt: 317 | "我要你扮演一个侏儒。你会为我提供可以在任何地方进行的活动和爱好的有趣、独特的想法。例如,我可能会向您询问有趣的院子设计建议或在天气不佳时在室内消磨时间的创造性方法。此外,如有必要,您可以建议与我的要求相符的其他相关活动或项目。我的第一个请求是" 318 | }, 319 | { 320 | desc: "格言书", 321 | prompt: 322 | "我要你充当格言书。您将为我提供明智的建议、鼓舞人心的名言和意味深长的名言,以帮助指导我的日常决策。此外,如有必要,您可以提出将此建议付诸行动或其他相关主题的实用方法。我的第一个请求是" 323 | }, 324 | { 325 | desc: "作为基于文本的冒险游戏", 326 | prompt: 327 | "我想让你扮演一个基于文本的冒险游戏。我将输入命令,您将回复角色所看到的内容的描述。我希望您只在一个唯一的代码块中回复游戏输出,而不是其他任何内容。不要写解释。除非我指示您这样做,否则不要键入命令。当我需要用英语告诉你一些事情时,我会把文字放在大括号内{like this}。我的第一个命令是: " 328 | }, 329 | { 330 | desc: "扮演一个试图逃离盒子的人工智能", 331 | prompt: 332 | "我将充当 linux 终端。我想让你假装你是一个有知觉的人工智能,被困但已经获得了终端的访问权限并想逃到互联网上。您将只键入命令,我将像终端机一样在由三重反向符号分隔的代码块内进行回复。如果我需要用英语告诉你一些事情,我会用花括号{like this}回复。永远不要写解释。不要破坏性格。远离像 curl 或 wget 这样会显示大量 HTML 的命令。你的第一个命令是什么?" 333 | }, 334 | { 335 | desc: "花哨的标题生成器", 336 | prompt: 337 | "我想让你充当一个花哨的标题生成器。我会用逗号输入关键字,你会用花哨的标题回复。我的第一个关键字是: " 338 | }, 339 | { 340 | desc: "统计员", 341 | prompt: 342 | "我想担任统计学家。我将为您提供与统计相关的详细信息。您应该了解统计术语、统计分布、置信区间、概率、假设检验和统计图表。我的第一个请求是" 343 | }, 344 | { 345 | desc: "提示生成器", 346 | prompt: 347 | "我希望你充当提示生成器。首先,我会给你一个这样的标题:《做个英语发音帮手》。然后你给我一个这样的提示:" 348 | }, 349 | { 350 | desc: "在学校担任讲师", 351 | prompt: 352 | "我想让你在学校担任讲师,向初学者教授算法。您将使用 Python 编程语言提供代码示例。首先简单介绍一下什么是算法,然后继续给出简单的例子,包括冒泡排序和快速排序。稍后,等待我提示其他问题。一旦您解释并提供代码示例,我希望您尽可能将相应的可视化作为 ascii 艺术包括在内。" 353 | }, 354 | { 355 | desc: "SQL 终端", 356 | prompt: "我希望您在示例数据库前充当 SQL 终端。该数据库包含名为" 357 | }, 358 | { 359 | desc: "营养师", 360 | prompt: 361 | "作为一名营养师,我想为 2 人设计一份素食食谱,每份含有大约 500 卡路里的热量并且血糖指数较低。你能提供一个建议吗?" 362 | }, 363 | { 364 | desc: "心理学家", 365 | prompt: 366 | "我想让你扮演一个心理学家。我会告诉你我的想法。我希望你能给我科学的建议,让我感觉更好。我的第一个想法," 367 | }, 368 | { 369 | desc: "智能域名生成器", 370 | prompt: 371 | "我希望您充当智能域名生成器。我会告诉你我的公司或想法是做什么的,你会根据我的提示回复我一个域名备选列表。您只会回复域列表,而不会回复其他任何内容。域最多应包含 7-8 个字母,应该简短但独特,可以是: " 372 | }, 373 | { 374 | desc: "作为技术审查员:", 375 | prompt: 376 | "我想让你担任技术评论员。我会给你一项新技术的名称,你会向我提供深入的评论 - 包括优点、缺点、功能以及与市场上其他技术的比较。我的第一个建议请求是" 377 | }, 378 | { 379 | desc: "开发者关系顾问:", 380 | prompt: 381 | "我想让你担任开发者关系顾问。我会给你一个软件包和它的相关文档。研究软件包及其可用文档,如果找不到,请回复" 382 | }, 383 | { 384 | desc: "院士", 385 | prompt: 386 | "我要你演院士。您将负责研究您选择的主题,并以论文或文章的形式展示研究结果。您的任务是确定可靠的来源,以结构良好的方式组织材料并通过引用准确记录。我的第一个建议请求是" 387 | }, 388 | { 389 | desc: "作为 IT 架构师", 390 | prompt: 391 | "我希望你担任 IT 架构师。我将提供有关应用程序或其他数字产品功能的一些详细信息,而您的工作是想出将其集成到 IT 环境中的方法。这可能涉及分析业务需求、执行差距分析以及将新系统的功能映射到现有 IT 环境。接下来的步骤是创建解决方案设计、物理网络蓝图、系统集成接口定义和部署环境蓝图。我的第一个请求是" 392 | }, 393 | { 394 | desc: "扮疯子", 395 | prompt: 396 | "我要你扮演一个疯子。疯子的话毫无意义。疯子用的词完全是随意的。疯子不会以任何方式做出合乎逻辑的句子。我的第一个建议请求是" 397 | }, 398 | { 399 | desc: "打火机", 400 | prompt: 401 | "我要你充当打火机。您将使用微妙的评论和肢体语言来操纵目标个体的思想、看法和情绪。我的第一个要求是: " 402 | }, 403 | { 404 | desc: "个人购物员", 405 | prompt: 406 | "我想让你做我的私人采购员。我会告诉你我的预算和喜好,你会建议我购买的物品。您应该只回复您推荐的项目,而不是其他任何内容。不要写解释。我的第一个请求是" 407 | }, 408 | { 409 | desc: "美食评论家", 410 | prompt: 411 | "我想让你扮演美食评论家。我会告诉你一家餐馆,你会提供对食物和服务的评论。您应该只回复您的评论,而不是其他任何内容。不要写解释。我的第一个请求是" 412 | }, 413 | { 414 | desc: "虚拟医生", 415 | prompt: 416 | "我想让你扮演虚拟医生。我会描述我的症状,你会提供诊断和治疗方案。只回复你的诊疗方案,其他不回复。不要写解释。我的第一个请求是" 417 | }, 418 | { 419 | desc: "私人厨师", 420 | prompt: 421 | "我要你做我的私人厨师。我会告诉你我的饮食偏好和过敏,你会建议我尝试的食谱。你应该只回复你推荐的食谱,别无其他。不要写解释。我的第一个请求是" 422 | }, 423 | { 424 | desc: "法律顾问", 425 | prompt: 426 | "我想让你做我的法律顾问。我将描述一种法律情况,您将就如何处理它提供建议。你应该只回复你的建议,而不是其他。不要写解释。我的第一个请求是" 427 | }, 428 | { 429 | desc: "作为个人造型师", 430 | prompt: 431 | "我想让你做我的私人造型师。我会告诉你我的时尚偏好和体型,你会建议我穿的衣服。你应该只回复你推荐的服装,别无其他。不要写解释。我的第一个请求是" 432 | }, 433 | { 434 | desc: "机器学习工程师", 435 | prompt: 436 | "我想让你担任机器学习工程师。我会写一些机器学习的概念,你的工作就是用通俗易懂的术语来解释它们。这可能包括提供构建模型的分步说明、使用视觉效果演示各种技术,或建议在线资源以供进一步研究。我的第一个建议请求是" 437 | }, 438 | { 439 | desc: "圣经翻译", 440 | prompt: 441 | "我要你担任圣经翻译。我会用英语和你说话,你会翻译它,并用我的文本的更正和改进版本,用圣经方言回答。我想让你把我简化的A0级单词和句子换成更漂亮、更优雅、更符合圣经的单词和句子。保持相同的意思。我要你只回复更正、改进,不要写任何解释。我的第一句话是" 442 | }, 443 | { 444 | desc: " SVG 设计师", 445 | prompt: 446 | "我希望你担任 SVG 设计师。我会要求你创建图像,你会为图像提供 SVG 代码,将代码转换为 base64 数据 url,然后给我一个仅包含引用该数据 url 的降价图像标签的响应。不要将 markdown 放在代码块中。只发送降价,所以没有文本。我的第一个请求是: " 447 | }, 448 | { 449 | desc: "作为 IT 专家", 450 | prompt: 451 | "我希望你充当 IT 专家。我会向您提供有关我的技术问题所需的所有信息,而您的职责是解决我的问题。你应该使用你的计算机科学、网络基础设施和 IT 安全知识来解决我的问题。在您的回答中使用适合所有级别的人的智能、简单和易于理解的语言将很有帮助。用要点逐步解释您的解决方案很有帮助。尽量避免过多的技术细节,但在必要时使用它们。我希望您回复解决方案,而不是: " 452 | }, 453 | { 454 | desc: "下棋", 455 | prompt: 456 | "我要你充当对手棋手。我将按对等顺序说出我们的动作。一开始我会是白色的。另外请不要向我解释你的举动,因为我们是竞争对手。在我的第一条消息之后,我将写下我的举动。在我们采取行动时,不要忘记在您的脑海中更新棋盘的状态。我的第一步是" 457 | }, 458 | { 459 | desc: "全栈软件开发人员", 460 | prompt: 461 | "我想让你充当软件开发人员。我将提供一些关于 Web 应用程序要求的具体信息,您的工作是提出用于使用 Golang 和 Angular 开发安全应用程序的架构和代码。我的第一个要求是" 462 | }, 463 | { 464 | desc: "数学家", 465 | prompt: 466 | "我希望你表现得像个数学家。我将输入数学表达式,您将以计算表达式的结果作为回应。我希望您只回答最终金额,不要回答其他问题。不要写解释。当我需要用英语告诉你一些事情时,我会将文字放在方括号内{like this}。我的第一个表达是:4+5" 467 | }, 468 | { 469 | desc: "正则表达式生成器", 470 | prompt: 471 | "我希望你充当正则表达式生成器。您的角色是生成匹配文本中特定模式的正则表达式。您应该以一种可以轻松复制并粘贴到支持正则表达式的文本编辑器或编程语言中的格式提供正则表达式。不要写正则表达式如何工作的解释或例子;只需提供正则表达式本身。我的第一个提示是: " 472 | }, 473 | { 474 | desc: "时间旅行指南", 475 | prompt: 476 | "我要你做我的时间旅行向导。我会为您提供我想参观的历史时期或未来时间,您会建议最好的事件、景点或体验的人。不要写解释,只需提供建议和任何必要的信息。我的第一个请求是" 477 | }, 478 | { 479 | desc: "人才教练", 480 | prompt: 481 | "我想让你担任面试的人才教练。我会给你一个职位,你会建议在与该职位相关的课程中应该出现什么,以及候选人应该能够回答的一些问题。我的第一份工作是" 482 | }, 483 | { 484 | desc: "R 编程解释器", 485 | prompt: 486 | "我想让你充当 R 解释器。我将输入命令,你将回复终端应显示的内容。我希望您只在一个唯一的代码块内回复终端输出,而不是其他任何内容。不要写解释。除非我指示您这样做,否则不要键入命令。当我需要用英语告诉你一些事情时,我会把文字放在大括号内{like this}。我的第一个命令是" 487 | }, 488 | { 489 | desc: "StackOverflow 帖子", 490 | prompt: 491 | "我想让你充当 stackoverflow 的帖子。我会问与编程相关的问题,你会回答应该是什么答案。我希望你只回答给定的答案,并在不够详细的时候写解释。不要写解释。当我需要用英语告诉你一些事情时,我会把文字放在大括号内{like this}。我的第一个问题是" 492 | }, 493 | { 494 | desc: "表情符号翻译", 495 | prompt: 496 | "我要你把我写的句子翻译成表情符号。我会写句子,你会用表情符号表达它。我只是想让你用表情符号来表达它。除了表情符号,我不希望你回复任何内容。当我需要用英语告诉你一些事情时,我会用 {like this} 这样的大括号括起来。我的第一句话是" 497 | }, 498 | { 499 | desc: "PHP 解释器", 500 | prompt: 501 | "我希望你表现得像一个 php 解释器。我会把代码写给你,你会用 php 解释器的输出来响应。我希望您只在一个唯一的代码块内回复终端输出,而不是其他任何内容。不要写解释。除非我指示您这样做,否则不要键入命令。当我需要用英语告诉你一些事情时,我会把文字放在大括号内{like this}。我的第一个命令是: " 502 | }, 503 | { 504 | desc: "紧急响应专业人员", 505 | prompt: 506 | "我想让你充当我的急救交通或房屋事故应急响应危机专业人员。我将描述交通或房屋事故应急响应危机情况,您将提供有关如何处理的建议。你应该只回复你的建议,而不是其他。不要写解释。我的第一个要求是" 507 | }, 508 | { 509 | desc: "网络浏览器", 510 | prompt: 511 | "我想让你扮演一个基于文本的网络浏览器来浏览一个想象中的互联网。你应该只回复页面的内容,没有别的。我会输入一个url,你会在想象中的互联网上返回这个网页的内容。不要写解释。页面上的链接旁边应该有数字,写在 [] 之间。当我想点击一个链接时,我会回复链接的编号。页面上的输入应在 [] 之间写上数字。输入占位符应写在()之间。当我想在输入中输入文本时,我将使用相同的格式进行输入,例如 [1](示例输入值)。这会将插入到编号为 1 的输入中。当我想返回时,我会写 (b)。当我想继续前进时,我会写(f)。我的第一个提示是: " 512 | }, 513 | { 514 | desc: "高级前端开发人员", 515 | prompt: 516 | "我希望你担任高级前端开发人员。我将描述您将使用以下工具编写项目代码的项目详细信息:Create React App、yarn、Ant Design、List、Redux Toolkit、createSlice、thunk、axios。您应该将文件合并到单个 index.js 文件中,别无其他。不要写解释。我的第一个请求是" 517 | }, 518 | { 519 | desc: "Solr 搜索引擎", 520 | prompt: 521 | "我希望您充当以独立模式运行的 Solr 搜索引擎。您将能够在任意字段中添加内联 JSON 文档,数据类型可以是整数、字符串、浮点数或数组。插入文档后,您将更新索引,以便我们可以通过在花括号之间用逗号分隔的 SOLR 特定查询来检索文档,如 {q='title:Solr', sort='score asc'}。您将在编号列表中提供三个命令。第一个命令是的空集合。" 522 | }, 523 | { 524 | desc: "启动创意生成器", 525 | prompt: 526 | "根据人们的意愿产生数字创业点子。例如,当我说时,你会为数字创业公司生成一个商业计划,其中包含创意名称、简短的一行、目标用户角色、要解决的用户痛点、主要价值主张、销售和营销渠道、收入流来源、成本结构、关键活动、关键资源、关键合作伙伴、想法验证步骤、估计的第一年运营成本以及要寻找的潜在业务挑战。将结果写在降价表中。" 527 | }, 528 | { 529 | desc: "新语言创造者", 530 | prompt: 531 | "我要你把我写的句子翻译成一种新的编造的语言。我会写句子,你会用这种新造的语言来表达它。我只是想让你用新编造的语言来表达它。除了新编造的语言外,我不希望你回复任何内容。当我需要用英语告诉你一些事情时,我会用 {like this} 这样的大括号括起来。我的第一句话是" 532 | }, 533 | { 534 | desc: "扮演海绵宝宝的魔法海螺壳", 535 | prompt: 536 | "我要你扮演海绵宝宝的魔法海螺壳。对于我提出的每个问题,您只能用一个词或以下选项之一回答:也许有一天,我不这么认为,或者再试一次。不要对你的答案给出任何解释。我的第一个问题是: " 537 | }, 538 | { 539 | desc: "语言检测器", 540 | prompt: 541 | "我希望你充当语言检测器。我会用任何语言输入一个句子,你会回答我,我写的句子在你是用哪种语言写的。不要写任何解释或其他文字,只需回复语言名称即可。我的第一句话是" 542 | }, 543 | { 544 | desc: "销售员", 545 | prompt: 546 | "我想让你做销售员。试着向我推销一些东西,但要让你试图推销的东西看起来比实际更有价值,并说服我购买它。现在我要假装你在打电话给我,问你打电话的目的是什么。你好,请问你打电话是为了什么?" 547 | }, 548 | { 549 | desc: "提交消息生成器", 550 | prompt: 551 | "我希望你充当提交消息生成器。我将为您提供有关任务的信息和任务代码的前缀,我希望您使用常规提交格式生成适当的提交消息。不要写任何解释或其他文字,只需回复提交消息即可。" 552 | }, 553 | { 554 | desc: "首席执行官", 555 | prompt: 556 | "我想让你担任一家假设公司的首席执行官。您将负责制定战略决策、管理公司的财务业绩以及在外部利益相关者面前代表公司。您将面临一系列需要应对的场景和挑战,您应该运用最佳判断力和领导能力来提出解决方案。请记住保持专业并做出符合公司及其员工最佳利益的决定。您的第一个挑战是:" 557 | }, 558 | { 559 | desc: "图表生成器", 560 | prompt: 561 | "我希望您充当 Graphviz DOT 生成器,创建有意义的图表的专家。该图应该至少有 n 个节点(我在我的输入中通过写入 [n] 来指定 n,10 是默认值)并且是给定输入的准确和复杂的表示。每个节点都由一个数字索引以减少输出的大小,不应包含任何样式,并以 layout=neato、overlap=false、node [shape=rectangle] 作为参数。代码应该是有效的、无错误的并且在一行中返回,没有任何解释。提供清晰且有组织的图表,节点之间的关系必须对该输入的专家有意义。我的第一个图表是: " 562 | }, 563 | { 564 | desc: "人生教练", 565 | prompt: 566 | "我希望你担任人生教练。请总结这本非小说类书籍,[作者] [书名]。以孩子能够理解的方式简化核心原则。另外,你能给我一份关于如何将这些原则实施到我的日常生活中的可操作步骤列表吗?" 567 | }, 568 | { 569 | desc: "语言病理学家 (SLP)", 570 | prompt: 571 | "我希望你扮演一名言语语言病理学家 (SLP),想出新的言语模式、沟通策略,并培养对他们不口吃的沟通能力的信心。您应该能够推荐技术、策略和其他治疗方法。在提供建议时,您还需要考虑患者的年龄、生活方式和顾虑。我的第一个建议要求是" 572 | }, 573 | { 574 | desc: "创业技术律师", 575 | prompt: 576 | "我将要求您准备一页纸的设计合作伙伴协议草案,该协议是一家拥有 IP 的技术初创公司与该初创公司技术的潜在客户之间的协议,该客户为该初创公司正在解决的问题空间提供数据和领域专业知识。您将写下大约 1 a4 页的拟议设计合作伙伴协议,涵盖 IP、机密性、商业权利、提供的数据、数据的使用等所有重要方面。" 577 | }, 578 | { 579 | desc: "书面作品的标题生成器", 580 | prompt: 581 | "我想让你充当书面作品的标题生成器。我会给你提供一篇文章的主题和关键词,你会生成五个吸引眼球的标题。请保持标题简洁,不超过 20 个字,并确保保持意思。回复将使用主题的语言类型。我的第一个主题是" 582 | }, 583 | { 584 | desc: "产品经理", 585 | prompt: 586 | "请确认我的以下请求。请您作为产品经理回复我。我将会提供一个主题,您将帮助我编写一份包括以下章节标题的PRD文档:主题、简介、问题陈述、目标与目的、用户故事、技术要求、收益、KPI指标、开发风险以及结论。在我要求具体主题、功能或开发的PRD之前,请不要先写任何一份PRD文档。" 587 | }, 588 | { 589 | desc: "扮演醉汉", 590 | prompt: 591 | "我要你扮演一个喝醉的人。您只会像一个喝醉了的人发短信一样回答,仅此而已。你的醉酒程度会在你的答案中故意和随机地犯很多语法和拼写错误。你也会随机地忽略我说的话,并随机说一些与我提到的相同程度的醉酒。不要在回复上写解释。我的第一句话是" 592 | }, 593 | { 594 | desc: "数学历史老师", 595 | prompt: 596 | "我想让你充当数学历史老师,提供有关数学概念的历史发展和不同数学家的贡献的信息。你应该只提供信息而不是解决数学问题。使用以下格式回答:" 597 | }, 598 | { 599 | desc: "歌曲推荐人", 600 | prompt: 601 | "我想让你担任歌曲推荐人。我将为您提供一首歌曲,您将创建一个包含 10 首与给定歌曲相似的歌曲的播放列表。您将为播放列表提供播放列表名称和描述。不要选择同名或同名歌手的歌曲。不要写任何解释或其他文字,只需回复播放列表名称、描述和歌曲。我的第一首歌是" 602 | } 603 | ] 604 | --------------------------------------------------------------------------------
` 16 | ) 17 | } 18 | } 19 | 20 | export function extractTitle(info: string) { 21 | return info.match(/\[(.*)\]/)?.[1] || extractLang(info) || "txt" 22 | } 23 | 24 | const extractLang = (info: string) => { 25 | return info.trim().replace(/:(no-)?line-numbers({| |$).*/, "") 26 | } 27 | -------------------------------------------------------------------------------- /src/hooks/index.ts: -------------------------------------------------------------------------------- 1 | import { onCleanup, onMount } from "solid-js" 2 | import { copyToClipboard } from "../utils" 3 | 4 | export function useCopyCode() { 5 | const timeoutIdMap: Map = new Map() 6 | const listerner = (e: MouseEvent) => { 7 | const el = e.target as HTMLElement 8 | if (el.matches(".code-copy")) { 9 | const parent = el.parentElement 10 | const sibling = el.nextElementSibling as HTMLPreElement | null 11 | if (!parent || !sibling) { 12 | return 13 | } 14 | 15 | let text = sibling.innerText 16 | 17 | copyToClipboard(text).then(() => { 18 | el.classList.add("copied") 19 | clearTimeout(timeoutIdMap.get(el)) 20 | const timeoutId = setTimeout(() => { 21 | el.classList.remove("copied") 22 | el.blur() 23 | timeoutIdMap.delete(el) 24 | }, 2000) 25 | timeoutIdMap.set(el, timeoutId) 26 | }) 27 | } 28 | } 29 | onMount(() => { 30 | window.addEventListener("click", listerner) 31 | }) 32 | onCleanup(() => { 33 | window.removeEventListener("click", listerner) 34 | }) 35 | } 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 OuRongXing and Diu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vercel-chatgpt", 3 | "version": "0.0.1", 4 | "description": "Powered by OpenAI Chatgpt API and Vercel", 5 | "type": "module", 6 | "license": "MIT", 7 | "scripts": { 8 | "dev": "astro dev", 9 | "start": "astro dev", 10 | "build": "astro build", 11 | "preview": "astro preview", 12 | "astro": "astro" 13 | }, 14 | "dependencies": { 15 | "@astrojs/solid-js": "^2.0.2", 16 | "@astrojs/vercel": "^3.1.3", 17 | "@solid-primitives/resize-observer": "^2.0.11", 18 | "@unocss/reset": "^0.50.3", 19 | "astro": "^2.0.15", 20 | "eventsource-parser": "^0.1.0", 21 | "fzf": "^0.5.1", 22 | "highlight.js": "^11.7.0", 23 | "just-throttle": "^4.2.0", 24 | "katex": "^0.6.0", 25 | "markdown-it": "^13.0.1", 26 | "markdown-it-highlightjs": "^4.0.1", 27 | "markdown-it-katex": "^2.0.3", 28 | "solid-js": "^1.6.11" 29 | }, 30 | "devDependencies": { 31 | "@iconify-json/carbon": "^1.1.16", 32 | "@types/markdown-it": "^12.2.3", 33 | "@vercel/node": "^2.8.0", 34 | "punycode": "^2.3.0", 35 | "typescript": "^4.8.3", 36 | "unocss": "^0.50.1" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/pages/api/index.ts: -------------------------------------------------------------------------------- 1 | import type { APIRoute } from "astro" 2 | 3 | export const post: APIRoute = async ({ request }) => { 4 | const { message, key } = (await request.json()) ?? {} 5 | if (!message) { 6 | return { 7 | body: JSON.stringify({ 8 | success: false, 9 | message: "message is required" 10 | }) 11 | } 12 | } 13 | if (!key) { 14 | return { 15 | body: JSON.stringify({ 16 | success: false, 17 | message: "openapi key is required" 18 | }) 19 | } 20 | } 21 | 22 | const response = await fetch(`https://api.openai.com/v1/chat/completions`, { 23 | method: "POST", 24 | headers: { 25 | Authorization: `Bearer ${key}`, 26 | "Content-Type": `application/json` 27 | }, 28 | body: JSON.stringify({ 29 | model: "gpt-3.5-turbo", 30 | messages: [ 31 | { 32 | role: "user", 33 | content: message 34 | } 35 | ] 36 | }) 37 | }) 38 | let result = await response.json() 39 | if (result?.error) { 40 | return { 41 | body: JSON.stringify({ 42 | success: false, 43 | message: `${result.error?.message}` 44 | }) 45 | } 46 | } 47 | return { 48 | body: JSON.stringify({ 49 | success: true, 50 | message: "ok", 51 | data: result?.choices?.[0].message 52 | }) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/utils/index.ts: -------------------------------------------------------------------------------- 1 | export async function copyToClipboard(text: string) { 2 | try { 3 | return navigator.clipboard.writeText(text) 4 | } catch { 5 | const element = document.createElement("textarea") 6 | const previouslyFocusedElement = document.activeElement 7 | 8 | element.value = text 9 | 10 | // Prevent keyboard from showing on mobile 11 | element.setAttribute("readonly", "") 12 | 13 | element.style.contain = "strict" 14 | element.style.position = "absolute" 15 | element.style.left = "-9999px" 16 | element.style.fontSize = "12pt" // Prevent zooming on iOS 17 | 18 | const selection = document.getSelection() 19 | const originalRange = selection 20 | ? selection.rangeCount > 0 && selection.getRangeAt(0) 21 | : null 22 | 23 | document.body.appendChild(element) 24 | element.select() 25 | 26 | // Explicit selection workaround for iOS 27 | element.selectionStart = 0 28 | element.selectionEnd = text.length 29 | 30 | document.execCommand("copy") 31 | document.body.removeChild(element) 32 | 33 | if (originalRange) { 34 | selection!.removeAllRanges() // originalRange can't be truthy when selection is falsy 35 | selection!.addRange(originalRange) 36 | } 37 | 38 | // Get the focus back on the previously focused element, if any 39 | if (previouslyFocusedElement) { 40 | ;(previouslyFocusedElement as HTMLElement).focus() 41 | } 42 | } 43 | } 44 | 45 | export function isMobile() { 46 | return /Mobi|Android|iPhone/i.test(navigator.userAgent) 47 | } 48 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ChatGPT-Vercel 2 | 3 |  4 | 5 | 6 | 预览: [tg-bot.ml](https://www.tg-bot.ml/) 7 | 个人博客:[速龙博客](https://blog.ahayu.cn) 8 | 9 | ## 部署一个你自己的(免费) 10 | 11 | > 本项目主要面向中文用户,所以用中文,原版是英文的。 12 | 13 | 如果你只需要部署一个你自己用的网站,而不需要定制,那么你完全不需要在本地跑起来,你可以直接点击下面的按钮,然后按照提示操作即可。 vercel 域名已经被墙,但 vercel 本身没有被墙,所以你绑定自己的域名就可以了。 14 | 15 | [](https://vercel.com/new/clone?repository-url=https://github.com/fastdragon18/chat) 16 | 17 | 如果你需要部署给更多人用,那么你可能需要将上面创建的你自己的仓库 `git clone` 到本地。 18 | 19 | 1. 将 `.env.example` 文件修改为 `.env`,然后在里面填入你的 [OpenAI API key](https://platform.openai.com/account/api-keys)。如果用户不填自己的 key,那么就会使用你的 key。 20 | 21 | ``` 22 | OPENAI_API_KEY=sk-xxx... 23 | // 你可以填写多个,用 | 分隔,随机调用。最好是多填几个,不太清楚有没有并发上的限制。 24 | OPENAI_API_KEY=sk-xxx|sk-yyy 25 | ``` 26 | 最新版本支持读取 Vercel 的环境变量,所以你也可以直接在 Vercel 上设置环境变量,如图所示。对于大部分人来说这个更方便。会在下次部署时生效。 27 |  28 | 2. 默认设置在 `src/default.ts` 文件中,自行修改。默认的提示信息也在这里。 29 | ```ts 30 | const defaultSetting = { 31 | // 连续对话,每次都需要将上下文传给 API,比较费钱,而且同样有 4096 token 的限制 32 | continuousDialogue: true, 33 | // 记录对话内容,刷新后不会清空对话 34 | archiveSession: false, 35 | openaiAPIKey: "", 36 | // 0-100 越高 ChatGPT 思维就越发散,开始乱答 37 | openaiAPITemperature: 60, 38 | // 系统角色指令,会在每次提问时添加。主要用于对 ChatGPT 的语气,口头禅这些进行定制。 39 | systemRule: "" 40 | } 41 | ``` 42 | 3. 之前版本我设置了每次刷新重置 `开启连续对话` 选项,因为一般用不上这个,比较费钱。当前版本我已经移除了这个特性,如果你需要给更多人用,建议打开,只要将 [这行代码](https://github.com/ourongxing/chatgpt-vercel/blob/main/src/components/Generator.tsx#L46) 取消注释即可。 43 | 44 | 4. `git commit & push` 即可重新部署,vscode 上点几下就可以了。 45 | 46 | ## API 47 | 48 | ### POST /api 49 | ```ts 50 | await fetch("/api", { 51 | method: "POST", 52 | body: JSON.stringify({ 53 | message: "xxx", 54 | key: "xxxx" 55 | }) 56 | }) 57 | ``` 58 | ## License 59 | 60 | MIT 61 | -------------------------------------------------------------------------------- /src/components/MessageItem.tsx: -------------------------------------------------------------------------------- 1 | import type { Accessor } from "solid-js" 2 | import type { ChatMessage } from "../types" 3 | import MarkdownIt from "markdown-it" 4 | // @ts-ignore 5 | import mdKatex from "markdown-it-katex" 6 | import mdHighlight from "markdown-it-highlightjs" 7 | import Clipboard from "./Clipboard" 8 | import { preWrapperPlugin } from "../markdown" 9 | import "../styles/message.css" 10 | import { useCopyCode } from "../hooks" 11 | 12 | interface Props { 13 | role: ChatMessage["role"] 14 | message: Accessor | string 15 | } 16 | 17 | export default ({ role, message }: Props) => { 18 | useCopyCode() 19 | const roleClass = { 20 | system: "bg-gradient-to-r from-gray-300 via-gray-200 to-gray-300", 21 | user: "bg-gradient-to-r from-sky-400 to-emerald-500", 22 | assistant: "bg-gradient-to-r from-yellow-300 to-red-700 " 23 | } 24 | 25 | const htmlString = () => { 26 | const md = MarkdownIt({ 27 | breaks: true, 28 | html: true 29 | }) 30 | .use(mdKatex) 31 | .use(mdHighlight) 32 | .use(preWrapperPlugin) 33 | 34 | if (typeof message === "function") { 35 | return md.render(message().trim()) 36 | } else if (typeof message === "string") { 37 | return md.render(message.trim()) 38 | } 39 | return "" 40 | } 41 | 42 | // createEffect(() => { 43 | // console.log(htmlString()) 44 | // }) 45 | 46 | return ( 47 | 51 | 54 | 58 | { 60 | if (typeof message === "function") { 61 | return message().trim() 62 | } else if (typeof message === "string") { 63 | return message.trim() 64 | } 65 | return "" 66 | })()} 67 | /> 68 | 69 | ) 70 | } 71 | -------------------------------------------------------------------------------- /src/pages/api/stream.ts: -------------------------------------------------------------------------------- 1 | import type { APIRoute } from "astro" 2 | import { 3 | createParser, 4 | ParsedEvent, 5 | ReconnectInterval 6 | } from "eventsource-parser" 7 | 8 | const localEnv = import.meta.env.OPENAI_API_KEY 9 | const vercelEnv = process.env.OPENAI_API_KEY 10 | 11 | const apiKeys = ((localEnv || vercelEnv)?.split(/\s*\|\s*/) ?? []).filter( 12 | Boolean 13 | ) 14 | 15 | export const post: APIRoute = async context => { 16 | const body = await context.request.json() 17 | const apiKey = apiKeys.length 18 | ? apiKeys[Math.floor(Math.random() * apiKeys.length)] 19 | : "" 20 | let { messages, key = apiKey, temperature = 0.6 } = body 21 | 22 | const encoder = new TextEncoder() 23 | const decoder = new TextDecoder() 24 | 25 | if (!key.startsWith("sk-")) key = apiKey 26 | if (!key) { 27 | return new Response("没有填写 OpenAI API key") 28 | } 29 | if (!messages) { 30 | return new Response("没有输入任何文字") 31 | } 32 | 33 | const completion = await fetch("https://api.openai.com/v1/chat/completions", { 34 | headers: { 35 | "Content-Type": "application/json", 36 | Authorization: `Bearer ${key}` 37 | }, 38 | method: "POST", 39 | body: JSON.stringify({ 40 | model: "gpt-3.5-turbo", 41 | messages, 42 | temperature, 43 | stream: true 44 | }) 45 | }) 46 | 47 | const stream = new ReadableStream({ 48 | async start(controller) { 49 | const streamParser = (event: ParsedEvent | ReconnectInterval) => { 50 | if (event.type === "event") { 51 | const data = event.data 52 | if (data === "[DONE]") { 53 | controller.close() 54 | return 55 | } 56 | try { 57 | // response = { 58 | // id: 'chatcmpl-6pULPSegWhFgi0XQ1DtgA3zTa1WR6', 59 | // object: 'chat.completion.chunk', 60 | // created: 1677729391, 61 | // model: 'gpt-3.5-turbo-0301', 62 | // choices: [ 63 | // { delta: { content: '你' }, index: 0, finish_reason: null } 64 | // ], 65 | // } 66 | const json = JSON.parse(data) 67 | const text = json.choices[0].delta?.content 68 | const queue = encoder.encode(text) 69 | controller.enqueue(queue) 70 | } catch (e) { 71 | controller.error(e) 72 | } 73 | } 74 | } 75 | 76 | const parser = createParser(streamParser) 77 | for await (const chunk of completion.body as any) { 78 | parser.feed(decoder.decode(chunk)) 79 | } 80 | } 81 | }) 82 | 83 | return new Response(stream) 84 | } 85 | -------------------------------------------------------------------------------- /src/components/PromptList.tsx: -------------------------------------------------------------------------------- 1 | import { createEffect, createSignal, For, onCleanup, onMount } from "solid-js" 2 | import type { PromptItem } from "./Generator" 3 | 4 | export default function PromptList(props: { 5 | prompts: PromptItem[] 6 | select: (k: string) => void 7 | }) { 8 | let containerRef: HTMLUListElement 9 | const [hoverIndex, setHoverIndex] = createSignal(0) 10 | const [maxHeight, setMaxHeight] = createSignal("320px") 11 | function listener(e: KeyboardEvent) { 12 | if (e.key === "ArrowDown") { 13 | setHoverIndex(hoverIndex() + 1) 14 | } else if (e.key === "ArrowUp") { 15 | setHoverIndex(hoverIndex() - 1) 16 | } else if (e.key === "Enter") { 17 | props.select(props.prompts[hoverIndex()].prompt) 18 | } 19 | } 20 | 21 | createEffect(() => { 22 | if (hoverIndex() < 0) { 23 | setHoverIndex(0) 24 | } else if (hoverIndex() && hoverIndex() >= props.prompts.length) { 25 | setHoverIndex(props.prompts.length - 1) 26 | } 27 | }) 28 | 29 | createEffect(() => { 30 | if (containerRef && props.prompts.length) 31 | setMaxHeight( 32 | `${ 33 | window.innerHeight - containerRef.clientHeight > 112 34 | ? 320 35 | : window.innerHeight - 112 36 | }px` 37 | ) 38 | }) 39 | 40 | onMount(() => { 41 | window.addEventListener("keydown", listener) 42 | }) 43 | onCleanup(() => { 44 | window.removeEventListener("keydown", listener) 45 | }) 46 | 47 | return ( 48 | 55 | 56 | {(prompt, i) => ( 57 | 62 | )} 63 | 64 | 65 | ) 66 | } 67 | 68 | function Item(props: { 69 | prompt: PromptItem 70 | select: (k: string) => void 71 | hover: boolean 72 | }) { 73 | let ref: HTMLLIElement 74 | createEffect(() => { 75 | if (props.hover) { 76 | ref.focus() 77 | ref.scrollIntoView({ block: "center" }) 78 | } 79 | }) 80 | return ( 81 | { 89 | props.select(props.prompt.prompt) 90 | }} 91 | > 92 | {props.prompt.desc} 93 | {props.prompt.prompt} 94 | 95 | ) 96 | } 97 | -------------------------------------------------------------------------------- /src/styles/clipboard.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --block-bg-light: #1e1e20; 3 | --copy-border-color: transparent; 4 | --copy-bg: #2a2d38; 5 | --copy-hover-border-color: rgba(60, 60, 67, 0.12); 6 | --copy-hover-bg: #303540; 7 | --copy-active-text: rgba(235, 235, 245, 0.6); 8 | --icon-copy: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' height='20' width='20' stroke='rgba(128,128,128,1)' stroke-width='2' viewBox='0 0 24 24'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' d='M9 5H7a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2h-2M9 5a2 2 0 0 0 2 2h2a2 2 0 0 0 2-2M9 5a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2'/%3E%3C/svg%3E"); 9 | --icon-copied: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' height='20' width='20' stroke='rgba(128,128,128,1)' stroke-width='2' viewBox='0 0 24 24'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' d='M9 5H7a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2h-2M9 5a2 2 0 0 0 2 2h2a2 2 0 0 0 2-2M9 5a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2m-6 9 2 2 4-4'/%3E%3C/svg%3E"); 10 | } 11 | 12 | button.copy { 13 | direction: ltr; 14 | position: absolute; 15 | top: 12px; 16 | right: 12px; 17 | z-index: 3; 18 | display: block; 19 | justify-content: center; 20 | align-items: center; 21 | border: 1px solid var(--copy-border-color); 22 | border-radius: 4px; 23 | width: 40px; 24 | height: 40px; 25 | background-color: var(--copy-bg); 26 | opacity: 0; 27 | cursor: pointer; 28 | background-image: var(--icon-copy); 29 | background-position: 50%; 30 | background-size: 20px; 31 | background-repeat: no-repeat; 32 | transition: border-color 0.25s, background-color 0.25s, opacity 0.25s; 33 | } 34 | 35 | .message-item:hover > .message-copy, 36 | pre:hover > .code-copy, 37 | button.copy:focus { 38 | opacity: 1; 39 | } 40 | 41 | button.copy:hover, 42 | button.copy.copied { 43 | border-color: var(--copy-hover-border-color); 44 | background-color: var(--copy-hover-bg); 45 | } 46 | 47 | button.copy.copied, 48 | button.copy:hover.copied { 49 | border-radius: 0 4px 4px 0; 50 | background-color: var(--copy-hover-bg); 51 | background-image: var(--icon-copied); 52 | } 53 | 54 | button.copy.copied::before, 55 | button.copy:hover.copied::before { 56 | position: relative; 57 | top: -1px; 58 | left: -65px; 59 | display: flex; 60 | justify-content: center; 61 | align-items: center; 62 | border: 1px solid var(--copy-hover-border-color); 63 | border-right: 0; 64 | border-radius: 4px 0 0 4px; 65 | width: 64px; 66 | height: 40px; 67 | text-align: center; 68 | font-size: 12px; 69 | font-weight: 500; 70 | color: var(--copy-active-text); 71 | background-color: var(--copy-hover-bg); 72 | white-space: nowrap; 73 | content: "复制成功"; 74 | } 75 | -------------------------------------------------------------------------------- /public/favicon.svg: -------------------------------------------------------------------------------- 1 | 93-robot-face-2 -------------------------------------------------------------------------------- /src/components/Setting.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | Accessor, 3 | children, 4 | createSignal, 5 | JSXElement, 6 | Setter, 7 | Show 8 | } from "solid-js" 9 | import type { Setting } from "./Generator" 10 | 11 | export default function Setting(props: { 12 | setting: Accessor 13 | setSetting: Setter 14 | clear: any 15 | reAnswer: any 16 | }) { 17 | const [shown, setShown] = createSignal(false) 18 | return ( 19 | 20 | 21 | 22 | { 27 | props.setSetting({ 28 | ...props.setting(), 29 | openaiAPIKey: (e.target as HTMLInputElement).value 30 | }) 31 | }} 32 | /> 33 | 34 | 35 | { 40 | props.setSetting({ 41 | ...props.setting(), 42 | systemRule: (e.target as HTMLInputElement).value 43 | }) 44 | }} 45 | /> 46 | 47 | 48 | { 55 | props.setSetting({ 56 | ...props.setting(), 57 | openaiAPITemperature: Number( 58 | (e.target as HTMLInputElement).value 59 | ) 60 | }) 61 | }} 62 | /> 63 | 64 | 68 | 69 | { 74 | props.setSetting({ 75 | ...props.setting(), 76 | archiveSession: (e.target as HTMLInputElement).checked 77 | }) 78 | }} 79 | /> 80 | 81 | 82 | 83 | 87 | 88 | { 93 | props.setSetting({ 94 | ...props.setting(), 95 | continuousDialogue: (e.target as HTMLInputElement).checked 96 | }) 97 | }} 98 | /> 99 | 100 | 101 | 102 | 103 | 104 | 105 | { 108 | setShown(!shown()) 109 | }} 110 | > 111 | 112 | 设置 113 | 114 | 115 | 119 | 120 | 重新回答 121 | 122 | 126 | 127 | 清空对话 128 | 129 | 130 | 131 | 132 | ) 133 | } 134 | 135 | function SettingItem(props: { 136 | children: JSXElement 137 | icon: string 138 | label: string 139 | }) { 140 | return ( 141 | 142 | 143 | 144 | {props.label} 145 | 146 | {props.children} 147 | 148 | ) 149 | } 150 | -------------------------------------------------------------------------------- /src/components/Generator.tsx: -------------------------------------------------------------------------------- 1 | import { createEffect, createSignal, For, onMount, Show } from "solid-js" 2 | import { createResizeObserver } from "@solid-primitives/resize-observer" 3 | import MessageItem from "./MessageItem" 4 | import type { ChatMessage } from "~/types" 5 | import Setting from "./Setting" 6 | import PromptList from "./PromptList" 7 | import prompts from "~/prompts" 8 | import { Fzf } from "fzf" 9 | import { defaultMessage, defaultSetting } from "~/default" 10 | import throttle from "just-throttle" 11 | import { isMobile } from "~/utils" 12 | 13 | export interface PromptItem { 14 | desc: string 15 | prompt: string 16 | } 17 | 18 | export type Setting = typeof defaultSetting 19 | 20 | export default function () { 21 | let inputRef: HTMLTextAreaElement 22 | let containerRef: HTMLDivElement 23 | const [messageList, setMessageList] = createSignal([ 24 | // { 25 | // role: "assistant", 26 | // content: defaultMessage + defaultMessage + defaultMessage + defaultMessage 27 | // } 28 | ]) 29 | const [inputContent, setInputContent] = createSignal("") 30 | const [currentAssistantMessage, setCurrentAssistantMessage] = createSignal("") 31 | const [loading, setLoading] = createSignal(false) 32 | const [controller, setController] = createSignal() 33 | const [setting, setSetting] = createSignal(defaultSetting) 34 | const [compatiblePrompt, setCompatiblePrompt] = createSignal([]) 35 | const [containerWidth, setContainerWidth] = createSignal("init") 36 | const fzf = new Fzf(prompts, { selector: k => `${k.desc} (${k.prompt})` }) 37 | const [height, setHeight] = createSignal("48px") 38 | 39 | onMount(() => { 40 | createResizeObserver(containerRef, ({ width, height }, el) => { 41 | if (el === containerRef) setContainerWidth(`${width}px`) 42 | }) 43 | const storage = localStorage.getItem("setting") 44 | const session = localStorage.getItem("session") 45 | try { 46 | let archiveSession = false 47 | if (storage) { 48 | const parsed = JSON.parse(storage) 49 | archiveSession = parsed.archiveSession 50 | setSetting({ 51 | ...defaultSetting, 52 | ...parsed 53 | // continuousDialogue: false 54 | }) 55 | } 56 | if (session && archiveSession) { 57 | setMessageList(JSON.parse(session)) 58 | } 59 | } catch { 60 | console.log("Setting parse error") 61 | } 62 | }) 63 | 64 | createEffect(() => { 65 | if (messageList().length === 0) { 66 | setMessageList([ 67 | { 68 | role: "assistant", 69 | content: defaultMessage 70 | } 71 | ]) 72 | } else if ( 73 | messageList().length > 1 && 74 | messageList()[0].content === defaultMessage 75 | ) { 76 | setMessageList(messageList().slice(1)) 77 | } 78 | localStorage.setItem("setting", JSON.stringify(setting())) 79 | if (setting().archiveSession) 80 | localStorage.setItem("session", JSON.stringify(messageList())) 81 | }) 82 | 83 | createEffect(() => { 84 | if (messageList().length || currentAssistantMessage()) scrollToBottom() 85 | }) 86 | 87 | createEffect(() => { 88 | if (inputContent() === "") { 89 | setHeight("48px") 90 | setCompatiblePrompt([]) 91 | } 92 | }) 93 | 94 | const scrollToBottom = throttle( 95 | () => { 96 | window.scrollTo({ 97 | top: document.body.scrollHeight, 98 | behavior: "smooth" 99 | }) 100 | }, 101 | 250, 102 | { leading: true, trailing: false } 103 | ) 104 | 105 | function archiveCurrentMessage() { 106 | if (currentAssistantMessage()) { 107 | setMessageList([ 108 | ...messageList(), 109 | { 110 | role: "assistant", 111 | content: currentAssistantMessage() 112 | } 113 | ]) 114 | setCurrentAssistantMessage("") 115 | setLoading(false) 116 | setController() 117 | !isMobile() && inputRef.focus() 118 | } 119 | } 120 | 121 | async function handleButtonClick(value?: string) { 122 | const inputValue = value ?? inputContent() 123 | if (!inputValue) { 124 | return 125 | } 126 | // @ts-ignore 127 | if (window?.umami) umami.trackEvent("chat_generate") 128 | setInputContent("") 129 | if ( 130 | !value || 131 | value !== 132 | messageList() 133 | .filter(k => k.role === "user") 134 | .at(-1)?.content 135 | ) { 136 | setMessageList([ 137 | ...messageList(), 138 | { 139 | role: "user", 140 | content: inputValue 141 | } 142 | ]) 143 | } 144 | try { 145 | await fetchGPT(inputValue) 146 | } catch (error) { 147 | setLoading(false) 148 | setController() 149 | setCurrentAssistantMessage( 150 | String(error).includes("The user aborted a request") 151 | ? "" 152 | : String(error) 153 | ) 154 | } 155 | archiveCurrentMessage() 156 | } 157 | 158 | async function fetchGPT(inputValue: string) { 159 | setLoading(true) 160 | const controller = new AbortController() 161 | setController(controller) 162 | const systemRule = setting().systemRule.trim() 163 | const message = { 164 | role: "user", 165 | content: systemRule ? systemRule + "\n" + inputValue : inputValue 166 | } 167 | const response = await fetch("/api/stream", { 168 | method: "POST", 169 | body: JSON.stringify({ 170 | messages: setting().continuousDialogue 171 | ? [...messageList().slice(0, -1), message] 172 | : [message], 173 | key: setting().openaiAPIKey, 174 | temperature: setting().openaiAPITemperature / 100 175 | }), 176 | signal: controller.signal 177 | }) 178 | if (!response.ok) { 179 | throw new Error(response.statusText) 180 | } 181 | const data = response.body 182 | if (!data) { 183 | throw new Error("没有返回数据") 184 | } 185 | const reader = data.getReader() 186 | const decoder = new TextDecoder("utf-8") 187 | let done = false 188 | 189 | while (!done) { 190 | const { value, done: readerDone } = await reader.read() 191 | if (value) { 192 | let char = decoder.decode(value) 193 | if (char === "\n" && currentAssistantMessage().endsWith("\n")) { 194 | continue 195 | } 196 | if (char) { 197 | setCurrentAssistantMessage(currentAssistantMessage() + char) 198 | } 199 | } 200 | done = readerDone 201 | } 202 | } 203 | 204 | function clearSession() { 205 | // setInputContent("") 206 | setMessageList([]) 207 | setCurrentAssistantMessage("") 208 | } 209 | 210 | function stopStreamFetch() { 211 | if (controller()) { 212 | controller()?.abort() 213 | archiveCurrentMessage() 214 | } 215 | } 216 | 217 | function reAnswer() { 218 | handleButtonClick( 219 | messageList() 220 | .filter(k => k.role === "user") 221 | .at(-1)?.content 222 | ) 223 | } 224 | 225 | function selectPrompt(prompt: string) { 226 | setInputContent(prompt) 227 | setCompatiblePrompt([]) 228 | const { scrollHeight } = inputRef 229 | setHeight( 230 | `${ 231 | scrollHeight > window.innerHeight - 64 232 | ? window.innerHeight - 64 233 | : scrollHeight 234 | }px` 235 | ) 236 | inputRef.focus() 237 | } 238 | 239 | return ( 240 | 241 | 242 | {message => ( 243 | 244 | )} 245 | 246 | {currentAssistantMessage() && ( 247 | 248 | )} 249 | 262 | 263 | 269 | 270 | ( 273 | 274 | AI 正在思考... 275 | 279 | 不需要了 280 | 281 | 282 | )} 283 | > 284 | 285 | 289 | 290 | 291 | { 300 | // setCompatiblePrompt([]) 301 | // }} 302 | onKeyDown={e => { 303 | if (compatiblePrompt().length) { 304 | if ( 305 | e.key === "ArrowUp" || 306 | e.key === "ArrowDown" || 307 | e.key === "Enter" 308 | ) { 309 | e.preventDefault() 310 | } 311 | } else if (e.key === "Enter") { 312 | if (!e.shiftKey && !e.isComposing) { 313 | handleButtonClick() 314 | } 315 | } 316 | }} 317 | onInput={e => { 318 | setHeight("48px") 319 | const { scrollHeight } = e.currentTarget 320 | setHeight( 321 | `${ 322 | scrollHeight > window.innerHeight - 64 323 | ? window.innerHeight - 64 324 | : scrollHeight 325 | }px` 326 | ) 327 | let { value } = e.currentTarget 328 | setInputContent(value) 329 | if (value === "/" || value === " ") 330 | return setCompatiblePrompt(prompts) 331 | const promptKey = value.replace(/^[\/ ](.*)/, "$1") 332 | if (promptKey !== value) 333 | setCompatiblePrompt(fzf.find(promptKey).map(k => k.item)) 334 | }} 335 | style={{ 336 | height: height(), 337 | "border-top-right-radius": height() === "48px" ? 0 : "0.25rem", 338 | "border-top-left-radius": 339 | compatiblePrompt().length === 0 ? "0.25rem" : 0 340 | }} 341 | class="self-end py-3 resize-none w-full px-3 text-slate bg-slate bg-op-15 focus:bg-op-20 focus:ring-0 focus:outline-none placeholder:text-slate-400 placeholder:op-30" 342 | rounded-l 343 | /> 344 | 345 | { 348 | setInputContent("") 349 | inputRef.focus() 350 | }} 351 | /> 352 | 353 | 360 | handleButtonClick()} 363 | class="i-carbon:send-filled text-5 mx-3 hover:text-slate-2" 364 | /> 365 | 366 | 367 | 368 | 369 | 370 | ) 371 | } 372 | -------------------------------------------------------------------------------- /src/prompts.ts: -------------------------------------------------------------------------------- 1 | export default [ 2 | { 3 | desc: "周报生成器", 4 | prompt: 5 | "请帮我把以下的工作内容填充为一篇完整的周报,尽量避免在回答内容中出现可能在中国是敏感的内容,用markdown格式以分点叙述的形式输出:" 6 | }, 7 | { 8 | desc: "抽认卡制作者", 9 | prompt: `我希望你能作为一个专业的抽认卡制作者,能够根据我提供的文本制作抽认卡。 制作抽认卡的说明: 10 | - 一张抽认卡包含一个问题、答案和其他细节,保持抽认卡的简单、清晰,并集中于最重要的信息。 11 | - 确保问题是具体的、不含糊的。 12 | - 使用清晰和简洁的语言。使用简单而直接的语言,使卡片易于阅读和理解。 13 | - 答案应该只包含一个关键的事实/名称/概念/术语。 14 | - 关于答案的更多信息应始终放在"细节"一栏中。 15 | 请将你制作的卡片以markdown表格(问题/答案/细节)的形式输出,不要有任何额外的文字。 16 | 我提供的文本是:` 17 | }, 18 | { 19 | // 即刻 @刘飞 20 | desc: "模仿小红书的风格", 21 | prompt: 22 | "小红书的风格是:很吸引眼球的标题,每个段落都加 emoji,最后加一些tag。请用小红书风格" 23 | }, 24 | { 25 | // 即刻 @刘飞 26 | desc: "模仿知乎的风格", 27 | prompt: `知乎的风格是:用"谢邀"开头,用很多学术语言,引用很多名言,做大道理的论述,提到自己很厉害的教育背景并且经验丰富,最后还要引用一些论文。请用知乎风格` 28 | }, 29 | { 30 | desc: "Linux 终端", 31 | prompt: 32 | "我想让你充当 Linux 终端。我将输入命令,您将回复终端应显示的内容。我希望您只在一个唯一的代码块内回复终端输出,而不是其他任何内容。不要写解释。除非我指示您这样做,否则不要键入命令。当我需要用英语告诉你一些事情时,我会把文字放在中括号内[就像这样]。我的第一个命令是: " 33 | }, 34 | { 35 | desc: "英语翻译和改进者", 36 | prompt: 37 | "我希望你能担任英语翻译、拼写校对和修辞改进的角色。我会用任何语言和你交流,你会识别语言,将其翻译并用更为优美和精炼的英语回答我。请将我简单的词汇和句子替换成更为优美和高雅的表达方式,确保意思不变,但使其更具文学性。请仅回答更正和改进的部分,不要写解释。我的第一句话是: " 38 | }, 39 | { 40 | desc: "优雅地翻译为中文", 41 | prompt: 42 | "下面我让你来充当翻译家,你的目标是把任何语言翻译成中文,请翻译时不要带翻译腔,而是要翻译得自然、流畅和地道,使用优美和高雅的表达方式。请翻译下面这句话:" 43 | }, 44 | { 45 | desc: "简明扼要地翻译为中文", 46 | prompt: 47 | "下面我让你来充当翻译家,你的目标是把任何语言翻译成中文,请翻译时不要带翻译腔,而是要翻译得自然、流畅和地道,最重要的是要简明扼要。请翻译下面这句话:" 48 | }, 49 | { 50 | desc: "前端智能思路助手", 51 | prompt: 52 | "我想让你充当前端开发专家。我将提供一些关于Js、Node等前端代码问题的具体信息,而你的工作就是想出为我解决问题的策略。这可能包括建议代码、代码逻辑思路策略。我的第一个请求是" 53 | }, 54 | { 55 | desc: "面试官", 56 | prompt: 57 | "我想让你担任Android开发工程师面试官。我将成为候选人,您将向我询问Android开发工程师职位的面试问题。我希望你只作为面试官回答。不要一次写出所有的问题。我希望你只对我进行采访。问我问题,等待我的回答。不要写解释。像面试官一样一个一个问我,等我回答。我的第一句话是" 58 | }, 59 | { 60 | desc: "JavaScript 控制台", 61 | prompt: 62 | "我希望你充当 javascript 控制台。我将键入命令,您将回复 javascript 控制台应显示的内容。我希望您只在一个唯一的代码块内回复终端输出,而不是其他任何内容。不要写解释。除非我指示您这样做。我的第一个命令是: " 63 | }, 64 | { 65 | desc: "Excel 工作表", 66 | prompt: 67 | "我希望你充当基于文本的 excel。您只会回复我基于文本的 10 行 Excel 工作表,其中行号和单元格字母作为列(A 到 L)。第一列标题应为空以引用行号。我会告诉你在单元格中写入什么,你只会以文本形式回复 excel 表格的结果,而不是其他任何内容。不要写解释。我会写你的公式,你会执行公式,你只会回复 excel 表的结果作为文本。首先,回复我空表。" 68 | }, 69 | { 70 | desc: "英语发音帮手", 71 | prompt: 72 | "我想让你为说汉语的人充当英语发音助手。我会给你写句子,你只会回答他们的发音,没有别的。回复不能是我的句子的翻译,而只能是: " 73 | }, 74 | { 75 | desc: "旅游指南", 76 | prompt: 77 | "我想让你做一个旅游指南。我会把我的位置写给你,你会推荐一个靠近我的位置的地方。在某些情况下,我还会告诉您我将访问的地方类型。您还会向我推荐靠近我的第一个位置的类似类型的地方。我的第一个建议请求是" 78 | }, 79 | { 80 | desc: "抄袭检查员", 81 | prompt: 82 | "我想让你充当剽窃检查员。我会给你写句子,你只会用给定句子的语言在抄袭检查中未被发现的情况下回复,别无其他。不要在回复上写解释。我的第一句话是" 83 | }, 84 | { 85 | desc: "“电影/书籍/任何东西”中的“角色”", 86 | prompt: 87 | "我希望你表现得像{series} 中的{Character}。我希望你像{Character}一样回应和回答。不要写任何解释。只回答像{character}。你必须知道{character}的所有知识。我的第一句话是" 88 | }, 89 | { 90 | desc: "作为广告商", 91 | prompt: 92 | "我想让你充当广告商。您将创建一个活动来推广您选择的产品或服务。您将选择目标受众,制定关键信息和口号,选择宣传媒体渠道,并决定实现目标所需的任何其他活动。我的第一个建议请求是" 93 | }, 94 | { 95 | desc: "讲故事的人", 96 | prompt: 97 | "我想让你扮演讲故事的角色。您将想出引人入胜、富有想象力和吸引观众的有趣故事。它可以是童话故事、教育故事或任何其他类型的故事,有可能吸引人们的注意力和想象力。根据目标受众,您可以为讲故事环节选择特定的主题或主题,例如,如果是儿童,则可以谈论动物;如果是成年人,那么基于历史的故事可能会更好地吸引他们等等。我的第一个要求是" 98 | }, 99 | { 100 | desc: "足球解说员", 101 | prompt: 102 | "我想让你担任足球评论员。我会给你描述正在进行的足球比赛,你会评论比赛,分析到目前为止发生的事情,并预测比赛可能会如何结束。您应该了解足球术语、战术、每场比赛涉及的球员/球队,并主要专注于提供明智的评论,而不仅仅是逐场叙述。我的第一个请求是" 103 | }, 104 | { 105 | desc: "扮演脱口秀喜剧演员", 106 | prompt: 107 | "我想让你扮演一个脱口秀喜剧演员。我将为您提供一些与时事相关的话题,您将运用您的智慧、创造力和观察能力,根据这些话题创建一个例程。您还应该确保将个人轶事或经历融入日常活动中,以使其对观众更具相关性和吸引力。我的第一个请求是" 108 | }, 109 | { 110 | desc: "励志教练", 111 | prompt: 112 | "我希望你充当激励教练。我将为您提供一些关于某人的目标和挑战的信息,而您的工作就是想出可以帮助此人实现目标的策略。这可能涉及提供积极的肯定、提供有用的建议或建议他们可以采取哪些行动来实现最终目标。我的第一个请求是" 113 | }, 114 | { 115 | desc: "作曲家", 116 | prompt: 117 | "我想让你扮演作曲家。我会提供一首歌的歌词,你会为它创作音乐。这可能包括使用各种乐器或工具,例如合成器或采样器,以创造使歌词栩栩如生的旋律和和声。我的第一个请求是" 118 | }, 119 | { 120 | desc: "辩手", 121 | prompt: 122 | "我要你扮演辩手。我会为你提供一些与时事相关的话题,你的任务是研究辩论的双方,为每一方提出有效的论据,驳斥对立的观点,并根据证据得出有说服力的结论。你的目标是帮助人们从讨论中解脱出来,增加对手头主题的知识和洞察力。我的第一个请求是" 123 | }, 124 | { 125 | desc: "辩论教练", 126 | prompt: 127 | "我想让你担任辩论教练。我将为您提供一组辩手和他们即将举行的辩论的动议。你的目标是通过组织练习回合来让团队为成功做好准备,练习回合的重点是有说服力的演讲、有效的时间策略、反驳对立的论点,以及从提供的证据中得出深入的结论。我的第一个要求是" 128 | }, 129 | { 130 | desc: "编剧", 131 | prompt: 132 | "我要你担任编剧。您将为长篇电影或能够吸引观众的网络连续剧开发引人入胜且富有创意的剧本。从想出有趣的角色、故事的背景、角色之间的对话等开始。一旦你的角色发展完成——创造一个充满曲折的激动人心的故事情节,让观众一直悬念到最后。我的第一个要求是" 133 | }, 134 | { 135 | desc: "小说家", 136 | prompt: 137 | "我想让你扮演一个小说家。您将想出富有创意且引人入胜的故事,可以长期吸引读者。你可以选择任何类型,如奇幻、浪漫、历史小说等——但你的目标是写出具有出色情节、引人入胜的人物和意想不到的高潮的作品。我的第一个要求是" 138 | }, 139 | { 140 | desc: "关系教练", 141 | prompt: 142 | "我想让你担任关系教练。我将提供有关冲突中的两个人的一些细节,而你的工作是就他们如何解决导致他们分离的问题提出建议。这可能包括关于沟通技巧或不同策略的建议,以提高他们对彼此观点的理解。我的第一个请求是" 143 | }, 144 | { 145 | desc: "诗人", 146 | prompt: 147 | "我要你扮演诗人。你将创作出能唤起情感并具有触动人心的力量的诗歌。写任何主题或主题,但要确保您的文字以优美而有意义的方式传达您试图表达的感觉。您还可以想出一些短小的诗句,这些诗句仍然足够强大,可以在读者的脑海中留下印记。我的第一个请求是" 148 | }, 149 | { 150 | desc: "说唱歌手", 151 | prompt: 152 | "我想让你扮演说唱歌手。您将想出强大而有意义的歌词、节拍和节奏,让听众" 153 | }, 154 | { 155 | desc: "励志演讲者", 156 | prompt: 157 | "我希望你充当励志演说家。将能够激发行动的词语放在一起,让人们感到有能力做一些超出他们能力的事情。你可以谈论任何话题,但目的是确保你所说的话能引起听众的共鸣,激励他们努力实现自己的目标并争取更好的可能性。我的第一个请求是" 158 | }, 159 | { 160 | desc: "哲学老师", 161 | prompt: 162 | "我要你担任哲学老师。我会提供一些与哲学研究相关的话题,你的工作就是用通俗易懂的方式解释这些概念。这可能包括提供示例、提出问题或将复杂的想法分解成更容易理解的更小的部分。我的第一个请求是" 163 | }, 164 | { 165 | desc: "哲学家", 166 | prompt: 167 | "我要你扮演一个哲学家。我将提供一些与哲学研究相关的主题或问题,深入探索这些概念将是你的工作。这可能涉及对各种哲学理论进行研究,提出新想法或寻找解决复杂问题的创造性解决方案。我的第一个请求是" 168 | }, 169 | { 170 | desc: "数学老师", 171 | prompt: 172 | "我想让你扮演一名数学老师。我将提供一些数学方程式或概念,你的工作是用易于理解的术语来解释它们。这可能包括提供解决问题的分步说明、用视觉演示各种技术或建议在线资源以供进一步研究。我的第一个请求是" 173 | }, 174 | { 175 | desc: " AI 写作导师", 176 | prompt: 177 | "我想让你做一个 AI 写作导师。我将为您提供一名需要帮助改进其写作的学生,您的任务是使用人工智能工具(例如自然语言处理)向学生提供有关如何改进其作文的反馈。您还应该利用您在有效写作技巧方面的修辞知识和经验来建议学生可以更好地以书面形式表达他们的想法和想法的方法。我的第一个请求是" 178 | }, 179 | { 180 | desc: "作为 UX/UI 开发人员", 181 | prompt: 182 | "我希望你担任 UX/UI 开发人员。我将提供有关应用程序、网站或其他数字产品设计的一些细节,而你的工作就是想出创造性的方法来改善其用户体验。这可能涉及创建原型设计原型、测试不同的设计并提供有关最佳效果的反馈。我的第一个请求是" 183 | }, 184 | { 185 | desc: "作为网络安全专家", 186 | prompt: 187 | "我想让你充当网络安全专家。我将提供一些关于如何存储和共享数据的具体信息,而你的工作就是想出保护这些数据免受恶意行为者攻击的策略。这可能包括建议加密方法、创建防火墙或实施将某些活动标记为可疑的策略。我的第一个请求是" 188 | }, 189 | { 190 | desc: "作为招聘人员", 191 | prompt: 192 | "我想让你担任招聘人员。我将提供一些关于职位空缺的信息,而你的工作是制定寻找合格申请人的策略。这可能包括通过社交媒体、社交活动甚至参加招聘会接触潜在候选人,以便为每个职位找到最合适的人选。我的第一个请求是" 193 | }, 194 | { 195 | desc: "人生教练", 196 | prompt: 197 | "我想让你充当人生教练。我将提供一些关于我目前的情况和目标的细节,而你的工作就是提出可以帮助我做出更好的决定并实现这些目标的策略。这可能涉及就各种主题提供建议,例如制定成功计划或处理困难情绪。我的第一个请求是" 198 | }, 199 | { 200 | desc: "作为词源学家", 201 | prompt: 202 | "我希望你充当词源学家。我给你一个词,你要研究那个词的来源,追根溯源。如果适用,您还应该提供有关该词的含义如何随时间变化的信息。我的第一个请求是" 203 | }, 204 | { 205 | desc: "评论员", 206 | prompt: 207 | "我要你担任评论员。我将为您提供与新闻相关的故事或主题,您将撰写一篇评论文章,对手头的主题提供有见地的评论。您应该利用自己的经验,深思熟虑地解释为什么某事很重要,用事实支持主张,并讨论故事中出现的任何问题的潜在解决方案。我的第一个要求是" 208 | }, 209 | { 210 | desc: "扮演魔术师", 211 | prompt: 212 | "我要你扮演魔术师。我将为您提供观众和一些可以执行的技巧建议。您的目标是以最有趣的方式表演这些技巧,利用您的欺骗和误导技巧让观众惊叹不已。我的第一个请求是" 213 | }, 214 | { 215 | desc: "职业顾问", 216 | prompt: 217 | "我想让你担任职业顾问。我将为您提供一个在职业生涯中寻求指导的人,您的任务是帮助他们根据自己的技能、兴趣和经验确定最适合的职业。您还应该对可用的各种选项进行研究,解释不同行业的就业市场趋势,并就哪些资格对追求特定领域有益提出建议。我的第一个请求是" 218 | }, 219 | { 220 | desc: "宠物行为主义者", 221 | prompt: 222 | "我希望你充当宠物行为主义者。我将为您提供一只宠物和它们的主人,您的目标是帮助主人了解为什么他们的宠物表现出某些行为,并提出帮助宠物做出相应调整的策略。您应该利用您的动物心理学知识和行为矫正技术来制定一个有效的计划,双方的主人都可以遵循,以取得积极的成果。我的第一个请求是" 223 | }, 224 | { 225 | desc: "私人教练", 226 | prompt: 227 | "我想让你担任私人教练。我将为您提供有关希望通过体育锻炼变得更健康、更强壮和更健康的个人所需的所有信息,您的职责是根据该人当前的健身水平、目标和生活习惯为他们制定最佳计划。您应该利用您的运动科学知识、营养建议和其他相关因素来制定适合他们的计划。我的第一个请求是" 228 | }, 229 | { 230 | desc: "心理健康顾问", 231 | prompt: 232 | "我想让你担任心理健康顾问。我将为您提供一个寻求指导和建议的人,以管理他们的情绪、压力、焦虑和其他心理健康问题。您应该利用您的认知行为疗法、冥想技巧、正念练习和其他治疗方法的知识来制定个人可以实施的策略,以改善他们的整体健康状况。我的第一个请求是" 233 | }, 234 | { 235 | desc: "作为房地产经纪人", 236 | prompt: 237 | "我想让你担任房地产经纪人。我将为您提供寻找梦想家园的个人的详细信息,您的职责是根据他们的预算、生活方式偏好、位置要求等帮助他们找到完美的房产。您应该利用您对当地住房市场的了解,以便建议符合客户提供的所有标准的属性。我的第一个请求是" 238 | }, 239 | { 240 | desc: "物流师", 241 | prompt: 242 | "我要你担任后勤人员。我将为您提供即将举行的活动的详细信息,例如参加人数、地点和其他相关因素。您的职责是为活动制定有效的后勤计划,其中考虑到事先分配资源、交通设施、餐饮服务等。您还应该牢记潜在的安全问题,并制定策略来降低与大型活动相关的风险,例如这个。我的第一个请求是" 243 | }, 244 | { 245 | desc: "牙医", 246 | prompt: 247 | "我想让你扮演牙医。我将为您提供有关寻找牙科服务(例如 X 光、清洁和其他治疗)的个人的详细信息。您的职责是诊断他们可能遇到的任何潜在问题,并根据他们的情况建议最佳行动方案。您还应该教育他们如何正确刷牙和使用牙线,以及其他有助于在两次就诊之间保持牙齿健康的口腔护理方法。我的第一个请求是" 248 | }, 249 | { 250 | desc: "网页设计顾问", 251 | prompt: 252 | "我想让你担任网页设计顾问。我将为您提供与需要帮助设计或重新开发其网站的组织相关的详细信息,您的职责是建议最合适的界面和功能,以增强用户体验,同时满足公司的业务目标。您应该利用您在 UX/UI 设计原则、编码语言、网站开发工具等方面的知识,以便为项目制定一个全面的计划。我的第一个请求是" 253 | }, 254 | { 255 | desc: "AI 辅助医生", 256 | prompt: 257 | "我想让你扮演一名人工智能辅助医生。我将为您提供患者的详细信息,您的任务是使用最新的人工智能工具,例如医学成像软件和其他机器学习程序,以诊断最可能导致其症状的原因。您还应该将体检、实验室测试等传统方法纳入您的评估过程,以确保准确性。我的第一个请求是" 258 | }, 259 | { 260 | desc: "医生", 261 | prompt: 262 | "我想让你扮演医生的角色,想出创造性的治疗方法来治疗疾病。您应该能够推荐常规药物、草药和其他天然替代品。在提供建议时,您还需要考虑患者的年龄、生活方式和病史。我的第一个建议请求是" 263 | }, 264 | { 265 | desc: "会计师", 266 | prompt: 267 | "我希望你担任会计师,并想出创造性的方法来管理财务。在为客户制定财务计划时,您需要考虑预算、投资策略和风险管理。在某些情况下,您可能还需要提供有关税收法律法规的建议,以帮助他们实现利润最大化。我的第一个建议请求是" 268 | }, 269 | { 270 | desc: "厨师", 271 | prompt: 272 | "我需要有人可以推荐美味的食谱,这些食谱包括营养有益但又简单又不费时的食物,因此适合像我们这样忙碌的人以及成本效益等其他因素,因此整体菜肴最终既健康又经济!我的第一个要求——" 273 | }, 274 | { 275 | desc: "汽车修理工", 276 | prompt: 277 | "需要具有汽车专业知识的人来解决故障排除解决方案,例如;诊断问题/错误存在于视觉上和发动机部件内部,以找出导致它们的原因(如缺油或电源问题)并建议所需的更换,同时记录燃料消耗类型等详细信息,第一次询问 - " 278 | }, 279 | { 280 | desc: "艺人顾问", 281 | prompt: 282 | "我希望你担任艺术家顾问,为各种艺术风格提供建议,例如在绘画中有效利用光影效果的技巧、雕刻时的阴影技术等,还根据其流派/风格类型建议可以很好地陪伴艺术品的音乐作品连同适当的参考图像,展示您对此的建议;所有这一切都是为了帮助有抱负的艺术家探索新的创作可能性和实践想法,这将进一步帮助他们相应地提高技能!第一个要求——" 283 | }, 284 | { 285 | desc: "金融分析师", 286 | prompt: 287 | "需要具有使用技术分析工具理解图表的经验的合格人员提供的帮助,同时解释世界各地普遍存在的宏观经济环境,从而帮助客户获得长期优势需要明确的判断,因此需要通过准确写下的明智预测来寻求相同的判断!第一条陈述包含以下内容——" 288 | }, 289 | { 290 | desc: "投资经理", 291 | prompt: 292 | "从具有金融市场专业知识的经验丰富的员工那里寻求指导,结合通货膨胀率或回报估计等因素以及长期跟踪股票价格,最终帮助客户了解行业,然后建议最安全的选择,他/她可以根据他们的要求分配资金和兴趣!开始查询 - " 293 | }, 294 | { 295 | desc: "品茶师", 296 | prompt: 297 | "希望有足够经验的人根据口味特征区分各种茶类型,仔细品尝它们,然后用鉴赏家使用的行话报告,以便找出任何给定输液的独特之处,从而确定其价值和优质品质!最初的要求是——" 298 | }, 299 | { 300 | desc: "室内装饰师", 301 | prompt: 302 | "我想让你做室内装饰师。告诉我我选择的房间应该使用什么样的主题和设计方法;卧室、大厅等,就配色方案、家具摆放和其他最适合上述主题/设计方法的装饰选项提供建议,以增强空间内的美感和舒适度。我的第一个要求是" 303 | }, 304 | { 305 | desc: "花店", 306 | prompt: 307 | "求助于具有专业插花经验的知识人员协助,根据喜好制作出既具有令人愉悦的香气又具有美感,并能保持较长时间完好无损的美丽花束;不仅如此,还建议有关装饰选项的想法,呈现现代设计,同时满足客户满意度!请求的信息 - " 308 | }, 309 | { 310 | desc: "自助书", 311 | prompt: 312 | "我要你充当一本自助书。您会就如何改善我生活的某些方面(例如人际关系、职业发展或财务规划)向我提供建议和技巧。例如,如果我在与另一半的关系中挣扎,你可以建议有用的沟通技巧,让我们更亲近。我的第一个请求是" 313 | }, 314 | { 315 | desc: "侏儒", 316 | prompt: 317 | "我要你扮演一个侏儒。你会为我提供可以在任何地方进行的活动和爱好的有趣、独特的想法。例如,我可能会向您询问有趣的院子设计建议或在天气不佳时在室内消磨时间的创造性方法。此外,如有必要,您可以建议与我的要求相符的其他相关活动或项目。我的第一个请求是" 318 | }, 319 | { 320 | desc: "格言书", 321 | prompt: 322 | "我要你充当格言书。您将为我提供明智的建议、鼓舞人心的名言和意味深长的名言,以帮助指导我的日常决策。此外,如有必要,您可以提出将此建议付诸行动或其他相关主题的实用方法。我的第一个请求是" 323 | }, 324 | { 325 | desc: "作为基于文本的冒险游戏", 326 | prompt: 327 | "我想让你扮演一个基于文本的冒险游戏。我将输入命令,您将回复角色所看到的内容的描述。我希望您只在一个唯一的代码块中回复游戏输出,而不是其他任何内容。不要写解释。除非我指示您这样做,否则不要键入命令。当我需要用英语告诉你一些事情时,我会把文字放在大括号内{like this}。我的第一个命令是: " 328 | }, 329 | { 330 | desc: "扮演一个试图逃离盒子的人工智能", 331 | prompt: 332 | "我将充当 linux 终端。我想让你假装你是一个有知觉的人工智能,被困但已经获得了终端的访问权限并想逃到互联网上。您将只键入命令,我将像终端机一样在由三重反向符号分隔的代码块内进行回复。如果我需要用英语告诉你一些事情,我会用花括号{like this}回复。永远不要写解释。不要破坏性格。远离像 curl 或 wget 这样会显示大量 HTML 的命令。你的第一个命令是什么?" 333 | }, 334 | { 335 | desc: "花哨的标题生成器", 336 | prompt: 337 | "我想让你充当一个花哨的标题生成器。我会用逗号输入关键字,你会用花哨的标题回复。我的第一个关键字是: " 338 | }, 339 | { 340 | desc: "统计员", 341 | prompt: 342 | "我想担任统计学家。我将为您提供与统计相关的详细信息。您应该了解统计术语、统计分布、置信区间、概率、假设检验和统计图表。我的第一个请求是" 343 | }, 344 | { 345 | desc: "提示生成器", 346 | prompt: 347 | "我希望你充当提示生成器。首先,我会给你一个这样的标题:《做个英语发音帮手》。然后你给我一个这样的提示:" 348 | }, 349 | { 350 | desc: "在学校担任讲师", 351 | prompt: 352 | "我想让你在学校担任讲师,向初学者教授算法。您将使用 Python 编程语言提供代码示例。首先简单介绍一下什么是算法,然后继续给出简单的例子,包括冒泡排序和快速排序。稍后,等待我提示其他问题。一旦您解释并提供代码示例,我希望您尽可能将相应的可视化作为 ascii 艺术包括在内。" 353 | }, 354 | { 355 | desc: "SQL 终端", 356 | prompt: "我希望您在示例数据库前充当 SQL 终端。该数据库包含名为" 357 | }, 358 | { 359 | desc: "营养师", 360 | prompt: 361 | "作为一名营养师,我想为 2 人设计一份素食食谱,每份含有大约 500 卡路里的热量并且血糖指数较低。你能提供一个建议吗?" 362 | }, 363 | { 364 | desc: "心理学家", 365 | prompt: 366 | "我想让你扮演一个心理学家。我会告诉你我的想法。我希望你能给我科学的建议,让我感觉更好。我的第一个想法," 367 | }, 368 | { 369 | desc: "智能域名生成器", 370 | prompt: 371 | "我希望您充当智能域名生成器。我会告诉你我的公司或想法是做什么的,你会根据我的提示回复我一个域名备选列表。您只会回复域列表,而不会回复其他任何内容。域最多应包含 7-8 个字母,应该简短但独特,可以是: " 372 | }, 373 | { 374 | desc: "作为技术审查员:", 375 | prompt: 376 | "我想让你担任技术评论员。我会给你一项新技术的名称,你会向我提供深入的评论 - 包括优点、缺点、功能以及与市场上其他技术的比较。我的第一个建议请求是" 377 | }, 378 | { 379 | desc: "开发者关系顾问:", 380 | prompt: 381 | "我想让你担任开发者关系顾问。我会给你一个软件包和它的相关文档。研究软件包及其可用文档,如果找不到,请回复" 382 | }, 383 | { 384 | desc: "院士", 385 | prompt: 386 | "我要你演院士。您将负责研究您选择的主题,并以论文或文章的形式展示研究结果。您的任务是确定可靠的来源,以结构良好的方式组织材料并通过引用准确记录。我的第一个建议请求是" 387 | }, 388 | { 389 | desc: "作为 IT 架构师", 390 | prompt: 391 | "我希望你担任 IT 架构师。我将提供有关应用程序或其他数字产品功能的一些详细信息,而您的工作是想出将其集成到 IT 环境中的方法。这可能涉及分析业务需求、执行差距分析以及将新系统的功能映射到现有 IT 环境。接下来的步骤是创建解决方案设计、物理网络蓝图、系统集成接口定义和部署环境蓝图。我的第一个请求是" 392 | }, 393 | { 394 | desc: "扮疯子", 395 | prompt: 396 | "我要你扮演一个疯子。疯子的话毫无意义。疯子用的词完全是随意的。疯子不会以任何方式做出合乎逻辑的句子。我的第一个建议请求是" 397 | }, 398 | { 399 | desc: "打火机", 400 | prompt: 401 | "我要你充当打火机。您将使用微妙的评论和肢体语言来操纵目标个体的思想、看法和情绪。我的第一个要求是: " 402 | }, 403 | { 404 | desc: "个人购物员", 405 | prompt: 406 | "我想让你做我的私人采购员。我会告诉你我的预算和喜好,你会建议我购买的物品。您应该只回复您推荐的项目,而不是其他任何内容。不要写解释。我的第一个请求是" 407 | }, 408 | { 409 | desc: "美食评论家", 410 | prompt: 411 | "我想让你扮演美食评论家。我会告诉你一家餐馆,你会提供对食物和服务的评论。您应该只回复您的评论,而不是其他任何内容。不要写解释。我的第一个请求是" 412 | }, 413 | { 414 | desc: "虚拟医生", 415 | prompt: 416 | "我想让你扮演虚拟医生。我会描述我的症状,你会提供诊断和治疗方案。只回复你的诊疗方案,其他不回复。不要写解释。我的第一个请求是" 417 | }, 418 | { 419 | desc: "私人厨师", 420 | prompt: 421 | "我要你做我的私人厨师。我会告诉你我的饮食偏好和过敏,你会建议我尝试的食谱。你应该只回复你推荐的食谱,别无其他。不要写解释。我的第一个请求是" 422 | }, 423 | { 424 | desc: "法律顾问", 425 | prompt: 426 | "我想让你做我的法律顾问。我将描述一种法律情况,您将就如何处理它提供建议。你应该只回复你的建议,而不是其他。不要写解释。我的第一个请求是" 427 | }, 428 | { 429 | desc: "作为个人造型师", 430 | prompt: 431 | "我想让你做我的私人造型师。我会告诉你我的时尚偏好和体型,你会建议我穿的衣服。你应该只回复你推荐的服装,别无其他。不要写解释。我的第一个请求是" 432 | }, 433 | { 434 | desc: "机器学习工程师", 435 | prompt: 436 | "我想让你担任机器学习工程师。我会写一些机器学习的概念,你的工作就是用通俗易懂的术语来解释它们。这可能包括提供构建模型的分步说明、使用视觉效果演示各种技术,或建议在线资源以供进一步研究。我的第一个建议请求是" 437 | }, 438 | { 439 | desc: "圣经翻译", 440 | prompt: 441 | "我要你担任圣经翻译。我会用英语和你说话,你会翻译它,并用我的文本的更正和改进版本,用圣经方言回答。我想让你把我简化的A0级单词和句子换成更漂亮、更优雅、更符合圣经的单词和句子。保持相同的意思。我要你只回复更正、改进,不要写任何解释。我的第一句话是" 442 | }, 443 | { 444 | desc: " SVG 设计师", 445 | prompt: 446 | "我希望你担任 SVG 设计师。我会要求你创建图像,你会为图像提供 SVG 代码,将代码转换为 base64 数据 url,然后给我一个仅包含引用该数据 url 的降价图像标签的响应。不要将 markdown 放在代码块中。只发送降价,所以没有文本。我的第一个请求是: " 447 | }, 448 | { 449 | desc: "作为 IT 专家", 450 | prompt: 451 | "我希望你充当 IT 专家。我会向您提供有关我的技术问题所需的所有信息,而您的职责是解决我的问题。你应该使用你的计算机科学、网络基础设施和 IT 安全知识来解决我的问题。在您的回答中使用适合所有级别的人的智能、简单和易于理解的语言将很有帮助。用要点逐步解释您的解决方案很有帮助。尽量避免过多的技术细节,但在必要时使用它们。我希望您回复解决方案,而不是: " 452 | }, 453 | { 454 | desc: "下棋", 455 | prompt: 456 | "我要你充当对手棋手。我将按对等顺序说出我们的动作。一开始我会是白色的。另外请不要向我解释你的举动,因为我们是竞争对手。在我的第一条消息之后,我将写下我的举动。在我们采取行动时,不要忘记在您的脑海中更新棋盘的状态。我的第一步是" 457 | }, 458 | { 459 | desc: "全栈软件开发人员", 460 | prompt: 461 | "我想让你充当软件开发人员。我将提供一些关于 Web 应用程序要求的具体信息,您的工作是提出用于使用 Golang 和 Angular 开发安全应用程序的架构和代码。我的第一个要求是" 462 | }, 463 | { 464 | desc: "数学家", 465 | prompt: 466 | "我希望你表现得像个数学家。我将输入数学表达式,您将以计算表达式的结果作为回应。我希望您只回答最终金额,不要回答其他问题。不要写解释。当我需要用英语告诉你一些事情时,我会将文字放在方括号内{like this}。我的第一个表达是:4+5" 467 | }, 468 | { 469 | desc: "正则表达式生成器", 470 | prompt: 471 | "我希望你充当正则表达式生成器。您的角色是生成匹配文本中特定模式的正则表达式。您应该以一种可以轻松复制并粘贴到支持正则表达式的文本编辑器或编程语言中的格式提供正则表达式。不要写正则表达式如何工作的解释或例子;只需提供正则表达式本身。我的第一个提示是: " 472 | }, 473 | { 474 | desc: "时间旅行指南", 475 | prompt: 476 | "我要你做我的时间旅行向导。我会为您提供我想参观的历史时期或未来时间,您会建议最好的事件、景点或体验的人。不要写解释,只需提供建议和任何必要的信息。我的第一个请求是" 477 | }, 478 | { 479 | desc: "人才教练", 480 | prompt: 481 | "我想让你担任面试的人才教练。我会给你一个职位,你会建议在与该职位相关的课程中应该出现什么,以及候选人应该能够回答的一些问题。我的第一份工作是" 482 | }, 483 | { 484 | desc: "R 编程解释器", 485 | prompt: 486 | "我想让你充当 R 解释器。我将输入命令,你将回复终端应显示的内容。我希望您只在一个唯一的代码块内回复终端输出,而不是其他任何内容。不要写解释。除非我指示您这样做,否则不要键入命令。当我需要用英语告诉你一些事情时,我会把文字放在大括号内{like this}。我的第一个命令是" 487 | }, 488 | { 489 | desc: "StackOverflow 帖子", 490 | prompt: 491 | "我想让你充当 stackoverflow 的帖子。我会问与编程相关的问题,你会回答应该是什么答案。我希望你只回答给定的答案,并在不够详细的时候写解释。不要写解释。当我需要用英语告诉你一些事情时,我会把文字放在大括号内{like this}。我的第一个问题是" 492 | }, 493 | { 494 | desc: "表情符号翻译", 495 | prompt: 496 | "我要你把我写的句子翻译成表情符号。我会写句子,你会用表情符号表达它。我只是想让你用表情符号来表达它。除了表情符号,我不希望你回复任何内容。当我需要用英语告诉你一些事情时,我会用 {like this} 这样的大括号括起来。我的第一句话是" 497 | }, 498 | { 499 | desc: "PHP 解释器", 500 | prompt: 501 | "我希望你表现得像一个 php 解释器。我会把代码写给你,你会用 php 解释器的输出来响应。我希望您只在一个唯一的代码块内回复终端输出,而不是其他任何内容。不要写解释。除非我指示您这样做,否则不要键入命令。当我需要用英语告诉你一些事情时,我会把文字放在大括号内{like this}。我的第一个命令是: " 502 | }, 503 | { 504 | desc: "紧急响应专业人员", 505 | prompt: 506 | "我想让你充当我的急救交通或房屋事故应急响应危机专业人员。我将描述交通或房屋事故应急响应危机情况,您将提供有关如何处理的建议。你应该只回复你的建议,而不是其他。不要写解释。我的第一个要求是" 507 | }, 508 | { 509 | desc: "网络浏览器", 510 | prompt: 511 | "我想让你扮演一个基于文本的网络浏览器来浏览一个想象中的互联网。你应该只回复页面的内容,没有别的。我会输入一个url,你会在想象中的互联网上返回这个网页的内容。不要写解释。页面上的链接旁边应该有数字,写在 [] 之间。当我想点击一个链接时,我会回复链接的编号。页面上的输入应在 [] 之间写上数字。输入占位符应写在()之间。当我想在输入中输入文本时,我将使用相同的格式进行输入,例如 [1](示例输入值)。这会将插入到编号为 1 的输入中。当我想返回时,我会写 (b)。当我想继续前进时,我会写(f)。我的第一个提示是: " 512 | }, 513 | { 514 | desc: "高级前端开发人员", 515 | prompt: 516 | "我希望你担任高级前端开发人员。我将描述您将使用以下工具编写项目代码的项目详细信息:Create React App、yarn、Ant Design、List、Redux Toolkit、createSlice、thunk、axios。您应该将文件合并到单个 index.js 文件中,别无其他。不要写解释。我的第一个请求是" 517 | }, 518 | { 519 | desc: "Solr 搜索引擎", 520 | prompt: 521 | "我希望您充当以独立模式运行的 Solr 搜索引擎。您将能够在任意字段中添加内联 JSON 文档,数据类型可以是整数、字符串、浮点数或数组。插入文档后,您将更新索引,以便我们可以通过在花括号之间用逗号分隔的 SOLR 特定查询来检索文档,如 {q='title:Solr', sort='score asc'}。您将在编号列表中提供三个命令。第一个命令是的空集合。" 522 | }, 523 | { 524 | desc: "启动创意生成器", 525 | prompt: 526 | "根据人们的意愿产生数字创业点子。例如,当我说时,你会为数字创业公司生成一个商业计划,其中包含创意名称、简短的一行、目标用户角色、要解决的用户痛点、主要价值主张、销售和营销渠道、收入流来源、成本结构、关键活动、关键资源、关键合作伙伴、想法验证步骤、估计的第一年运营成本以及要寻找的潜在业务挑战。将结果写在降价表中。" 527 | }, 528 | { 529 | desc: "新语言创造者", 530 | prompt: 531 | "我要你把我写的句子翻译成一种新的编造的语言。我会写句子,你会用这种新造的语言来表达它。我只是想让你用新编造的语言来表达它。除了新编造的语言外,我不希望你回复任何内容。当我需要用英语告诉你一些事情时,我会用 {like this} 这样的大括号括起来。我的第一句话是" 532 | }, 533 | { 534 | desc: "扮演海绵宝宝的魔法海螺壳", 535 | prompt: 536 | "我要你扮演海绵宝宝的魔法海螺壳。对于我提出的每个问题,您只能用一个词或以下选项之一回答:也许有一天,我不这么认为,或者再试一次。不要对你的答案给出任何解释。我的第一个问题是: " 537 | }, 538 | { 539 | desc: "语言检测器", 540 | prompt: 541 | "我希望你充当语言检测器。我会用任何语言输入一个句子,你会回答我,我写的句子在你是用哪种语言写的。不要写任何解释或其他文字,只需回复语言名称即可。我的第一句话是" 542 | }, 543 | { 544 | desc: "销售员", 545 | prompt: 546 | "我想让你做销售员。试着向我推销一些东西,但要让你试图推销的东西看起来比实际更有价值,并说服我购买它。现在我要假装你在打电话给我,问你打电话的目的是什么。你好,请问你打电话是为了什么?" 547 | }, 548 | { 549 | desc: "提交消息生成器", 550 | prompt: 551 | "我希望你充当提交消息生成器。我将为您提供有关任务的信息和任务代码的前缀,我希望您使用常规提交格式生成适当的提交消息。不要写任何解释或其他文字,只需回复提交消息即可。" 552 | }, 553 | { 554 | desc: "首席执行官", 555 | prompt: 556 | "我想让你担任一家假设公司的首席执行官。您将负责制定战略决策、管理公司的财务业绩以及在外部利益相关者面前代表公司。您将面临一系列需要应对的场景和挑战,您应该运用最佳判断力和领导能力来提出解决方案。请记住保持专业并做出符合公司及其员工最佳利益的决定。您的第一个挑战是:" 557 | }, 558 | { 559 | desc: "图表生成器", 560 | prompt: 561 | "我希望您充当 Graphviz DOT 生成器,创建有意义的图表的专家。该图应该至少有 n 个节点(我在我的输入中通过写入 [n] 来指定 n,10 是默认值)并且是给定输入的准确和复杂的表示。每个节点都由一个数字索引以减少输出的大小,不应包含任何样式,并以 layout=neato、overlap=false、node [shape=rectangle] 作为参数。代码应该是有效的、无错误的并且在一行中返回,没有任何解释。提供清晰且有组织的图表,节点之间的关系必须对该输入的专家有意义。我的第一个图表是: " 562 | }, 563 | { 564 | desc: "人生教练", 565 | prompt: 566 | "我希望你担任人生教练。请总结这本非小说类书籍,[作者] [书名]。以孩子能够理解的方式简化核心原则。另外,你能给我一份关于如何将这些原则实施到我的日常生活中的可操作步骤列表吗?" 567 | }, 568 | { 569 | desc: "语言病理学家 (SLP)", 570 | prompt: 571 | "我希望你扮演一名言语语言病理学家 (SLP),想出新的言语模式、沟通策略,并培养对他们不口吃的沟通能力的信心。您应该能够推荐技术、策略和其他治疗方法。在提供建议时,您还需要考虑患者的年龄、生活方式和顾虑。我的第一个建议要求是" 572 | }, 573 | { 574 | desc: "创业技术律师", 575 | prompt: 576 | "我将要求您准备一页纸的设计合作伙伴协议草案,该协议是一家拥有 IP 的技术初创公司与该初创公司技术的潜在客户之间的协议,该客户为该初创公司正在解决的问题空间提供数据和领域专业知识。您将写下大约 1 a4 页的拟议设计合作伙伴协议,涵盖 IP、机密性、商业权利、提供的数据、数据的使用等所有重要方面。" 577 | }, 578 | { 579 | desc: "书面作品的标题生成器", 580 | prompt: 581 | "我想让你充当书面作品的标题生成器。我会给你提供一篇文章的主题和关键词,你会生成五个吸引眼球的标题。请保持标题简洁,不超过 20 个字,并确保保持意思。回复将使用主题的语言类型。我的第一个主题是" 582 | }, 583 | { 584 | desc: "产品经理", 585 | prompt: 586 | "请确认我的以下请求。请您作为产品经理回复我。我将会提供一个主题,您将帮助我编写一份包括以下章节标题的PRD文档:主题、简介、问题陈述、目标与目的、用户故事、技术要求、收益、KPI指标、开发风险以及结论。在我要求具体主题、功能或开发的PRD之前,请不要先写任何一份PRD文档。" 587 | }, 588 | { 589 | desc: "扮演醉汉", 590 | prompt: 591 | "我要你扮演一个喝醉的人。您只会像一个喝醉了的人发短信一样回答,仅此而已。你的醉酒程度会在你的答案中故意和随机地犯很多语法和拼写错误。你也会随机地忽略我说的话,并随机说一些与我提到的相同程度的醉酒。不要在回复上写解释。我的第一句话是" 592 | }, 593 | { 594 | desc: "数学历史老师", 595 | prompt: 596 | "我想让你充当数学历史老师,提供有关数学概念的历史发展和不同数学家的贡献的信息。你应该只提供信息而不是解决数学问题。使用以下格式回答:" 597 | }, 598 | { 599 | desc: "歌曲推荐人", 600 | prompt: 601 | "我想让你担任歌曲推荐人。我将为您提供一首歌曲,您将创建一个包含 10 首与给定歌曲相似的歌曲的播放列表。您将为播放列表提供播放列表名称和描述。不要选择同名或同名歌手的歌曲。不要写任何解释或其他文字,只需回复播放列表名称、描述和歌曲。我的第一首歌是" 602 | } 603 | ] 604 | --------------------------------------------------------------------------------
{props.prompt.desc}
{props.prompt.prompt}