Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

メッセージの折りたたみ機能実装 #9

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
14 changes: 14 additions & 0 deletions .github/workflows/render-cold-start.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
name: render-cold-start
on:
schedule:
- cron: '1/5 * * * *'

jobs:
build:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- name: Run script
run: |
curl ${{secrets.HOST}}
39 changes: 39 additions & 0 deletions api/app/clients/BaseClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const { addSpaceIfNeeded, isEnabled } = require('~/server/utils');
const checkBalance = require('~/models/checkBalance');
const TextStream = require('./TextStream');
const { logger } = require('~/config');
const { setTimeout } = require('timers/promises');

class BaseClient {
constructor(apiKey, options = {}) {
Expand Down Expand Up @@ -372,6 +373,44 @@ class BaseClient {
return { payload, tokenCountMap, promptTokens, messages: orderedWithInstructions };
}

async sendDummyMessage(res, message, opts = {}) {
const { user, isEdited, conversationId, responseMessageId, saveOptions, userMessage } =
await this.handleStartMethods(message, opts);

logger.warn(`[BaseClient] user: ${user}`);
logger.warn(`[BaseClient] message: ${message}`);

const completion =
'Hahaha, you are not me!\n笑止千万!\n哈哈,你不是我!\nJajaja, ¡no eres yo!\nMdr t’es pas moi!';
let text = '';
for (let i = 0; i < completion.length; i++) {
text = text + completion[i];
const message = {
text,
message: true,
initial: false,
parentMessageId: undefined,
};
res.write(`event: message\ndata: ${JSON.stringify(message)}\n\n`);
await setTimeout(10);
}

const { generation = '' } = opts;
await this.saveMessageToDatabase(userMessage, saveOptions, user);
const responseMessage = {
messageId: responseMessageId,
conversationId,
parentMessageId: userMessage.messageId,
isCreatedByUser: false,
isEdited,
model: this.modelOptions.model,
sender: this.sender,
text: addSpaceIfNeeded(generation) + completion,
promptTokens: 8,
};
return responseMessage;
}

async sendMessage(message, opts = {}) {
const { user, head, isEdited, conversationId, responseMessageId, saveOptions, userMessage } =
await this.handleStartMethods(message, opts);
Expand Down
10 changes: 8 additions & 2 deletions api/server/controllers/AskController.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ const { sendMessage, createOnProgress } = require('~/server/utils');
const { saveMessage, getConvoTitle, getConvo } = require('~/models');
const { createAbortController, handleAbortError } = require('~/server/middleware');
const { logger } = require('~/config');
const { isMyUser, isDummyMode } = require('~/utils/user');

const AskController = async (req, res, next, initializeClient, addTitle) => {
let {
Expand Down Expand Up @@ -108,7 +109,10 @@ const AskController = async (req, res, next, initializeClient, addTitle) => {
}),
};

let response = await client.sendMessage(text, messageOptions);
let response =
!isDummyMode() && isMyUser(req.user.email)
? await client.sendMessage(text, messageOptions)
: await client.sendDummyMessage(res, text, messageOptions);

if (overrideParentMessageId) {
response.parentMessageId = overrideParentMessageId;
Expand Down Expand Up @@ -139,8 +143,10 @@ const AskController = async (req, res, next, initializeClient, addTitle) => {
}

await saveMessage(userMessage);

if (addTitle && parentMessageId === Constants.NO_PARENT && newConvo) {
if (!isMyUser(req.user.email) || isDummyMode()) {
return;
}
addTitle(req, {
text,
response,
Expand Down
8 changes: 8 additions & 0 deletions api/server/controllers/AuthController.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const {
requestPasswordReset,
} = require('~/server/services/AuthService');
const { logger } = require('~/config');
const { isMyUser } = require('~/utils/user');

const registrationController = async (req, res) => {
try {
Expand Down Expand Up @@ -84,6 +85,13 @@ const refreshController = async (req, res) => {
return res.status(401).redirect('/login');
}

// 環境変数で定めたユーザーのみログインを許可
// FIXME: Basic認証導入するまでの仮実装
if (!isMyUser(user.email)) {
logger.error(`[refreshController] No my user!! - ${user.email}`);
return res.status(401).redirect('/login');
}

if (process.env.NODE_ENV === 'CI') {
const token = await setAuthTokens(userId, res);
const userObj = user.toJSON();
Expand Down
6 changes: 6 additions & 0 deletions api/strategies/localStrategy.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ const { Strategy: PassportLocalStrategy } = require('passport-local');
const User = require('../models/User');
const { loginSchema, errorsToString } = require('./validators');
const logger = require('../utils/logger');
const { isMyUser } = require('../utils/user');

async function validateLoginRequest(req) {
const { error } = loginSchema.safeParse(req.body);
Expand Down Expand Up @@ -46,6 +47,11 @@ async function passportLogin(req, email, password, done) {
return done(null, false, { message: 'Incorrect password.' });
}

if (!isMyUser(email)) {
logError('Passport Local Strategy - No My User!!', { email });
return done(null, false, { message: 'Incorrect User!!' });
}

logger.info(`[Login] [Login successful] [Username: ${email}] [Request-IP: ${req.ip}]`);
return done(null, user);
} catch (err) {
Expand Down
21 changes: 21 additions & 0 deletions api/utils/user.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* 環境変数で定めたユーザーのみログインを許可
* FIXME: Basic認証導入するまでの仮実装
*/
function isMyUser(email) {
return email === process.env.MY_USER;
}

/**
* デバッグ用関数
*
* GPTの代わりにダミーのレスポンスを返すためのフラグ
*/
function isDummyMode() {
return process.env.DUMMY_MODE === 'true';
}

module.exports = {
isMyUser,
isDummyMode,
};
3 changes: 3 additions & 0 deletions client/src/components/Auth/Registration.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ const Registration: React.FC = () => {
const password = watch('password');

const onRegisterUserFormSubmit = async (data: TRegisterUser) => {
// 自分以外登録させない
alert('Haha, you wish!\n笑止千万!\n哈哈,你不是我!\nJajaja, ¡no eres yo!\nMdr t’es pas moi!');
return;
try {
await registerUser.mutateAsync(data);
navigate('/c/new');
Expand Down
7 changes: 5 additions & 2 deletions client/src/components/Chat/Messages/HoverButtons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ import { cn } from '~/utils';
type THoverButtons = {
isEditing: boolean;
enterEdit: (cancel?: boolean) => void;
copyToClipboard: (setIsCopied: React.Dispatch<React.SetStateAction<boolean>>) => void;
copyToClipboard: (
e: React.MouseEvent<HTMLButtonElement, MouseEvent>,
setIsCopied: React.Dispatch<React.SetStateAction<boolean>>,
) => void;
conversation: TConversation | null;
isSubmitting: boolean;
message: TMessage;
Expand Down Expand Up @@ -72,7 +75,7 @@ export default function HoverButtons({
'ml-0 flex items-center gap-1.5 rounded-md p-1 pl-0 text-xs hover:text-gray-950 dark:text-gray-400/70 dark:hover:text-gray-200 disabled:dark:hover:text-gray-400 md:group-hover:visible md:group-[.final-completion]:visible',
isSubmitting && isCreatedByUser ? 'md:opacity-0 md:group-hover:opacity-100' : '',
)}
onClick={() => copyToClipboard(setIsCopied)}
onClick={(e) => copyToClipboard(e, setIsCopied)}
type="button"
title={
isCopied ? localize('com_ui_copied_to_clipboard') : localize('com_ui_copy_to_clipboard')
Expand Down
39 changes: 32 additions & 7 deletions client/src/components/Chat/Messages/Message.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import MultiMessage from './MultiMessage';
import HoverButtons from './HoverButtons';
import SubRow from './SubRow';
import { cn } from '~/utils';
import { ArrowUpIcon, ArrowDownIcon } from '~/components/svg';
import store from '~/store';

export default function Message(props: TMessageProps) {
Expand All @@ -29,6 +30,10 @@ export default function Message(props: TMessageProps) {
handleContinue,
copyToClipboard,
regenerateMessage,
messageRef,
showExpand,
isExpand,
handleExpand,
} = useMessageHelpers(props);

const { message, siblingIdx, siblingCount, setSiblingIdx, currentEditId, setCurrentEditId } =
Expand All @@ -54,8 +59,8 @@ export default function Message(props: TMessageProps) {
onWheel={handleScroll}
onTouchMove={handleScroll}
>
<div className="m-auto justify-center p-4 py-2 text-base md:gap-6 ">
<div className="} group mx-auto flex flex-1 gap-3 text-base md:max-w-3xl md:px-5 lg:max-w-[40rem] lg:px-1 xl:max-w-[48rem] xl:px-5">
<div className="m-auto justify-center p-4 py-2 text-base md:gap-6">
<div className="group mx-auto flex flex-1 gap-3 text-base md:max-w-3xl md:px-5 lg:max-w-[40rem] lg:px-1 xl:max-w-[48rem] xl:px-5">
<div className="relative flex flex-shrink-0 flex-col items-end">
<div>
<div className="pt-0.5">
Expand All @@ -69,12 +74,32 @@ export default function Message(props: TMessageProps) {
</div>
</div>
</div>
<div
className={cn('relative flex w-full flex-col', isCreatedByUser ? '' : 'agent-turn')}
>
<div className="select-none font-semibold">{messageLabel}</div>
<div className={cn('relative w-full flex-col', isCreatedByUser ? '' : 'agent-turn')}>
<div className="flex select-none items-center justify-between font-semibold ">
{isCreatedByUser ? 'You' : message.sender}
{isCreatedByUser && !edit && showExpand && (
<button
className="rounded-full p-1 hover:bg-gray-100 hover:brightness-110 dark:hover:bg-gray-700"
onClick={handleExpand}
>
{isExpand ? <ArrowUpIcon /> : <ArrowDownIcon />}
</button>
)}
</div>
<div className="flex-col gap-1 md:gap-3">
<div className="flex max-w-full flex-grow flex-col gap-0">
<div
ref={messageRef}
className={cn(
'flex max-w-full flex-grow flex-col gap-0',
isCreatedByUser && !edit && showExpand
? 'h-[120px] cursor-pointer brightness-100 hover:bg-gray-50 dark:hover:bg-[rgba(39,39,37,1)]'
: '',
!isCreatedByUser || isExpand || edit
? 'h-auto'
: 'readmore-blur overflow-hidden',
)}
onClick={handleExpand}
>
{/* Legacy Plugins */}
{message?.plugin && <Plugin plugin={message?.plugin} />}
<MessageContent
Expand Down
4 changes: 2 additions & 2 deletions client/src/components/Messages/ScrollToBottom.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from "react";
import React from 'react';

type Props = {
scrollHandler: React.MouseEventHandler<HTMLButtonElement>;
Expand All @@ -8,7 +8,7 @@ export default function ScrollToBottom({ scrollHandler }: Props) {
return (
<button
onClick={scrollHandler}
className="cursor-pointer absolute rounded-full border border-white bg-gray-50 text-gray-600 dark:border-white/10 dark:bg-white/10 bottom-5 right-1/2 dark:text-gray-200"
className="absolute bottom-5 right-1/2 cursor-pointer rounded-full border border-white bg-gray-50 text-gray-600 dark:border-white/10 dark:bg-white/10 dark:text-gray-200"
>
<svg
width="24"
Expand Down
24 changes: 8 additions & 16 deletions client/src/components/Nav/Settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,9 @@ export default function Settings({ open, onOpenChange }: TDialogProps) {
className={cn(
'group m-1 flex items-center justify-start gap-2 rounded-md px-2 py-1.5 text-sm text-black radix-state-active:bg-white radix-state-active:text-black dark:text-white dark:radix-state-active:bg-gray-800',
isSmallScreen
? 'flex-col flex-1 items-center justify-center text-sm dark:text-gray-500 dark:radix-state-active:text-white'
? 'flex-1 flex-col items-center justify-center text-sm dark:text-gray-500 dark:radix-state-active:text-white'
: 'bg-white radix-state-active:bg-gray-100',
isSmallScreen
? ''
: 'dark:bg-gray-900',
isSmallScreen ? '' : 'dark:bg-gray-900',
)}
value={SettingsTabValues.GENERAL}
>
Expand All @@ -64,11 +62,9 @@ export default function Settings({ open, onOpenChange }: TDialogProps) {
className={cn(
'group m-1 flex items-center justify-start gap-2 rounded-md px-2 py-1.5 text-sm text-black radix-state-active:bg-white radix-state-active:text-black dark:text-white dark:radix-state-active:bg-gray-800',
isSmallScreen
? 'flex-col flex-1 items-center justify-center text-sm dark:text-gray-500 dark:radix-state-active:text-white'
? 'flex-1 flex-col items-center justify-center text-sm dark:text-gray-500 dark:radix-state-active:text-white'
: 'bg-white radix-state-active:bg-gray-100',
isSmallScreen
? ''
: 'dark:bg-gray-900',
isSmallScreen ? '' : 'dark:bg-gray-900',
)}
value={SettingsTabValues.BETA}
>
Expand All @@ -79,11 +75,9 @@ export default function Settings({ open, onOpenChange }: TDialogProps) {
className={cn(
'group m-1 flex items-center justify-start gap-2 rounded-md px-2 py-1.5 text-sm text-black radix-state-active:bg-white radix-state-active:text-black dark:text-white dark:radix-state-active:bg-gray-800',
isSmallScreen
? 'flex-col flex-1 items-center justify-center text-sm dark:text-gray-500 dark:radix-state-active:text-white'
? 'flex-1 flex-col items-center justify-center text-sm dark:text-gray-500 dark:radix-state-active:text-white'
: 'bg-white radix-state-active:bg-gray-100',
isSmallScreen
? ''
: 'dark:bg-gray-900',
isSmallScreen ? '' : 'dark:bg-gray-900',
)}
value={SettingsTabValues.DATA}
>
Expand All @@ -94,11 +88,9 @@ export default function Settings({ open, onOpenChange }: TDialogProps) {
className={cn(
'group m-1 flex items-center justify-start gap-2 rounded-md px-2 py-1.5 text-sm text-black radix-state-active:bg-white radix-state-active:text-black dark:text-white dark:radix-state-active:bg-gray-800',
isSmallScreen
? 'flex-col flex-1 items-center justify-center text-sm dark:text-gray-500 dark:radix-state-active:text-white'
? 'flex-1 flex-col items-center justify-center text-sm dark:text-gray-500 dark:radix-state-active:text-white'
: 'bg-white radix-state-active:bg-gray-100',
isSmallScreen
? ''
: 'dark:bg-gray-900',
isSmallScreen ? '' : 'dark:bg-gray-900',
)}
value={SettingsTabValues.ACCOUNT}
>
Expand Down
4 changes: 2 additions & 2 deletions client/src/components/Plugins/Store/PluginStoreDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -127,10 +127,10 @@ function PluginStoreDialog({ isOpen, setIsOpen }: TPluginStoreDialogProps) {
{/* Full-screen container to center the panel */}
<div className="fixed inset-0 flex items-center justify-center p-4">
<Dialog.Panel
className="relative w-full transform overflow-hidden overflow-y-auto rounded-lg bg-white text-left shadow-xl transition-all max-sm:h-full sm:mx-7 sm:my-8 sm:max-w-2xl lg:max-w-5xl xl:max-w-7xl dark:bg-gray-900"
className="relative w-full transform overflow-hidden overflow-y-auto rounded-lg bg-white text-left shadow-xl transition-all dark:bg-gray-900 max-sm:h-full sm:mx-7 sm:my-8 sm:max-w-2xl lg:max-w-5xl xl:max-w-7xl"
style={{ minHeight: '610px' }}
>
<div className="flex items-center justify-between border-b-[1px] border-black/10 px-4 pb-4 pt-5 sm:p-6 dark:border-white/10">
<div className="flex items-center justify-between border-b-[1px] border-black/10 px-4 pb-4 pt-5 dark:border-white/10 sm:p-6">
<div className="flex items-center">
<div className="text-center sm:text-left">
<Dialog.Title className="text-lg font-medium leading-6 text-gray-900 dark:text-gray-200">
Expand Down
16 changes: 16 additions & 0 deletions client/src/components/svg/ArrowDownIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
export default function ArrowDownIcon({ className = '' }) {
return (
<svg
stroke="currentColor"
fill="currentColor"
strokeWidth="0"
viewBox="0 0 512 512"
height="1em"
width="1em"
xmlns="http://www.w3.org/2000/svg"
className={className}
>
<path d="M256 294.1L383 167c9.4-9.4 24.6-9.4 33.9 0s9.3 24.6 0 34L273 345c-9.1 9.1-23.7 9.3-33.1.7L95 201.1c-4.7-4.7-7-10.9-7-17s2.3-12.3 7-17c9.4-9.4 24.6-9.4 33.9 0l127.1 127z"></path>
</svg>
);
}
16 changes: 16 additions & 0 deletions client/src/components/svg/ArrowUpIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
export default function ArrowDownIcon({ className = '' }) {
return (
<svg
stroke="currentColor"
fill="currentColor"
strokeWidth="0"
viewBox="0 0 512 512"
height="1em"
width="1em"
xmlns="http://www.w3.org/2000/svg"
className={className}
>
<path d="M256 217.9L383 345c9.4 9.4 24.6 9.4 33.9 0 9.4-9.4 9.3-24.6 0-34L273 167c-9.1-9.1-23.7-9.3-33.1-.7L95 310.9c-4.7 4.7-7 10.9-7 17s2.3 12.3 7 17c9.4 9.4 24.6 9.4 33.9 0l127.1-127z"></path>
</svg>
);
}
2 changes: 2 additions & 0 deletions client/src/components/svg/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ export { default as GoogleMinimalIcon } from './GoogleMinimalIcon';
export { default as AnthropicMinimalIcon } from './AnthropicMinimalIcon';
export { default as SendMessageIcon } from './SendMessageIcon';
export { default as UserIcon } from './UserIcon';
export { default as ArrowUpIcon } from './ArrowUpIcon';
export { default as ArrowDownIcon } from './ArrowDownIcon';
export { default as NewChatIcon } from './NewChatIcon';
export { default as ExperimentIcon } from './ExperimentIcon';
export { default as GoogleIconChat } from './GoogleIconChat';
Expand Down
Loading
Loading