Skip to content

Commit

Permalink
Merge branch 'main' into linksfix
Browse files Browse the repository at this point in the history
  • Loading branch information
pamelafox authored Mar 20, 2024
2 parents 0be9f2a + 40e9887 commit 69afd4a
Show file tree
Hide file tree
Showing 16 changed files with 198 additions and 32 deletions.
2 changes: 1 addition & 1 deletion .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ check the box below and notify the tutorial author. A Microsoft employee can do

## Code quality checklist

See [CONTRIBUTING.md](../CONTRIBUTING.md#submit-pr) for more details.
See [CONTRIBUTING.md](https://github.com/Azure-Samples/azure-search-openai-demo/blob/main/CONTRIBUTING.md#submit-pr) for more details.

- [ ] The current tests all pass (`python -m pytest`).
- [ ] I added tests that prove my fix is effective or that my feature works
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/validate-markdown.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout Repo
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
- name: Check broken Paths
Expand All @@ -37,7 +37,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout Repo
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
- name: Run Check URLs Country Locale
Expand All @@ -54,7 +54,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout Repo
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
- name: Run Check Broken URLs
Expand Down
4 changes: 2 additions & 2 deletions app/backend/approaches/chatreadretrieveread.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ async def run_until_final_call(

chat_completion: ChatCompletion = await self.openai_client.chat.completions.create(
messages=query_messages, # type: ignore
# Azure Open AI takes the deployment name as the model name
# Azure OpenAI takes the deployment name as the model name
model=self.chatgpt_deployment if self.chatgpt_deployment else self.chatgpt_model,
temperature=0.0, # Minimize creativity for search query generation
max_tokens=100, # Setting too low risks malformed JSON, setting too high may affect performance
Expand Down Expand Up @@ -215,7 +215,7 @@ async def run_until_final_call(
}

chat_coroutine = self.openai_client.chat.completions.create(
# Azure Open AI takes the deployment name as the model name
# Azure OpenAI takes the deployment name as the model name
model=self.chatgpt_deployment if self.chatgpt_deployment else self.chatgpt_model,
messages=messages,
temperature=overrides.get("temperature", 0.3),
Expand Down
2 changes: 1 addition & 1 deletion app/backend/approaches/retrievethenread.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ async def run(
updated_messages = message_builder.messages
chat_completion = (
await self.openai_client.chat.completions.create(
# Azure Open AI takes the deployment name as the model name
# Azure OpenAI takes the deployment name as the model name
model=self.chatgpt_deployment if self.chatgpt_deployment else self.chatgpt_model,
messages=updated_messages,
temperature=overrides.get("temperature", 0.3),
Expand Down
17 changes: 17 additions & 0 deletions app/frontend/package-lock.json

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

1 change: 1 addition & 0 deletions app/frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"@fluentui/react-components": "^9.37.3",
"@fluentui/react-icons": "^2.0.221",
"@react-spring/web": "^9.7.3",
"marked": "^9.1.6",
"dompurify": "^3.0.6",
"react": "^18.2.0",
"react-dom": "^18.2.0",
Expand Down
23 changes: 18 additions & 5 deletions app/frontend/src/components/AnalysisPanel/AnalysisPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { SupportingContent } from "../SupportingContent";
import { ChatAppResponse } from "../../api";
import { AnalysisPanelTabs } from "./AnalysisPanelTabs";
import { ThoughtProcess } from "./ThoughtProcess";
import { MarkdownViewer } from "../MarkdownViewer";
import { useMsal } from "@azure/msal-react";
import { getHeaders } from "../../api";
import { useLogin, getToken } from "../../authConfig";
Expand Down Expand Up @@ -53,6 +54,22 @@ export const AnalysisPanel = ({ answer, activeTab, activeCitation, citationHeigh
fetchCitation();
}, []);

const renderFileViewer = () => {
if (!activeCitation) {
return null;
}

const fileExtension = activeCitation.split(".").pop()?.toLowerCase();
switch (fileExtension) {
case "png":
return <img src={citation} className={styles.citationImg} alt="Citation Image" />;
case "md":
return <MarkdownViewer src={activeCitation} />;
default:
return <iframe title="Citation" src={citation} width="100%" height={citationHeight} />;
}
};

return (
<Pivot
className={className}
Expand All @@ -78,11 +95,7 @@ export const AnalysisPanel = ({ answer, activeTab, activeCitation, citationHeigh
headerText="Citation"
headerButtonProps={isDisabledCitationTab ? pivotItemDisabledStyle : undefined}
>
{activeCitation?.endsWith(".png") ? (
<img src={citation} className={styles.citationImg} />
) : (
<iframe title="Citation" src={citation} width="100%" height={citationHeight} />
)}
{renderFileViewer()}
</PivotItem>
</Pivot>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
.downloadButton {
position: relative;
float: right;
}

.markdownViewer {
border-radius: 8px;
box-shadow:
#0000000d 0 0 0 1px,
#0000001a 0 2px 3px;
background-color: white;
margin: 20px 0;
}

.loading {
padding: 100px;
height: 100vh;
background-color: white;
}

.error {
height: 100vh;
background-color: white;
}

.markdown {
padding: 30px;
}

table {
border-collapse: collapse;
}

th,
td {
border: 1px solid #ddd;
padding: 8px;
}

tr:nth-child(even) {
background-color: #f6f8fa;
}

code {
display: block;
font-family: monospace;
padding: 10px;
background-color: #f6f8fa;
}
78 changes: 78 additions & 0 deletions app/frontend/src/components/MarkdownViewer/MarkdownViewer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import React, { useState, useEffect } from "react";
import { marked } from "marked";
import styles from "./MarkdownViewer.module.css";
import { Spinner, SpinnerSize, MessageBar, MessageBarType, Link, IconButton } from "@fluentui/react";

interface MarkdownViewerProps {
src: string;
}

export const MarkdownViewer: React.FC<MarkdownViewerProps> = ({ src }) => {
const [content, setContent] = useState<string>("");
const [isLoading, setIsLoading] = useState<boolean>(true);
const [error, setError] = useState<Error | null>(null);

/**
* Anchor links are not handled well by 'marked' and result in HTTP 404 errors as the URL they point to does not exist.
* This function removes them from the resulted HTML.
*/
const removeAnchorLinks = (html: string) => {
const ancorLinksRegex = /<a\s+(?:[^>]*?\s+)?href=['"](#[^"']*?)['"][^>]*?>/g;
return html.replace(ancorLinksRegex, "");
};

useEffect(() => {
const fetchMarkdown = async () => {
try {
const response = await fetch(src);

if (!response.ok) {
throw new Error("Failed loading markdown file.");
}

const markdownText = await response.text();
const parsedHtml = await marked.parse(markdownText);
const cleanedHtml = removeAnchorLinks(parsedHtml);
setContent(cleanedHtml);
} catch (error: any) {
setError(error);
} finally {
setIsLoading(false);
}
};

fetchMarkdown();
}, [src]);

return (
<div>
{isLoading ? (
<div className={`${styles.loading} ${styles.markdownViewer}`}>
<Spinner size={SpinnerSize.large} label="Loading file" />
</div>
) : error ? (
<div className={`${styles.error} ${styles.markdownViewer}`}>
<MessageBar messageBarType={MessageBarType.error} isMultiline={false}>
{error.message}
<Link href={src} download>
Download the file
</Link>
</MessageBar>
</div>
) : (
<div>
<IconButton
className={styles.downloadButton}
style={{ color: "black" }}
iconProps={{ iconName: "Save" }}
title="Save"
ariaLabel="Save"
href={src}
download
/>
<div className={`${styles.markdown} ${styles.markdownViewer}`} dangerouslySetInnerHTML={{ __html: content }} />
</div>
)}
</div>
);
};
1 change: 1 addition & 0 deletions app/frontend/src/components/MarkdownViewer/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./MarkdownViewer";
2 changes: 1 addition & 1 deletion docs/azd.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Deploying with the Azure Developer CLI

This guide includes advanced topics that are not necessary for a basic deployment. If you are new to the project, please consult the main [README](../README.md#deploying-from-scratch) for steps on deploying the project.
This guide includes advanced topics that are not necessary for a basic deployment. If you are new to the project, please consult the main [README](../README.md#deploying) for steps on deploying the project.

[📺 Watch: Deployment of your chat app](https://www.youtube.com/watch?v=mDFZdmn7nhk)

Expand Down
8 changes: 5 additions & 3 deletions docs/deploy_features.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,15 @@ To enable integrated vectorization with this sample:

## Enabling authentication

By default, the deployed Azure web app will have no authentication or access restrictions enabled, meaning anyone with routable network access to the web app can chat with your indexed data. You can require authentication to your Azure Active Directory by following the [Add app authentication](https://learn.microsoft.com/azure/app-service/scenario-secure-app-authentication-app-service) tutorial and set it up against the deployed web app.
By default, the deployed Azure web app will have no authentication or access restrictions enabled, meaning anyone with routable network access to the web app can chat with your indexed data. If you'd like to automatically setup authentication and user login as part of the `azd up` process, see [this guide](./login_and_acl.md).

Alternatively, you can manually require authentication to your Azure Active Directory by following the [Add app authentication](https://learn.microsoft.com/azure/app-service/scenario-secure-app-authentication-app-service) tutorial and set it up against the deployed web app.

To then limit access to a specific set of users or groups, you can follow the steps from [Restrict your Azure AD app to a set of users](https://learn.microsoft.com/azure/active-directory/develop/howto-restrict-your-app-to-a-set-of-users) by changing "Assignment Required?" option under the Enterprise Application, and then assigning users/groups access. Users not granted explicit access will receive the error message -AADSTS50105: Your administrator has configured the application <app_name> to block users unless they are specifically granted ('assigned') access to the application.-

## Enabling login and document level access control

By default, the deployed Azure web app allows users to chat with all your indexed data. You can enable an optional login system using Azure Active Directory to restrict access to indexed data based on the logged in user. Enable the optional login and document level access control system by following [this guide](docs/login_and_acl.md).
By default, the deployed Azure web app allows users to chat with all your indexed data. You can enable an optional login system using Azure Active Directory to restrict access to indexed data based on the logged in user. Enable the optional login and document level access control system by following [this guide](./login_and_acl.md).

## Enabling CORS for an alternate frontend

Expand All @@ -60,7 +62,7 @@ Both these repositories adhere to the same [HTTP protocol for RAG chat apps](htt

## Using local parsers

If you want to decrease the charges by using local parsers instead of Azure Document Intelligence, you can set environment variables before running the [data ingestion script](/docs/data_ingestion.md). Note that local parsers will generally be not as sophisticated.
If you want to decrease the charges by using local parsers instead of Azure Document Intelligence, you can set environment variables before running the [data ingestion script](./data_ingestion.md). Note that local parsers will generally be not as sophisticated.

1. Run `azd env set USE_LOCAL_PDF_PARSER true` to use the local PDF parser.
1. Run `azd env set USE_LOCAL_HTML_PARSER true` to use the local HTML parser.
2 changes: 1 addition & 1 deletion docs/deploy_lowcost.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ However, if your goal is to minimize costs while prototyping your application, f

4. Use the free tier of Azure Document Intelligence (used in analyzing files):


```shell
azd env set AZURE_DOCUMENTINTELLIGENCE_SKU F0
```
Expand Down
2 changes: 1 addition & 1 deletion docs/gpt4v.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ This repository now includes an example of integrating GPT-4 Turbo with Vision w
|`gpt-4`|`vision-preview`|

- Ensure that you can deploy the Azure OpenAI resource group in [a region where all required components are available](https://learn.microsoft.com/azure/cognitive-services/openai/concepts/models#model-summary-table-and-region-availability):
- Azure Open AI models
- Azure OpenAI models
- gpt-35-turbo
- text-embedding-ada-002
- gpt-4v
Expand Down
Loading

0 comments on commit 69afd4a

Please sign in to comment.