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

feat: upgraded the methods for Copilot using pieces-copilot-sdk #138

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@
"ts-node": "^10.9.1",
"jest-environment-jsdom": "^29.7.0",
"rehype-sanitize": "6.0.0",
"react-markdown": "9.0.1"
"react-markdown": "9.0.1",
"pieces-copilot-sdk": "^1.1.9"
},
"devDependencies": {
"@testing-library/jest-dom": "^6.2.0",
Expand Down
4 changes: 1 addition & 3 deletions src/app/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import {Header} from './components/Header/Header'
import {CopilotChat} from './components/Copilot/Copilot'
import {connect} from './utils/Connect'
import { Indicator } from "./components/Indicator/Indicator";
import CopilotStreamController from "./controllers/copilotStreamController";
import "./global.css";
import WorkflowActivityList from "./components/WorkflowActivity";
import { OSApi } from "@pieces.app/pieces-os-client";
Expand Down Expand Up @@ -80,8 +79,7 @@ export function App(): React.JSX.Element {

useEffect(() => {
refreshSnippetList();
CopilotStreamController.getInstance();
}, []);
}, []);

const clearArray = () => {
setArray([])
Expand Down
153 changes: 78 additions & 75 deletions src/app/components/Copilot/Copilot.tsx
Original file line number Diff line number Diff line change
@@ -1,55 +1,21 @@
import * as React from 'react'
import {useEffect, useState} from 'react'
import * as Pieces from "@pieces.app/pieces-os-client";
import {ConversationTypeEnum, SeededConversation} from "@pieces.app/pieces-os-client";
import "./Copilot.css";


import { applicationData } from "../../App";
import CopilotStreamController from '../../controllers/copilotStreamController';
import Markdown from '../ResponseFormat/Markdown';
import { config } from '../../../platform.config';
import { piecesClient } from '../../../platform.config';

// Replace 'your_base_url' with your actual base URL

let GlobalConversationID: string;


// going to use get all conversations with a few extra steps to store the current conversations locally.
export function createNewConversation() {
export async function createNewConversation() {
try {

// logs --> CREATING CONVERSATION
console.log('Begin creating conversation...')

// to create a new conversation, you need to first pass in a seeded conversation in the request body.
// the only mandatory parameter is the ConversationTypeEnum.Copilot value.
let seededConversation: SeededConversation = { type: ConversationTypeEnum.Copilot, name: "Demo Seeded Conversation" }

console.log('Conversation seeded')
console.log('Passing over the new conversation with name: ' + seededConversation.name)

// creates new conversation, .then is for confirmation on creation.
// note the usage of transfereables here to expose the full conversation data and give access to the id and other
// conversation values.
new Pieces.ConversationsApi(config).conversationsCreateSpecificConversationRaw({transferables: true, seededConversation}).then((_c) => {
console.log('Conversation created! : Here is the response:');
console.log(_c);

// check and ensure the response back is clean.
if (_c.raw.ok == true && _c.raw.status == 200) {
console.log('CLEAN RESPONSE BACK.')
_c.value().then(_conversation => {
console.log('Returning new conversation values.');
// console.log('ID | ' + _conversation.id);
// console.log('NAME | ' + _conversation.name);
// console.log('CREATED | ' + _conversation.created.readable);
// console.log('ID: ' + _conversation.);

// Set the conversation variable here for the local file:
GlobalConversationID = _conversation.id;
})
}
})
const newConversation = await piecesClient.createConversation({
name: 'Hello World Conversation'
});
GlobalConversationID = newConversation.conversation.id;
} catch (error) {
console.error('An error occurred while creating a conversation:', error);
}
Expand Down Expand Up @@ -77,24 +43,31 @@ export function createNewConversation() {
// })
// }
export function CopilotChat(): React.JSX.Element {
const [chatSelected, setChatSelected] = useState('-- no chat selected --');
const [chatSelected, setChatSelected] = useState('no chat selected');
const [chatInputData, setData] = useState('');
const [message, setMessage] = useState<string>('');
const [conversations, setConversations] = useState([]);


// handles the data changes on the chat input.
const handleCopilotChatInputChange = (event: { target: { value: React.SetStateAction<string>; }; }) => {
setData(event.target.value);
};

// handles the ask button click.
const handleCopilotAskbuttonClick = async (chatInputData, setMessage)=>{
CopilotStreamController.getInstance().askQGPT({
query: chatInputData,
setMessage,
});
setData("");
}

const handleCopilotAskButtonClick = async (chatInputData) => {
try {
const { text } = await piecesClient.promptConversation({
message: chatInputData,
conversationId: GlobalConversationID
});
setMessage(text);
setData("");
} catch (error) {
console.error('An error occurred while prompting the conversation:', error);
}
};

// handles the new conversation button click.
const handleNewConversation = async () => {
createNewConversation();
Expand All @@ -104,46 +77,76 @@ export function CopilotChat(): React.JSX.Element {

// for setting the initial copilot chat that takes place on page load.
useEffect(() => {
const getInitialChat = async () => {
let _name: string;

await new Pieces.ConversationsApi(config)
.conversationsSnapshot({})
.then((output) => {
if (
output.iterable.length > 0 &&
output.iterable.at(0).hasOwnProperty("name")
) {
_name = output.iterable.at(0).name;
GlobalConversationID = output.iterable.at(0).id;
const getInitialChat = async () => {
try {
const allConversations = await piecesClient.getConversations();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @VishalPawar1010 great work with this implementation. I was just wondering if you would like to also implement an additional functionality actually to list all of the conversations using the getConversations endpoint. on the UI. right now the back and forward buttons are not functionality. We can have a conversations list. and let the user select which conversation they wish to view. And you can use the piecesClient to then return that conversation ID and display the existing conversation in the Copilot chat window
image

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So we can remove the back and forward buttons and have a UI button for: choose copilot conversation

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What are your thoughts @Arindam-at-Pieces

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, I will implement this functinality to list conversations and give option to select then display selected conversation.
Do we have any plan to use TailwindCss in future for UI feature additions (like dropdown etc) like this ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes I think we can definitely introduce Tailwind @VishalPawar1010
I think that is a larger discussion as part to restructure the UI / Revamp the entire project, so that can definitely be explored.

Copy link
Contributor Author

@VishalPawar1010 VishalPawar1010 Jul 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok then, until it is finalised I will implement UI in Vanilla Js + Css.

Copy link
Contributor Author

@VishalPawar1010 VishalPawar1010 Jul 25, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @VishalPawar1010 what I will recommend is if you can also display the messages of the specific chat that you have selected in the chat window

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay sure. Will try to display message as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

setConversations(allConversations);
// console.log('allConversations', allConversations);
if (allConversations.length > 0) {
const { id, name, messages } = allConversations[0];
GlobalConversationID = id;
setChatSelected(name);
getConversationMessage(id);
}
} catch (error) {
console.error('Error fetching conversations:', error);
}
return _name;
});

if (_name) {
setChatSelected(_name);
}
};
getInitialChat();
};
getInitialChat();
}, []);

const getConversationMessage = async (selectedId) => {
try {
const {rawMessages} = await piecesClient.getConversation({
conversationId: selectedId,
includeRawMessages: true,
});
console.log("getMessages === ",rawMessages);
if (rawMessages.length>1) {
if(rawMessages[1].isUserMessage){
setMessage(rawMessages[2].message)
}
else setMessage(rawMessages[1].message)
}
else setMessage("No previous conversation history, please ask the question below.");
} catch (error) {
console.error('Error fetching conversations:', error);
}
}

const handleConversationChange = (event: React.ChangeEvent<HTMLSelectElement>) => {
const selectedId = event.target.value;
const selectedConversation = conversations.find(convo => convo.id === selectedId);
if (selectedConversation) {
GlobalConversationID = selectedId;
setChatSelected(selectedConversation.name);

getConversationMessage(selectedId);
}
};

return (
<div className="container">
<div className="header">
<div>
<h1>Copilot Chat</h1>
<button className="button" onClick={handleNewConversation}>Create Fresh Conversation</button>
</div>
<div className="footer">
<button>back</button>
<p>{chatSelected}</p>
<button>forward</button>
<div>
Select your chat:
<select onChange={handleConversationChange} value={GlobalConversationID}>
{conversations.map((conversation) => (
<option key={conversation.id} value={conversation.id}>
{conversation.name}
</option>
))}
</select>
</div>
</div>
<div className="chat-box">
<div className="text-area">
<textarea placeholder="Type your prompt here..." value={chatInputData} onChange={handleCopilotChatInputChange}></textarea>
<button onClick={() => handleCopilotAskbuttonClick(chatInputData,setMessage) }>Ask</button>
<button onClick={() => handleCopilotAskButtonClick(chatInputData) }>Ask</button>
</div>
<div className="messages">
<div>
Expand Down
Loading
Loading