research mode and web image search removed
This commit is contained in:
parent
049c4ea01a
commit
19477e0919
7 changed files with 28 additions and 208 deletions
|
|
@ -4,7 +4,7 @@ import path from "path"
|
|||
export const localhost = "http://0.0.0.0"
|
||||
|
||||
|
||||
export const isDev = !app.isPackaged;
|
||||
export const isDev = false;
|
||||
export const baseDir = app.getAppPath();
|
||||
export const fastapiDir = isDev ? path.join(baseDir, "servers/fastapi") : path.join(baseDir, "resources/fastapi");
|
||||
export const nextjsDir = isDev ? path.join(baseDir, "servers/nextjs") : path.join(baseDir, "resources/nextjs");
|
||||
|
|
|
|||
|
|
@ -234,27 +234,7 @@ const ImageEditor = ({
|
|||
}
|
||||
};
|
||||
|
||||
const handleSearchImage = async () => {
|
||||
const presentation_id = path.split("/")[2];
|
||||
|
||||
try {
|
||||
setIsSearching(true);
|
||||
setError(null);
|
||||
|
||||
const response = await PresentationGenerationApi.imageSearch({
|
||||
presentation_id: presentation_id,
|
||||
query: searchQuery,
|
||||
page: 1,
|
||||
limit: 20,
|
||||
});
|
||||
|
||||
setSearchedImages(response.urls);
|
||||
} catch (err) {
|
||||
setError("Failed to fetch images. Please try again.");
|
||||
} finally {
|
||||
setIsSearching(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleFileUpload = async (
|
||||
event: React.ChangeEvent<HTMLInputElement>
|
||||
|
|
@ -527,13 +507,7 @@ const ImageEditor = ({
|
|||
<TabsTrigger className="font-medium" value="generate">
|
||||
AI Generate
|
||||
</TabsTrigger>
|
||||
<TabsTrigger
|
||||
className="font-medium"
|
||||
onClick={handleSearchImage}
|
||||
value="search"
|
||||
>
|
||||
Web Images
|
||||
</TabsTrigger>
|
||||
|
||||
<TabsTrigger className="font-medium" value="upload">
|
||||
Upload
|
||||
</TabsTrigger>
|
||||
|
|
@ -599,58 +573,6 @@ const ImageEditor = ({
|
|||
</div>
|
||||
</div>
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="search" className="mt-4 space-y-4">
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
handleSearchImage();
|
||||
}}
|
||||
>
|
||||
<div className="relative mb-3">
|
||||
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-500 w-4 h-4" />
|
||||
<Input
|
||||
placeholder="Search images..."
|
||||
value={searchQuery}
|
||||
onChange={(e) => setSearchQuery(e.target.value)}
|
||||
className="pl-10"
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
type="submit"
|
||||
variant="outline"
|
||||
className="w-full text-semibold text-[#51459e]"
|
||||
>
|
||||
Search
|
||||
</Button>
|
||||
</form>
|
||||
{error && <p className="text-red-500 text-sm">{error}</p>}
|
||||
|
||||
<div className="grid grid-cols-2 gap-4 max-h-[80vh] hide-scrollbar overflow-y-auto">
|
||||
{isSearching
|
||||
? Array.from({ length: 6 }).map((_, index) => (
|
||||
<Skeleton
|
||||
key={index}
|
||||
className="aspect-[4/3] w-full rounded-lg"
|
||||
/>
|
||||
))
|
||||
: searchedImages.map((imgSrc, index) => (
|
||||
<div
|
||||
key={index}
|
||||
onClick={() => handleImageChange(imgSrc)}
|
||||
className="aspect-[4/3] cursor-pointer group relative rounded-lg overflow-hidden"
|
||||
>
|
||||
<img
|
||||
src={imgSrc}
|
||||
alt={`Search result ${index + 1}`}
|
||||
className="w-full h-full object-cover group-hover:scale-105 transition-transform"
|
||||
/>
|
||||
<div className="absolute inset-0 bg-black/0 group-hover:bg-black/20 transition-all duration-200" />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="upload" className="mt-4 space-y-4">
|
||||
<div className="space-y-4">
|
||||
<div
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ const DocumentsPreviewPage: React.FC = () => {
|
|||
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
||||
|
||||
// Redux state
|
||||
const { config, reports, documents, images, charts, tables } = useSelector(
|
||||
const { config, documents, images, charts, tables } = useSelector(
|
||||
(state: RootState) => state.pptGenUpload
|
||||
);
|
||||
|
||||
|
|
@ -68,10 +68,9 @@ const DocumentsPreviewPage: React.FC = () => {
|
|||
});
|
||||
|
||||
// Memoized values
|
||||
const reportKeys = useMemo(() => Object.keys(reports), [reports]);
|
||||
const documentKeys = useMemo(() => Object.keys(documents), [documents]);
|
||||
const imageKeys = useMemo(() => Object.keys(images), [images]);
|
||||
const allSources = useMemo(() => [...reportKeys, ...documentKeys, ...imageKeys], [reportKeys, documentKeys, imageKeys]);
|
||||
const allSources = useMemo(() => [...documentKeys, ...imageKeys], [documentKeys, imageKeys]);
|
||||
|
||||
|
||||
|
||||
|
|
@ -96,14 +95,7 @@ const DocumentsPreviewPage: React.FC = () => {
|
|||
}
|
||||
});
|
||||
|
||||
// Process reports
|
||||
reportKeys.forEach(key => {
|
||||
if (!(key in textContents)) {
|
||||
newDocuments.push(key);
|
||||
// @ts-ignore
|
||||
promises.push(window.electron.readFile(reports[key]));
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
if (promises.length > 0) {
|
||||
setDownloadingDocuments(newDocuments);
|
||||
|
|
@ -148,13 +140,11 @@ const DocumentsPreviewPage: React.FC = () => {
|
|||
});
|
||||
|
||||
const documentPaths = documentKeys.map(key => documents[key]);
|
||||
const researchReportPath = reports['research_report_content'];
|
||||
const createResponse = await PresentationGenerationApi.getQuestions({
|
||||
prompt: config?.prompt ?? "",
|
||||
n_slides: config?.slides ? parseInt(config.slides) : null,
|
||||
documents: documentPaths,
|
||||
images: imageKeys,
|
||||
research_reports: researchReportPath ? [researchReportPath] : [],
|
||||
language: config?.language ?? "",
|
||||
|
||||
});
|
||||
|
|
@ -219,10 +209,9 @@ const DocumentsPreviewPage: React.FC = () => {
|
|||
if (!selectedDocument) return null;
|
||||
|
||||
const isDocument = documentKeys.includes(selectedDocument);
|
||||
const isReport = reportKeys.includes(selectedDocument);
|
||||
const hasTablesAndCharts = documentTablesAndCharts().length > 0;
|
||||
|
||||
if (!isDocument && !isReport) return null;
|
||||
if (!isDocument) return null;
|
||||
|
||||
return (
|
||||
<div className="h-full mr-4">
|
||||
|
|
@ -271,24 +260,7 @@ const DocumentsPreviewPage: React.FC = () => {
|
|||
size={20}
|
||||
/>
|
||||
|
||||
{reportKeys.length > 0 && (
|
||||
<div
|
||||
onClick={() => updateSelectedDocument(reportKeys[0])}
|
||||
className={`${selectedDocument === reportKeys[0]
|
||||
? styles.selected_border
|
||||
: styles.unselected_border
|
||||
} ${styles.report_icon_box} flex justify-center items-center rounded-lg w-full h-32 cursor-pointer`}
|
||||
>
|
||||
<div>
|
||||
<img
|
||||
className="mx-auto h-20"
|
||||
src="/report.png"
|
||||
alt="Research Report"
|
||||
/>
|
||||
<p className="text-sm mt-2 text-[#2E2E2E]">Research Report</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
{documentKeys.length > 0 && (
|
||||
<div className="mt-8">
|
||||
|
|
|
|||
|
|
@ -64,34 +64,7 @@ export class PresentationGenerationApi {
|
|||
}
|
||||
}
|
||||
|
||||
static async generateResearchReport(prompt: string, language: string | null) {
|
||||
const apiBody = {
|
||||
query: prompt,
|
||||
language: language,
|
||||
};
|
||||
try {
|
||||
const response = await fetch(
|
||||
`${BASE_URL}/ppt/report/generate`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: getHeader(),
|
||||
body: JSON.stringify(apiBody),
|
||||
cache: "no-cache",
|
||||
}
|
||||
);
|
||||
|
||||
if (response.status === 200) {
|
||||
const data = await response.json();
|
||||
|
||||
return data;
|
||||
} else {
|
||||
throw new Error(`Failed to generate report: ${response.statusText}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error in Generate Research Report", error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static async decomposeDocuments(documentKeys: string[], imageKeys: string[]) {
|
||||
try {
|
||||
|
|
@ -452,7 +425,6 @@ export class PresentationGenerationApi {
|
|||
n_slides,
|
||||
documents,
|
||||
images,
|
||||
research_reports,
|
||||
language,
|
||||
|
||||
}: {
|
||||
|
|
@ -460,7 +432,6 @@ export class PresentationGenerationApi {
|
|||
n_slides: number | null;
|
||||
documents?: string[];
|
||||
images?: string[];
|
||||
research_reports?: string[];
|
||||
language: string | null;
|
||||
|
||||
}) {
|
||||
|
|
@ -475,7 +446,6 @@ export class PresentationGenerationApi {
|
|||
n_slides,
|
||||
language,
|
||||
documents,
|
||||
research_reports,
|
||||
images,
|
||||
|
||||
}),
|
||||
|
|
|
|||
|
|
@ -1,20 +1,17 @@
|
|||
import { Textarea } from "@/components/ui/textarea";
|
||||
import { useState } from "react";
|
||||
import * as Switch from "@radix-ui/react-switch";
|
||||
import styles from "../styles/main.module.css";
|
||||
|
||||
|
||||
interface PromptInputProps {
|
||||
value: string;
|
||||
onChange: (value: string) => void;
|
||||
researchMode: boolean;
|
||||
setResearchMode: (value: boolean) => void;
|
||||
|
||||
}
|
||||
|
||||
export function PromptInput({
|
||||
value,
|
||||
onChange,
|
||||
researchMode,
|
||||
setResearchMode,
|
||||
|
||||
}: PromptInputProps) {
|
||||
const [showHint, setShowHint] = useState(false);
|
||||
const handleChange = (value: string) => {
|
||||
|
|
@ -23,33 +20,7 @@ export function PromptInput({
|
|||
};
|
||||
return (
|
||||
<div className="space-y-2">
|
||||
<div className="flex justify-between">
|
||||
<h4 className=" font-instrument_sans text-lg text-[#444] font-medium ">
|
||||
Prompt
|
||||
</h4>
|
||||
<div className="flex justify-end">
|
||||
<div
|
||||
className={`inline-flex items-center gap-2 px-3 py-1.5 rounded-md border border-[#5146E5] text-sm font-semibold ${researchMode ? "bg-[#5146E5] text-white" : "text-[#5146E5]"
|
||||
}`}
|
||||
>
|
||||
<span>Research Mode</span>
|
||||
<Switch.Root
|
||||
defaultChecked={researchMode}
|
||||
onCheckedChange={(val) => setResearchMode(val)}
|
||||
className={`${styles.SwitchRoot}`}
|
||||
data-testid="research-mode-switch"
|
||||
>
|
||||
<Switch.Thumb className={styles.SwitchThumb} />
|
||||
</Switch.Root>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{researchMode && (
|
||||
<p className="bg-blue-100 border font-instrument_sans text-sm md:text-base transition-all duration-300 border-blue-200 p-2 text-center rounded-md ">
|
||||
Research mode searches the web to gather the latest information based
|
||||
on your prompt and documents.
|
||||
</p>
|
||||
)}
|
||||
|
||||
|
||||
<div className="relative">
|
||||
<Textarea
|
||||
|
|
@ -58,8 +29,7 @@ export function PromptInput({
|
|||
onChange={(e) => handleChange(e.target.value)}
|
||||
placeholder="Tell us about your presentation"
|
||||
data-testid="prompt-input"
|
||||
className={`py-4 px-5 border-2 font-medium font-instrument_sans text-base min-h-[150px] max-h-[300px] border-[#5146E5] focus-visible:ring-offset-0 focus-visible:ring-[#5146E5] overflow-y-auto custom_scrollbar ${researchMode ? "border-dashed" : ""
|
||||
}`}
|
||||
className={`py-4 px-5 border-2 font-medium font-instrument_sans text-base min-h-[150px] max-h-[300px] border-[#5146E5] focus-visible:ring-offset-0 focus-visible:ring-[#5146E5] overflow-y-auto custom_scrollbar `}
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
* - Configure presentation settings (slides, language)
|
||||
* - Input prompts
|
||||
* - Upload supporting documents and images
|
||||
* - Generate presentations with or without research mode
|
||||
|
||||
*
|
||||
* @component
|
||||
*/
|
||||
|
|
@ -51,7 +51,6 @@ interface DecomposedResponse {
|
|||
|
||||
interface ProcessedData {
|
||||
config: PresentationConfig;
|
||||
reports: Record<string, string>;
|
||||
documents: Record<string, any>;
|
||||
images: Record<string, any>;
|
||||
charts: Record<string, any>;
|
||||
|
|
@ -65,7 +64,6 @@ const UploadPage = () => {
|
|||
const { toast } = useToast();
|
||||
|
||||
// State management
|
||||
const [researchMode, setResearchModel] = useState<boolean>(false);
|
||||
const [documents, setDocuments] = useState<File[]>([]);
|
||||
const [images, setImages] = useState<File[]>([]);
|
||||
const [config, setConfig] = useState<PresentationConfig>({
|
||||
|
|
@ -142,8 +140,8 @@ const UploadPage = () => {
|
|||
try {
|
||||
const hasUploadedAssets = documents.length > 0 || images.length > 0;
|
||||
|
||||
if (researchMode || hasUploadedAssets) {
|
||||
await handleResearchAndDocumentProcessing();
|
||||
if (hasUploadedAssets) {
|
||||
await handleDocumentProcessing();
|
||||
} else {
|
||||
await handleDirectPresentationGeneration();
|
||||
}
|
||||
|
|
@ -153,14 +151,14 @@ const UploadPage = () => {
|
|||
};
|
||||
|
||||
/**
|
||||
* Handles research mode and document processing
|
||||
* Handles document processing
|
||||
*/
|
||||
const handleResearchAndDocumentProcessing = async () => {
|
||||
const handleDocumentProcessing = async () => {
|
||||
setLoadingState({
|
||||
isLoading: true,
|
||||
message: researchMode ? "Creating research report..." : "Processing documents...",
|
||||
message: "Processing documents...",
|
||||
showProgress: true,
|
||||
duration: researchMode ? 80 : 90,
|
||||
duration: 90,
|
||||
extra_info: documents.length > 0 ? "It might take a few minutes for large documents." : "",
|
||||
});
|
||||
|
||||
|
|
@ -174,11 +172,7 @@ const UploadPage = () => {
|
|||
}
|
||||
|
||||
const promises: Promise<any>[] = [];
|
||||
if (researchMode) {
|
||||
promises.push(
|
||||
PresentationGenerationApi.generateResearchReport(config.prompt, config.language)
|
||||
);
|
||||
}
|
||||
|
||||
if (documents.length > 0 || images.length > 0) {
|
||||
promises.push(
|
||||
PresentationGenerationApi.decomposeDocuments(documentKeys, imageKeys)
|
||||
|
|
@ -187,7 +181,7 @@ const UploadPage = () => {
|
|||
|
||||
const responses = await Promise.all(promises);
|
||||
|
||||
const processedData = processApiResponses(responses, researchMode);
|
||||
const processedData = processApiResponses(responses);
|
||||
|
||||
dispatch(setPptGenUploadState(processedData));
|
||||
router.push("/documents-preview");
|
||||
|
|
@ -196,21 +190,15 @@ const UploadPage = () => {
|
|||
/**
|
||||
* Processes API responses and formats data for state update
|
||||
*/
|
||||
const processApiResponses = (responses: (any | DecomposedResponse)[], isResearchMode: boolean): ProcessedData => {
|
||||
const processApiResponses = (responses: (any | DecomposedResponse)[],): ProcessedData => {
|
||||
const result: ProcessedData = {
|
||||
config,
|
||||
reports: {},
|
||||
documents: {},
|
||||
images: {},
|
||||
charts: {},
|
||||
tables: {},
|
||||
};
|
||||
|
||||
if (isResearchMode) {
|
||||
const researchResponse = responses.shift();
|
||||
result.reports['research_report_content'] = researchResponse;
|
||||
}
|
||||
|
||||
if (responses.length > 0) {
|
||||
const decomposedResponse = responses.shift() as DecomposedResponse;
|
||||
Object.assign(result, {
|
||||
|
|
@ -226,7 +214,7 @@ const UploadPage = () => {
|
|||
};
|
||||
|
||||
/**
|
||||
* Handles direct presentation generation without research or documents
|
||||
* Handles direct presentation generation without documents
|
||||
*/
|
||||
const handleDirectPresentationGeneration = async () => {
|
||||
setLoadingState({
|
||||
|
|
@ -241,7 +229,7 @@ const UploadPage = () => {
|
|||
n_slides: config?.slides ? parseInt(config.slides) : null,
|
||||
documents: [],
|
||||
images: [],
|
||||
research_reports: [],
|
||||
|
||||
language: config?.language ?? "",
|
||||
|
||||
});
|
||||
|
|
@ -302,8 +290,7 @@ const UploadPage = () => {
|
|||
<PromptInput
|
||||
value={config.prompt}
|
||||
onChange={(value) => handleConfigChange("prompt", value)}
|
||||
researchMode={researchMode}
|
||||
setResearchMode={setResearchModel}
|
||||
|
||||
data-testid="prompt-input"
|
||||
/>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { createSlice, PayloadAction } from "@reduxjs/toolkit";
|
|||
|
||||
interface PresentationGenUploadState {
|
||||
config: PresentationConfig | null;
|
||||
reports: any;
|
||||
|
||||
documents: any;
|
||||
images: any;
|
||||
charts: any;
|
||||
|
|
@ -14,7 +14,7 @@ interface PresentationGenUploadState {
|
|||
|
||||
const initialState: PresentationGenUploadState = {
|
||||
config: null,
|
||||
reports: {},
|
||||
|
||||
documents: {},
|
||||
images: {},
|
||||
charts: {},
|
||||
|
|
@ -38,7 +38,6 @@ export const presentationGenUploadSlice = createSlice({
|
|||
) => {
|
||||
const payload = action.payload;
|
||||
state.config = payload.config!;
|
||||
state.reports = payload.reports;
|
||||
state.documents = payload.documents;
|
||||
state.images = payload.images;
|
||||
state.charts = payload.charts;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue