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

Add /answer/explain route for explaining file ranges #785

Merged
merged 23 commits into from
Aug 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
a92e213
FE adjustments for file explanation
anastasiya1155 Jul 27, 2023
282799a
show explanation next to file
anastasiya1155 Jul 31, 2023
7b07228
Add /answer/explain route for explaining file ranges
calyptobai Aug 1, 2023
9036025
Amend query to search steps, and flatten `lines`
calyptobai Aug 1, 2023
311016e
Add branch to /answer/explain
calyptobai Aug 1, 2023
bcbc560
Add focused code chunk to exchange
calyptobai Aug 1, 2023
c2de585
updates after rebase
anastasiya1155 Aug 2, 2023
2befbd7
Swap file_content for file_path in FocussedChunk
ggordonhall Aug 2, 2023
07a2dd6
feedback fixes
anastasiya1155 Aug 2, 2023
023fe97
fix scroll into view to the same element
anastasiya1155 Aug 2, 2023
6337193
fix overlapping highlights
anastasiya1155 Aug 2, 2023
23638e2
Solve some rebased conflicts
calyptobai Aug 2, 2023
7429d12
fix compile errors
ggordonhall Aug 3, 2023
ba74dc8
fixes after rebase
anastasiya1155 Aug 3, 2023
661bfe5
linter fixes
anastasiya1155 Aug 3, 2023
f5c1742
add more highlight colors, remove highlights when navigating from res…
anastasiya1155 Aug 3, 2023
3b7c2ec
show markdown copy button only on hover
anastasiya1155 Aug 3, 2023
9d6d117
fix incorrect snippet end_line
ggordonhall Aug 3, 2023
f00b326
Merge branch 'explain-file' of github.com:BloopAI/bloop into explain-…
ggordonhall Aug 3, 2023
5a4ee00
copy button for code on hover
anastasiya1155 Aug 3, 2023
f6bbea3
fix types
anastasiya1155 Aug 3, 2023
ca68093
Track errors in /answer/explain as well as /answer
calyptobai Aug 3, 2023
4e6fdc5
Clarify error messages
calyptobai Aug 3, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 9 additions & 6 deletions client/src/Tab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import FileModalContainer from './pages/ResultModal/FileModalContainer';
import { FileModalContextProvider } from './context/providers/FileModalContextProvider';
import PromptGuidePopup from './components/PromptGuidePopup';
import Onboarding from './pages/Onboarding';
import { FileHighlightsContextProvider } from './context/providers/FileHighlightsContextProvider';

type Props = {
isActive: boolean;
Expand All @@ -31,12 +32,14 @@ class Tab extends PureComponent<Props> {
<AppNavigationProvider tab={tab}>
<SearchContextProvider tab={tab}>
<ChatContextProvider>
<ContentContainer tab={tab} />
<Settings />
<ReportBugModal />
<FileModalContainer repoName={tab.repoName} />
<PromptGuidePopup />
<Onboarding />
<FileHighlightsContextProvider>
<ContentContainer tab={tab} />
<Settings />
<ReportBugModal />
<FileModalContainer repoName={tab.repoName} />
<PromptGuidePopup />
<Onboarding />
</FileHighlightsContextProvider>
</ChatContextProvider>
</SearchContextProvider>
</AppNavigationProvider>
Expand Down
1 change: 1 addition & 0 deletions client/src/components/Chat/AllCoversations/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ const AllConversations = ({
isFromHistory: true,
queryId: m.id,
responseTimestamp: m.response_timestamp,
explainedFile: m.focused_chunk?.file_path,
});
});
setTitle(conv[0].text || '');
Expand Down
3 changes: 3 additions & 0 deletions client/src/components/Chat/Conversation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ const Conversation = ({
responseTimestamp={
m.author === ChatMessageAuthor.Server ? m.responseTimestamp : null
}
explainedFile={
m.author === ChatMessageAuthor.Server ? m.explainedFile : undefined
}
/>
))}
</div>
Expand Down
83 changes: 81 additions & 2 deletions client/src/components/Chat/ConversationMessage/FileChip.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,100 @@
import React from 'react';
import React, {
Dispatch,
MutableRefObject,
SetStateAction,
useEffect,
useRef,
} from 'react';
import FileIcon from '../../FileIcon';
import { ArrowOut } from '../../../icons';
import { highlightColors } from '../../../consts/code';
import { FileHighlightsType } from '../../../types/general';

type Props = {
onClick: () => void;
fileName: string;
filePath: string;
skipIcon?: boolean;
lines?: [number, number];
fileChips?: MutableRefObject<HTMLButtonElement[]>;
setFileHighlights?: Dispatch<SetStateAction<FileHighlightsType>>;
};

