Skip to content

Commit eae8079

Browse files
lickem22MustafaAkolawalaziakhan04
authored
Add related contents to content cards (#528)
* Add language detection to external apis * fix mypy error * Change to faster-wshiper for language detection * fix mypy issue * fix ruff issue * Update deploy_gcp_core_backend.yaml * Fix google signin issue * Adding termcolor to requirements. * Adding new litellm model for chat. * Fixing import path for add dummy data script. * Adding openai/chat litellm config. * Add utils to generate random int32. * Adding chat management functionalities. * Adding prompts for ChatHistory. * Removed zero-shot cot and updated system message passing. * Updated pre-commit to include types-requests. * Added chat fallback model. * Added REDIS timeout variable to config. * Updated prompts for ChatHistory. * Passing in paraphrase argument so that paraphrasing can be skipped for chat histories. * Updat chat management utilities. * Updated prompts for ChatHistory. * Added response generation with RAG and chat history. * Updated decorators and llm query generation to include chat history. Added /chat endpoint. Temporariliy commented out /search endpoint for quick testing. * Updated chat manager functions. Updated parameter name for _ask_llm_async from json to _json. * Updated prompts for spacing. * Updated prompt and chat management. * Added utils for generating random int32. * Refactored chat and search endpoints. * Consolidated chat and search endpoints. * CCs. * Removed termcolor package. * Adding types-requests to requirements-dev.txt for github workflow. * Passing along session ID for QueryResponse. * Logic shift to query refined template. * CCs. * Removing paraphrase argument. * Removing paraphrase argument. * CCs. * No need to return session ID. * Added tests for chat. * Fixing os env issue with github workflow. * Fixing os env issue with github workflow. * Fixing os env issue with github workflow. * Fixing os env issue with github workflow. * Fixing os env issue with github workflow. * Test. * Reverting tests. * CCs. * Checking mocked tests for github actions. * Updated tests. * Updated tests and fixed issue with truncation. * CCs. * CCs. * CCs. * CCs. * Removed WorkspaceRetrieve pydantic model. * CCs. * CCs. * CCs. * CCs. * Updated contents and tags packages for workspaces * Updated question_answer package for workspaces. Modified parts of data_api and llm_call packages. Finished up lagging function calls that were missing workspaces in previous commits. * Fixed function signatures. * Finished data_api package. * Finished admin package. * Updated urgency_detection and urgency_rules packages. * CCs. * Updated user_tools package. CCs. * CCs to utils and tags packages. * Updated question_answer and contents packages. * CCs to urgency_detection and uregncy_rules packages. * Updated data_api package. * CCs to llm_call/dashboard.py. * CCs to llm_call/llm_prompts.py. * Updated add_dummy_data_to_db to use workspace_id. * Updated add_new_data_to_db to use workspace_id. * Removed unused import. * Separated workspace logic into its own package with its own routers, utils, and schemas. Updated auth dependencies and routers to resolve circular import issues. * Linting. * Changing default workspace to be Workspace_{user.username}. * Added delete workspace and get workspace by user ID endpoints. * Updated table names. Added default_workspace column. Updated auth to pull default workspace. Added login-workspace endpoint. Updating tests... * CCs. * Updated workspace endpoints and schemas. Included better checks for quotas. * Checking for unique workspace name when updating workspace. Added ability to remove users from workspaces. * Added user removal functionality. * CCs to remaining modules. Fixed circular import issue and removed user_tools package---consolidated with users package now. Additional updates to users routers. * CCs. * Updated tests/rails package. * CCs. Going through and updating tests/api/conftest.py. * Updated test_admin.py. * Fixed alembic migration naming issue. Verified alembic tests pass. * Verified test_archive_content.py. * Verified test_chat.py * Verified test_data_api.py. * Verified test_import_content.py. * Verified test_import_content.py test_manage_content.py test_manage_tags.py * Verified test_manage_ud_rules.py. * Finished verifying existing tests except for dashboard tests. Added migration for on cascade deletion. * Finished verifying existing tests with pytest-randomly. Fixed lagging issues. * Added ability for any user to create a workspace. * commit message * commit message * Adding BDD tests. * Updating workspace BDD tests. * Updating workspace BDD tests. * Merging in frontend changes only for multi-turn conv. * Updating with multi-turn conv frontend PR and pylint fixes. * Adding linting make command. * Merged with topic modeling PR. * Folding in hotfixes to admin_app. * CCs. * CCs. * CCs. * CCs. * Folding in hotfixes to admin_app. * Updated dashboard package for workspace. * Verified remaining tests. * Add workspace bar * Updated github workflow for tests. Updated test_urgency_detect.py to include proper teardown. Updated dashboard filtering logic to point to UrgencyResponseDB instead of ResponseFeedbackDB. CCs. * Updated optional_components for linting and updated httpx dependency in order to pass github workflow. * Testing reverting back to using type. * Testing reverting back to using isinstance. * CCs. * CCs. * CCs. * CCs. * Added accidentally deleted pytest fixture. * Moved archive content test to its own workspace. * login endpoints now return workspace_name in AuthenticatedDetails. login-workspace now has dependency injection on get_current_user so that access token is required. workspace default quotas changed to env defaults. UserRetrieve now returns list of dicts instead of two separate lists. retrieve_all_users is now retrieve_all_users_in_current_workspace. added get_current_workspace endpoint. * Create new workspace component * Returning WorkspaceRetrieve after creating workspaces instead of WorkspaceCreate so that workspace_id is available. * Edit workspace button * Moved login-workspace endpoint to workspace/routers.py and changed to switch-workspace endpoint due to authentication requirement. Disabled updating workspace quotas on backend. * Update edit users * Added is_default_workspace in return object when adding existing users to a workspace. * Switch to diferent workspaces feature * Folding in changes for frontend and backend from update dashboard page 2 PR. * Modularizing BDD test. * CCs. * Added user resetting passwords BDD tests. * Changed endpoint from /workspace/current to /workspace/current-workspace. * Added retrieving user information BDD tests. * Added removing user BDD tests. * Fixed error in removing users from workspaces BDD tests. * Added updating user information BDD tests. Other CCs. * Added creating workspaces BDD tests. * Updating tests to pass in GHA. * Adding user role to access token and authentication. Removed is_admin attribute. * Added users endpoint to check if a username exists. * Added user routers to differentiate between creating new users and adding existing users. * Added adding users BDD tests. Put endpoint for checking if username exists back in. Separated out logic for creating new users vs. adding existing users to workspaces. * Added updating workspaces BDD tests. * Added type check. * Added retrieving workspaces BDD tests. Updated pyproject.toml and requirements-dev for coverage. * Router name change to add-existing-user-to-workspace. * Updated tests. * Add new changes * Add new changes * Updated user head endpoint to check if username exists to return a status code instead of a boolean. * CCs. * Add user to workspace * Removed access token requirement when resetting user password. Updated tests. * Default workspace implementation * Merging frontend changes from main. * Added official docs for multi-turn chat and workspaces. Removed HACK FIX comments. * Add reset user logic * Remove quotas from form * clean up * Fix read only issue * Remove section from integration page for read only users * Few bug fixes * Handle long workspace names * Changing default workspace name to {username}'s Workspace. * Fix user role bug * Consolidated workspace migration files to a single migration file that also takes care of data migration. Updated tests. * Fixing github workflow for tests. * Separated single workspace migration file into 3 stages for production. * Final fixes * Final final changes * Fixing migration script errors. * Fixing migration script errors. * Removed typo in front of Make command. * Fixing migration script errors. * Fixing migration script errors. * Updating with main. * Remove pragma comments * Fix recovery_code being null issue * Fix comments * Check for user default workspace when logging in with google * Add docmuncher to aaq deployment * Add docmuncher to aaq deployment * Implement bulk delete to make sure non-deleted contents are still selected * Add related contents feature * Docmuncher UI updates (#524) * Update indexing to PDF in UI * Fix PDF create card to generate card wording * Switch status open to zustand * Add open status button to pdf import modal * change message when PDF upload successful * Nahh change text again * Make upload-pdf trigger status-fetch using tanstack * Modify to align with PR comments * Fix UI bugs * Update the migration file --------- Co-authored-by: MustafaAkolawala <mustafaakolawala@eng.rizvi.edu.in> Co-authored-by: tonyzhao6 <> Co-authored-by: ziakhan04 <86958339+ziakhan04@users.noreply.github.com>
1 parent 4e7c70a commit eae8079

File tree

14 files changed

+633
-94
lines changed

14 files changed

+633
-94
lines changed

.secrets.baseline

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -145,15 +145,6 @@
145145
"line_number": 62
146146
}
147147
],
148-
".github/workflows/deploy_gcp_core_backend.yaml": [
149-
{
150-
"type": "Secret Keyword",
151-
"filename": ".github/workflows/deploy_gcp_core_backend.yaml",
152-
"hashed_secret": "14a9a30abdb4f24769083489080470ca78f002f6",
153-
"is_verified": false,
154-
"line_number": 64
155-
}
156-
],
157148
".github/workflows/deploy_gcp_litellm_proxy.yaml": [
158149
{
159150
"type": "Secret Keyword",

admin_app/src/app/content/components/ContentCard.tsx

Lines changed: 73 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -13,28 +13,12 @@ import {
1313
import Link from "next/link";
1414
import React from "react";
1515
import { Layout } from "../../../components/Layout";
16-
import { Tag } from "@/app/content/page";
16+
import { Content, ContentDisplay, Tag } from "../types";
1717

1818
const CARD_HEIGHT = 210;
1919
const CARD_MIN_WIDTH = 280;
2020

21-
const ContentCard = ({
22-
title,
23-
text,
24-
content_id,
25-
display_number,
26-
last_modified,
27-
tags,
28-
positive_votes,
29-
negative_votes,
30-
onSuccessfulArchive,
31-
onFailedArchive,
32-
archiveContent,
33-
editAccess,
34-
isSelectMode,
35-
selectedContents,
36-
setSelectedContents,
37-
}: {
21+
interface ContentCardProps {
3822
title: string;
3923
text: string;
4024
content_id: number;
@@ -43,20 +27,53 @@ const ContentCard = ({
4327
tags: Tag[];
4428
positive_votes: number;
4529
negative_votes: number;
30+
related_contents: Content[];
4631
onSuccessfulArchive: (content_id: number) => void;
4732
onFailedArchive: (content_id: number, error_message: string) => void;
4833
archiveContent: (content_id: number) => Promise<any>;
4934
editAccess: boolean;
5035
isSelectMode: boolean;
5136
selectedContents: number[];
5237
setSelectedContents: (selectedContents: number[]) => void;
38+
getRelatedContent: (content_id: number[]) => Content[];
39+
}
40+
const ContentCard: React.FC<ContentCardProps> = ({
41+
title,
42+
text,
43+
content_id,
44+
display_number,
45+
last_modified,
46+
tags,
47+
positive_votes,
48+
negative_votes,
49+
related_contents,
50+
onSuccessfulArchive,
51+
onFailedArchive,
52+
archiveContent,
53+
editAccess,
54+
isSelectMode,
55+
selectedContents,
56+
setSelectedContents,
57+
getRelatedContent,
5358
}) => {
5459
const [openReadModal, setOpenReadModal] = React.useState<boolean>(false);
5560
const [openArchiveModal, setOpenArchiveModal] = React.useState<boolean>(false);
5661
const [isHovered, setIsHovered] = React.useState<boolean>(false);
5762
const [checked, setChecked] = React.useState<boolean>(
5863
selectedContents.includes(content_id),
5964
);
65+
const [currentContent, setCurrentContent] = React.useState<ContentDisplay>({
66+
title,
67+
text,
68+
content_id,
69+
display_number,
70+
last_modified,
71+
tags,
72+
positive_votes,
73+
negative_votes,
74+
related_contents,
75+
});
76+
6077
const truncateTagName = (tagName: string): string => {
6178
return tagName.length > 15 ? `${tagName.slice(0, 15)}...` : tagName;
6279
};
@@ -65,10 +82,37 @@ const ContentCard = ({
6582
setChecked(selectedContents.includes(content_id));
6683
}, [selectedContents]);
6784

85+
const handleRelatedContentClick = (content: Content) => {
86+
setCurrentContent({
87+
title: content.content_title,
88+
text: content.content_text,
89+
content_id: content.content_id!,
90+
display_number: content.display_number,
91+
last_modified: content.updated_datetime_utc,
92+
tags: tags.filter((tag) => content.content_tags.includes(tag.tag_id)),
93+
positive_votes: content.positive_votes,
94+
negative_votes: content.negative_votes,
95+
related_contents: getRelatedContent(content.related_contents_id),
96+
} as ContentDisplay);
97+
};
98+
6899
return (
69100
<>
70101
<Card
71-
onClick={() => setOpenReadModal(true)}
102+
onClick={() => {
103+
setCurrentContent({
104+
title,
105+
text,
106+
content_id,
107+
display_number,
108+
last_modified,
109+
tags,
110+
positive_votes,
111+
negative_votes,
112+
related_contents,
113+
});
114+
setOpenReadModal(true);
115+
}}
72116
onMouseEnter={() => setIsHovered(true)}
73117
onMouseLeave={() => setIsHovered(false)}
74118
sx={[
@@ -192,20 +236,19 @@ const ContentCard = ({
192236
</Layout.FlexBox>
193237
</Card>
194238
<ContentViewModal
195-
title={title}
196-
text={text}
197-
content_id={content_id}
198-
display_number={display_number}
199-
last_modified={last_modified}
200-
tags={tags}
239+
title={currentContent.title}
240+
text={currentContent.text}
241+
content_id={currentContent.content_id}
242+
display_number={currentContent.display_number}
243+
last_modified={currentContent.last_modified}
244+
related_contents={currentContent.related_contents}
245+
tags={currentContent.tags}
201246
open={openReadModal}
202-
positive_votes={positive_votes}
203-
negative_votes={negative_votes}
247+
positive_votes={currentContent.positive_votes}
248+
negative_votes={currentContent.negative_votes}
204249
onClose={() => setOpenReadModal(false)}
205250
editAccess={editAccess}
206-
setRefreshKey={function (value: React.SetStateAction<number>): void {
207-
throw new Error("Function not implemented.");
208-
}}
251+
onRelatedContentClick={handleRelatedContentClick}
209252
/>
210253
<ArchiveContentModal
211254
content_id={content_id}

admin_app/src/app/content/components/ContentModal.tsx

Lines changed: 51 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ import DialogContentText from "@mui/material/DialogContentText";
99
import DialogTitle from "@mui/material/DialogTitle";
1010
import Link from "next/link";
1111
import { Layout } from "@/components/Layout";
12-
import { Tag } from "@/app/content/page";
1312
import { CustomError } from "@/utils/api";
13+
import { Content, Tag } from "../types";
1414
import { useValidateContentCard, useArchiveContentCard } from "../api";
1515

1616
const ContentViewModal = ({
@@ -22,10 +22,13 @@ const ContentViewModal = ({
2222
negative_votes,
2323
last_modified,
2424
tags,
25+
related_contents,
2526
open,
2627
onClose,
2728
setRefreshKey,
29+
onRelatedContentClick,
2830
editAccess,
31+
2932
validation_mode = false,
3033
}: {
3134
title: string;
@@ -34,12 +37,14 @@ const ContentViewModal = ({
3437
display_number: number;
3538
last_modified: string;
3639
tags?: Tag[];
40+
related_contents: Content[];
3741
positive_votes: number;
3842
negative_votes: number;
3943
open: boolean;
4044
onClose: () => void;
4145
setRefreshKey?: React.Dispatch<React.SetStateAction<number>>;
4246
editAccess: boolean;
47+
onRelatedContentClick: (content: Content) => void;
4348
validation_mode?: boolean;
4449
}) => {
4550
const token = typeof window !== "undefined" ? localStorage.getItem("token") : null;
@@ -96,10 +101,11 @@ const ContentViewModal = ({
96101
</Layout.FlexBox>
97102
</Layout.FlexBox>
98103
)}
104+
99105
<Layout.FlexBox
100106
flexDirection={"column"}
101107
sx={{
102-
maxHeight: "60vh", // this controls overall modal height too
108+
maxHeight: "60vh",
103109
padding: sizes.baseGap,
104110
marginTop: 1,
105111
overflowY: "auto",
@@ -121,6 +127,38 @@ const ContentViewModal = ({
121127
<ReactMarkdown>{text}</ReactMarkdown>
122128
</Typography>
123129
</Layout.FlexBox>
130+
{related_contents && related_contents.length > 0 && (
131+
<Layout.FlexBox
132+
flexDirection={"column"}
133+
sx={{
134+
my: sizes.smallGap,
135+
}}
136+
>
137+
<Typography variant="subtitle1" gutterBottom>
138+
Related Contents
139+
</Typography>
140+
<Layout.FlexBox
141+
sx={{
142+
flexDirection: "row",
143+
flexWrap: "wrap",
144+
py: sizes.smallGap,
145+
alignItems: "center",
146+
gap: sizes.smallGap,
147+
}}
148+
>
149+
{related_contents.map((content) => (
150+
<Chip
151+
key={content.content_id}
152+
variant="outlined"
153+
onClick={() => {
154+
onRelatedContentClick(content);
155+
}}
156+
label={content.content_title}
157+
/>
158+
))}
159+
</Layout.FlexBox>
160+
</Layout.FlexBox>
161+
)}
124162
<Layout.FlexBox
125163
sx={{
126164
flexDirection: "row",
@@ -212,20 +250,22 @@ const ContentViewModal = ({
212250
);
213251
};
214252

215-
const ArchiveContentModal = ({
216-
content_id,
217-
open,
218-
onClose,
219-
onSuccessfulArchive,
220-
onFailedArchive,
221-
archiveContent,
222-
}: {
253+
interface ArchiveContentModalProps {
223254
content_id: number;
224255
open: boolean;
225256
onClose: () => void;
226257
onSuccessfulArchive: (content_id: number) => void;
227258
onFailedArchive: (content_id: number, error_message: string) => void;
228259
archiveContent: (content_id: number) => Promise<any>;
260+
}
261+
262+
const ArchiveContentModal: React.FC<ArchiveContentModalProps> = ({
263+
content_id,
264+
open,
265+
onClose,
266+
onSuccessfulArchive,
267+
onFailedArchive,
268+
archiveContent,
229269
}) => {
230270
return (
231271
<Dialog
@@ -247,13 +287,12 @@ const ArchiveContentModal = ({
247287
<Button
248288
onClick={() => {
249289
const handleArchiveContent = async (content_id: number) => {
250-
const results = archiveContent(content_id)
290+
archiveContent(content_id)
251291
.then((res) => {
252292
onSuccessfulArchive(content_id);
253293
})
254294
.catch((err) => {
255295
const customError = err as CustomError;
256-
console.log("error", customError.message);
257296
onFailedArchive(content_id, customError.message);
258297
});
259298
};

admin_app/src/app/content/components/DownloadModal.tsx

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@ import { useAuth } from "@/utils/auth";
1111
import Papa from "papaparse";
1212
import { useState } from "react";
1313
import { LoadingButton } from "@mui/lab";
14-
import { Content } from "../edit/page";
14+
import { Content, Tag } from "../types";
1515
import { Layout } from "@/components/Layout";
1616
import { getContentList, getTagList } from "../api";
17-
import { CustomError, handleApiError } from "@/utils/api";
17+
import { handleApiError } from "@/utils/api";
1818

1919
interface ContentDownload {
2020
content_id: number | null;
@@ -28,11 +28,6 @@ interface ContentDownload {
2828
updated_datetime_utc: string;
2929
}
3030

31-
interface Tag {
32-
tag_id: string;
33-
tag_name: string;
34-
}
35-
3631
const DownloadModal = ({
3732
open,
3833
onClose,

0 commit comments

Comments
 (0)