Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.env
__pycache__/
*.pyc
.vscode/
.idea/
.env.*
11 changes: 11 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
openai
fastapi
uvicorn
pydantic
httpx
python-dotenv
tavily-python
streamlit
requests
langgraph
reportlab
Empty file added src/__init__.py
Empty file.
Empty file added src/agents/__init__.py
Empty file.
16 changes: 16 additions & 0 deletions src/agents/llm_agent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from dataclasses import dataclass
from src.services.lmstudio_client import chat_with_lmstudio


@dataclass
class LLMAgent:
name: str = "local_llm"

def run(self, query: str, context: str | None = None) -> str:
prompt = query
if context:
prompt = (
"Use the following context to answer the question.\n\n"
f"Context:\n{context}\n\nQuestion:\n{query}"
)
return chat_with_lmstudio(prompt)
14 changes: 14 additions & 0 deletions src/agents/planner_agent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
class PlannerAgent:
def run(self, state: dict) -> dict:
state["outline"] = [
"Abstract",
"Introduction",
"Background",
"Applications",
"Trends",
"Challenges",
"Future Scope",
"Conclusion",
"References"
]
return state
93 changes: 93 additions & 0 deletions src/agents/searcher_agent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
from src.services.tavily_client import TavilyClient


class SearcherAgent:
def __init__(self):
self.client = TavilyClient()

def _clean(self, text: str) -> str:
if not text:
return ""

remove = [
"subscribe", "likes", "views", "watch", "upgrade",
"reddit", "youtube", "emoji"
]

text = text.replace("\n", " ")
for r in remove:
text = text.replace(r, "")

return text.strip()

def _summarize(self, content: str) -> str:
content = self._clean(content)
sentences = [s.strip() for s in content.split(".") if len(s.strip()) > 40]
return ". ".join(sentences[:3]) + "." if sentences else ""

def run(self, state: dict):
results = []

for question in state.get("sub_questions", []):
data = self.client.search(question)

sources = []
for item in data.get("results", []):
summary = self._summarize(item.get("content", ""))
if not summary:
continue

sources.append({
"summary": summary,
"url": item.get("url", ""),
"confidence": round(item.get("score", 0.85), 2)
})

results.append({
"question": question,
"sources": sources
})

state["search_results"] = results
return state









































119 changes: 119 additions & 0 deletions src/agents/writer_agent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
class WriterAgent:
def __init__(self, llm):
self.llm = llm

def _section(self, title: str, topic: str, min_words: int):
prompt = f"""
You are writing an academic research paper.

Write the section titled:
{title}

Research topic:
{topic}

Rules:
- Formal academic writing
- Paragraph-based (no bullets unless necessary)
- Minimum {min_words} words
- Do NOT write conclusion
- Do NOT write references
"""
return self.llm.invoke(prompt)

def _conclusion(self, topic: str):
prompt = f"""
Write the FINAL CONCLUSION section for an academic research paper.

Topic:
{topic}

Rules:
- Summarize key insights
- Discuss implications
- Mention future scope
- 300–400 words
"""
return self.llm.invoke(prompt)

def run(self, state: dict):
topic = state["input"]

paper = []

# Title
paper.append(f"# {topic}\n")

# Abstract
paper.append("## Abstract\n" + self._section("Abstract", topic, 200))

# Keywords
paper.append(
"## Keywords\n"
"Artificial Intelligence, Machine Learning, Data Analytics, Automation, Ethics, Sustainability\n"
)

# Main body sections
paper.append("## 1. Introduction\n" + self._section("Introduction", topic, 400))
paper.append("## 2. Literature Review\n" + self._section("Literature Review", topic, 500))
paper.append("## 3. Methodology\n" + self._section("Methodology", topic, 400))
paper.append("## 4. Applications\n" + self._section("Applications", topic, 500))
paper.append("## 5. Challenges and Limitations\n" + self._section("Challenges and Limitations", topic, 400))
paper.append("## 6. Future Trends\n" + self._section("Future Trends", topic, 400))

# ONE final conclusion
paper.append("## 7. Conclusion\n" + self._conclusion(topic))

# ONE references section
paper.append(
"## References\n"
"[1] https://www.ajournals.org/ijai/article/details/1006-2538/79\n"
"[2] https://www.sciencedirect.com/topics/artificial-intelligence\n"
"[3] https://ieeexplore.ieee.org/Xplore/home.jsp\n"
)

state["final_answer"] = "\n\n".join(paper)
return state











































19 changes: 19 additions & 0 deletions src/api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from fastapi import FastAPI
from pydantic import BaseModel
from src.core.langgraph_pipeline import build_graph

app = FastAPI()
graph = build_graph()


class Prompt(BaseModel):
message: str


@app.post("/chat")
def chat(prompt: Prompt):
result = graph.invoke({"query": prompt.message})
return {
"reply": result["answer"],
"plan": result["plan"]
}
15 changes: 15 additions & 0 deletions src/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from pydantic_settings import BaseSettings


class Settings(BaseSettings):
LMSTUDIO_BASE_URL: str
LMSTUDIO_API_KEY: str
LMSTUDIO_MODEL: str

class Config:
env_file = ".env"
extra = "ignore"


settings = Settings()

Empty file added src/core/__init__.py
Empty file.
45 changes: 45 additions & 0 deletions src/core/langgraph_pipeline.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
from langgraph.graph import StateGraph
from src.agents.writer_agent import WriterAgent
from src.services.llm import get_llm


def build_graph():
llm = get_llm()

graph = StateGraph(dict)

writer = WriterAgent(llm)

graph.add_node("writer", writer.run)
graph.set_entry_point("writer")

return graph.compile()





























20 changes: 20 additions & 0 deletions src/core/state.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from typing import TypedDict, List, Dict


class GraphState(TypedDict, total=False):
input: str

planner_steps: List[str]
sub_questions: List[str]

search_results: List[Dict[str, str]]
sources: List[Dict[str, str]]

final_answer: str
final_output: str






3 changes: 3 additions & 0 deletions src/debug_env.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from src.config import settings

print("TAVILY_API_KEY =", settings.TAVILY_API_KEY)
Loading