const FileChip = ({ onClick, fileName, skipIcon }: Props) => {
const FileChip = ({
onClick,
fileName,
filePath,
skipIcon,
lines,
fileChips,
setFileHighlights,
}: Props) => {
const ref = useRef<HTMLButtonElement>(null);

useEffect(() => {
let chip = ref.current;
if (chip && fileChips) {
fileChips.current.push(chip);
}

return () => {
if (chip && fileChips) {
const index = fileChips.current.indexOf(chip);
if (index !== -1) {
fileChips.current.splice(index, 1);
}
}
};
}, []);

const index =
ref.current && fileChips ? fileChips.current.indexOf(ref.current) : -1;

useEffect(() => {
if (lines && index > -1 && setFileHighlights) {
setFileHighlights((prev) => {
const newHighlights = { ...prev };
if (!newHighlights[filePath]) {
newHighlights[filePath] = [];
}
newHighlights[filePath][index] = {
lines,
color: `rgb(${highlightColors[index % highlightColors.length].join(
', ',
)})`,
index,
};
// newHighlights[filePath] = newHighlights[filePath].filter((h) => !!h);
if (JSON.stringify(prev) === JSON.stringify(newHighlights)) {
return prev;
}
return newHighlights;
});
}
}, [lines, filePath, index]);

return (
<button
className={`inline-flex items-center bg-chat-bg-shade rounded-4 overflow-hidden
text-label-base hover:text-label-title border border-transparent hover:border-chat-bg-border
cursor-pointer align-middle ellipsis`}
ref={ref}
onClick={onClick}
>
{!!lines && (
<span
className="w-0.5 h-4 ml-1 rounded-px"
style={{
width: 2,
height: 14,
backgroundColor: `rgb(${
index > -1
? highlightColors[index % highlightColors.length].join(', ')
: ''
})`,
}}
/>
)}
<span className="flex gap-1 px-1 py-0.5 items-center border-r border-chat-bg-border code-s ellipsis">
{!skipIcon && <FileIcon filename={fileName} noMargin />}
<span className="ellipsis">{fileName}</span>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,17 @@ type Props = {
article: string;
i: number;
threadId: string;
explainedFile?: string;
};

const SummaryCardsArticle = ({ article, i, threadId }: Props) => {
const { navigateArticleResponse } = useContext(AppNavigationContext);
const SummaryCardsArticle = ({
article,
i,
threadId,
explainedFile,
}: Props) => {
const { navigateArticleResponse, navigateFullResult } =
useContext(AppNavigationContext);
return (
<>
{article
Expand All @@ -29,7 +36,13 @@ const SummaryCardsArticle = ({ article, i, threadId }: Props) => {
.map((p, index, array) =>
index === array.length - 1 ? (
<SummaryCardMain
onClick={() => navigateArticleResponse(i, threadId)}
onClick={() => {
if (explainedFile) {
navigateFullResult(explainedFile, undefined, i, threadId);
} else {
navigateArticleResponse(i, threadId);
}
}}
key={index}
isArticle
>
Expand Down
4 changes: 4 additions & 0 deletions client/src/components/Chat/ConversationMessage/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ type Props = {
results?: string;
i: number;
onMessageEdit: (queryId: string, i: number) => void;
explainedFile?: string;
};

const ConversationMessage = ({
Expand All @@ -61,6 +62,7 @@ const ConversationMessage = ({
repoName,
onMessageEdit,
responseTimestamp,
explainedFile,
}: Props) => {
const { t } = useTranslation();
const [isLoadingStepsShown, setLoadingStepsShown] = useState(false);
Expand Down Expand Up @@ -95,6 +97,7 @@ const ConversationMessage = ({
<FileChip
onClick={() => openFileModal(s.path)}
fileName={s.path.split('/').pop() || ''}
filePath={s.path || ''}
/>
) : null}
</div>
Expand Down Expand Up @@ -144,6 +147,7 @@ const ConversationMessage = ({
article={results}
threadId={threadId}
i={i}
explainedFile={explainedFile}
/>
) : null}
</div>
Expand Down
81 changes: 54 additions & 27 deletions client/src/components/Chat/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ const Chat = () => {
navigateRepoPath,
navigatedItem,
navigateArticleResponse,
navigateFullResult,
} = useContext(AppNavigationContext);
const [isLoading, setLoading] = useState(false);
const [showPopup, setShowPopup] = useState(false);
Expand All @@ -77,7 +78,10 @@ const Chat = () => {
}, [isChatOpen]);

const makeSearch = useCallback(
(query: string) => {
(
query: string,
options?: { filePath: string; lineStart: string; lineEnd: string },
) => {
if (!query) {
return;
}
Expand All @@ -87,23 +91,23 @@ const Chat = () => {
setLoading(true);
setQueryIdToEdit('');
setHideMessagesFrom(null);
const eventSource = new EventSource(
`${apiUrl.replace('https:', '')}/answer?q=${encodeURIComponent(query)}${
selectedBranch ? ` branch:${selectedBranch}` : ''
}&repo_ref=${tab.key}${threadId ? `&thread_id=${threadId}` : ''}${
navigatedItem?.type === 'repo' && navigatedItem?.path
? `&relative_path=${navigatedItem?.path}&is_folder=true`
: ''
}${
navigatedItem?.type === 'full-result' && navigatedItem?.path
? `&relative_path=${navigatedItem?.path}&is_folder=false`
: ''
}${
selectedLines
? `&start=${selectedLines[0]}&end=${selectedLines[1]}`
: ''
}${queryIdToEdit ? `&parent_exchange_id=${queryIdToEdit}` : ''}`,
);
const url = `${apiUrl.replace(/http(s)*:/, '')}/answer${
options
? `/explain?relative_path=${encodeURIComponent(
options.filePath,
)}&line_start=${options.lineStart}&line_end=${options.lineEnd}`
: `?q=${encodeURIComponent(query)}${
selectedBranch ? ` branch:${selectedBranch}` : ''
}`
}&repo_ref=${tab.key}${
threadId
? `&thread_id=${threadId}${
queryIdToEdit ? `&parent_query_id=${queryIdToEdit}` : ''
}`
: ''
}`;
console.log(url);
const eventSource = new EventSource(url);
prevEventSource = eventSource;
setSelectedLines(null);
let firstResultCame: boolean;
Expand All @@ -126,7 +130,9 @@ const Chat = () => {
queryId: '',
responseTimestamp: new Date().toISOString(),
};
setInputValue(prev[prev.length - 2]?.text || submittedQuery);
if (!options) {
setInputValue(prev[prev.length - 2]?.text || submittedQuery);
}
setSubmittedQuery('');
return [...newConversation, lastMessage];
});
Expand Down Expand Up @@ -155,7 +161,9 @@ const Chat = () => {
queryId: '',
responseTimestamp: new Date().toISOString(),
};
setInputValue(prev[prev.length - 1]?.text || submittedQuery);
if (!options) {
setInputValue(prev[prev.length - 1]?.text || submittedQuery);
}
setSubmittedQuery('');
return [...newConversation, lastMessage];
});
Expand Down Expand Up @@ -203,6 +211,7 @@ const Chat = () => {
results: newMessage.answer,
queryId: newMessage.id,
responseTimestamp: newMessage.response_timestamp,
explainedFile: newMessage.focused_chunk?.file_path,
};
const lastMessages: ChatMessage[] =
lastMessage?.author === ChatMessageAuthor.Server
Expand All @@ -213,8 +222,18 @@ const Chat = () => {
// workaround: sometimes we get [^summary]: before it is removed from response
if (newMessage.answer?.length > 11 && !firstResultCame) {
setConversation((prev) => {
setChatOpen(false);
navigateArticleResponse(prev.length - 1, thread_id);
if (newMessage.focused_chunk?.file_path) {
setChatOpen(false);
navigateFullResult(
newMessage.focused_chunk?.file_path,
undefined,
prev.length - 1,
thread_id,
);
} else {
setChatOpen(false);
navigateArticleResponse(prev.length - 1, thread_id);
}
return prev;
});
firstResultCame = true;
Expand Down Expand Up @@ -246,10 +265,12 @@ const Chat = () => {
"We couldn't answer your question. You can try asking again in a few moments, or rephrasing your question.",
),
};
setInputValue(
prev[prev.length - (lastMessageIsServer ? 2 : 1)]?.text ||
submittedQuery,
);
if (!options) {
setInputValue(
prev[prev.length - (lastMessageIsServer ? 2 : 1)]?.text ||
submittedQuery,
);
}
setSubmittedQuery('');
return [...newConversation, lastMessage];
});
Expand Down Expand Up @@ -279,10 +300,16 @@ const Chat = () => {
return;
}
let userQuery = submittedQuery;
let options = undefined;
if (submittedQuery.startsWith('#explain_')) {
const [prefix, ending] = submittedQuery.split(':');
const [lineStart, lineEnd] = ending.split('-');
const filePath = prefix.slice(9);
options = {
filePath,
lineStart,
lineEnd,
};
userQuery = t(
`Explain lines {{lineStart}} - {{lineEnd}} in {{filePath}}`,
{
Expand All @@ -300,7 +327,7 @@ const Chat = () => {
isLoading: false,
},
]);
makeSearch(userQuery);
makeSearch(userQuery, options);
}, [submittedQuery]);

const stopGenerating = useCallback(() => {
Expand Down
Loading
Loading