mirror of
https://github.com/khoj-ai/khoj.git
synced 2024-11-23 15:38:55 +01:00
Automatically carry over research mode from home page to chat
- Improve mobile friendliness with new research mode toggle, since chat input area is now taking up more space - Remove clunky title from the suggestion card - Fix fk lookup error for agent.creator
This commit is contained in:
parent
ebaed53069
commit
1f1b182461
8 changed files with 62 additions and 55 deletions
|
@ -42,6 +42,7 @@ function ChatBodyData(props: ChatBodyDataProps) {
|
|||
const [images, setImages] = useState<string[]>([]);
|
||||
const [processingMessage, setProcessingMessage] = useState(false);
|
||||
const [agentMetadata, setAgentMetadata] = useState<AgentData | null>(null);
|
||||
const [isInResearchMode, setIsInResearchMode] = useState(false);
|
||||
const chatInputRef = useRef<HTMLTextAreaElement>(null);
|
||||
|
||||
const setQueryToProcess = props.setQueryToProcess;
|
||||
|
@ -70,6 +71,10 @@ function ChatBodyData(props: ChatBodyDataProps) {
|
|||
if (storedMessage) {
|
||||
setProcessingMessage(true);
|
||||
setQueryToProcess(storedMessage);
|
||||
|
||||
if (storedMessage.trim().startsWith("/research")) {
|
||||
setIsInResearchMode(true);
|
||||
}
|
||||
}
|
||||
}, [setQueryToProcess, props.setImages]);
|
||||
|
||||
|
@ -130,6 +135,7 @@ function ChatBodyData(props: ChatBodyDataProps) {
|
|||
isMobileWidth={props.isMobileWidth}
|
||||
setUploadedFiles={props.setUploadedFiles}
|
||||
ref={chatInputRef}
|
||||
isResearchModeEnabled={isInResearchMode}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
|
|
|
@ -71,7 +71,7 @@ function TrainOfThoughtComponent(props: TrainOfThoughtComponentProps) {
|
|||
</Button>
|
||||
) : (
|
||||
<Button
|
||||
className="w-fit text-left justify-start content-start text-xs p-0"
|
||||
className="w-fit text-left justify-start content-start text-xs p-0 h-fit"
|
||||
onClick={() => setCollapsed(true)}
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
|
@ -283,13 +283,11 @@ export default function ChatHistory(props: ChatHistoryProps) {
|
|||
}
|
||||
|
||||
return (
|
||||
<ScrollArea className={`h-[80vh] relative`} ref={scrollAreaRef}>
|
||||
<ScrollArea className={`h-[73vh] relative`} ref={scrollAreaRef}>
|
||||
<div>
|
||||
<div className={`${styles.chatHistory} ${props.customClassName}`}>
|
||||
<div ref={sentinelRef} style={{ height: "1px" }}>
|
||||
{fetchingData && (
|
||||
<InlineLoading message="Loading Conversation" className="opacity-50" />
|
||||
)}
|
||||
{fetchingData && <InlineLoading className="opacity-50" />}
|
||||
</div>
|
||||
{data &&
|
||||
data.chat &&
|
||||
|
|
|
@ -37,12 +37,7 @@ import { Popover, PopoverContent } from "@/components/ui/popover";
|
|||
import { PopoverTrigger } from "@radix-ui/react-popover";
|
||||
import { Textarea } from "@/components/ui/textarea";
|
||||
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip";
|
||||
import {
|
||||
convertColorToTextClass,
|
||||
convertToBGClass,
|
||||
convertColorToBorderClass,
|
||||
convertColorToRingClass,
|
||||
} from "@/app/common/colorUtils";
|
||||
import { convertColorToTextClass, convertToBGClass } from "@/app/common/colorUtils";
|
||||
|
||||
import LoginPrompt from "../loginPrompt/loginPrompt";
|
||||
import { uploadDataForIndexing } from "../../common/chatFunctions";
|
||||
|
@ -63,6 +58,7 @@ interface ChatInputProps {
|
|||
isMobileWidth?: boolean;
|
||||
isLoggedIn: boolean;
|
||||
agentColor?: string;
|
||||
isResearchModeEnabled?: boolean;
|
||||
}
|
||||
|
||||
export const ChatInputArea = forwardRef<HTMLTextAreaElement, ChatInputProps>((props, ref) => {
|
||||
|
@ -86,7 +82,9 @@ export const ChatInputArea = forwardRef<HTMLTextAreaElement, ChatInputProps>((pr
|
|||
const [isDragAndDropping, setIsDragAndDropping] = useState(false);
|
||||
|
||||
const [showCommandList, setShowCommandList] = useState(false);
|
||||
const [useResearchMode, setUseResearchMode] = useState(false);
|
||||
const [useResearchMode, setUseResearchMode] = useState<boolean>(
|
||||
props.isResearchModeEnabled || false,
|
||||
);
|
||||
|
||||
const chatInputRef = ref as React.MutableRefObject<HTMLTextAreaElement>;
|
||||
useEffect(() => {
|
||||
|
@ -128,6 +126,12 @@ export const ChatInputArea = forwardRef<HTMLTextAreaElement, ChatInputProps>((pr
|
|||
fetchImageData();
|
||||
}, [imagePaths]);
|
||||
|
||||
useEffect(() => {
|
||||
if (props.isResearchModeEnabled) {
|
||||
setUseResearchMode(props.isResearchModeEnabled);
|
||||
}
|
||||
}, [props.isResearchModeEnabled]);
|
||||
|
||||
function onSendMessage() {
|
||||
if (imageUploaded) {
|
||||
setImageUploaded(false);
|
||||
|
@ -454,7 +458,7 @@ export const ChatInputArea = forwardRef<HTMLTextAreaElement, ChatInputProps>((pr
|
|||
onChange={handleFileChange}
|
||||
style={{ display: "none" }}
|
||||
/>
|
||||
<div className="flex items-end pb-4">
|
||||
<div className="flex items-center">
|
||||
<Button
|
||||
variant={"ghost"}
|
||||
className="!bg-none p-0 m-2 h-auto text-3xl rounded-full text-gray-300 hover:text-gray-500"
|
||||
|
@ -464,7 +468,7 @@ export const ChatInputArea = forwardRef<HTMLTextAreaElement, ChatInputProps>((pr
|
|||
<Paperclip className="w-8 h-8" />
|
||||
</Button>
|
||||
</div>
|
||||
<div className="flex-grow flex flex-col w-full gap-1.5 relative pb-2">
|
||||
<div className="flex-grow flex flex-col w-full gap-1.5 relative">
|
||||
<div className="flex items-center gap-2 overflow-x-auto">
|
||||
{imageUploaded &&
|
||||
imagePaths.map((path, index) => (
|
||||
|
@ -490,8 +494,8 @@ export const ChatInputArea = forwardRef<HTMLTextAreaElement, ChatInputProps>((pr
|
|||
</div>
|
||||
<Textarea
|
||||
ref={chatInputRef}
|
||||
className={`border ${props.agentColor ? convertColorToBorderClass(props.agentColor) : "border-orange-300"} focus:border-none
|
||||
focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 ${convertColorToRingClass(props.agentColor)}
|
||||
className={`border-none focus:border-none
|
||||
focus:outline-none focus-visible:ring-transparent
|
||||
w-full h-16 min-h-16 max-h-[128px] md:py-4 rounded-lg resize-none dark:bg-neutral-700
|
||||
${props.isMobileWidth ? "text-md" : "text-lg"}`}
|
||||
placeholder="Type / to see a list of commands"
|
||||
|
@ -510,7 +514,7 @@ export const ChatInputArea = forwardRef<HTMLTextAreaElement, ChatInputProps>((pr
|
|||
disabled={props.sendDisabled || recording}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-end pb-4">
|
||||
<div className="flex items-center">
|
||||
{recording ? (
|
||||
<TooltipProvider>
|
||||
<Tooltip>
|
||||
|
@ -569,7 +573,7 @@ export const ChatInputArea = forwardRef<HTMLTextAreaElement, ChatInputProps>((pr
|
|||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
variant="ghost"
|
||||
className="float-right justify-center gap-1 flex items-center p-0 mr-2"
|
||||
className="float-right justify-center gap-1 flex items-center p-1.5 mr-2 h-fit"
|
||||
onClick={() => {
|
||||
setUseResearchMode(!useResearchMode);
|
||||
chatInputRef?.current?.focus();
|
||||
|
@ -585,7 +589,7 @@ export const ChatInputArea = forwardRef<HTMLTextAreaElement, ChatInputProps>((pr
|
|||
)}
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<TooltipContent className="text-xs">
|
||||
Research Mode allows you to get more deeply researched, detailed
|
||||
responses. Response times may be longer.
|
||||
</TooltipContent>
|
||||
|
|
|
@ -14,25 +14,21 @@ interface SuggestionCardProps {
|
|||
|
||||
export default function SuggestionCard(data: SuggestionCardProps) {
|
||||
const bgColors = converColorToBgGradient(data.color);
|
||||
const cardClassName = `${styles.card} ${bgColors} md:w-full md:h-fit sm:w-full h-fit md:w-[200px] md:h-[200px] cursor-pointer`;
|
||||
const titleClassName = `${styles.title} pt-2 dark:text-white dark:font-bold`;
|
||||
const cardClassName = `${styles.card} ${bgColors} md:w-full md:h-fit sm:w-full h-fit md:w-[200px] md:h-[180px] cursor-pointer md:p-2`;
|
||||
const descriptionClassName = `${styles.text} dark:text-white`;
|
||||
|
||||
const cardContent = (
|
||||
<Card className={cardClassName}>
|
||||
<CardHeader className="m-0 p-2 pb-1 relative">
|
||||
<div className="flex flex-row md:flex-col">
|
||||
<div className="flex">
|
||||
<CardContent className="m-0 p-2">
|
||||
{convertSuggestionTitleToIconClass(data.title, data.color.toLowerCase())}
|
||||
<CardTitle className={titleClassName}>{data.title}</CardTitle>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent className="m-0 p-2 pr-4 pt-1">
|
||||
<CardDescription
|
||||
className={`${descriptionClassName} sm:line-clamp-2 md:line-clamp-4`}
|
||||
>
|
||||
{data.body}
|
||||
</CardDescription>
|
||||
</CardContent>
|
||||
<CardDescription
|
||||
className={`${descriptionClassName} sm:line-clamp-2 md:line-clamp-4 pt-1`}
|
||||
>
|
||||
{data.body}
|
||||
</CardDescription>
|
||||
</CardContent>
|
||||
</div>
|
||||
</Card>
|
||||
);
|
||||
|
||||
|
|
|
@ -1,12 +1,9 @@
|
|||
|
||||
.card {
|
||||
padding: 0.5rem;
|
||||
margin: 0.05rem;
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 1.0rem;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.text {
|
||||
|
|
|
@ -47,24 +47,24 @@ const DEFAULT_COLOR = "orange";
|
|||
|
||||
export function convertSuggestionTitleToIconClass(title: string, color: string) {
|
||||
if (title === SuggestionType.Automation)
|
||||
return getIconFromIconName("Robot", color, "w-8", "h-8");
|
||||
if (title === SuggestionType.Paint) return getIconFromIconName("Palette", color, "w-8", "h-8");
|
||||
return getIconFromIconName("Robot", color, "w-6", "h-6");
|
||||
if (title === SuggestionType.Paint) return getIconFromIconName("Palette", color, "w-6", "h-6");
|
||||
if (title === SuggestionType.PopCulture)
|
||||
return getIconFromIconName("Confetti", color, "w-8", "h-8");
|
||||
if (title === SuggestionType.Travel) return getIconFromIconName("Jeep", color, "w-8", "h-8");
|
||||
if (title === SuggestionType.Learning) return getIconFromIconName("Book", color, "w-8", "h-8");
|
||||
return getIconFromIconName("Confetti", color, "w-6", "h-6");
|
||||
if (title === SuggestionType.Travel) return getIconFromIconName("Jeep", color, "w-6", "h-6");
|
||||
if (title === SuggestionType.Learning) return getIconFromIconName("Book", color, "w-6", "h-6");
|
||||
if (title === SuggestionType.Health)
|
||||
return getIconFromIconName("Asclepius", color, "w-8", "h-8");
|
||||
if (title === SuggestionType.Fun) return getIconFromIconName("Island", color, "w-8", "h-8");
|
||||
if (title === SuggestionType.Home) return getIconFromIconName("House", color, "w-8", "h-8");
|
||||
return getIconFromIconName("Asclepius", color, "w-6", "h-6");
|
||||
if (title === SuggestionType.Fun) return getIconFromIconName("Island", color, "w-6", "h-6");
|
||||
if (title === SuggestionType.Home) return getIconFromIconName("House", color, "w-6", "h-6");
|
||||
if (title === SuggestionType.Language)
|
||||
return getIconFromIconName("Translate", color, "w-8", "h-8");
|
||||
if (title === SuggestionType.Code) return getIconFromIconName("Code", color, "w-8", "h-8");
|
||||
if (title === SuggestionType.Food) return getIconFromIconName("BowlFood", color, "w-8", "h-8");
|
||||
return getIconFromIconName("Translate", color, "w-6", "h-6");
|
||||
if (title === SuggestionType.Code) return getIconFromIconName("Code", color, "w-6", "h-6");
|
||||
if (title === SuggestionType.Food) return getIconFromIconName("BowlFood", color, "w-6", "h-6");
|
||||
if (title === SuggestionType.Interviewing)
|
||||
return getIconFromIconName("Lectern", color, "w-8", "h-8");
|
||||
if (title === SuggestionType.Finance) return getIconFromIconName("Wallet", color, "w-8", "h-8");
|
||||
else return getIconFromIconName("Lightbulb", color, "w-8", "h-8");
|
||||
return getIconFromIconName("Lectern", color, "w-6", "h-6");
|
||||
if (title === SuggestionType.Finance) return getIconFromIconName("Wallet", color, "w-6", "h-6");
|
||||
else return getIconFromIconName("Lightbulb", color, "w-6", "h-6");
|
||||
}
|
||||
|
||||
export const suggestionsData: Suggestion[] = [
|
||||
|
|
|
@ -116,8 +116,8 @@ function ChatBodyData(props: ChatBodyDataProps) {
|
|||
`What would you like to get done${nameSuffix}?`,
|
||||
`Hey${nameSuffix}! How can I help?`,
|
||||
`Good ${timeOfDay}${nameSuffix}! What's on your mind?`,
|
||||
`Ready to breeze through your ${["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"][day]}?`,
|
||||
`Want help navigating your ${["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"][day]} workload?`,
|
||||
`Ready to breeze through ${["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"][day]}?`,
|
||||
`Let's navigate your ${["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"][day]} workload`,
|
||||
];
|
||||
const greeting = greetings[Math.floor(Math.random() * greetings.length)];
|
||||
setGreeting(greeting);
|
||||
|
|
|
@ -657,6 +657,8 @@ class AgentAdapters:
|
|||
|
||||
@staticmethod
|
||||
async def ais_agent_accessible(agent: Agent, user: KhojUser) -> bool:
|
||||
agent = await Agent.objects.select_related("creator").aget(pk=agent.pk)
|
||||
|
||||
if agent.privacy_level == Agent.PrivacyLevel.PUBLIC:
|
||||
return True
|
||||
if agent.creator == user:
|
||||
|
@ -866,9 +868,13 @@ class ConversationAdapters:
|
|||
agent = await AgentAdapters.aget_readonly_agent_by_slug(agent_slug, user)
|
||||
if agent is None:
|
||||
raise HTTPException(status_code=400, detail="No such agent currently exists.")
|
||||
return await Conversation.objects.acreate(user=user, client=client_application, agent=agent, title=title)
|
||||
return await Conversation.objects.select_related("agent", "agent__creator", "agent__chat_model").acreate(
|
||||
user=user, client=client_application, agent=agent, title=title
|
||||
)
|
||||
agent = await AgentAdapters.aget_default_agent()
|
||||
return await Conversation.objects.acreate(user=user, client=client_application, agent=agent, title=title)
|
||||
return await Conversation.objects.select_related("agent", "agent__creator", "agent__chat_model").acreate(
|
||||
user=user, client=client_application, agent=agent, title=title
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def create_conversation_session(
|
||||
|
|
Loading…
Reference in a new issue