Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/src/packages/next/components/openai/chatgpt-help.tsx
Views: 687
import { Alert, Button, Col, Input, Row } from "antd";1import { useRouter } from "next/router";2import { CSSProperties, useRef, useState } from "react";34import OpenAIAvatar from "@cocalc/frontend/components/openai-avatar";5import ProgressEstimate from "@cocalc/frontend/components/progress-estimate";6import Markdown from "@cocalc/frontend/editors/slate/static-markdown";7import { FileContext } from "@cocalc/frontend/lib/file-context";8import InPlaceSignInOrUp from "components/auth/in-place-sign-in-or-up";9import A from "components/misc/A";10import Loading from "components/share/loading";11import apiPost from "lib/api/post";12import { useCustomize } from "lib/customize";1314type State = "input" | "wait";1516const PROMPT = [17"ASSUME I HAVE FULL ACCESS TO COCALC.", // otherwise it says things like "as a large language model I don't have access to cocalc."18"ENCLOSE MATH IN $.", // so math gets typeset nicely19"INCLUDE THE LANGUAGE DIRECTLY AFTER THE TRIPLE BACKTICKS IN ALL MARKDOWN CODE BLOCKS.", // otherwise often we can't evaluate code.20"BE BRIEF.", // since it's slow.21"How can I do the following using CoCalc?", // give the context of how the question the user asks should be answered.22].join(" ");2324export default function ChatGPTHelp({25style,26prompt,27size,28placeholder,29tag = "",30}: {31style?: CSSProperties;32prompt?: string;33size?;34placeholder?: string;35tag?: string;36}) {37const [state, setState] = useState<State>("input");38const [focus, setFocus] = useState<boolean>(false);39const [output, setOutput] = useState<string | null>(null);40const [input, setInput] = useState<string>("");41const [error, setError] = useState<string>("");42const router = useRouter();4344const counterRef = useRef<number>(0);45const { account, jupyterApiEnabled, siteName } = useCustomize();4647const chatgpt = async (value?) => {48if (value == null) {49value = input;50}51if (!value.trim()) return;52const system = `${PROMPT} ${prompt ?? ""}`;53const counter = counterRef.current + 1;54try {55counterRef.current += 1;56setInput(value);57setState("wait");58let output;59try {60({ output } = await apiPost("/llm/evaluate", {61input: value,62system,63tag: `next:${tag}`,64}));65} catch (err) {66if (counterRef.current != counter) return;67setError(`${err}`);68return;69}70if (counterRef.current != counter) return;71setOutput(output);72} finally {73if (counterRef.current != counter) return;74setState("input");75}76};7778function renderAlertErrorDescription() {79return (80<>81{error}82<hr />83OpenAI <A href="https://status.openai.com/">status</A> and{" "}84<A href="https://downdetector.com/status/openai/">downdetector</A>.85</>86);87}8889return (90<FileContext.Provider value={{ jupyterApiEnabled }}>91<Row style={{ margin: "5px 0", ...style }}>92<Col93xs={{ span: 24 }}94md={{ span: 17 }}95style={{ marginBottom: "5px" }}96>97<Input.TextArea98value={input}99maxLength={2000}100onChange={(e) => setInput(e.target.value)}101size={size}102autoSize={{ minRows: focus ? 2 : 1, maxRows: 5 }}103disabled={state == "wait" || account?.account_id == null}104onFocus={() => setFocus(true)}105onBlur={() => setFocus(false)}106placeholder={107placeholder ?? `Ask ChatGPT: how can I do this on ${siteName}?`108}109allowClear110onPressEnter={(e) => {111if (e.shiftKey) {112chatgpt();113}114}}115/>116{account?.account_id == null && (117<InPlaceSignInOrUp118title="ChatGPT"119why="to use ChatGPT"120onSuccess={() => {121router.reload();122}}123/>124)}125</Col>126<Col127xs={{ span: 24, offset: 0 }}128md={{ span: 6, offset: 1 }}129style={{130marginBottom: "5px",131display: "flex",132justifyContent: "center",133}}134>135<Button136disabled={account?.account_id == null}137size={size}138type="primary"139onClick={() => {140if (input?.trim()) {141chatgpt();142}143}}144>145<OpenAIAvatar146size={size == "large" ? 24 : 18}147backgroundColor="transparent"148style={{ marginRight: "5px", marginTop: "-4px" }}149/>150{input?.trim() && focus151? "Shift+Enter"152: size == "large"153? "Ask ChatGPT"154: "ChatGPT"}155</Button>156</Col>157<Col xs={{ span: 24 }} md={{ span: 24 }}>158{error && (159<Alert160style={{ margin: "15px 0" }}161type="error"162message="Error"163showIcon164closable165banner166onClose={() => setError("")}167description={renderAlertErrorDescription()}168/>169)}170{state == "wait" && (171<div style={{ textAlign: "center", margin: "15px 0" }}>172<OpenAIAvatar size={18} /> ChatGPT is figuring out how to do this173using {siteName}...{" "}174<Button175style={{ float: "right" }}176onClick={() => {177counterRef.current += 1; // so result of outstanding request is totally ignored178setState("input");179}}180>181<Loading delay={0}>Cancel...</Loading>182</Button>183<ProgressEstimate seconds={30} />184</div>185)}186{output != null && (187<Alert188type="success"189closable190banner191onClose={() => setOutput("")}192style={{ margin: "15px 0" }}193description={194<div>195<Markdown value={output} />196</div>197}198/>199)}200</Col>201</Row>202</FileContext.Provider>203);204}205206207