resolve conflict
This commit is contained in:
commit
c51de32384
|
@ -2,13 +2,14 @@ name: Upstream Sync
|
||||||
|
|
||||||
on:
|
on:
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '0 */12 * * *' # every 12 hours
|
- cron: "0 */6 * * *" # every 6 hours
|
||||||
workflow_dispatch: # on button click
|
workflow_dispatch:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
sync_latest_from_upstream:
|
sync_latest_from_upstream:
|
||||||
name: Sync latest commits from upstream repo
|
name: Sync latest commits from upstream repo
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
if: ${{ github.event.repository.fork }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
# Step 1: run a standard checkout action, provided by github
|
# Step 1: run a standard checkout action, provided by github
|
||||||
|
|
|
@ -182,16 +182,8 @@ docker run -d -p 3000:3000 -e OPENAI_API_KEY="" -e CODE="" yidadaa/chatgpt-next-
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## 捐赠 Donate USDT
|
|
||||||
|
|
||||||
> BNB Smart Chain (BEP 20)
|
|
||||||
|
|
||||||
```
|
|
||||||
0x67cD02c7EB62641De576a1fA3EdB32eA0c3ffD89
|
|
||||||
```
|
|
||||||
|
|
||||||
## 鸣谢 Special Thanks
|
## 鸣谢 Special Thanks
|
||||||
|
|
||||||
### 捐赠者 Sponsor
|
### 捐赠者 Sponsor
|
||||||
|
|
||||||
[@mushan0x0](https://github.com/mushan0x0)
|
[@mushan0x0](https://github.com/mushan0x0)
|
||||||
|
|
|
@ -8,6 +8,15 @@ async function createStream(req: NextRequest) {
|
||||||
|
|
||||||
const res = await requestOpenai(req);
|
const res = await requestOpenai(req);
|
||||||
|
|
||||||
|
const contentType = res.headers.get("Content-Type") ?? "";
|
||||||
|
if (!contentType.includes("stream")) {
|
||||||
|
const content = await (
|
||||||
|
await res.text()
|
||||||
|
).replace(/provided:.*. You/, "provided: ***. You");
|
||||||
|
console.log("[Stream] error ", content);
|
||||||
|
return "```json\n" + content + "```";
|
||||||
|
}
|
||||||
|
|
||||||
const stream = new ReadableStream({
|
const stream = new ReadableStream({
|
||||||
async start(controller) {
|
async start(controller) {
|
||||||
function onParse(event: any) {
|
function onParse(event: any) {
|
||||||
|
|
|
@ -452,7 +452,7 @@ export function Chat(props: {}) {
|
||||||
role: "user",
|
role: "user",
|
||||||
content: userInput,
|
content: userInput,
|
||||||
date: new Date().toLocaleString(),
|
date: new Date().toLocaleString(),
|
||||||
preview: false,
|
preview: true,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
: [],
|
: [],
|
||||||
|
@ -460,6 +460,12 @@ export function Chat(props: {}) {
|
||||||
|
|
||||||
const [showPromptModal, setShowPromptModal] = useState(false);
|
const [showPromptModal, setShowPromptModal] = useState(false);
|
||||||
|
|
||||||
|
// Auto focus
|
||||||
|
useEffect(() => {
|
||||||
|
if (sidebarCollapse && isMobileScreen()) return;
|
||||||
|
inputRef.current?.focus();
|
||||||
|
}, [sidebarCollapse]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.chat} key={session.id}>
|
<div className={styles.chat} key={session.id}>
|
||||||
<div className={styles["window-header"]}>
|
<div className={styles["window-header"]}>
|
||||||
|
@ -525,6 +531,7 @@ export function Chat(props: {}) {
|
||||||
className={styles["chat-body"]}
|
className={styles["chat-body"]}
|
||||||
ref={scrollRef}
|
ref={scrollRef}
|
||||||
onScroll={(e) => onChatBodyScroll(e.currentTarget)}
|
onScroll={(e) => onChatBodyScroll(e.currentTarget)}
|
||||||
|
onTouchStart={() => inputRef.current?.blur()}
|
||||||
>
|
>
|
||||||
{messages.map((message, i) => {
|
{messages.map((message, i) => {
|
||||||
const isUser = message.role === "user";
|
const isUser = message.role === "user";
|
||||||
|
@ -545,10 +552,7 @@ export function Chat(props: {}) {
|
||||||
{Locale.Chat.Typing}
|
{Locale.Chat.Typing}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div
|
<div className={styles["chat-message-item"]}>
|
||||||
className={styles["chat-message-item"]}
|
|
||||||
onMouseOver={() => inputRef.current?.blur()}
|
|
||||||
>
|
|
||||||
{!isUser &&
|
{!isUser &&
|
||||||
!(message.preview || message.content.length === 0) && (
|
!(message.preview || message.content.length === 0) && (
|
||||||
<div className={styles["chat-message-top-actions"]}>
|
<div className={styles["chat-message-top-actions"]}>
|
||||||
|
@ -588,6 +592,7 @@ export function Chat(props: {}) {
|
||||||
if (!isMobileScreen()) return;
|
if (!isMobileScreen()) return;
|
||||||
setUserInput(message.content);
|
setUserInput(message.content);
|
||||||
}}
|
}}
|
||||||
|
onMouseOver={() => inputRef.current?.blur()}
|
||||||
>
|
>
|
||||||
<Markdown content={message.content} />
|
<Markdown content={message.content} />
|
||||||
</div>
|
</div>
|
||||||
|
@ -622,6 +627,9 @@ export function Chat(props: {}) {
|
||||||
setAutoScroll(false);
|
setAutoScroll(false);
|
||||||
setTimeout(() => setPromptHints([]), 500);
|
setTimeout(() => setPromptHints([]), 500);
|
||||||
}}
|
}}
|
||||||
|
onMouseOver={() => {
|
||||||
|
inputRef.current?.focus();
|
||||||
|
}}
|
||||||
autoFocus={sidebarCollapse}
|
autoFocus={sidebarCollapse}
|
||||||
/>
|
/>
|
||||||
<IconButton
|
<IconButton
|
||||||
|
|
|
@ -449,6 +449,7 @@
|
||||||
.chat-input-panel {
|
.chat-input-panel {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
|
padding-top: 5px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,7 +59,7 @@ export function Markdown(props: { content: string }) {
|
||||||
[
|
[
|
||||||
RehypeHighlight,
|
RehypeHighlight,
|
||||||
{
|
{
|
||||||
detect: true,
|
detect: false,
|
||||||
ignoreMissing: true,
|
ignoreMissing: true,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
|
@ -128,6 +128,8 @@
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|
||||||
.toast-content {
|
.toast-content {
|
||||||
|
max-width: 80vw;
|
||||||
|
word-break: break-all;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
background-color: var(--white);
|
background-color: var(--white);
|
||||||
box-shadow: var(--card-shadow);
|
box-shadow: var(--card-shadow);
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import type { ChatRequest, ChatReponse } from "./api/openai/typing";
|
import type { ChatRequest, ChatReponse } from "./api/openai/typing";
|
||||||
import { filterConfig, Message, ModelConfig, useAccessStore } from "./store";
|
import { filterConfig, Message, ModelConfig, useAccessStore } from "./store";
|
||||||
import Locale from "./locales";
|
import Locale from "./locales";
|
||||||
|
import { showToast } from "./components/ui-lib";
|
||||||
|
|
||||||
if (!Array.prototype.at) {
|
if (!Array.prototype.at) {
|
||||||
require("array.prototype.at/auto");
|
require("array.prototype.at/auto");
|
||||||
|
@ -91,8 +92,21 @@ export async function requestUsage() {
|
||||||
try {
|
try {
|
||||||
const response = (await res.json()) as {
|
const response = (await res.json()) as {
|
||||||
total_usage: number;
|
total_usage: number;
|
||||||
|
error?: {
|
||||||
|
type: string;
|
||||||
|
message: string;
|
||||||
};
|
};
|
||||||
return Math.round(response.total_usage) / 100;
|
};
|
||||||
|
|
||||||
|
if (response.error && response.error.type) {
|
||||||
|
showToast(response.error.message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response.total_usage) {
|
||||||
|
response.total_usage = Math.round(response.total_usage) / 100;
|
||||||
|
}
|
||||||
|
return response.total_usage;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("[Request usage] ", error, res.body);
|
console.error("[Request usage] ", error, res.body);
|
||||||
}
|
}
|
||||||
|
|
|
@ -106,7 +106,7 @@ export function filterConfig(oldConfig: ModelConfig): Partial<ModelConfig> {
|
||||||
return isValidModel(x as string);
|
return isValidModel(x as string);
|
||||||
},
|
},
|
||||||
max_tokens(x) {
|
max_tokens(x) {
|
||||||
return isValidNumber(x as number, 100, 4000);
|
return isValidNumber(x as number, 100, 32000);
|
||||||
},
|
},
|
||||||
presence_penalty(x) {
|
presence_penalty(x) {
|
||||||
return isValidNumber(x as number, -2, 2);
|
return isValidNumber(x as number, -2, 2);
|
||||||
|
|
|
@ -190,7 +190,7 @@ input[type="text"] {
|
||||||
appearance: none;
|
appearance: none;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
border: var(--border-in-light);
|
border: var(--border-in-light);
|
||||||
height: 36px;
|
min-height: 36px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
background: var(--white);
|
background: var(--white);
|
||||||
color: var(--black);
|
color: var(--black);
|
||||||
|
|
|
@ -8,16 +8,22 @@
|
||||||
font-family: Consolas, Monaco, "Andale Mono", "Ubuntu Mono", monospace;
|
font-family: Consolas, Monaco, "Andale Mono", "Ubuntu Mono", monospace;
|
||||||
}
|
}
|
||||||
|
|
||||||
pre code.hljs {
|
pre code {
|
||||||
display: block;
|
display: block;
|
||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
padding: 1em;
|
padding: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
code.hljs {
|
code {
|
||||||
padding: 3px 5px;
|
padding: 3px 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.hljs,
|
||||||
|
pre {
|
||||||
|
background: #1a1b26;
|
||||||
|
color: #cbd2ea;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Theme: Tokyo-night-Dark
|
Theme: Tokyo-night-Dark
|
||||||
origin: https://github.com/enkia/tokyo-night-vscode-theme
|
origin: https://github.com/enkia/tokyo-night-vscode-theme
|
||||||
|
@ -99,11 +105,6 @@
|
||||||
color: #c0caf5;
|
color: #c0caf5;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hljs {
|
|
||||||
background: #1a1b26;
|
|
||||||
color: #9aa5ce;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hljs-emphasis {
|
.hljs-emphasis {
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
}
|
}
|
||||||
|
|
20
app/utils.ts
20
app/utils.ts
|
@ -5,15 +5,19 @@ export function trimTopic(topic: string) {
|
||||||
return topic.replace(/[,。!?、,.!?]*$/, "");
|
return topic.replace(/[,。!?、,.!?]*$/, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
export function copyToClipboard(text: string) {
|
export async function copyToClipboard(text: string) {
|
||||||
navigator.clipboard
|
try {
|
||||||
.writeText(text)
|
await navigator.clipboard.writeText(text);
|
||||||
.then((res) => {
|
} catch (error) {
|
||||||
|
const textarea = document.createElement("textarea");
|
||||||
|
textarea.value = text;
|
||||||
|
document.body.appendChild(textarea);
|
||||||
|
textarea.select();
|
||||||
|
document.execCommand("copy");
|
||||||
|
document.body.removeChild(textarea);
|
||||||
|
} finally {
|
||||||
showToast(Locale.Copy.Success);
|
showToast(Locale.Copy.Success);
|
||||||
})
|
}
|
||||||
.catch((err) => {
|
|
||||||
showToast(Locale.Copy.Failed);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function downloadAs(text: string, filename: string) {
|
export function downloadAs(text: string, filename: string) {
|
||||||
|
|
Loading…
Reference in New Issue