Soham Waghmare commited on
Commit
27a07a9
·
1 Parent(s): 73fba58

fix: react fixes

Browse files
backend/app.py CHANGED
@@ -33,7 +33,7 @@ app.add_middleware(
33
 
34
  sio = socketio.AsyncServer(
35
  cors_allowed_origins=CORS_ALLOWED_ORIGINS,
36
- ping_timeout=120,
37
  ping_interval=10,
38
  async_mode="asgi",
39
  )
 
33
 
34
  sio = socketio.AsyncServer(
35
  cors_allowed_origins=CORS_ALLOWED_ORIGINS,
36
+ ping_timeout=1200,
37
  ping_interval=10,
38
  async_mode="asgi",
39
  )
backend/knet.py CHANGED
@@ -138,11 +138,11 @@ class ResearchProgress:
138
  self.callback = callback
139
 
140
  async def update(self, progress: int, message: str):
141
- self.progress = min(100, self.progress + progress) # max 100
142
  await self.callback({"progress": self.progress, "message": message})
143
 
144
  async def setter(self, progress: int, message: str):
145
- self.progress = min(100, progress) # max 100
146
  await self.callback({"progress": self.progress, "message": message})
147
 
148
 
@@ -189,21 +189,25 @@ class KNet:
189
  self.research_plan = self.generate_content(self.prompt.research_plan.format(topic=topic), schema=self.schema.research_plan)["steps"]
190
  self.logger.info(f"Research plan:\n{json.dumps(self.research_plan, indent=2)}")
191
 
192
- # Generate initial search query
193
- query = self.generate_content(
194
- self.prompt.search_query.format(vertical=self.research_plan[self.idx_research_plan]), schema=self.schema.search_query
195
- )["branches"][0]
196
-
197
- # Initialize research tree
198
- root_node = ResearchNode(query)
199
- to_explore = deque([(root_node, 0)]) # (node, depth) pairs
200
- explored_queries = set() # {string, string, ...}
201
 
202
  await self.progress.update(0, "Starting research...")
203
 
204
  # Iterate on research plan
205
  for self.idx_research_plan, _ in enumerate(self.research_plan):
206
- current_node, current_depth = to_explore.popleft()
 
 
 
 
 
 
 
 
 
 
 
 
207
  await self.progress.update(100 / (len(self.research_plan) + 1), f"{self.research_plan[self.idx_research_plan]}")
208
 
209
  while to_explore:
@@ -230,9 +234,9 @@ class KNet:
230
 
231
  # Generate final report
232
  await self.progress.update(100 / (len(self.research_plan) + 1), "Generating final report...")
233
- final_report = self._generate_final_report(root_node, topic)
234
 
235
- self.logger.info(f"Research completed. Explored {len(explored_queries)} queries across {root_node.max_depth()} levels")
236
  await self.progress.update(100, "Research complete!")
237
 
238
  with open("output.log.json", "w", encoding="utf-8") as f:
@@ -256,7 +260,7 @@ class KNet:
256
  report = []
257
  # Fill in report outline
258
  for i, heading in enumerate(outline["headings"]):
259
- self.progress.update(100 / (len(outline["headings"] + 1)), "Generating report...")
260
  content = self.generate_content(
261
  self.prompt.report_fillin.format(
262
  topic=topic,
@@ -267,6 +271,8 @@ class KNet:
267
  schema=self.schema.report_fillin,
268
  )["content"]
269
  report.append({"heading": heading, "content": content})
 
 
270
 
271
  # Collate multimedia content
272
  media_content = {"images": [], "videos": [], "links": [], "references": []}
@@ -297,9 +303,9 @@ class KNet:
297
  }
298
 
299
  return {
300
- "topic": root_node.query,
301
  "timestamp": datetime.now().isoformat(),
302
- "content": report,
303
  "media": media_content,
304
  "research_tree": build_tree_structure(root_node),
305
  "metadata": {
@@ -337,7 +343,7 @@ class KNet:
337
  # node -|-> child
338
  # |-> child
339
  new_nodes = []
340
- for branch in response.get("branches", []):
341
  child_node = node.add_child(branch)
342
  new_nodes.append(child_node)
343
 
@@ -360,7 +366,7 @@ class KNet:
360
  if node.data:
361
  findings = ("\n" + "-" * 10 + "Next data" + "-" * 10 + "\n").join([json.dumps(d, indent=2) for d in node.data])
362
  response = self.generate_content(self.prompt.site_summary.format(query=node.query, findings=findings), temp=0.2)
363
- self.ctx_manager.append(response)
364
 
365
  # Research manager takes decision to proceed or not
366
  prompt = self.prompt.continue_branch.format(
 
138
  self.callback = callback
139
 
140
  async def update(self, progress: int, message: str):
141
+ self.progress = int(min(100, self.progress + progress)) # max 100
142
  await self.callback({"progress": self.progress, "message": message})
143
 
144
  async def setter(self, progress: int, message: str):
145
+ self.progress = int(min(100, progress)) # max 100
146
  await self.callback({"progress": self.progress, "message": message})
147
 
148
 
 
189
  self.research_plan = self.generate_content(self.prompt.research_plan.format(topic=topic), schema=self.schema.research_plan)["steps"]
190
  self.logger.info(f"Research plan:\n{json.dumps(self.research_plan, indent=2)}")
191
 
192
+ master_node = ResearchNode()
 
 
 
 
 
 
 
 
193
 
194
  await self.progress.update(0, "Starting research...")
195
 
196
  # Iterate on research plan
197
  for self.idx_research_plan, _ in enumerate(self.research_plan):
198
+ # Generate initial search query
199
+ query = self.generate_content(
200
+ self.prompt.search_query.format(
201
+ vertical=self.research_plan[self.idx_research_plan], research_plan="None", past_queries="None", ctx_manager="None", n=1
202
+ ),
203
+ schema=self.schema.search_query,
204
+ )["branches"][0]
205
+
206
+ root_node = ResearchNode(query)
207
+ master_node.add_child(root_node)
208
+ to_explore = deque([(root_node, 0)]) # (node, depth) pairs
209
+ explored_queries = set() # {string, string, ...}
210
+
211
  await self.progress.update(100 / (len(self.research_plan) + 1), f"{self.research_plan[self.idx_research_plan]}")
212
 
213
  while to_explore:
 
234
 
235
  # Generate final report
236
  await self.progress.update(100 / (len(self.research_plan) + 1), "Generating final report...")
237
+ final_report = self._generate_final_report(master_node, topic)
238
 
239
+ self.logger.info(f"Research completed. Explored {len(explored_queries)} queries across {master_node.max_depth()} levels")
240
  await self.progress.update(100, "Research complete!")
241
 
242
  with open("output.log.json", "w", encoding="utf-8") as f:
 
260
  report = []
261
  # Fill in report outline
262
  for i, heading in enumerate(outline["headings"]):
263
+ self.progress.update(100 / (len(outline["headings"]) + 1), "Generating report...")
264
  content = self.generate_content(
265
  self.prompt.report_fillin.format(
266
  topic=topic,
 
271
  schema=self.schema.report_fillin,
272
  )["content"]
273
  report.append({"heading": heading, "content": content})
274
+ # Rasterize report
275
+ raster_report = f"# {outline['title']}\n\n" + "\n\n".join([f"## {r['heading']}\n\n{r['content']}" for r in report])
276
 
277
  # Collate multimedia content
278
  media_content = {"images": [], "videos": [], "links": [], "references": []}
 
303
  }
304
 
305
  return {
306
+ "topic": topic,
307
  "timestamp": datetime.now().isoformat(),
308
+ "content": raster_report,
309
  "media": media_content,
310
  "research_tree": build_tree_structure(root_node),
311
  "metadata": {
 
343
  # node -|-> child
344
  # |-> child
345
  new_nodes = []
346
+ for branch in response.get("branches", [])[:1]:
347
  child_node = node.add_child(branch)
348
  new_nodes.append(child_node)
349
 
 
366
  if node.data:
367
  findings = ("\n" + "-" * 10 + "Next data" + "-" * 10 + "\n").join([json.dumps(d, indent=2) for d in node.data])
368
  response = self.generate_content(self.prompt.site_summary.format(query=node.query, findings=findings), temp=0.2)
369
+ self.ctx_manager.append(response) if isinstance(response, str) else None
370
 
371
  # Research manager takes decision to proceed or not
372
  prompt = self.prompt.continue_branch.format(
backend/research_node.py CHANGED
@@ -3,7 +3,7 @@ from typing import Any, Dict, List, Optional
3
 
4
 
5
  class ResearchNode:
6
- def __init__(self, query: str, parent: Optional["ResearchNode"] = None, depth: int = 0):
7
  self.query = query
8
  self.parent = parent
9
  self.depth = depth
@@ -42,3 +42,11 @@ class ResearchNode:
42
  for child in self.children:
43
  data.extend(child.get_all_data())
44
  return data
 
 
 
 
 
 
 
 
 
3
 
4
 
5
  class ResearchNode:
6
+ def __init__(self, query: str = "_", parent: Optional["ResearchNode"] = None, depth: int = 0):
7
  self.query = query
8
  self.parent = parent
9
  self.depth = depth
 
42
  for child in self.children:
43
  data.extend(child.get_all_data())
44
  return data
45
+
46
+ def __repr__(self) -> dict:
47
+ return {
48
+ "query": self.query,
49
+ "depth": self.depth,
50
+ "children": [child.__repr__() for child in self.children],
51
+ "data": self.data,
52
+ }
frontend/src/components/ChatInterface.tsx CHANGED
@@ -45,7 +45,6 @@ const ChatInterface = () => {
45
  sources: true,
46
  citations: false,
47
  max_depth: 1,
48
- max_breadth: 3,
49
  num_sites_per_query: 5,
50
  });
51
 
@@ -131,11 +130,25 @@ const ChatInterface = () => {
131
  },
132
  ];
133
 
134
- return {
 
135
  ...prevState,
136
  isLoading: false,
137
  messages: newMessages,
138
  };
 
 
 
 
 
 
 
 
 
 
 
 
 
139
  });
140
  });
141
 
@@ -230,7 +243,6 @@ const ChatInterface = () => {
230
  socket.emit("start_research", {
231
  topic: content,
232
  max_depth: researchOptions.max_depth,
233
- max_breadth: researchOptions.max_breadth,
234
  num_sites_per_query: researchOptions.num_sites_per_query,
235
  });
236
  } catch (error) {
 
45
  sources: true,
46
  citations: false,
47
  max_depth: 1,
 
48
  num_sites_per_query: 5,
49
  });
