Skip to content

Commit

Permalink
Merge pull request #1 from blacksev/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
blacksev committed Dec 25, 2023
2 parents 6a0be4f + 20ff4e3 commit 4412c1f
Show file tree
Hide file tree
Showing 26 changed files with 252 additions and 101 deletions.
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/功能建议.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ assignees: ''

> 为了提高交流效率,我们设立了官方 QQ 群和 QQ 频道,如果你在使用或者搭建过程中遇到了任何问题,请先第一时间加群或者频道咨询解决,除非是可以稳定复现的 Bug 或者较为有创意的功能建议,否则请不要随意往 Issue 区发送低质无意义帖子。
> [点击加入官方群聊](https://github.com/Yidadaa/ChatGPT-Next-Web/discussions/1724)
> [点击加入官方群聊](https://github.com/blacksev/Gemini-Next-Web/discussions/1724)
**这个功能与现有的问题有关吗?**
如果有关,请在此列出链接或者描述问题。
Expand Down
8 changes: 4 additions & 4 deletions .github/ISSUE_TEMPLATE/反馈问题.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,16 @@ assignees: ''

> 为了提高交流效率,我们设立了官方 QQ 群和 QQ 频道,如果你在使用或者搭建过程中遇到了任何问题,请先第一时间加群或者频道咨询解决,除非是可以稳定复现的 Bug 或者较为有创意的功能建议,否则请不要随意往 Issue 区发送低质无意义帖子。
> [点击加入官方群聊](https://github.com/Yidadaa/ChatGPT-Next-Web/discussions/1724)
> [点击加入官方群聊](https://github.com/blacksev/Gemini-Next-Web/discussions/1724)
**反馈须知**

⚠️ 注意:不遵循此模板的任何帖子都会被立即关闭,如果没有提供下方的信息,我们无法定位你的问题。

请在下方中括号内输入 x 来表示你已经知晓相关内容。
- [ ] 我确认已经在 [常见问题](https://github.com/Yidadaa/ChatGPT-Next-Web/blob/main/docs/faq-cn.md) 中搜索了此次反馈的问题,没有找到解答;
- [ ] 我确认已经在 [Issues](https://github.com/Yidadaa/ChatGPT-Next-Web/issues) 列表(包括已经 Close 的)中搜索了此次反馈的问题,没有找到解答。
- [ ] 我确认已经在 [Vercel 使用教程](https://github.com/Yidadaa/ChatGPT-Next-Web/blob/main/docs/vercel-cn.md) 中搜索了此次反馈的问题,没有找到解答。
- [ ] 我确认已经在 [常见问题](https://github.com/blacksev/Gemini-Next-Web/blob/main/docs/faq-cn.md) 中搜索了此次反馈的问题,没有找到解答;
- [ ] 我确认已经在 [Issues](https://github.com/blacksev/Gemini-Next-Web/issues) 列表(包括已经 Close 的)中搜索了此次反馈的问题,没有找到解答。
- [ ] 我确认已经在 [Vercel 使用教程](https://github.com/blacksev/Gemini-Next-Web/blob/main/docs/vercel-cn.md) 中搜索了此次反馈的问题,没有找到解答。

**描述问题**
请在此描述你遇到了什么问题。
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/sync.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
id: sync
uses: aormsby/Fork-Sync-With-Upstream-action@v3.4
with:
upstream_sync_repo: ChatGPTNextWeb/ChatGPT-Next-Web
upstream_sync_repo: blacksev/Gemini-Next-Web
upstream_sync_branch: main
target_sync_branch: main
target_repo_token: ${{ secrets.GITHUB_TOKEN }} # automatically generated, no need to set
Expand All @@ -35,6 +35,6 @@ jobs:
- name: Sync check
if: failure()
run: |
echo "[Error] 由于上游仓库的 workflow 文件变更,导致 GitHub 自动暂停了本次自动更新,你需要手动 Sync Fork 一次,详细教程请查看:https://github.com/Yidadaa/ChatGPT-Next-Web/blob/main/README_CN.md#%E6%89%93%E5%BC%80%E8%87%AA%E5%8A%A8%E6%9B%B4%E6%96%B0"
echo "[Error] Due to a change in the workflow file of the upstream repository, GitHub has automatically suspended the scheduled automatic update. You need to manually sync your fork. Please refer to the detailed tutorial for instructions: https://github.com/Yidadaa/ChatGPT-Next-Web#enable-automatic-updates"
echo "[Error] 由于上游仓库的 workflow 文件变更,导致 GitHub 自动暂停了本次自动更新,你需要手动 Sync Fork 一次,详细教程请查看:https://github.com/blacksev/Gemini-Next-Web/blob/main/README_CN.md#%E6%89%93%E5%BC%80%E8%87%AA%E5%8A%A8%E6%9B%B4%E6%96%B0"
echo "[Error] Due to a change in the workflow file of the upstream repository, GitHub has automatically suspended the scheduled automatic update. You need to manually sync your fork. Please refer to the detailed tutorial for instructions: https://github.com/blacksev/Gemini-Next-Web#enable-automatic-updates"
exit 1
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ One-Click to get well-designed cross-platform Gemini web UI.
[![MacOS][MacOS-image]][download-url]
[![Linux][Linux-image]][download-url]

[Web App](https://gemini-chat.pro/) / [Desktop App](https://github.com/blacksev/Gemini-Next-Web/releases)
[Web App](https://gemini-chat.pro/) / [Desktop App](https://github.com/blacksev/Gemini-Next-Web/releases) / [Telegram](https://t.me/+EqnFU-q52_IxYjA1)

[网页版](https://gemini-chat.pro/) / [客户端](https://github.com/blacksev/Gemini-Next-Web/releases) / [反馈](https://github.com/blacksev/Gemini-Next-Web/issues)
[网页版](https://gemini-chat.pro/) / [客户端](https://github.com/blacksev/Gemini-Next-Web/releases) / [反馈](https://github.com/blacksev/Gemini-Next-Web/issues) / [电报](https://t.me/+EqnFU-q52_IxYjA1)

[web-url]: https://gemini-chat.pro/
[download-url]: https://github.com/blacksev/Gemini-Next-Web/releases
Expand Down Expand Up @@ -102,7 +102,7 @@ One-Click to get well-designed cross-platform Gemini web UI.
1. Get [OpenAI API Key](https://platform.openai.com/account/api-keys);
2. Click
[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2FYidadaa%2FChatGPT-Next-Web&env=OPENAI_API_KEY&env=CODE&project-name=chatgpt-next-web&repository-name=ChatGPT-Next-Web), remember that `CODE` is your page password;
[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fblacksev%2FGemini-Next-Web&env=OPENAI_API_KEY&env=CODE&project-name=chatgpt-next-web&repository-name=ChatGPT-Next-Web), remember that `CODE` is your page password;
3. Enjoy :)

## FAQ
Expand Down
11 changes: 10 additions & 1 deletion app/client/api.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { getClientConfig } from "../config/client";
import { ACCESS_CODE_PREFIX, ServiceProvider } from "../constant";
import { ChatMessage, ModelType, useAccessStore } from "../store";
import { AttachFile, ChatMessage, ModelType, useAccessStore } from "../store";
import { ChatGPTApi } from "./platforms/openai";

export const ROLES = ["system", "user", "assistant"] as const;
Expand All @@ -9,9 +9,18 @@ export type MessageRole = (typeof ROLES)[number];
export const Models = ["gemini-pro", "gpt-4"] as const;
export type ChatModel = ModelType;

export interface TypedContent {
type: "text" | "image_url";
text?: string;
image_url?: {
url: string;
};
}

export interface RequestMessage {
role: MessageRole;
content: string;
attachFiles?: AttachFile[];
}

export interface LLMConfig {
Expand Down
30 changes: 26 additions & 4 deletions app/client/platforms/openai.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,32 @@ export class ChatGPTApi implements LLMApi {
}

async chat(options: ChatOptions) {
const messages = options.messages.map((v) => ({
role: v.role,
content: v.content,
}));
const messages = options.messages.map((v) => {
if (v.attachFiles && v.attachFiles.length > 0) {
const content = [];
for (const file of v.attachFiles) {
content.push({
type: "image_url",
image_url: {
url: file.base64,
},
});
}
content.push({
type: "text",
text: v.content,
});
return {
role: v.role,
content,
};
} else {
return {
role: v.role,
content: v.content,
};
}
});

const modelConfig = {
...useAppConfig.getState().modelConfig,
Expand Down
7 changes: 7 additions & 0 deletions app/components/chat.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,13 @@
}
}

.chat-select-images{
img{
width: 100px;
height: 100px;
}
}

.prompt-toast {
position: absolute;
bottom: -50px;
Expand Down
100 changes: 90 additions & 10 deletions app/components/chat.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable @next/next/no-img-element */
import { useDebouncedCallback } from "use-debounce";
import React, {
useState,
Expand Down Expand Up @@ -27,13 +28,15 @@ import PinIcon from "../icons/pin.svg";
import EditIcon from "../icons/rename.svg";
import ConfirmIcon from "../icons/confirm.svg";
import CancelIcon from "../icons/cancel.svg";
import UploadIcon from "../icons/upload.svg";

import LightIcon from "../icons/light.svg";
import DarkIcon from "../icons/dark.svg";
import AutoIcon from "../icons/auto.svg";
import BottomIcon from "../icons/bottom.svg";
import StopIcon from "../icons/pause.svg";
import RobotIcon from "../icons/robot.svg";
import Image from "next/image";

import {
ChatMessage,
Expand All @@ -46,6 +49,7 @@ import {
useAppConfig,
DEFAULT_TOPIC,
ModelType,
AttachFile,
} from "../store";

import {
Expand Down Expand Up @@ -329,7 +333,9 @@ function ClearContextDivider() {
function ChatAction(props: {
text: string;
icon: JSX.Element;
innerNode?: JSX.Element;
onClick: () => void;
style?: React.CSSProperties;
}) {
const iconRef = useRef<HTMLDivElement>(null);
const textRef = useRef<HTMLDivElement>(null);
Expand Down Expand Up @@ -359,18 +365,24 @@ function ChatAction(props: {
onMouseEnter={updateWidth}
onTouchStart={updateWidth}
style={
{
"--icon-width": `${width.icon}px`,
"--full-width": `${width.full}px`,
} as React.CSSProperties
props.icon
? ({
"--icon-width": `${width.icon}px`,
"--full-width": `${width.full}px`,
...props.style,
} as React.CSSProperties)
: props.style
}
>
<div ref={iconRef} className={styles["icon"]}>
{props.icon}
</div>
<div className={styles["text"]} ref={textRef}>
{props.icon ? (
<div ref={iconRef} className={styles["icon"]}>
{props.icon}
</div>
) : null}
<div className={props.icon ? styles["text"] : undefined} ref={textRef}>
{props.text}
</div>
{props.innerNode}
</div>
);
}
Expand Down Expand Up @@ -409,6 +421,7 @@ export function ChatActions(props: {
showPromptModal: () => void;
scrollToBottom: () => void;
showPromptHints: () => void;
imageSelected: (img: any) => void;
hitBottom: boolean;
}) {
const config = useAppConfig();
Expand All @@ -429,6 +442,25 @@ export function ChatActions(props: {
const couldStop = ChatControllerPool.hasPending();
const stopAll = () => ChatControllerPool.stopAll();

function selectImage() {
document.getElementById("chat-image-file-select-upload")?.click();
}

const onImageSelected = (e: any) => {
const file = e.target.files[0];
const filename = file.name;
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => {
const base64 = reader.result;
props.imageSelected({
filename,
base64,
});
};
e.target.value = null;
};

// switch model
const currentModel = chatStore.currentSession().mask.modelConfig.model;
const allModels = useAllModels();
Expand Down Expand Up @@ -526,6 +558,21 @@ export function ChatActions(props: {
icon={<RobotIcon />}
/>

<ChatAction
onClick={selectImage}
text="选择图片"
icon={<UploadIcon />}
innerNode={
<input
type="file"
accept=".png,.jpg,.webp,.jpeg,.heic,.heif"
id="chat-image-file-select-upload"
style={{ display: "none" }}
onChange={onImageSelected}
/>
}
/>

{showModelSelector && (
<Selector
defaultSelectedValue={currentModel}
Expand Down Expand Up @@ -622,6 +669,7 @@ function _Chat() {

const inputRef = useRef<HTMLTextAreaElement>(null);
const [userInput, setUserInput] = useState("");
const [useImages, setUseImages] = useState<AttachFile[]>([]);
const [isLoading, setIsLoading] = useState(false);
const { submitKey, shouldSubmit } = useSubmitHandler();
const { scrollRef, setAutoScroll, scrollDomToBottom } = useScrollToBottom();
Expand Down Expand Up @@ -705,10 +753,11 @@ function _Chat() {
return;
}
setIsLoading(true);
chatStore.onUserInput(userInput).then(() => setIsLoading(false));
chatStore.onUserInput(userInput, useImages).then(() => setIsLoading(false));
localStorage.setItem(LAST_INPUT_KEY, userInput);
setUserInput("");
setPromptHints([]);
setUseImages([]);
if (!isMobileScreen) inputRef.current?.focus();
setAutoScroll(true);
};
Expand Down Expand Up @@ -1138,6 +1187,15 @@ function _Chat() {

const shouldShowClearContextDivider = i === clearContextIndex - 1;

let textContent: string = "";

if (message.attachFiles && message.attachFiles.length > 0) {
textContent += message.attachFiles
.map((f: AttachFile) => `![${f.filename}](${f.base64})\n`)
.join("");
}
if (message.content) textContent += message.content;

return (
<Fragment key={message.id}>
<div
Expand Down Expand Up @@ -1232,7 +1290,7 @@ function _Chat() {
)}
<div className={styles["chat-message-item"]}>
<Markdown
content={message.content}
content={textContent}
loading={
(message.preview || message.streaming) &&
message.content.length === 0 &&
Expand Down Expand Up @@ -1280,7 +1338,29 @@ function _Chat() {
setUserInput("/");
onSearch("");
}}
imageSelected={(img: any) => {
if (useImages.length >= 16) {
alert(Locale.Gemini.SelectImgMax(16));
return;
}
setUseImages([...useImages, img]);
}}
/>
{useImages.length > 0 && (
<div className={styles["chat-select-images"]}>
{useImages.map((img: any, i) => (
<img
src={img.base64}
key={i}
onClick={() => {
setUseImages(useImages.filter((_, ii) => ii != i));
}}
title={img.filename}
alt={img.filename}
/>
))}
</div>
)}
<div className={styles["chat-input-panel-inner"]}>
<textarea
ref={inputRef}
Expand Down
7 changes: 5 additions & 2 deletions app/locales/cn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ const cn = {
Download: "下载文件",
Share: "分享到 ShareGPT",
MessageFromYou: "用户",
MessageFromChatGPT: "Gemini",
MessageFromChatGPT: "ChatGPT",
Format: {
Title: "导出格式",
SubTitle: "可以导出 Markdown 文本或者 PNG 图片",
Expand All @@ -104,6 +104,9 @@ const cn = {
Modal: "长按或右键保存图片",
},
},
Gemini: {
SelectImgMax: (max: number) => `最多可选择 ${max} 张图片`,
},
Select: {
Search: "搜索消息",
All: "选取全部",
Expand Down Expand Up @@ -153,7 +156,7 @@ const cn = {
},
InjectSystemPrompts: {
Title: "注入系统级提示信息",
SubTitle: "强制给每次请求的消息列表开头添加一个模拟 Gemini 的系统提示",
SubTitle: "强制给每次请求的消息列表开头添加一个模拟 ChatGPT 的系统提示",
},
InputTemplate: {
Title: "用户输入预处理",
Expand Down
7 changes: 5 additions & 2 deletions app/locales/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,9 @@ const en: LocaleType = {
Latest: "Select Latest",
Clear: "Clear",
},
Gemini: {
SelectImgMax: (max: number) => `Select up to ${max} images`,
},
Memory: {
Title: "Memory Prompt",
EmptyContent: "Nothing yet.",
Expand Down Expand Up @@ -443,8 +446,8 @@ const en: LocaleType = {
},
Exporter: {
Description: {
Title: "Only messages after clearing the context will be displayed"
},
Title: "Only messages after clearing the context will be displayed",
},
Model: "Model",
Messages: "Messages",
Topic: "Topic",
Expand Down
Loading

0 comments on commit 4412c1f

Please sign in to comment.