Skip to content

Commit

Permalink
Merge pull request #37 from vasilecampeanu/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
vasilecampeanu authored May 21, 2023
2 parents 3892861 + 7305cfc commit dfc5fe8
Show file tree
Hide file tree
Showing 37 changed files with 1,073 additions and 836 deletions.
2 changes: 1 addition & 1 deletion manifest.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"id": "obsidian-weaver",
"name": "Weaver",
"version": "0.4.0",
"version": "0.5.0",
"minAppVersion": "1.0.0",
"description": "Weaver is a useful Obsidian plugin that integrates ChatGPT/GPT-3 into your note-taking workflow. This plugin makes it easy to access AI-generated suggestions and insights within Obsidian, helping you improve your writing and brainstorming process.",
"author": "Vasile Câmpeanu",
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "obsidian-weaver",
"version": "0.4.0",
"version": "0.5.0",
"description": "Weaver is a useful Obsidian plugin that integrates ChatGPT/GPT-3 into your note-taking workflow. This plugin makes it easy to access AI-generated suggestions and insights within Obsidian, helping you improve your writing and brainstorming process.",
"main": "main.js",
"scripts": {
Expand Down
4 changes: 2 additions & 2 deletions src/components/Conversation/Conversation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { ConversationInput } from "./ConversationInput";
interface ConversationProps {
plugin: Weaver;
onTabSwitch: (tabId: string) => void;
conversation: IConversation | null;
conversation: IConversation | undefined;
onConversationLoad: (conversation: IConversation) => void;
}

Expand All @@ -18,7 +18,7 @@ export const Conversation: React.FC<ConversationProps> = ({
conversation,
onConversationLoad
}) => {
const [conversationSession, setConversationSession] = useState<IConversation | null>(null);
const [conversationSession, setConversationSession] = useState<IConversation | undefined>();

useEffect(() => {
setConversationSession(conversation);
Expand Down
179 changes: 52 additions & 127 deletions src/components/Conversation/ConversationDialogue.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ import React, { useEffect, useState, useMemo, useRef } from "react";
import { ConversationMessageBubble } from "./ConversationMessageBubble";
import { ConversationManager } from "utils/ConversationManager";
import { ConversationEngineInfo } from "./ConversationEngineInfo";
import { ConversationRenderer } from "helpers/ConversationRenderer";
import MessageRenderer from "./ConversationMessageRenderer";

interface ConversationDialogueProps {
plugin: Weaver;
conversation: IConversation | null | undefined;
setConversationSession: React.Dispatch<React.SetStateAction<IConversation | null>>;
conversation: IConversation | undefined;
setConversationSession: React.Dispatch<React.SetStateAction<IConversation | undefined>>;
}

export const ConversationDialogue: React.FC<ConversationDialogueProps> = ({
Expand All @@ -18,9 +20,19 @@ export const ConversationDialogue: React.FC<ConversationDialogueProps> = ({
}) => {
const [selectedChildren, setSelectedChildren] = useState<{ [key: string]: number }>({});
const [activeEngine, setActiveEngine] = useState<"gpt-3.5-turbo" | "gpt-4">(plugin.settings.engine as any);
const dialogueTimelineRef = useRef<HTMLDivElement>(null);
const [showEngineInfo, setShowEngineInfo] = useState(false);

const dialogueTimelineRef = useRef<HTMLDivElement>(null);
const rootMessage = conversation?.messages.find((msg) => msg.role === "system");
const TIMEOUT_DELAY = 250;

useEffect(() => {
const timer = setTimeout(() => {
setShowEngineInfo(true);
}, TIMEOUT_DELAY);

return () => clearTimeout(timer);
}, []);

useEffect(() => {
const messageList = dialogueTimelineRef.current;
Expand Down Expand Up @@ -62,61 +74,6 @@ export const ConversationDialogue: React.FC<ConversationDialogueProps> = ({
}
}, [conversation]);

const getRenderedMessages = (conversation: IConversation | null | undefined): IChatMessage[] => {
if (!conversation) {
return [];
}

// Initialize selected children object.
const selectedChildren: { [key: string]: number } = {};

// Function to find path to current node and populate selectedChildren.
const findPathToCurrentNode = (messageId: string, path: string[]): string[] => {
const message = conversation.messages.find(msg => msg.id === messageId);
if (message) {
if (message.children && message.children.length > 0) {
for (let i = 0; i < message.children.length; i++) {
const childId = message.children[i];
if (childId === conversation.currentNode || findPathToCurrentNode(childId, [...path, messageId]).length > 0) {
selectedChildren[messageId] = i;
return [...path, messageId];
}
}
}
}

return [];
}

// Start finding path from the root message.
findPathToCurrentNode(conversation.messages.find(msg => msg.role === "system")?.id || '', []);

// Function to get messages to be rendered.
const deriveRenderedMessages = (messageId: string): IChatMessage[] => {
const message: IChatMessage | undefined | null = conversation.messages.find((msg) => msg.id === messageId);

if (!message) {
return [];
}

const childIds = message.children || [];
const selectedChildIndex = selectedChildren[messageId] || 0;

if (message.role === "system") {
return childIds[selectedChildIndex] ? deriveRenderedMessages(childIds[selectedChildIndex]) : [];
}

return [
message,
...(childIds[selectedChildIndex] ? deriveRenderedMessages(childIds[selectedChildIndex]) : [])
];
};

const rootMessage = conversation.messages.find((msg) => msg.role === "system");

return rootMessage ? deriveRenderedMessages(rootMessage.id) : [];
};

const changeSelectedChild = async (messageId: string | undefined, increment: number) => {
const message = conversation?.messages.find((msg) => msg.id === messageId);

Expand Down Expand Up @@ -159,48 +116,6 @@ export const ConversationDialogue: React.FC<ConversationDialogueProps> = ({
}
};

const renderMessages = (messageId: string, previousMessage: IChatMessage | undefined = undefined): React.ReactNode => {
const message: IChatMessage | undefined | null = conversation?.messages.find((msg) => msg.id === messageId);

if (!message) {
return null;
}

const childIds = message.children || [];
const selectedChildIndex = selectedChildren[messageId] || 0;
const selectedPreviousChildIndex = selectedChildren[previousMessage?.id as string] || 0;

if (message.role === "system") {
return childIds[selectedChildIndex] && renderMessages(childIds[selectedChildIndex], message);
}

const messagesRendered = getRenderedMessages(conversation);
const reverseMessages = messagesRendered.reverse();

const lastUserMessage = reverseMessages.find(message => message.role === 'user');
const lastAssistantMessage = reverseMessages.find(message => message.role === 'assistant');

let contextDisplay = false;

if (conversation?.context === false && ((message.id === lastUserMessage?.id) || (message.id === lastAssistantMessage?.id))) {
contextDisplay = true;
}

return (
<>
<ConversationMessageBubble
plugin={plugin}
message={message}
previousMessage={previousMessage}
selectedChild={selectedPreviousChildIndex}
onSelectedChildChange={(increment: number) => changeSelectedChild(previousMessage?.id, increment)}
contextDisplay={contextDisplay}
/>
{childIds[selectedChildIndex] && renderMessages(childIds[selectedChildIndex], message)}
</>
);
};

const handleSetGPT3 = () => {
setActiveEngine("gpt-3.5-turbo");
plugin.settings.engine = "gpt-3.5-turbo";
Expand All @@ -217,35 +132,45 @@ export const ConversationDialogue: React.FC<ConversationDialogueProps> = ({
<div className={`ow-conversation-dialogue ${conversation?.context === false ? "ow-context" : ""}`} ref={dialogueTimelineRef}>
{
conversation!?.messages.length > 1 ? (
rootMessage && renderMessages(rootMessage.id)
rootMessage && (
<MessageRenderer
messageId={rootMessage.id}
selectedChildren={selectedChildren}
changeSelectedChild={changeSelectedChild}
conversation={conversation}
plugin={plugin}
/>
)
) : (
<div className="ow-message-empty-dialogue">
<div className="ow-change-engine">
<button
className={activeEngine === "gpt-3.5-turbo" ? "ow-active" : ""}
onClick={handleSetGPT3}
>
<div className="ow-icon">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className="lucide lucide-zap"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"></polygon></svg>
</div>
<span>
GPT-3.5
</span>
</button>
<button
className={activeEngine === "gpt-4" ? "ow-active" : ""}
onClick={handleSetGPT4}
>
<div className="ow-icon">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className="lucide lucide-sparkles"><path d="m12 3-1.912 5.813a2 2 0 0 1-1.275 1.275L3 12l5.813 1.912a2 2 0 0 1 1.275 1.275L12 21l1.912-5.813a2 2 0 0 1 1.275-1.275L21 12l-5.813-1.912a2 2 0 0 1-1.275-1.275L12 3Z"></path><path d="M5 3v4"></path><path d="M19 17v4"></path><path d="M3 5h4"></path><path d="M17 19h4"></path></svg>
</div>
<span>
GPT-4
</span>
</button>
showEngineInfo && (
<div className="ow-message-empty-dialogue">
<div className="ow-change-engine">
<button
className={activeEngine === "gpt-3.5-turbo" ? "ow-active" : ""}
onClick={handleSetGPT3}
>
<div className="ow-icon">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className="lucide lucide-zap"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"></polygon></svg>
</div>
<span>
GPT-3.5
</span>
</button>
<button
className={activeEngine === "gpt-4" ? "ow-active" : ""}
onClick={handleSetGPT4}
>
<div className="ow-icon">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className="lucide lucide-sparkles"><path d="m12 3-1.912 5.813a2 2 0 0 1-1.275 1.275L3 12l5.813 1.912a2 2 0 0 1 1.275 1.275L12 21l1.912-5.813a2 2 0 0 1 1.275-1.275L21 12l-5.813-1.912a2 2 0 0 1-1.275-1.275L12 3Z"></path><path d="M5 3v4"></path><path d="M19 17v4"></path><path d="M3 5h4"></path><path d="M17 19h4"></path></svg>
</div>
<span>
GPT-4
</span>
</button>
</div>
<ConversationEngineInfo plugin={plugin} activeEngine={activeEngine} />
</div>
<ConversationEngineInfo plugin={plugin} activeEngine={activeEngine} />
</div>
)
)
}
</div>
Expand Down
13 changes: 8 additions & 5 deletions src/components/Conversation/ConversationHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import { ThreadManager } from "utils/ThreadManager";

interface ConversationHeaderProps {
plugin: Weaver;
conversation: IConversation | null | undefined;
conversation: IConversation | undefined;
onTabSwitch: (tabId: string) => void;
setConversationSession: React.Dispatch<React.SetStateAction<IConversation | null>>;
setConversationSession: React.Dispatch<React.SetStateAction<IConversation | undefined>>;
}

export const ConversationHeader: React.FC<ConversationHeaderProps> = ({
Expand Down Expand Up @@ -83,9 +83,12 @@ export const ConversationHeader: React.FC<ConversationHeaderProps> = ({
} else {
setConversationSession(prevConversation => {
if (prevConversation) {
return { ...prevConversation, title: uniqueTitle };
return {
...prevConversation,
title: uniqueTitle
};
} else {
return null;
return prevConversation;
}
});

Expand Down Expand Up @@ -131,7 +134,7 @@ export const ConversationHeader: React.FC<ConversationHeaderProps> = ({
if (prevConversation) {
return { ...prevConversation, context: newContext };
} else {
return null;
return;
}
});

Expand Down
Loading

0 comments on commit dfc5fe8

Please sign in to comment.