Skip to content

Commit

Permalink
refactor: Implement lazy loading for images in PlansModal, LandingPag…
Browse files Browse the repository at this point in the history
…ePromotion, and DashboardV2 components
  • Loading branch information
Arghya721 committed Aug 12, 2024
1 parent 534d2ed commit b094eb9
Show file tree
Hide file tree
Showing 16 changed files with 475 additions and 146 deletions.
16 changes: 10 additions & 6 deletions app.py
Original file line number Diff line number Diff line change
Expand Up @@ -774,12 +774,13 @@ async def chat_title(request: ChatRequest, token_info: dict = Depends(verify_tok
# Get the chat model from the request and create the corresponding chat instance
chat_config = model_company_mapping.get("gpt-4o-mini")

if chat_config['premium']:
if not verify_active_subscription(token_info):
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Forbidden",
)
# check the number of generations left for the user
generations_left = get_generations(token_info)
if generations_left == 0:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Generations limit exceeded",
)

chat = chat_config['model'](
model_name="gpt-4o-mini",
Expand Down Expand Up @@ -817,6 +818,9 @@ async def chat_title(request: ChatRequest, token_info: dict = Depends(verify_tok
# Handle validation errors specifically for better user feedback
logging.error("Validation error: %s", ve)
raise HTTPException(status_code=400, detail="Invalid request data") from ve
except HTTPException as he:
# Handle HTTP exceptions specifically for better user feedback
raise he
except Exception as e:
# Log and handle generic exceptions gracefully
logging.error("Error processing chat request: %s", e)
Expand Down
2 changes: 1 addition & 1 deletion web/public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Chat-with-LLMs is your one-stop destination to try out and compare the latest large language models from leading AI providers."
content="Unleash the power of AI conversation with Chat-with-LLMs! Our innovative platform lets you chat with a variety of Large Language Models (LLMs) from leading providers like OpenAI, Anthrophic, and Google. Go beyond a single model - switch seamlessly between them mid-conversation to explore diverse capabilities. It's like having multiple AI experts at your fingertips, all in one place. Discover the power of choice in AI conversation with Chat-with-LLMs."
/>
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Montserrat:wght@400;700&display=swap" rel="stylesheet">
Expand Down
8 changes: 8 additions & 0 deletions web/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { LoginPage } from "./pages/LoginPage";
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import { ProtectedPage } from "./pages/ProtectedPage";
import { DashboardV2 } from "./pages/DashboardV2";
import TermsAndConditions from "./components/TermsAndConditions";
import PrivacyPolicy from "./components/PrivacyPolicy";



Expand Down Expand Up @@ -48,6 +50,12 @@ function App() {
<Dashboard />
</ProtectedPage>
} /> */}
<Route path="/terms-and-conditions" element={
<TermsAndConditions />
} />
<Route path="/privacy" element={
<PrivacyPolicy />
} />
<Route path="/chat"
element={
<ProtectedPage>
Expand Down
136 changes: 67 additions & 69 deletions web/src/components/AiCard.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
import React, { useState } from 'react';
import React, { useState, useMemo } from 'react';
import { Card, CardBody, CardFooter } from "@nextui-org/react";
import { AiOutlineCopy, AiOutlineCheck } from 'react-icons/ai'; // Import AiOutlineReload for the retry icon
import { AiOutlineCopy, AiOutlineCheck } from 'react-icons/ai';
import ReactMarkdown from 'react-markdown';
import remarkGfm from 'remark-gfm';
import { useTheme } from '../components/ThemeContext';
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
import { okaidia } from 'react-syntax-highlighter/dist/esm/styles/prism';

export const AiCard = ({ message, retryComponent }) => {
const [copied, setCopied] = useState(false);
const [codeToCopy, setCodeToCopy] = useState('');
const { theme } = useTheme();

const handleCopy = async () => {
try {
Expand All @@ -32,77 +30,77 @@ export const AiCard = ({ message, retryComponent }) => {
}
};

const renderedMarkdown = useMemo(() => (
<ReactMarkdown
remarkPlugins={[remarkGfm]}
children={message}
components={{
code({ children, className, node, ...rest }) {
const match = /language-(\w+)/.exec(className || '');
const code = String(children).replace(/\n$/, '');
return match ? (
<div className="relative">
<SyntaxHighlighter
{...rest}
PreTag="div"
children={code}
language={match[1]}
style={okaidia}
/>
<button
className={`absolute top-2 right-2 flex items-center gap-2 p-2 rounded transition duration-300 ease-in-out dark:text-gray-400 dark:hover:text-white text-gray-600 hover:text-gray-800`}
onClick={() => handleCodeCopy(code)}
>
{codeToCopy === code ? (
<>
<AiOutlineCheck className="text-green-600" />
<span className="text-green-600">Copied</span>
</>
) : (
<>
<AiOutlineCopy />
<span>Copy Code</span>
</>
)}
</button>
</div>
) : (
<code {...rest} className={className}>
{children}
</code>
);
},
}}
/>
), [message, codeToCopy]); // Memoize based on the message and codeToCopy

const renderedCopyButton = useMemo(() => (
<button
className={`flex items-center gap-2 dark:text-gray-400 dark:hover:text-white text-gray-600 hover:text-gray-800 p-2 rounded transition duration-300 ease-in-out`}
onClick={handleCopy}
>
{copied ? (
<>
<AiOutlineCheck className="text-green-600" />
<span className="text-green-600">Copied</span>
</>
) : (
<>
<AiOutlineCopy />
<span>Copy</span>
</>
)}
</button>
), [copied]); // Memoize the copy button based on the copied state

return (
<Card className={`max-w-max dark:bg-gray-700 dark:text-gray-200 bg-white text-gray-800`}>
<CardBody>
<ReactMarkdown
remarkPlugins={[remarkGfm]}
children={message}
components={{
code({ children, className, node, ...rest }) {
const match = /language-(\w+)/.exec(className || '');
const code = String(children).replace(/\n$/, '');
return match ? (
<div className="relative">
<SyntaxHighlighter
{...rest}
PreTag="div"
children={code}
language={match[1]}
style={okaidia}
/>
<button
className={`absolute top-2 right-2 flex items-center gap-2 p-2 rounded transition duration-300 ease-in-out dark:text-gray-400 dark:hover:text-white text-gray-600 hover:text-gray-800}`}
onClick={() => handleCodeCopy(code)}
>
{codeToCopy === code ? (
<>
<AiOutlineCheck className="text-green-600" />
<span className="text-green-600">Copied</span>
</>
) : (
<>
<AiOutlineCopy />
<span>Copy Code</span>
</>
)}
</button>
</div>
) : (
<code {...rest} className={className}>
{children}
</code>
);
},
}}
/>
{renderedMarkdown}
</CardBody>
<CardFooter className="flex justify-end items-center p-2">
{/* {showRetry && (
<button
className="flex items-center gap-2 text-gray-600 hover:text-gray-800 p-2 rounded transition duration-300 ease-in-out"
onClick={handleRetry}
>
<AiOutlineReload />
</button>
)} */}
{retryComponent}
<button
className={`flex items-center gap-2 dark:text-gray-400 dark:hover:text-white text-gray-600 hover:text-gray-800 p-2 rounded transition duration-300 ease-in-out`}
onClick={handleCopy}
>
{copied ? (
<>
<AiOutlineCheck className="text-green-600" />
<span className="text-green-600">Copied</span>
</>
) : (
<>
<AiOutlineCopy />
<span>Copy</span>
</>
)}
</button>
{renderedCopyButton}
</CardFooter>
</Card>
);
Expand Down
5 changes: 1 addition & 4 deletions web/src/components/Footer.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,7 @@ export const Footer = () => {
© 2024 chat-with-llms. All rights reserved. This is an open-source project.
</p>
<nav className="sm:ml-auto flex gap-4 sm:gap-6">
<Link className="text-xs hover:underline underline-offset-4" href="#">
Terms of Service
</Link>
<Link className="text-xs hover:underline underline-offset-4" href="#">
<Link className="text-xs hover:underline underline-offset-4" to="/privacy">
Privacy
</Link>
<a
Expand Down
90 changes: 76 additions & 14 deletions web/src/components/LandingPageDescription.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,32 @@
import React from 'react';
import { Button } from '@nextui-org/react';
import { useGoogleLogin } from '@react-oauth/google';
import { useGoogleAuth } from '../utils/useGoogleAuth';
import { verifyGoogleAuth } from '../utils/verifyGoogleAuth';
import { useNavigate } from 'react-router-dom';


export const LandingPageDescription = React.forwardRef((props, ref) => {
const navigate = useNavigate();
const { handleGoogleSuccess, handleGoogleFailure } = useGoogleAuth();
let model = "gpt-4o-mini";

const login =
useGoogleLogin({
onSuccess: (response) => handleGoogleSuccess(response, model),
onFailure: (error) => handleGoogleFailure(error),
});

export const LandingPageDescription = () => {
return (
<React.Fragment>
<div className="w-full pb-12 md:pb-24 lg:pb-32 border-b border-gray-200 my-8 md:col-span-2"></div>
<div ref={ref} className="w-full pb-12 md:pb-24 lg:pb-32 border-b border-gray-200 my-8 md:col-span-2"></div>
<div className="flex flex-col items-center justify-center space-y-4 text-center px-4 sm:px-0">
<div className="inline-block rounded-lg text-md bg-gray-100 px-3 py-1 text-sm dark:bg-gray-800">
Try Different LLMs
</div>
<h2 className="text-3xl font-bold tracking-tighter sm:text-5xl">Explore the Latest Language Models</h2>
<p className="max-w-[900px] text-gray-500 md:text-xl/relaxed lg:text-base/relaxed xl:text-xl/relaxed dark:text-gray-400">
Chat-with-LLMs allows you to try out and compare the most popular large language models, including
GPT, Gemini, Perplexity, Mistral, and Anthropic, all in one place.
Unleash the power of AI conversation with Chat-with-LLMs! Our innovative platform lets you chat with a variety of Large Language Models (LLMs) from leading providers like OpenAI, Anthrophic, and Google. Go beyond a single model - switch seamlessly between them mid-conversation to explore diverse capabilities. It's like having multiple AI experts at your fingertips, all in one place. Discover the power of choice in AI conversation with Chat-with-LLMs.
</p>
</div>
<div className="mx-auto justify-center grid items-start gap-8 sm:max-w-4xl sm:grid-cols-2 md:gap-12 lg:max-w-5xl lg:grid-cols-3 mt-16 px-4 sm:px-0">
Expand All @@ -21,30 +35,62 @@ export const LandingPageDescription = () => {
<p className="text-sm text-gray-500 dark:text-gray-400">
The original large language model, developed by OpenAI.
</p>
<Button className="justify-start" variant="link">
<Button className="justify-start" variant="link" onClick={async () => {
const isVerified = await verifyGoogleAuth();
if (isVerified) navigate('/chat', { state: { userModel: "gpt-4o" } });

else {
model = "gpt-4o";
login();
}
}}>
Try GPT
</Button>
</div>
<div className="grid gap-1">
<h3 className="text-lg font-bold">Gemini</h3>
<p className="text-sm text-gray-500 dark:text-gray-400">A powerful language model from Anthropic.</p>
<Button className="justify-start" variant="link">
<p className="text-sm text-gray-500 dark:text-gray-400">A powerful language model from Google.</p>
<Button className="justify-start" variant="link" onClick={async () => {
const isVerified = await verifyGoogleAuth();
if (isVerified) navigate('/chat', { state: { userModel: "gemini-1.5-flash-latest" } });

else {
model = "gemini-1.5-flash-latest";
login();
}
}}>
Try Gemini
</Button>
</div>
<div className="grid gap-1">
<h3 className="text-lg font-bold">Perplexity</h3>
<p className="text-sm text-gray-500 dark:text-gray-400">A versatile language model from Anthropic.</p>
<Button className="justify-start" variant="link">
<p className="text-sm text-gray-500 dark:text-gray-400">A versatile language model from Perplexity.</p>
<Button className="justify-start" variant="link" onClick={async () => {
const isVerified = await verifyGoogleAuth();
if (isVerified) navigate('/chat', { state: { userModel: "sonar-medium-online" } });

else {
model = "sonar-medium-online";
login();
}
}}>
Try Perplexity
</Button>
</div>
<div className="grid gap-1">
<h3 className="text-lg font-bold">Mistral</h3>
<p className="text-sm text-gray-500 dark:text-gray-400">
A cutting-edge language model from Anthropic.
A cutting-edge language model from Mistral.
</p>
<Button className="justify-start" variant="link">
<Button className="justify-start" variant="link" onClick={async () => {
const isVerified = await verifyGoogleAuth();
if (isVerified) navigate('/chat', { state: { userModel: "mistral-large-2402" } });

else {
model = "mistral-large-2402";
login();
}
}}>
Try Mistral
</Button>
</div>
Expand All @@ -53,7 +99,15 @@ export const LandingPageDescription = () => {
<p className="text-sm text-gray-500 dark:text-gray-400">
Explore Anthropic's suite of language models.
</p>
<Button className="justify-start" variant="link">
<Button className="justify-start" variant="link" onClick={async () => {
const isVerified = await verifyGoogleAuth();
if (isVerified) navigate('/chat', { state: { userModel: "claude-3-5-sonnet-20240620" } });

else {
model = "claude-3-5-sonnet-20240620";
login();
}
}}>
Try Anthropic
</Button>
</div>
Expand All @@ -62,11 +116,19 @@ export const LandingPageDescription = () => {
<p className="text-sm text-gray-500 dark:text-gray-400">
Check back often for updates on new language models.
</p>
<Button className="justify-start" variant="link">
<Button className="justify-start" variant="link" onClick={async () => {
const isVerified = await verifyGoogleAuth();
if (isVerified) navigate('/chat', { state: { userModel: "meta-llama/Meta-Llama-3.1-70B-Instruct-Turbo" } });

else {
model = "meta-llama/Meta-Llama-3.1-70B-Instruct-Turbo";
login();
}
}}>
Explore More
</Button>
</div>
</div>
</React.Fragment>
)
}
});
Loading

0 comments on commit b094eb9

Please sign in to comment.