Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 0 additions & 1 deletion samples/apps/github-qna-webapp-react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
"@types/node": "^16.7.13",
"@types/react": "^18.0.0",
"@types/react-dom": "^18.0.0",
"openai": "^3.2.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-scripts": "5.0.1",
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// Copyright (c) Microsoft. All rights reserved.

import { Body1, Button, Input, Label, Spinner, Title3 } from '@fluentui/react-components';
import { ArrowDownload16Regular, CheckmarkCircle20Filled } from '@fluentui/react-icons';
import React, { FC, useState } from 'react';
import { ArrowDownload16Regular, CheckmarkCircle20Filled, ErrorCircle20Regular } from '@fluentui/react-icons';
import { FC, useEffect, useState } from 'react';
import { useSemanticKernel } from '../hooks/useSemanticKernel';
import { IKeyConfig } from '../model/KeyConfig';

Expand All @@ -15,23 +15,26 @@ interface IData {
onLoadProject: (project: string, branch: string) => void;
}

const enum DownloadState {
Setup = 0,
Loading = 1,
Loaded = 2,
Error = 3,
}

const GitHubProjectSelection: FC<IData> = ({ uri, keyConfig, prevProject, prevBranch, onLoadProject, onBack }) => {
const [project, setProject] = useState<string>(prevProject);
const [branch, setBranch] = useState<string>(prevBranch);
const [isLoading, setIsLoading] = useState<boolean>(false);
const [isLoaded, setIsLoaded] = useState<boolean>(project !== '' && branch !== '');
const [isLoadError, setIsLoadError] = useState<boolean>(false);
const [downloadState, setDownloadState] = useState<DownloadState>(DownloadState.Setup);
const sk = useSemanticKernel(uri);

const isSameProjectAndBranch = () => {
return project === prevProject && branch === prevBranch && project !== '' && branch !== '';
}
};