50
 
 
130
  },
131
  ];
132
 
133
+ // Save updated messages to localStorage
134
+ const updatedState = {
135
  ...prevState,
136
  isLoading: false,
137
  messages: newMessages,
138
  };
139
+
140
+ // Update localStorage with the new messages
141
+ const updatedData: ChatData = {
142
+ conversations: conversations.map((conv) => ({
143
+ ...conv,
144
+ messages: conv.id === currentConversationId ? newMessages : conv.messages || [],
145
+ lastUpdated: conv.id === currentConversationId ? new Date().toISOString() : conv.lastUpdated,
146
+ })),
147
+ currentConversationId,
148
+ };
149
+ saveToStorage(updatedData);
150
+
151
+ return updatedState;
152
  });
153
  });
154
 
 
243
  socket.emit("start_research", {
244
  topic: content,
245
  max_depth: researchOptions.max_depth,
 
246
  num_sites_per_query: researchOptions.num_sites_per_query,
247
  });
248
  } catch (error) {
frontend/src/components/ResearchControls.tsx CHANGED
@@ -65,17 +65,6 @@ const ResearchControls: React.FC<ResearchControlsProps> = ({ options, onOptionCh
65
  />
66
  </div>
67
 
68
- <div className="space-y-2">
69
- <Label htmlFor="max-breadth">Max Breadth</Label>
70
- <Input
71
- type="number"
72
- id="max-breadth"
73
- value={options.max_breadth}
74
- onChange={(e) => onOptionChange({ ...options, max_breadth: parseInt(e.target.value, 10) })}
75
- className="w-full"
76
- />
77
- </div>
78
-
79
  <div className="space-y-2">
80
  <Label htmlFor="num-sites-per-query">Number of Sites per Query</Label>
81
  <Input
 
65
  />
66
  </div>
67
 
 
 
 
 
 
 
 
 
 
 
 
68
  <div className="space-y-2">
69
  <Label htmlFor="num-sites-per-query">Number of Sites per Query</Label>
70
  <Input
frontend/src/components/ui/ChatLayout.tsx CHANGED
@@ -2,12 +2,12 @@ import { Button } from "@/components/ui/button";
2
  import { Card } from "@/components/ui/card";
3
  import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from "@/components/ui/resizable";
4
  import { ScrollArea } from "@/components/ui/scroll-area";
5
- import { Sheet, SheetContent, SheetTrigger } from "@/components/ui/sheet";
6
  import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
7
  import { LayoutGrid, MessageCircle, Settings } from "lucide-react";
8
  import React from "react";
9
  import { ThemeToggle } from "./ThemeToggle";
10
  import Link from "next/link";
 
11
 
12
  interface ChatLayoutProps {
13
  sidebar: React.ReactNode;
@@ -24,24 +24,27 @@ const ChatLayout: React.FC<ChatLayoutProps> = ({ sidebar, mainContent, settingsP
24
  </Link>
25
  <div className="flex-1" />
26
  <ThemeToggle />
27
- <Sheet>
28
- <SheetTrigger asChild>
29
- <Button variant="ghost" size="icon">
30
  <Settings size={20} />
31
  </Button>
32
- </SheetTrigger>
33
- <SheetContent>
34
- <div className="py-4">
35
- <h2 className="text-lg font-semibold mb-4">Research Settings</h2>
36
- {settingsPanel}
37
- </div>
38
- </SheetContent>
39
- </Sheet>
 
 
 
40
  </header>
41
 
42
  <div className="flex-1 overflow-hidden">
43
  <ResizablePanelGroup direction="horizontal">
44
- <ResizablePanel defaultSize={20} minSize={15} maxSize={30} className="hidden md:block">
45
  <Card className="h-full rounded-none border-r border-t-0 border-l-0 border-b-0">
46
  <ScrollArea className="h-full">{sidebar}</ScrollArea>
47
  </Card>
@@ -49,7 +52,7 @@ const ChatLayout: React.FC<ChatLayoutProps> = ({ sidebar, mainContent, settingsP
49
 
50
  <ResizableHandle withHandle className="hidden md:flex" />
51
 
52
- <ResizablePanel defaultSize={80}>
53
  <Tabs defaultValue="chat" className="h-full flex flex-col">
54
  <div className="p-4">
55
  <TabsList className="">
 
2
  import { Card } from "@/components/ui/card";
3
  import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from "@/components/ui/resizable";
4
  import { ScrollArea } from "@/components/ui/scroll-area";
 
5
  import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
6
  import { LayoutGrid, MessageCircle, Settings } from "lucide-react";
7
  import React from "react";
8
  import { ThemeToggle } from "./ThemeToggle";
9
  import Link from "next/link";
10
+ import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog";
11
 
12
  interface ChatLayoutProps {
13
  sidebar: React.ReactNode;
 
24
  </Link>
25
  <div className="flex-1" />
26
  <ThemeToggle />
27
+ <Dialog>
28
+ <DialogTrigger asChild>
29
+ <Button variant="ghost" size="icon" className="h-9 w-9" title="Settings">
30
  <Settings size={20} />
31
  </Button>
32
+ </DialogTrigger>
33
+ <DialogContent>
34
+ <DialogHeader>
35
+ <DialogTitle>Research Settings</DialogTitle>
36
+ <DialogDescription>
37
+ Configure your research parameters and preferences.
38
+ </DialogDescription>
39
+ </DialogHeader>
40
+ {settingsPanel}
41
+ </DialogContent>
42
+ </Dialog>
43
  </header>
44
 
45
  <div className="flex-1 overflow-hidden">
46
  <ResizablePanelGroup direction="horizontal">
47
+ <ResizablePanel defaultSize={25} minSize={17} maxSize={30} className="hidden md:block">
48
  <Card className="h-full rounded-none border-r border-t-0 border-l-0 border-b-0">
49
  <ScrollArea className="h-full">{sidebar}</ScrollArea>
50
  </Card>
 
52
 
53
  <ResizableHandle withHandle className="hidden md:flex" />
54
 
55
+ <ResizablePanel defaultSize={75}>
56
  <Tabs defaultValue="chat" className="h-full flex flex-col">
57
  <div className="p-4">
58
  <TabsList className="">
frontend/src/lib/types.ts CHANGED
@@ -16,7 +16,6 @@ export interface ResearchOptions {
16
  sources: boolean;
17
  citations: boolean;
18
  max_depth: number;
19
- max_breadth: number;
20
  num_sites_per_query: number;
21
  }
22
 
 
16
  sources: boolean;
17
  citations: boolean;
18
  max_depth: number;
 
19
  num_sites_per_query: number;
20
  }
21