Skip to content

Commit

Permalink
feat: 支持无轮次限制对话及更多系统角色
Browse files Browse the repository at this point in the history
  • Loading branch information
weaigc committed Nov 9, 2023
1 parent 8a1c71d commit bffb019
Show file tree
Hide file tree
Showing 17 changed files with 297 additions and 104 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "bingo",
"version": "1.0.0",
"version": "1.1.0",
"private": true,
"main": "./cloudflare/cli.js",
"scripts": {
Expand Down
24 changes: 0 additions & 24 deletions src/components/advance-switcher.tsx

This file was deleted.

2 changes: 1 addition & 1 deletion src/components/chat-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export function ChatList({ messages }: ChatList) {
<div className="chat-container relative flex flex-col">
{messages.map((message, index) => (
<React.Fragment key={index}>
<ChatMessage message={message} />
<ChatMessage message={message} index={index} />
{index < messages.length - 1 && (
<Separator className="my-2" />
)}
Expand Down
5 changes: 3 additions & 2 deletions src/components/chat-message.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,11 @@ import { ChatFeedback } from './chat-feedback'
import { ChatProgress } from './chat-progress'

export interface ChatMessageProps {
index: number
message: ChatMessageModel
}

export function ChatMessage({ message, ...props }: ChatMessageProps) {
export function ChatMessage({ message, index, ...props }: ChatMessageProps) {
useEffect(() => {
if (document.body.scrollHeight - window.innerHeight - window.scrollY - 200 < 0) {
window.scrollBy(0, 200)
Expand Down Expand Up @@ -88,7 +89,7 @@ export function ChatMessage({ message, ...props }: ChatMessageProps) {
</div>
<div className="text-message-footer">
{message.author === 'bot' && <LearnMore sourceAttributions={message.sourceAttributions} />}
{message.author === 'bot' && <TurnCounter throttling={message.throttling} />}
{message.author === 'bot' && <TurnCounter throttling={message.throttling} index={index} />}
</div>
</div> : null}
</div>
Expand Down
4 changes: 2 additions & 2 deletions src/components/chat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import { ChatNotification } from './chat-notification'
import { Settings } from './settings'
import { ChatHistory } from './chat-history'
import { PromptsManage } from './prompts'
import { AdvanceSwither } from './advance-switcher'


export type ChatProps = React.ComponentProps<'div'> & { initialMessages?: ChatMessageModel[] }

Expand Down Expand Up @@ -67,7 +67,7 @@ export default function Chat({ className }: ChatProps) {
<ChatHeader />
<WelcomeScreen setInput={setInput} />
<ToneSelector type={bingStyle} onChange={setBingStyle} />
<AdvanceSwither disabled={messages.length >= 2} />
{/* <AdvanceSwither disabled={messages.length >= 2} /> */}
{messages.length ? (
<>
<ChatList messages={messages} />
Expand Down
118 changes: 118 additions & 0 deletions src/components/settings/advanced.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import { useCallback, useState } from 'react'
import { useAtom } from 'jotai'
import { Switch, RadioGroup } from '@headlessui/react'

import {
DialogDescription,
DialogHeader,
DialogTitle
} from '@/components/ui/dialog'
import { PrompsTemplates, systemPromptsAtom, unlimitAtom } from '@/state'

export function AdvancedSetting() {
const [enableUnlimit, setUnlimit] = useAtom(unlimitAtom)
const [systemPrompt, setSystemPrompt] = useAtom(systemPromptsAtom)
const [selected, setSelected] = useState(PrompsTemplates.find((item) => item.content === (systemPrompt || '')))

const handleChangePrompt = useCallback((value: typeof PrompsTemplates[0]) => {
setSelected(value)
setSystemPrompt(value.content)
}, [setSelected, setSystemPrompt])

return (
<>
<DialogHeader>
<DialogTitle>高级设置</DialogTitle>
<DialogDescription>
为 New Bing 添加一些实用的功能。
</DialogDescription>
</DialogHeader>

<div className="flex flex-col gap-2">
突破对话次数限制
<Switch
checked={enableUnlimit}
className={`${enableUnlimit ? 'bg-blue-600' : 'bg-gray-200'} relative inline-flex h-6 w-11 items-center rounded-full`}
onChange={(checked: boolean) => setUnlimit(checked)}
>
<span
className={`${enableUnlimit ? 'translate-x-6' : 'translate-x-1'} inline-block h-4 w-4 transform rounded-full bg-white transition`}
/>
</Switch>
</div>
<div className="flex flex-col gap-2">
预设角色
<div className="w-full py-1">
<div className="mx-auto w-full">
<RadioGroup value={selected} onChange={handleChangePrompt}>
<RadioGroup.Label className="sr-only">Server size</RadioGroup.Label>
<div className="space-y-2">
{PrompsTemplates.map((prompt) => (
<RadioGroup.Option
key={prompt.label}
value={prompt}
className={({ active, checked }) =>
`${active
? 'ring-2 ring-white/60 ring-offset-2 ring-offset-sky-300'
: ''
}
${checked ? 'bg-sky-900/75 text-white' : 'bg-white'}
relative flex cursor-pointer rounded-lg px-5 py-4 shadow-md focus:outline-none`
}
>
{({ checked }) => (
<>
<div className="flex w-full items-center justify-between">
<div className="flex items-center">
<div className="text-sm">
<RadioGroup.Label
as="p"
className={`font-medium ${checked ? 'text-white' : 'text-gray-900'
}`}
>
{prompt.label}
</RadioGroup.Label>
<RadioGroup.Description
as="span"
className={`inline ${checked ? 'text-sky-100' : 'text-gray-500'}`}
>
<span>
{prompt.desc}
</span>
</RadioGroup.Description>
</div>
</div>
{checked && (
<div className="shrink-0 text-white">
<CheckIcon className="h-6 w-6" />
</div>
)}
</div>
</>
)}
</RadioGroup.Option>
))}
</div>
</RadioGroup>
</div>
</div>
</div>
</>
)
}


function CheckIcon(props: React.SVGProps<SVGSVGElement>) {
return (
<svg viewBox="0 0 24 24" fill="none" {...props}>
<circle cx={12} cy={12} r={12} fill="#fff" opacity="0.2" />
<path
d="M7 13l3 3 7-7"
stroke="#fff"
strokeWidth={1.5}
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
)
}
38 changes: 10 additions & 28 deletions src/components/settings.tsx → src/components/settings/index.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { useCallback, useEffect, useState } from 'react'
import { useAtom } from 'jotai'
import { Switch } from '@headlessui/react'
import { toast } from 'react-hot-toast'
import { hashAtom, historyAtom, isImageOnly, voiceAtom } from '@/state'
import { Switch } from '@headlessui/react'
import { hashAtom, historyAtom, isImageOnly } from '@/state'
import {
Dialog,
DialogContent,
Expand All @@ -11,19 +11,20 @@ import {
DialogHeader,
DialogTitle
} from '@/components/ui/dialog'
import { Button } from './ui/button'
import { Input } from './ui/input'
import { Button } from '../ui/button'
import { Input } from '../ui/input'
import { ChunkKeys, parseCookies, extraCurlFromCookie, parseHeadersFromCurl, encodeHeadersToCookie, setCookie, resetCookies } from '@/lib/utils'
import { ExternalLink } from './external-link'
import { ExternalLink } from '../external-link'
import { useCopyToClipboard } from '@/lib/hooks/use-copy-to-clipboard'
import { VoiceSetting } from './voice'
import { AdvancedSetting } from './advanced'

export function Settings() {
const { isCopied, copyToClipboard } = useCopyToClipboard({ timeout: 2000 })
const [loc, setLoc] = useAtom(hashAtom)
const [curlValue, setCurlValue] = useState(extraCurlFromCookie(parseCookies(document.cookie, ChunkKeys)))
const [imageOnly, setImageOnly] = useState(isImageOnly)
const [enabledHistory, setHistory] = useAtom(historyAtom)
const [enableTTS, setEnableTTS] = useAtom(voiceAtom)

useEffect(() => {
if (isCopied) {
Expand Down Expand Up @@ -148,33 +149,14 @@ export function Settings() {
</DialogContent>
</Dialog>
)
} else if (loc === 'voice') {
} else if (loc) {
return (
<Dialog open onOpenChange={() => setLoc('')} modal>
<DialogContent>
<DialogHeader>
<DialogTitle>语音设置</DialogTitle>
<DialogDescription>
目前仅支持 PC 端 Edge 及 Chrome 浏览器
</DialogDescription>
</DialogHeader>

<div className="flex gap-2">
启用语音回答
<Switch
checked={enableTTS}
className={`${enableTTS ? 'bg-blue-600' : 'bg-gray-200'} relative inline-flex h-6 w-11 items-center rounded-full`}
onChange={(checked: boolean) => setEnableTTS(checked)}
>
<span
className={`${enableTTS ? 'translate-x-6' : 'translate-x-1'} inline-block h-4 w-4 transform rounded-full bg-white transition`}
/>
</Switch>
</div>

{ loc === 'voice' ? <VoiceSetting /> : <AdvancedSetting /> }
<DialogFooter className="items-center">
<Button
variant="secondary"
variant="primary"
onClick={() => {
toast.success('保存成功')
setLoc('')
Expand Down
37 changes: 37 additions & 0 deletions src/components/settings/voice.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { useAtom } from 'jotai'
import { Switch } from '@headlessui/react'

import {
DialogDescription,
DialogHeader,
DialogTitle
} from '@/components/ui/dialog'
import { voiceAtom } from '@/state'

export function VoiceSetting() {
const [enableTTS, setEnableTTS] = useAtom(voiceAtom)

return (
<>
<DialogHeader>
<DialogTitle>语音设置</DialogTitle>
<DialogDescription>
目前仅支持 PC 端 Edge 及 Chrome 浏览器
</DialogDescription>
</DialogHeader>

<div className="flex gap-2">
启用语音回答
<Switch
checked={enableTTS}
className={`${enableTTS ? 'bg-blue-600' : 'bg-gray-200'} relative inline-flex h-6 w-11 items-center rounded-full`}
onChange={(checked: boolean) => setEnableTTS(checked)}
>
<span
className={`${enableTTS ? 'translate-x-6' : 'translate-x-1'} inline-block h-4 w-4 transform rounded-full bg-white transition`}
/>
</Switch>
</div>
</>
)
}
10 changes: 7 additions & 3 deletions src/components/turn-counter.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,25 @@
import React from 'react'
import { useAtomValue } from 'jotai'
import { Throttling } from '@/lib/bots/bing/types'
import { unlimitAtom } from '@/state'

export interface TurnCounterProps {
throttling?: Throttling
index: number
}

export function TurnCounter({ throttling }: TurnCounterProps) {
export function TurnCounter({ throttling, index }: TurnCounterProps) {
const unlimit = useAtomValue(unlimitAtom)
if (!throttling) {
return null
}

return (
<div className="turn-counter">
<div className="text">
<span>{throttling.numUserMessagesInConversation}</span>
<span>{unlimit ? Math.floor(index / 2) + 1 : throttling?.numUserMessagesInConversation}</span>
<span></span>
<span>{throttling.maxNumUserMessagesInConversation}</span>
<span>{unlimit ? '999' : throttling?.maxNumUserMessagesInConversation}</span>
</div>
<div className="indicator"></div>
</div>
Expand Down
9 changes: 9 additions & 0 deletions src/components/user-menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,15 @@ export function UserMenu() {
设置用户
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem
onClick={() =>
location.href='#dialog="advanced-settings"'
}
className="cursor-pointer"
>
高级设置
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem
onClick={() =>
location.href='#dialog="voice"'
Expand Down
6 changes: 5 additions & 1 deletion src/lib/bots/bing/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,10 @@ export class BingWebBot {
private lastText = ''
private asyncTasks: Array<Promise<any>> = []

get isInitial() {
return (this.conversationContext?.invocationId??0) < 1
}

constructor(opts: {
endpoint?: string
cookie?: string
Expand Down Expand Up @@ -219,7 +223,7 @@ export class BingWebBot {
'GenerateContentQuery',
'SearchQuery',
],
previousMessages: conversation.invocationId === 0 && conversation.context?.length ? [{
previousMessages: conversation.context?.length ? [{
author: 'user',
description: conversation.context,
contextType: 'WebPage',
Expand Down
8 changes: 8 additions & 0 deletions src/lib/bots/bing/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -255,3 +255,11 @@ export interface FileItem {
url: string;
status?: 'loading' | 'error' | 'loaded'
}

export type Role = 'user' | 'assistant'
export type Action = 'next' | 'variant';

export interface APIMessage {
role: Role
content: string
}
Loading

0 comments on commit bffb019

Please sign in to comment.