const download = async () => {
try {
setIsLoading(true);
setIsLoaded(false);
setIsLoadError(false);
setDownloadState(DownloadState.Loading);
var result = await sk.invokeAsync(
keyConfig,
{
Expand All @@ -44,22 +47,24 @@ const GitHubProjectSelection: FC<IData> = ({ uri, keyConfig, prevProject, prevBr
'GitHubSkill',
'SummarizeRepository',
);
setIsLoaded(true);
setDownloadState(DownloadState.Loaded);
console.log(result);
} catch (e) {
setIsLoadError(true);
setDownloadState(DownloadState.Error);
alert('Something went wrong.\n\nDetails:\n' + e);
} finally {
setIsLoading(false);
}
};

React.useEffect(() => {
setIsLoaded(isSameProjectAndBranch())
useEffect(() => {
if (isSameProjectAndBranch()) {
setDownloadState(DownloadState.Loaded);
}
}, [project]);

React.useEffect(() => {
setIsLoaded(isSameProjectAndBranch())
useEffect(() => {
if (isSameProjectAndBranch()) {
setDownloadState(DownloadState.Loaded);
}
}, [branch]);

return (
Expand Down Expand Up @@ -98,46 +103,44 @@ const GitHubProjectSelection: FC<IData> = ({ uri, keyConfig, prevProject, prevBr
placeholder="main"
/>
<Button
disabled={isLoading || isLoaded || project === '' || branch === '' }
disabled={
project === '' ||
branch === '' ||
downloadState === DownloadState.Loading ||
downloadState === DownloadState.Loaded
}
appearance="transparent"
icon={<ArrowDownload16Regular />}
onClick={() => download()}
/>
</div>
{isLoading ? (
<div>
<Spinner />
<Body1>
Summarizing repository markdown files. Please wait, this can take several minutes depending on
the number of files.
</Body1>
</div>
) : (
<></>
)}
{isLoaded ? (
<div>
<CheckmarkCircle20Filled />
<Body1>
Repository markdown files summarized. You can ask questions about it on the next page.
</Body1>
</div>
) : (
<></>
)}
{isLoadError ? (
<div>
<Body1>There was an error summarizing the repository. Please try again.</Body1>
</div>
) : (
<></>
)}
<div style={{ display: 'flex', flexDirection: 'row', gap: 10, alignItems: 'center' }}>
{downloadState === DownloadState.Loading ? (
<>
<Spinner size="tiny" />
<Body1>
Downloading repository. Please wait, this can take several minutes depending on the number
of files.
</Body1>
</>
) : downloadState === DownloadState.Loaded ? (
<>
<CheckmarkCircle20Filled color="green" />
<Body1>Repository downloaded. You can learn more about it on the next page.</Body1>
</>
) : downloadState === DownloadState.Error ? (
<>
<ErrorCircle20Regular color="red" />
<Body1>There was an error downloading the repository. Please try again.</Body1>
</>
) : null}
</div>
<div style={{ display: 'flex', flexDirection: 'row', alignItems: 'left', gap: 20 }}>
<Button style={{ width: 54 }} appearance="secondary" onClick={() => onBack()}>
Back
</Button>
<Button
disabled={!isLoaded}
disabled={downloadState !== DownloadState.Loaded}
appearance="primary"
onClick={() => {
if (project !== undefined && branch !== undefined) onLoadProject(project, branch);
Expand Down
31 changes: 27 additions & 4 deletions samples/apps/github-qna-webapp-react/src/components/QnA.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
// Copyright (c) Microsoft. All rights reserved.

import { Body1, Button, Label, Slider, SliderOnChangeData, Title3 } from '@fluentui/react-components';
import { Avatar, Body1, Button, Label, Slider, SliderOnChangeData, Title3 } from '@fluentui/react-components';
import React, { FC, useCallback, useState } from 'react';
import { ChatHistoryItem, IChatMessage } from './chat/ChatHistoryItem';

import GithubAvatar from '../assets/icons8-github-512.png';
import { useSemanticKernel } from '../hooks/useSemanticKernel';
import { IKeyConfig } from '../model/KeyConfig';
import { ChatInput } from './chat/ChatInput';
Expand All @@ -24,7 +25,7 @@ const QnA: FC<IData> = ({ uri, project, branch, keyConfig, onBack }) => {
const [chatHistory, setChatHistory] = useState<IChatMessage[]>([
{
content:
"Hi! I'm your GitHub Repo bot. Here's the GitHub repo you selected: <a href={project}>" +
"Hi! I'm your GitHub Repo bot. Here's the repo you are interested in: <a href={project}>" +
project +
'</a>',
author: 'GitHub Repo Bot',
Expand Down Expand Up @@ -89,15 +90,36 @@ const QnA: FC<IData> = ({ uri, project, branch, keyConfig, onBack }) => {
<div
style={{
position: 'relative',
maxHeight: '70vh',
maxHeight: '690px',
maxWidth: '1052px',
display: 'grid',
gridTemplateColumns: 'minmax(300px, 800px)',
gridTemplateRows: 'auto 1fr auto',
gridTemplateAreas: "'menu' 'content' 'footer'",
justifyContent: 'center',
boxShadow: '0 2px 4px 0 lightgray',
padding: '2% 5% 2%',
}}
>
<div style={{ gridArea: 'content', overflowY: 'auto', overflowX: 'hidden', padding: '1rem 0' }}>
<div
style={{
gridArea: 'content',
overflowY: 'auto',
overflowX: 'hidden',
padding: '1rem 0',
height: '500px',
display: 'flex',
flexDirection: 'row',
gap: 10,
}}
>
<Avatar
image={{
src: GithubAvatar,
}}
color="neutral"
badge={{ status: 'available' }}
/>
<div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
{chatHistory.map((m, idx) => (
<ChatHistoryItem key={idx} message={m} />
Expand Down Expand Up @@ -127,6 +149,7 @@ const QnA: FC<IData> = ({ uri, project, branch, keyConfig, onBack }) => {
alignItems: 'left',
gap: '20',
justifyContent: 'space-between',
marginTop: 20,
}}
>
<Button onClick={() => onBack()} style={{ height: 'fit-content' }}>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright (c) Microsoft. All rights reserved.

import React, { CSSProperties, FC } from 'react';
import { CSSProperties, FC } from 'react';

interface IData {
message: IChatMessage;
Expand All @@ -10,7 +10,7 @@ export interface IChatMessage {
content: string;
author: string;
timestamp: string;
mine: boolean
mine: boolean;
}

export const ChatHistoryItem: FC<IData> = ({ message }) => {
Expand All @@ -20,18 +20,25 @@ export const ChatHistoryItem: FC<IData> = ({ message }) => {

const style: CSSProperties = {
alignSelf: message.mine ? 'flex-end' : 'flex-start',
backgroundColor: message.mine ? '#e6f4ff' : '#f4f4f4',
backgroundColor: message.mine ? '#E8EBFA' : '#f4f4f4',
borderRadius: 10,
padding: '0.5rem',
padding: '6px 12px',
maxWidth: '75%',
};

const content = message.content.trim().replace(/\n/g, '<br />');

const time = new Date(message.timestamp).toLocaleTimeString();

return (
<div style={style}>
<div style={{ display: 'flex', flexDirection: 'column', gap: 20 }}>
<div style={{ paddingBottom: 10 }}>{message.mine ? null : <span style={{ paddingRight: 20, fontWeight: 'bold' }}>{message.author}</span>}<span style={{ fontSize: 10 }}> Date: {message.timestamp}</span></div>
<div style={{ paddingBottom: 10 }}>
{message.mine ? null : (
<span style={{ paddingRight: 30, fontWeight: 'bold', fontSize: 16 }}>{message.author}</span>
)}
<span style={{ fontSize: 12 }}> {time}</span>
</div>
</div>
<div dangerouslySetInnerHTML={{ __html: content }} />
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export const ChatInput: FC<ChatInputProps> = (props) => {
<div style={{ display: 'flex', flexDirection: 'row', gap: 10 }}>
<Input
style={{ width: '100%' }}
placeholder="Type your question here"
placeholder="Type a question you have for the repo"
value={value}
multiple
onChange={(e, d) => setValue(d.value)}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
// Copyright (c) Microsoft. All rights reserved.

import { Dropdown, Label, Option, Spinner } from '@fluentui/react-components';
import { Dropdown, Link, Option, Spinner } from '@fluentui/react-components';
import { InfoLabel } from '@fluentui/react-components/unstable';
// import { Configuration, OpenAIApi } from 'openai';
import { FC, useEffect, useState } from 'react';
import '../../App.css';
import { IBackendConfig } from '../../model/KeyConfig';

interface IData {
Expand Down Expand Up @@ -32,7 +34,7 @@ const ModelConfig: FC<IData> = ({
setBackendConfig,
defaultModel = '',
}) => {
const modelTitle = modelType === ModelType.Embeddings ? ['embedding', 'Embedding'] : ['completion', 'Completion'];
const modelTitle = modelType === ModelType.Embeddings ? ['embeddings', 'Embeddings'] : ['completion', 'Completion'];
const labelPrefix = `${isOpenAI ? 'oai' : 'aoai'}${modelTitle[0]}`;
const [modelIds, setModelIds] = useState<ModelOption[] | undefined>();
const [isBusy, setIsBusy] = useState(false);
Expand Down Expand Up @@ -107,7 +109,19 @@ const ModelConfig: FC<IData> = ({

return (
<div style={{ paddingTop: 20, gap: 10, display: 'flex', flexDirection: 'column', alignItems: 'left' }}>
<Label htmlFor={`${labelPrefix}model`}>{modelTitle[1]} Model</Label>
<InfoLabel
info={
<div style={{ maxWidth: 250 }}>
Please note this drop down lists all available models, but not all will work as{' '}
{(modelType === ModelType.Completion ? 'a ' : 'an ') + modelTitle[0]} model.{' '}
<Link href="https://platform.openai.com/docs/models"> Click here to learn more </Link>
about the differences between completion and embedding models.
</div>
}
htmlFor={`${labelPrefix}model`}
>
{modelTitle[1]} Model
</InfoLabel>
<div style={{ display: 'flex', gap: 10, flexDirection: 'row', alignItems: 'left' }}>
{isBusy ? <Spinner size="tiny" /> : null}
<Dropdown
Expand All @@ -116,7 +130,7 @@ const ModelConfig: FC<IData> = ({
placeholder={
modelIds
? 'Select a model id'
: `Enter valid key ${isOpenAI ? '' : 'and endpoint to load'} models`
: `Enter valid key ${isOpenAI ? '' : 'and endpoint'} to load models`
}
onOptionSelect={(_e, model) => {
setSelectedModel(model.optionValue ?? '');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export const SK_HTTP_HEADER_EMBEDDING_KEY: string = 'x-ms-sk-embedding-key';
export const SK_HTTP_HEADER_MSGRAPH: string = 'x-ms-sk-msgraph';

export interface IBackendConfig {
backend: number; //OpenAI = 0, Azure OpenAI = 1
backend: number; //OpenAI = 1, Azure OpenAI = 0
label: string;
deploymentOrModelId: string;
endpoint: string;
Expand Down
26 changes: 1 addition & 25 deletions samples/apps/github-qna-webapp-react/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3393,13 +3393,6 @@ axe-core@^4.6.2:
resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.6.3.tgz#fc0db6fdb65cc7a80ccf85286d91d64ababa3ece"
integrity sha512-/BQzOX780JhsxDnPpH4ZiyrJAzcd8AfzFPkv+89veFSr1rcMjuq2JDCwypKaPeB6ljHp9KjXhPpjgCvQlWYuqg==

axios@^0.26.0:
version "0.26.1"
resolved "https://registry.yarnpkg.com/axios/-/axios-0.26.1.tgz#1ede41c51fcf51bbbd6fd43669caaa4f0495aaa9"
integrity sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==
dependencies:
follow-redirects "^1.14.8"

axobject-query@^3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-3.1.1.tgz#3b6e5c6d4e43ca7ba51c5babf99d22a9c68485e1"
Expand Down Expand Up @@ -5209,7 +5202,7 @@ flatted@^3.1.0:
resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.7.tgz#609f39207cb614b89d0765b477cb2d437fbf9787"
integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==

follow-redirects@^1.0.0, follow-redirects@^1.14.8:
follow-redirects@^1.0.0:
version "1.15.2"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13"
integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==
Expand Down Expand Up @@ -5249,15 +5242,6 @@ form-data@^3.0.0:
combined-stream "^1.0.8"
mime-types "^2.1.12"

form-data@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452"
integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==
dependencies:
asynckit "^0.4.0"
combined-stream "^1.0.8"
mime-types "^2.1.12"

forwarded@0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811"
Expand Down Expand Up @@ -7283,14 +7267,6 @@ open@^8.0.9, open@^8.4.0:
is-docker "^2.1.1"
is-wsl "^2.2.0"

openai@^3.2.1:
version "3.2.1"
resolved "https://registry.yarnpkg.com/openai/-/openai-3.2.1.tgz#1fa35bdf979cbde8453b43f2dd3a7d401ee40866"
integrity sha512-762C9BNlJPbjjlWZi4WYK9iM2tAVAv0uUp1UmI34vb0CN5T2mjB/qM6RYBmNKMh/dN9fC+bxqPwWJZUTWW052A==
dependencies:
axios "^0.26.0"
form-data "^4.0.0"

optionator@^0.8.1:
version "0.8.3"
resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495"
Expand Down