diff --git a/servers/fastapi/services/llm_client.py b/servers/fastapi/services/llm_client.py index f016e763..eaf61770 100644 --- a/servers/fastapi/services/llm_client.py +++ b/servers/fastapi/services/llm_client.py @@ -39,8 +39,6 @@ class LLMClient: # ? Disable thinking def disable_thinking(self) -> bool: - if self.llm_provider != LLMProvider.CUSTOM: - return False return parse_bool_or_none(get_disable_thinking_env()) or False # ? Clients @@ -122,15 +120,14 @@ class LLMClient: model: str, messages: List[LLMMessage], max_tokens: Optional[int] = None, + extra_body: Optional[dict] = None, ): client: AsyncOpenAI = self._client response = await client.chat.completions.create( model=model, messages=[message.model_dump() for message in messages], max_completion_tokens=max_tokens, - extra_body={ - "enable_thinking": not self.disable_thinking(), - }, + extra_body=extra_body, ) return response.choices[0].message.content @@ -185,7 +182,10 @@ class LLMClient: async def _generate_custom( self, model: str, messages: List[LLMMessage], max_tokens: Optional[int] = None ): - return await self._generate_openai(model, messages, max_tokens) + extra_body = {"enable_thinking": not self.disable_thinking()} + return await self._generate_openai( + model, messages, max_tokens, extra_body=extra_body + ) async def generate( self, @@ -220,6 +220,7 @@ class LLMClient: response_format: dict, strict: bool = False, max_tokens: Optional[int] = None, + extra_body: Optional[dict] = None, ): client: AsyncOpenAI = self._client use_tool_calls = self.use_tool_calls() @@ -245,9 +246,7 @@ class LLMClient: ), }, max_completion_tokens=max_tokens, - extra_body={ - "enable_thinking": not self.disable_thinking(), - }, + extra_body=extra_body, ) content = response.choices[0].message.content else: @@ -267,9 +266,7 @@ class LLMClient: ], tool_choice="required", max_completion_tokens=max_tokens, - extra_body={ - "enable_thinking": not self.disable_thinking(), - }, + extra_body=extra_body, ) tool_calls = response.choices[0].message.tool_calls if tool_calls: @@ -359,8 +356,9 @@ class LLMClient: strict: bool = False, max_tokens: Optional[int] = None, ): + extra_body = {"enable_thinking": not self.disable_thinking()} return await self._generate_openai_structured( - model, messages, response_format, strict, max_tokens + model, messages, response_format, strict, max_tokens, extra_body ) async def generate_structured( @@ -406,15 +404,14 @@ class LLMClient: model: str, messages: List[LLMMessage], max_tokens: Optional[int] = None, + extra_body: Optional[dict] = None, ): client: AsyncOpenAI = self._client async with client.chat.completions.stream( model=model, messages=[message.model_dump() for message in messages], max_completion_tokens=max_tokens, - extra_body={ - "enable_thinking": not self.disable_thinking(), - }, + extra_body=extra_body, ) as stream: async for event in stream: if event.type == "content.delta": @@ -474,7 +471,8 @@ class LLMClient: messages: List[LLMMessage], max_tokens: Optional[int] = None, ): - return self._stream_openai(model, messages, max_tokens) + extra_body = {"enable_thinking": not self.disable_thinking()} + return self._stream_openai(model, messages, max_tokens, extra_body) def stream( self, model: str, messages: List[LLMMessage], max_tokens: Optional[int] = None @@ -499,6 +497,7 @@ class LLMClient: response_format: dict, strict: bool = False, max_tokens: Optional[int] = None, + extra_body: Optional[dict] = None, ): client: AsyncOpenAI = self._client use_tool_calls = self.use_tool_calls() @@ -524,9 +523,7 @@ class LLMClient: }, } ), - extra_body={ - "enable_thinking": not self.disable_thinking(), - }, + extra_body=extra_body, ) as stream: async for event in stream: if event.type == "content.delta": @@ -548,9 +545,7 @@ class LLMClient: } ], tool_choice="required", - extra_body={ - "enable_thinking": not self.disable_thinking(), - }, + extra_body=extra_body, ) as stream: async for event in stream: if event.type == "tool_calls.function.arguments.delta": @@ -630,8 +625,9 @@ class LLMClient: strict: bool = False, max_tokens: Optional[int] = None, ): + extra_body = {"enable_thinking": not self.disable_thinking()} return self._stream_openai_structured( - model, messages, response_format, strict, max_tokens + model, messages, response_format, strict, max_tokens, extra_body ) def stream_structured( diff --git a/servers/nextjs/app/(presentation-generator)/outline/components/GenerateButton.tsx b/servers/nextjs/app/(presentation-generator)/outline/components/GenerateButton.tsx index bc5ee297..e5f37757 100644 --- a/servers/nextjs/app/(presentation-generator)/outline/components/GenerateButton.tsx +++ b/servers/nextjs/app/(presentation-generator)/outline/components/GenerateButton.tsx @@ -1,10 +1,10 @@ import React from "react"; import { Button } from "@/components/ui/button"; -import { LoadingState, StreamState, LayoutGroup } from "../types/index"; +import { LoadingState, LayoutGroup } from "../types/index"; interface GenerateButtonProps { loadingState: LoadingState; - streamState: StreamState; + streamState: { isStreaming: boolean, isLoading: boolean }; selectedLayoutGroup: LayoutGroup | null; onSubmit: () => void; } diff --git a/servers/nextjs/app/(presentation-generator)/outline/components/OutlineContent.tsx b/servers/nextjs/app/(presentation-generator)/outline/components/OutlineContent.tsx index 0748a6a3..21852f5e 100644 --- a/servers/nextjs/app/(presentation-generator)/outline/components/OutlineContent.tsx +++ b/servers/nextjs/app/(presentation-generator)/outline/components/OutlineContent.tsx @@ -32,7 +32,7 @@ const OutlineContent: React.FC = ({ onDragEnd, onAddSlide }) => { - + console.log('isLoading', isLoading) const sensors = useSensors( useSensor(PointerSensor), useSensor(KeyboardSensor, { diff --git a/servers/nextjs/app/(presentation-generator)/outline/components/PageHeader.tsx b/servers/nextjs/app/(presentation-generator)/outline/components/PageHeader.tsx deleted file mode 100644 index 8a20c78f..00000000 --- a/servers/nextjs/app/(presentation-generator)/outline/components/PageHeader.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import React from "react"; - -const PageHeader: React.FC = () => ( -
- {/*

- Customize Your Presentation -

*/} - {/*

- Review your outline and select a layout style for your presentation. -

*/} -
-); - -export default PageHeader; \ No newline at end of file diff --git a/servers/nextjs/app/(presentation-generator)/outline/hooks/useOutlineStreaming.ts b/servers/nextjs/app/(presentation-generator)/outline/hooks/useOutlineStreaming.ts index f5db594e..c09a0981 100644 --- a/servers/nextjs/app/(presentation-generator)/outline/hooks/useOutlineStreaming.ts +++ b/servers/nextjs/app/(presentation-generator)/outline/hooks/useOutlineStreaming.ts @@ -3,18 +3,15 @@ import { useDispatch, useSelector } from "react-redux"; import { toast } from "sonner"; import { setOutlines } from "@/store/slices/presentationGeneration"; import { jsonrepair } from "jsonrepair"; -import { StreamState } from "../types/index"; import { RootState } from "@/store/store"; -const DEFAULT_STREAM_STATE: StreamState = { - isStreaming: false, - isLoading: true, -}; + export const useOutlineStreaming = (presentationId: string | null) => { const dispatch = useDispatch(); const { outlines } = useSelector((state: RootState) => state.presentationGeneration); - const [streamState, setStreamState] = useState(DEFAULT_STREAM_STATE); + const [isStreaming, setIsStreaming] = useState(true); + const [isLoading, setIsLoading] = useState(true); useEffect(() => { if (!presentationId || outlines.length > 0) return; @@ -23,8 +20,8 @@ export const useOutlineStreaming = (presentationId: string | null) => { let accumulatedChunks = ""; const initializeStream = async () => { - setStreamState({ isStreaming: true, isLoading: true }); - + setIsStreaming(true) + setIsLoading(true) try { eventSource = new EventSource( `/api/v1/ppt/outlines/stream?presentation_id=${presentationId}` @@ -40,7 +37,7 @@ export const useOutlineStreaming = (presentationId: string | null) => { const partialData = JSON.parse(repairedJson); if (partialData.slides) { dispatch(setOutlines(partialData.slides)); - setStreamState(prev => ({ ...prev, isLoading: false })); + setIsLoading(false) } } catch (error) { // JSON isn't complete yet, continue accumulating @@ -51,8 +48,9 @@ export const useOutlineStreaming = (presentationId: string | null) => { try { const outlinesData: string[] = data.presentation.outlines.slides; dispatch(setOutlines(outlinesData)); - setStreamState({ isStreaming: false, isLoading: false }); - eventSource.close(); + setIsStreaming(false) + setIsLoading(false) + eventSource.close(); } catch (error) { console.error("Error parsing accumulated chunks:", error); toast.error("Failed to parse presentation data"); @@ -62,11 +60,13 @@ export const useOutlineStreaming = (presentationId: string | null) => { break; case "closing": - setStreamState({ isStreaming: false, isLoading: false }); + setIsStreaming(false) + setIsLoading(false) eventSource.close(); break; case "error": - setStreamState({ isStreaming: false, isLoading: false }); + setIsStreaming(false) + setIsLoading(false) eventSource.close(); toast.error('Error in outline streaming', { @@ -78,18 +78,21 @@ export const useOutlineStreaming = (presentationId: string | null) => { }); eventSource.onerror = () => { - setStreamState({ isStreaming: false, isLoading: false }); + setIsStreaming(false) + setIsLoading(false) eventSource.close(); toast.error("Failed to connect to the server. Please try again."); }; } catch (error) { - setStreamState({ isStreaming: false, isLoading: false }); + setIsStreaming(false) + setIsLoading(false) toast.error("Failed to initialize connection"); - }finally{ - setStreamState({ isStreaming: false, isLoading: false }); + } finally { + setIsStreaming(false) + setIsLoading(false) } }; - initializeStream(); + initializeStream(); return () => { if (eventSource) { eventSource.close(); @@ -97,5 +100,5 @@ export const useOutlineStreaming = (presentationId: string | null) => { }; }, [presentationId, dispatch]); - return streamState; + return { isStreaming, isLoading }; }; \ No newline at end of file diff --git a/servers/nextjs/app/(presentation-generator)/outline/types/index.ts b/servers/nextjs/app/(presentation-generator)/outline/types/index.ts index d3067f3e..c916c3a5 100644 --- a/servers/nextjs/app/(presentation-generator)/outline/types/index.ts +++ b/servers/nextjs/app/(presentation-generator)/outline/types/index.ts @@ -14,10 +14,7 @@ export interface LoadingState { duration: number; } -export interface StreamState { - isStreaming: boolean; - isLoading: boolean; -} + export const TABS = { OUTLINE: 'outline', diff --git a/servers/nextjs/app/(presentation-generator)/upload/components/UploadPage.tsx b/servers/nextjs/app/(presentation-generator)/upload/components/UploadPage.tsx index f8799d51..771160d9 100644 --- a/servers/nextjs/app/(presentation-generator)/upload/components/UploadPage.tsx +++ b/servers/nextjs/app/(presentation-generator)/upload/components/UploadPage.tsx @@ -131,7 +131,6 @@ const UploadPage = () => { config, files: responses, })); - dispatch(clearOutlines()); router.push("/documents-preview"); }; @@ -155,7 +154,6 @@ const UploadPage = () => { }); dispatch(setPresentationId(createResponse.id)); - dispatch(clearOutlines()); router.push("/outline"); };