Skip to content

Commit

Permalink
Merge branch 'dev-0.0.12'
Browse files Browse the repository at this point in the history
  • Loading branch information
crazygo committed Jan 23, 2025
2 parents 655caf8 + 38eb4eb commit 14faea9
Show file tree
Hide file tree
Showing 12 changed files with 232 additions and 89 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,5 @@ public/manifest.json
*.code-workspace
.shire
.vscode
.cursor
.cursor
.cursorrules
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "askman-chrome-extension",
"version": "0.0.11",
"version": "0.0.12",
"description": "Askman is an open-source browser extension that connects AI to web pages",
"license": "GPL-3.0-only",
"repository": {
Expand Down
12 changes: 6 additions & 6 deletions src/chat/chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ export class ChatCoreContext implements ChatCoreInterface {
private async initSystemMessage() {
try {
const systemPrompt = await StorageManager.getSystemPrompt();
this.history.push(new SystemInvisibleMessage(systemPrompt));
this.history.push(new SystemInvisibleMessage(systemPrompt.content));
} catch (e) {
console.error('Failed to initialize system message:', e);
}
Expand Down Expand Up @@ -188,7 +188,7 @@ export class ChatCoreContext implements ChatCoreInterface {
await this.createModelClient(currentModel);

// 2. 系统提示词:临时提示词优先于存储的提示词
const systemPrompt = options?.overrideSystem || (await StorageManager.getSystemPrompt());
const systemPrompt = options?.overrideSystem || (await StorageManager.getSystemPrompt()).content;
// Remove old system message if exists
this.history = this.history.filter(msg => !(msg instanceof SystemInvisibleMessage));
// Add new system message
Expand Down Expand Up @@ -222,7 +222,7 @@ export class ChatCoreContext implements ChatCoreInterface {
return;
}

this.history.push(new HumanMessage({ content: prompt, name: 'human' }));
this.history.push(new HumanMessage({ content: prompt }));
if (this._onDataListener) {
setTimeout(() => this._onDataListener(this.history));
}
Expand All @@ -233,7 +233,7 @@ export class ChatCoreContext implements ChatCoreInterface {
console.warn('no this._onDataListener');
}

const pendingResponse = new AIMessage({ content: 'Just Guessing ...', name: 'hint' });
const pendingResponse = new AIMessage({ content: 'Thinking ...' });
let hasResponse = false;
setTimeout(() => {
this.history.push(pendingResponse);
Expand All @@ -250,11 +250,11 @@ export class ChatCoreContext implements ChatCoreInterface {
for await (const chunk of stream) {
chunks.push(chunk);
const content = chunks.reduce((acc, cur) => acc + cur.content, '');
const name = chunk.name;
// const name = chunk.name;
if (content.trim() === '') continue;

pendingResponse.content = content;
pendingResponse.name = name || 'ai';
// pendingResponse.name = name || 'ai';
hasResponse = true;
if (this._onDataListener) {
setTimeout(() => this._onDataListener(this.history));
Expand Down
8 changes: 4 additions & 4 deletions src/components/ask-message.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export enum AskMessageType {
interface AskMessageItem {
type: AskMessageType | string;
text: string;
name?: string;
role?: string;
}

function decodeEntities(text: string): string {
Expand All @@ -25,7 +25,7 @@ function decodeEntities(text: string): string {
}

function AskMessage(props: AskMessageItem) {
const { type, text, name } = props;
const { type, text, role } = props;
const [codeHover, setCodeHover] = useState<number | null>(null);
const { isVisible, handlers } = useCopyButton(type !== AskMessageType.CODE);
let messageItem = <div>{text}</div>;
Expand Down Expand Up @@ -93,11 +93,11 @@ function AskMessage(props: AskMessageItem) {
<div
className={classNames(
'relative',
name === 'ai' ? 'text-gray-800 mb-3 leading-relaxed' : 'text-sky-600 mb-1 leading-relaxed max-h-16',
role === 'assistant' ? 'text-gray-800 mb-3 leading-relaxed' : 'text-sky-600 mb-1 leading-relaxed max-h-16',
'font-bold',
)}
{...handlers}>
<div className={classNames('pr-8', name === 'human' ? `max-h-16 ${SCROLLBAR_STYLES}` : '')}>{messageItem}</div>
<div className={classNames('pr-8', role === 'user' ? `max-h-16 ${SCROLLBAR_STYLES}` : '')}>{messageItem}</div>
{isVisible && type !== AskMessageType.CODE && (
<CopyButton text={text} className="top-[-6px] right-1 bg-gray-100 hover:bg-gray-200" />
)}
Expand Down
168 changes: 117 additions & 51 deletions src/components/ask-panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,8 @@ import { ChatPopupContext } from '../chat/chat';
import ToolDropdown, { tools } from './ask-tooldropdown';
import ModelDropdown from './ask/ModelDropDown';
import TextareaAutosize from 'react-textarea-autosize';
import { ArrowsPointingInIcon, ArrowsPointingOutIcon, XMarkIcon } from '@heroicons/react/20/solid';
import { ArrowsPointingInIcon, ArrowsPointingOutIcon, XMarkIcon, PlusIcon } from '@heroicons/react/20/solid';
import AskMessage from './ask-message';
import AskButton from './ask-button';
import {
ToolsPromptInterface,
AIInvisibleMessage,
Expand All @@ -23,6 +22,7 @@ import SystemPromptDropdown from './system-prompt-dropdown';
import { StorageManager } from '../utils/StorageManager';
import { Handlebars } from '../../third-party/kbn-handlebars/src/handlebars';
import { SCROLLBAR_STYLES_HIDDEN_X } from '../styles/common';
import { HumanMessage } from '@langchain/core/messages';

interface AskPanelProps extends React.HTMLAttributes<HTMLDivElement> {
code: string;
Expand Down Expand Up @@ -78,7 +78,7 @@ function AskPanel(props: AskPanelProps) {
const [userInput, setUserInput] = useState<string>('');
const [askPanelVisible, setAskPanelVisible] = useState<boolean>(visible);
//TODO 需要定义一个可渲染、可序列号的类型,疑似是 StoredMessage
const [history, setHistory] = useState<{ id: string; name: string; type: string; text: string }[]>([]);
const [history, setHistory] = useState<{ id: string; role: string; type: string; text: string }[]>([]);
const [initQuotes, setInitQuotes] = useState<Array<QuoteContext>>([]);
const [pageContext, setPageContext] = useState<QuoteContext>(new QuoteContext());
const inputRef = useRef<HTMLTextAreaElement>(null);
Expand All @@ -93,7 +93,6 @@ function AskPanel(props: AskPanelProps) {
const [isSystemPromptDropdownOpen, setIsSystemPromptDropdownOpen] = useState(false);

const showToolDropdown = () => {
// console.log('isToolDropdownOpen = ' + isToolDropdownOpen, 'set to true');
setIsToolDropdownOpen(true);
setIsQuoteDropdownOpen(false);
setIsModelDropdownOpen(false);
Expand Down Expand Up @@ -200,15 +199,25 @@ function AskPanel(props: AskPanelProps) {
),
)
.map((message, idx) => {
let role = 'assistant';
if (message instanceof HumanMessage) {
role = 'user';
}
if (message instanceof HumanAskMessage) {
return { type: 'text', id: `history-${idx}`, text: message.rendered, name: message.name };
return {
type: 'text',
id: `history-${idx}`,
text: message.rendered,
role: role,
name: 'HumanAskMessage',
};
} else if (typeof message.content == 'string') {
return { type: 'text', id: `history-${idx}`, text: message.content, name: message.name };
return { type: 'text', id: `history-${idx}`, text: message.content, role: role, name: 'AIMessage' };
} else if (message.content instanceof Array) {
return {
type: 'text',
id: `history-${idx}`,
name: message.name,
role: role,
text: message.content.reduce((acc, cur) => {
if (cur.type == 'text') {
return acc + '\n' + cur.text;
Expand Down Expand Up @@ -268,19 +277,19 @@ function AskPanel(props: AskPanelProps) {
e.stopPropagation();

if (e.key === 'ArrowRight') {
if (isToolDropdownOpen) {
if (isSystemPromptDropdownOpen) {
showModelDropdown();
} else if (isModelDropdownOpen) {
showSystemPromptDropdown();
} else if (isSystemPromptDropdownOpen) {
showToolDropdown();
} else if (isToolDropdownOpen) {
showSystemPromptDropdown();
}
} else if (e.key === 'ArrowLeft') {
if (isToolDropdownOpen) {
showSystemPromptDropdown();
} else if (isModelDropdownOpen) {
if (isSystemPromptDropdownOpen) {
showToolDropdown();
} else if (isSystemPromptDropdownOpen) {
} else if (isModelDropdownOpen) {
showSystemPromptDropdown();
} else if (isToolDropdownOpen) {
showModelDropdown();
}
}
Expand Down Expand Up @@ -377,6 +386,17 @@ function AskPanel(props: AskPanelProps) {
setDropdownPosition({ left, top });
}

// 清空历史记录和输入框
const clearHistory = () => {
// 保留系统消息
const systemMessages = chatContext.history.filter(message => message instanceof SystemInvisibleMessage);
chatContext.history = systemMessages;
// 清空可见消息
setHistory([]);
// 清空输入框
setUserInput('');
};

// myObject.test('你是谁');
// console.log('history = ' + JSON.stringify(history));
return (
Expand All @@ -389,6 +409,21 @@ function AskPanel(props: AskPanelProps) {
: 'w-[473px] min-w-80 max-w-lg min-h-[155px]',
`${askPanelVisible ? 'visible' : 'invisible'}`,
)}
onKeyDown={e => {
if (
e.key === 'Escape' &&
(isQuoteDropdownOpen || isToolDropdownOpen || isModelDropdownOpen || isSystemPromptDropdownOpen)
) {
setIsQuoteDropdownOpen(false);
setIsToolDropdownOpen(false);
setIsModelDropdownOpen(false);
setIsSystemPromptDropdownOpen(false);
inputRef.current?.focus();
e.stopPropagation();
e.preventDefault();
}
}}
tabIndex={-1}
{...rest}>
<div className="font-medium rounded-lg bg-transparent bg-gradient-to-r from-white via-white to-white/60 mb-2 text-base flex justify-between">
<span>
Expand All @@ -403,6 +438,21 @@ function AskPanel(props: AskPanelProps) {

<div className="grow"></div>

<button
title="New Chat"
aria-label="Start a new chat"
className="bg-gray-100 text-gray-600 rounded-full p-1 hover:bg-black hover:text-white mr-2 transition-colors duration-200"
onClick={() => {
clearHistory();
setUserTools(null);
// 将焦点设置到输入框
setTimeout(() => {
inputRef.current?.focus();
}, 100);
}}>
<PlusIcon className="w-4 h-4 cursor-pointer" aria-hidden="true" />
</button>

<button
className="bg-gray-100 text-gray-600 rounded-full p-1 hover:bg-black hover:text-white mr-2"
onClick={() => setIsMaximized(!isMaximized)}>
Expand All @@ -423,9 +473,9 @@ function AskPanel(props: AskPanelProps) {
</button>
</div>
<div className={classNames('py-2 mb-2', SCROLLBAR_STYLES_HIDDEN_X, isMaximized ? 'flex-grow' : 'max-h-80')}>
{history.map(message => (
<AskMessage key={message.id} {...message} />
))}
{history.map(message => {
return <AskMessage key={message.id} {...message} />;
})}

{history.length > 0 && (
<div className="pt-32">
Expand Down Expand Up @@ -493,7 +543,28 @@ function AskPanel(props: AskPanelProps) {
onKeyDown={e => {
// 检测 ESC 键
if (e.key === 'Escape') {
if (isQuoteDropdownOpen || isToolDropdownOpen || isModelDropdownOpen) {
console.log('ESC key detected in textarea', {
isQuoteDropdownOpen,
isToolDropdownOpen,
isModelDropdownOpen,
isSystemPromptDropdownOpen,
});
if (
isQuoteDropdownOpen ||
isToolDropdownOpen ||
isModelDropdownOpen ||
isSystemPromptDropdownOpen
) {
setIsQuoteDropdownOpen(false);
setIsToolDropdownOpen(false);
setIsModelDropdownOpen(false);
setIsSystemPromptDropdownOpen(false);
e.stopPropagation();
e.preventDefault();
return;
} else {
setAskPanelVisible(false);
onHide();
e.stopPropagation();
e.preventDefault();
return;
Expand Down Expand Up @@ -539,17 +610,26 @@ function AskPanel(props: AskPanelProps) {
}
// 检测左右方向键
if (e.key === 'ArrowLeft' || e.key === 'ArrowRight') {
if (isToolDropdownOpen || isModelDropdownOpen) {
if (isToolDropdownOpen || isModelDropdownOpen || isSystemPromptDropdownOpen) {
e.preventDefault();
e.stopPropagation();
if (isToolDropdownOpen && e.key === 'ArrowRight') {
showModelDropdown();
} else if (isModelDropdownOpen && e.key === 'ArrowRight') {
showToolDropdown();
} else if (isToolDropdownOpen && e.key === 'ArrowLeft') {
showModelDropdown();
} else if (isModelDropdownOpen && e.key === 'ArrowLeft') {
showToolDropdown();

if (e.key === 'ArrowRight') {
if (isSystemPromptDropdownOpen) {
showModelDropdown();
} else if (isModelDropdownOpen) {
showToolDropdown();
} else if (isToolDropdownOpen) {
showSystemPromptDropdown();
}
} else if (e.key === 'ArrowLeft') {
if (isSystemPromptDropdownOpen) {
showToolDropdown();
} else if (isModelDropdownOpen) {
showSystemPromptDropdown();
} else if (isToolDropdownOpen) {
showModelDropdown();
}
}
return;
}
Expand Down Expand Up @@ -592,17 +672,6 @@ function AskPanel(props: AskPanelProps) {
}
}}
/>
<ToolDropdown
initOpen={isToolDropdownOpen}
statusListener={updateToolDropdownStatus}
className="inline-block relative"
onItemClick={(item, withCommand) => {
setUserTools(item);
if (withCommand) {
onSend(item); // 按了 Command 键直接发送,使用临时工具
}
}}
/>
<ModelDropdown
initOpen={isModelDropdownOpen}
className="relative"
Expand All @@ -614,20 +683,17 @@ function AskPanel(props: AskPanelProps) {
statusListener={updateModelDropdownStatus}
/>
<div className="grow"></div>
<AskButton
primary
disabled={!(userInput || initQuotes.length)}
onClick={() => {
onSend();
<div className="w-px h-6 bg-gray-200 mx-2 my-auto"></div>
<ToolDropdown
initOpen={isToolDropdownOpen}
statusListener={updateToolDropdownStatus}
className="inline-block relative"
onItemClick={(_item, _withCommand) => {
setUserTools(_item);
onSend(_item); // 直接发送,不需要修改按钮文字
}}
onKeyDown={e => {
if (e.key === 'Enter' && !e.shiftKey && !e.ctrlKey && !e.altKey) {
e.preventDefault();
onSend();
}
}}>
</AskButton>
buttonDisplay="➔"
/>
</div>
</div>
</div>
Expand Down
Loading

0 comments on commit 14faea9

Please sign in to comment.