├── backend
├── __init__.py
├── tools
│ ├── __init__.py
│ ├── test_case_generator.py
│ ├── complexity_analyser.py
│ ├── explanation_generator.py
│ ├── code_generator.py
│ └── visualisation_generator.py
├── requirements.txt
├── langgraph.json
├── base.py
├── run_agent.py
└── graph.py
├── agent
├── dsa_agent
│ ├── __init__.py
│ ├── nodes
│ │ ├── question.py
│ │ ├── visualiser.py
│ │ ├── coding.py
│ │ ├── explainer.py
│ │ ├── complexity_finder.py
│ │ └── __init__.py
│ ├── demo.py
│ ├── state.py
│ ├── edges
│ │ ├── code_verify.py
│ │ ├── visualisation_verify.py
│ │ ├── explanation_verify.py
│ │ ├── complexity_verify.py
│ │ └── __init__.py
│ └── agent.py
├── .gitignore
├── .langgraph_api
│ ├── store.pckl
│ ├── .langgraph_ops.pckl
│ ├── store.vectors.pckl
│ ├── .langgraph_checkpoint.1.pckl
│ ├── .langgraph_checkpoint.2.pckl
│ └── .langgraph_retry_counter.pckl
├── langgraph.json
└── pyproject.toml
├── screenshots
├── cover.png
├── codechef-one.png
├── codechef-two.png
├── codechef-one-diagram.png
└── codechef-two-diagram.png
├── frontend-interface
├── app
│ ├── favicon.ico
│ ├── layout.tsx
│ ├── api
│ │ └── copilotkit
│ │ │ └── route.ts
│ ├── globals.css
│ ├── not-found.tsx
│ └── page.tsx
├── public
│ ├── thumbnail.png
│ ├── vercel.svg
│ ├── window.svg
│ ├── file.svg
│ ├── globe.svg
│ └── next.svg
├── next.config.ts
├── postcss.config.mjs
├── lib
│ └── utils.ts
├── eslint.config.mjs
├── components.json
├── .gitignore
├── tsconfig.json
├── components
│ ├── ui
│ │ ├── textarea.tsx
│ │ ├── input.tsx
│ │ ├── slider.tsx
│ │ ├── avatar.tsx
│ │ ├── alert.tsx
│ │ ├── tabs.tsx
│ │ ├── button.tsx
│ │ ├── card.tsx
│ │ └── select.tsx
│ ├── StarComponent.tsx
│ ├── ProblemInput.tsx
│ ├── StepNavigation.tsx
│ ├── ComplexityInput.tsx
│ ├── TestCases.tsx
│ ├── VideoSection.tsx
│ ├── ChatInterface.tsx
│ ├── SolutionDisplay.tsx
│ ├── Editor.tsx
│ └── MermaidRenderer.tsx
├── package.json
└── tailwind.config.ts
├── .github
└── workflows
│ └── ci.yml
├── LICENSE
└── README.md
/backend/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/agent/dsa_agent/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/backend/tools/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/agent/.gitignore:
--------------------------------------------------------------------------------
1 | venv/
2 | __pycache__/
3 | *.pyc
4 | .env
5 | .vercel
6 | myenv/
--------------------------------------------------------------------------------
/screenshots/cover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ARYPROGRAMMER/Learn-Coding-with-Copilotkit/HEAD/screenshots/cover.png
--------------------------------------------------------------------------------
/backend/requirements.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ARYPROGRAMMER/Learn-Coding-with-Copilotkit/HEAD/backend/requirements.txt
--------------------------------------------------------------------------------
/screenshots/codechef-one.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ARYPROGRAMMER/Learn-Coding-with-Copilotkit/HEAD/screenshots/codechef-one.png
--------------------------------------------------------------------------------
/screenshots/codechef-two.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ARYPROGRAMMER/Learn-Coding-with-Copilotkit/HEAD/screenshots/codechef-two.png
--------------------------------------------------------------------------------
/agent/.langgraph_api/store.pckl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ARYPROGRAMMER/Learn-Coding-with-Copilotkit/HEAD/agent/.langgraph_api/store.pckl
--------------------------------------------------------------------------------
/frontend-interface/app/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ARYPROGRAMMER/Learn-Coding-with-Copilotkit/HEAD/frontend-interface/app/favicon.ico
--------------------------------------------------------------------------------
/screenshots/codechef-one-diagram.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ARYPROGRAMMER/Learn-Coding-with-Copilotkit/HEAD/screenshots/codechef-one-diagram.png
--------------------------------------------------------------------------------
/screenshots/codechef-two-diagram.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ARYPROGRAMMER/Learn-Coding-with-Copilotkit/HEAD/screenshots/codechef-two-diagram.png
--------------------------------------------------------------------------------
/agent/.langgraph_api/.langgraph_ops.pckl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ARYPROGRAMMER/Learn-Coding-with-Copilotkit/HEAD/agent/.langgraph_api/.langgraph_ops.pckl
--------------------------------------------------------------------------------
/agent/.langgraph_api/store.vectors.pckl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ARYPROGRAMMER/Learn-Coding-with-Copilotkit/HEAD/agent/.langgraph_api/store.vectors.pckl
--------------------------------------------------------------------------------
/frontend-interface/public/thumbnail.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ARYPROGRAMMER/Learn-Coding-with-Copilotkit/HEAD/frontend-interface/public/thumbnail.png
--------------------------------------------------------------------------------
/frontend-interface/public/vercel.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/agent/.langgraph_api/.langgraph_checkpoint.1.pckl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ARYPROGRAMMER/Learn-Coding-with-Copilotkit/HEAD/agent/.langgraph_api/.langgraph_checkpoint.1.pckl
--------------------------------------------------------------------------------
/agent/.langgraph_api/.langgraph_checkpoint.2.pckl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ARYPROGRAMMER/Learn-Coding-with-Copilotkit/HEAD/agent/.langgraph_api/.langgraph_checkpoint.2.pckl
--------------------------------------------------------------------------------
/agent/.langgraph_api/.langgraph_retry_counter.pckl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ARYPROGRAMMER/Learn-Coding-with-Copilotkit/HEAD/agent/.langgraph_api/.langgraph_retry_counter.pckl
--------------------------------------------------------------------------------
/frontend-interface/next.config.ts:
--------------------------------------------------------------------------------
1 | import type { NextConfig } from "next";
2 |
3 | const nextConfig: NextConfig = {
4 | /* config options here */
5 | };
6 |
7 | export default nextConfig;
8 |
--------------------------------------------------------------------------------
/frontend-interface/postcss.config.mjs:
--------------------------------------------------------------------------------
1 | /** @type {import('postcss-load-config').Config} */
2 | const config = {
3 | plugins: {
4 | tailwindcss: {},
5 | },
6 | };
7 |
8 | export default config;
9 |
--------------------------------------------------------------------------------
/agent/langgraph.json:
--------------------------------------------------------------------------------
1 | {
2 | "python_version": "3.12",
3 | "dockerfile_lines": [],
4 | "dependencies": ["."],
5 | "graphs": {
6 | "dsa_agent": "./dsa_agent/agent.py:graph"
7 | },
8 | "env": ".env"
9 | }
--------------------------------------------------------------------------------
/frontend-interface/lib/utils.ts:
--------------------------------------------------------------------------------
1 | import { clsx, type ClassValue } from "clsx"
2 | import { twMerge } from "tailwind-merge"
3 |
4 | export function cn(...inputs: ClassValue[]) {
5 | return twMerge(clsx(inputs))
6 | }
7 |
--------------------------------------------------------------------------------
/backend/langgraph.json:
--------------------------------------------------------------------------------
1 | {
2 | "python_version": "3.12",
3 | "dockerfile_lines": [],
4 | "dependencies": ["."],
5 | "graphs": {
6 | "dsa_agent": "./graph.py:create_graph"
7 | },
8 | "env": ".env"
9 | }
--------------------------------------------------------------------------------
/frontend-interface/public/window.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/frontend-interface/public/file.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/agent/dsa_agent/nodes/question.py:
--------------------------------------------------------------------------------
1 | from langchain.text_splitter import RecursiveCharacterTextSplitter
2 |
3 | class QuestionRetriever:
4 | def __init__(self, question):
5 | self.question = question
6 |
7 | def update_question(self, question):
8 | self.question = question
9 |
10 |
11 | question = "Add 2 numbers without arithmetic operators"
12 | question_instance = QuestionRetriever(question)
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: Trigger Render Deploy
2 |
3 | on:
4 | schedule:
5 | - cron: '*/15 * * * *' # every 15 minutes
6 |
7 | jobs:
8 | ping-render:
9 | runs-on: ubuntu-latest
10 | steps:
11 | - name: Call Render Deploy Hook
12 | run: |
13 | curl https://learn-coding-with-copilotkit.onrender.com/copilotkit
14 | curl https://learn-coding-with-copilotkit-1.onrender.com/copilotkit
--------------------------------------------------------------------------------
/frontend-interface/eslint.config.mjs:
--------------------------------------------------------------------------------
1 | import { dirname } from "path";
2 | import { fileURLToPath } from "url";
3 | import { FlatCompat } from "@eslint/eslintrc";
4 |
5 | const __filename = fileURLToPath(import.meta.url);
6 | const __dirname = dirname(__filename);
7 |
8 | const compat = new FlatCompat({
9 | baseDirectory: __dirname,
10 | });
11 |
12 | const eslintConfig = [
13 | ...compat.extends("next/core-web-vitals", "next/typescript"),
14 | ];
15 |
16 | export default eslintConfig;
17 |
--------------------------------------------------------------------------------
/frontend-interface/components.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://ui.shadcn.com/schema.json",
3 | "style": "new-york",
4 | "rsc": true,
5 | "tsx": true,
6 | "tailwind": {
7 | "config": "tailwind.config.ts",
8 | "css": "app/globals.css",
9 | "baseColor": "neutral",
10 | "cssVariables": true,
11 | "prefix": ""
12 | },
13 | "aliases": {
14 | "components": "@/components",
15 | "utils": "@/lib/utils",
16 | "ui": "@/components/ui",
17 | "lib": "@/lib",
18 | "hooks": "@/hooks"
19 | },
20 | "iconLibrary": "lucide"
21 | }
--------------------------------------------------------------------------------
/backend/base.py:
--------------------------------------------------------------------------------
1 | from typing import Dict, List, Optional
2 | from langchain_core.messages import AIMessage, HumanMessage
3 | from langchain_core.output_parsers import StrOutputParser
4 | from langchain_groq import ChatGroq
5 | from langgraph.prebuilt import ToolExecutor
6 | from langchain_core.tools import Tool
7 | import os
8 | from dotenv import load_dotenv
9 | load_dotenv()
10 |
11 | class BaseTool:
12 | def __init__(self):
13 | self.model = ChatGroq(
14 | api_key=os.getenv("GROQ_API_KEY"),
15 | model="llama-3.3-70b-versatile",
16 | temperature=0.5,
17 | )
18 | self.output_parser = StrOutputParser()
--------------------------------------------------------------------------------
/frontend-interface/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 | .gitignore
3 |
4 | # dependencies
5 | /node_modules
6 | /.pnp
7 | .pnp.*
8 | .yarn/*
9 | !.yarn/patches
10 | !.yarn/plugins
11 | !.yarn/releases
12 | !.yarn/versions
13 |
14 | # testing
15 | /coverage
16 |
17 | # next.js
18 | /.next/
19 | /out/
20 |
21 | # production
22 | /build
23 |
24 | # misc
25 | .DS_Store
26 | *.pem
27 |
28 | # debug
29 | npm-debug.log*
30 | yarn-debug.log*
31 | yarn-error.log*
32 | .pnpm-debug.log*
33 |
34 | # env files (can opt-in for committing if needed)
35 | .env*
36 |
37 | # vercel
38 | .vercel
39 |
40 | # typescript
41 | *.tsbuildinfo
42 | next-env.d.ts
43 |
--------------------------------------------------------------------------------
/frontend-interface/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ES2017",
4 | "lib": ["dom", "dom.iterable", "esnext"],
5 | "allowJs": true,
6 | "skipLibCheck": true,
7 | "strict": true,
8 | "noEmit": true,
9 | "esModuleInterop": true,
10 | "module": "esnext",
11 | "moduleResolution": "bundler",
12 | "resolveJsonModule": true,
13 | "isolatedModules": true,
14 | "jsx": "preserve",
15 | "incremental": true,
16 | "plugins": [
17 | {
18 | "name": "next"
19 | }
20 | ],
21 | "paths": {
22 | "@/*": ["./*"]
23 | }
24 | },
25 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
26 | "exclude": ["node_modules"]
27 | }
28 |
--------------------------------------------------------------------------------
/frontend-interface/components/ui/textarea.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 |
3 | import { cn } from "@/lib/utils"
4 |
5 | const Textarea = React.forwardRef<
6 | HTMLTextAreaElement,
7 | React.ComponentProps<"textarea">
8 | >(({ className, ...props }, ref) => {
9 | return (
10 |
18 | )
19 | })
20 | Textarea.displayName = "Textarea"
21 |
22 | export { Textarea }
23 |
--------------------------------------------------------------------------------
/backend/tools/test_case_generator.py:
--------------------------------------------------------------------------------
1 | from base import BaseTool
2 | from typing import Dict, List
3 | from langchain_core.messages import AIMessage, HumanMessage
4 |
5 | class TestCaseGenerator(BaseTool):
6 | def generate_test_cases(self, code: str, existing_tests: List[str]) -> List[str]: # type: ignore
7 | prompt = f"""Given the following code and existing test cases, generate additional comprehensive test cases:
8 | Code: {code}
9 | Existing Tests: {existing_tests}
10 |
11 | Generate diverse test cases including edge cases, normal cases, and corner cases.
12 | """
13 |
14 | response = self.model.invoke([HumanMessage(content=prompt)]) # type: ignore
15 | return self.output_parser.invoke(response.content).split("\n")
16 |
--------------------------------------------------------------------------------
/backend/tools/complexity_analyser.py:
--------------------------------------------------------------------------------
1 | from base import BaseTool
2 | from typing import Dict, List
3 | from langchain_core.messages import AIMessage, HumanMessage
4 |
5 | class ComplexityAnalyzer(BaseTool):
6 | def analyze_complexity(self, code: str) -> List: # type: ignore
7 | prompt = f"""Analyze the following code very very carefully and determine its time and space complexity:
8 | {code}
9 |
10 | Provide only the values in the format:
11 |
12 |
13 | ["O(n)","O(1)"]
14 |
15 | 0 -> TIME COMPLEXITY
16 | 1 -> SPACE COMPLEXITY
17 |
18 | """
19 |
20 | response = self.model.invoke([HumanMessage(content=prompt)]) # type: ignore
21 | result = self.output_parser.invoke(response.content)
22 | return result
--------------------------------------------------------------------------------
/frontend-interface/app/layout.tsx:
--------------------------------------------------------------------------------
1 | import "./globals.css";
2 | import { Comfortaa } from "next/font/google";
3 | import { CopilotKit } from "@copilotkit/react-core";
4 |
5 | const comfortaa = Comfortaa({
6 | subsets: ["latin"],
7 | display: "swap",
8 | });
9 |
10 | export const metadata = {
11 | title: "Learn Coding with CopilotKit",
12 | description:
13 | "Solve Data Structures and Algorithms questions with AI assistance",
14 | };
15 |
16 | export default function RootLayout({
17 | children,
18 | }: {
19 | children: React.ReactNode;
20 | }) {
21 | return (
22 |
23 |
24 |
25 | {children}
26 |
27 |
28 |
29 | );
30 | }
31 |
--------------------------------------------------------------------------------
/agent/dsa_agent/demo.py:
--------------------------------------------------------------------------------
1 | """Demo"""
2 |
3 | import os
4 | from dotenv import load_dotenv
5 | load_dotenv() # pylint: disable=wrong-import-position
6 |
7 | from fastapi import FastAPI
8 | import uvicorn
9 | from copilotkit.integrations.fastapi import add_fastapi_endpoint
10 | from copilotkit import CopilotKitSDK, LangGraphAgent
11 | from dsa_agent.agent import graph
12 |
13 |
14 | app = FastAPI()
15 | sdk = CopilotKitSDK(
16 | agents=[
17 | LangGraphAgent(
18 | name="dsa_agent",
19 | description="A Competitive Programming Agent",
20 | graph=graph,
21 | )
22 | ],
23 | )
24 |
25 | add_fastapi_endpoint(app, sdk, "/copilotkit")
26 |
27 | def main():
28 | """Run the uvicorn server."""
29 | port = int(os.getenv("PORT", "8000"))
30 | uvicorn.run("dsa_agent.demo:app", host="0.0.0.0", port=port)
--------------------------------------------------------------------------------
/backend/tools/explanation_generator.py:
--------------------------------------------------------------------------------
1 | from base import BaseTool
2 | from typing import Dict, List
3 | from langchain_core.messages import AIMessage, HumanMessage
4 |
5 | class ExplanationGenerator(BaseTool):
6 | def generate_explanation(self, question: str,testCases: str, code: str) -> Dict: # type: ignore
7 | prompt = f"""Given the coding problem below, provide a well explanation of code and approach in python with explanation.
8 | Problem: {question}
9 | Test Cases: {testCases}
10 | Code: {code}
11 |
12 | Return the response in the following format:
13 | [detailed code explanation and approach to solve the problem]
14 | """
15 |
16 | response = self.model.invoke([HumanMessage(content=prompt)]) # type: ignore
17 | return self.output_parser.invoke(response.content)
18 |
--------------------------------------------------------------------------------
/backend/tools/code_generator.py:
--------------------------------------------------------------------------------
1 | from base import BaseTool
2 | from typing import Dict, List
3 | from langchain_core.messages import AIMessage, HumanMessage
4 |
5 | class CodeGenerator(BaseTool):
6 | def generate_code(self, question: str,testCases: str) -> Dict: # type: ignore
7 | prompt = f"""Given the coding problem below, provide only a well structured and full working code in python.
8 | Problem: {question}
9 | Test Cases: {testCases}
10 |
11 | Return only the structured and full working code as the response and nothing else no "python" keyword or any other thing:
12 |
13 |
14 | def function_name(): ..... pass
15 |
16 |
17 | """
18 |
19 | response = self.model.invoke([HumanMessage(content=prompt)]) # type: ignore
20 | return self.output_parser.invoke(response.content)
21 |
--------------------------------------------------------------------------------
/frontend-interface/app/api/copilotkit/route.ts:
--------------------------------------------------------------------------------
1 | import { NextRequest } from "next/server";
2 | import {
3 | CopilotRuntime,
4 | GroqAdapter,
5 | copilotRuntimeNextJSAppRouterEndpoint,
6 | } from "@copilotkit/runtime";
7 |
8 |
9 | const serviceAdapter = new GroqAdapter({ model: "llama-3.3-70b-versatile" });
10 |
11 | const runtime = new CopilotRuntime(
12 | {
13 | remoteEndpoints: [
14 | {
15 | url: process.env.REMOTE_ACTION_URL || "https://learn-coding-with-copilotkit-1.onrender.com/copilotkit" || "http://localhost:8000/copilotkit",
16 | },
17 | ],
18 | }
19 |
20 | );
21 |
22 | export const POST = async (req: NextRequest) => {
23 | const { handleRequest } = copilotRuntimeNextJSAppRouterEndpoint({
24 | runtime,
25 | serviceAdapter,
26 | endpoint: "/api/copilotkit",
27 |
28 | });
29 | return handleRequest(req);
30 | };
31 |
32 |
--------------------------------------------------------------------------------
/agent/dsa_agent/nodes/visualiser.py:
--------------------------------------------------------------------------------
1 | from langchain_core.prompts import ChatPromptTemplate
2 | from langchain_groq import ChatGroq
3 | from pydantic import BaseModel, Field
4 | from dotenv import load_dotenv
5 |
6 | load_dotenv()
7 |
8 |
9 | llm = ChatGroq(model="llama-3.3-70b-versatile", temperature=0)
10 |
11 | system = """You provide visualisation of a complex problem by generating corresponding mermaid flowchart code\n
12 | Given the question\n
13 | You have to provide the appropriate mermaid flowchart code to visualise the solution\n
14 | Make sure that your output contains only mermaid flowchart code in the format ```mermaid\n{code}\n```\n"""
15 |
16 | visualisation_prompt = ChatPromptTemplate.from_messages(
17 | [
18 | ("system", system),
19 | ("human", "question: \n\n {question}"),
20 | ]
21 | )
22 |
23 | visualization_generated = visualisation_prompt
--------------------------------------------------------------------------------
/frontend-interface/components/ui/input.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 |
3 | import { cn } from "@/lib/utils"
4 |
5 | const Input = React.forwardRef>(
6 | ({ className, type, ...props }, ref) => {
7 | return (
8 |
17 | )
18 | }
19 | )
20 | Input.displayName = "Input"
21 |
22 | export { Input }
23 |
--------------------------------------------------------------------------------
/agent/dsa_agent/nodes/coding.py:
--------------------------------------------------------------------------------
1 | from langchain_groq import ChatGroq
2 | from langchain_core.output_parsers import StrOutputParser
3 | from langchain_core.prompts import ChatPromptTemplate
4 | from dotenv import load_dotenv
5 |
6 | load_dotenv()
7 |
8 | llm = ChatGroq(model="llama-3.3-70b-versatile", temperature=0)
9 |
10 | system = """You a 4000 rated Competitive Programmer that writes optimised and fully detailed working code in python \n
11 | Given a question you are expected to write a working code in python that is generic and well optimised \n"""
12 |
13 | re_write_prompt = ChatPromptTemplate.from_messages(
14 | [
15 | ("system", system),
16 | (
17 | "human",
18 | "Here is the question: \n\n {question} \n. Formulate an optimised answer in python.",
19 | ),
20 | ]
21 | )
22 |
23 | code_writer = re_write_prompt | llm | StrOutputParser()
--------------------------------------------------------------------------------
/agent/dsa_agent/nodes/explainer.py:
--------------------------------------------------------------------------------
1 | from langchain_core.prompts import ChatPromptTemplate
2 | from langchain_groq import ChatGroq
3 | from pydantic import BaseModel, Field
4 | from dotenv import load_dotenv
5 |
6 | load_dotenv()
7 |
8 |
9 | llm = ChatGroq(model="llama-3.3-70b-versatile", temperature=0)
10 |
11 | system = """You a 4000 rated Competitive Programmer that writes explaination for a fully working code in python \n
12 | Given a question and the generated code for it \n
13 | You have to provide the appropriate explanation of the code in markdown to explain the code approach generated \n
14 | Make sure that your output contains only markdown code"""
15 |
16 | explain_prompt = ChatPromptTemplate.from_messages(
17 | [
18 | ("system", system),
19 | ("human", " User question: {question} \n\n code generated: \n\n {code}"),
20 | ]
21 | )
22 |
23 | explanation_generated = explain_prompt
--------------------------------------------------------------------------------
/agent/dsa_agent/nodes/complexity_finder.py:
--------------------------------------------------------------------------------
1 | from langchain_core.prompts import ChatPromptTemplate
2 | from langchain_groq import ChatGroq
3 | from pydantic import BaseModel, Field
4 | from dotenv import load_dotenv
5 |
6 | load_dotenv()
7 |
8 |
9 | llm = ChatGroq(model="llama-3.3-70b-versatile", temperature=0)
10 |
11 | system = """You a 4000 rated Competitive Programmer that figures out Time and Space Complexity of a fully working code in python \n
12 | Given a code in python language \n
13 | You have to provide the appropriate List of 2 elements having first as Time Complexity and Second as Space Complexity of the code provided \n
14 | Make sure that your output contains only a python list of 2 elements"""
15 |
16 | complexity_find = ChatPromptTemplate.from_messages(
17 | [
18 | ("system", system),
19 | ("human", "code: \n\n {code}"),
20 | ]
21 | )
22 |
23 | complexity_generated = complexity_find
--------------------------------------------------------------------------------
/agent/pyproject.toml:
--------------------------------------------------------------------------------
1 | [tool.poetry]
2 | name = "dsa_agent"
3 | version = "0.1.0"
4 | description = "Starter"
5 | authors = ["Arya Pratap Singh "]
6 | license = "MIT"
7 |
8 | [project]
9 | name = "dsa_agent"
10 | version = "0.0.1"
11 |
12 | [build-system]
13 | requires = ["setuptools >= 61.0"]
14 | build-backend = "setuptools.build_meta"
15 |
16 | [tool.poetry.dependencies]
17 | python = "^3.11.11"
18 | langchain-anthropic = "^0.2.1"
19 | langchain = "^0.3.1"
20 | openai = "^1.51.0"
21 | langchain-community = "^0.3.1"
22 | copilotkit = "0.1.30"
23 | uvicorn = "^0.31.0"
24 | python-dotenv = "^1.0.1"
25 | langchain-core = "^0.3.25"
26 | langgraph-cli = {extras = ["inmem"], version = "^0.1.64"}
27 | langchain-groq = "^0.2.2"
28 | chroma = "^0.2.0"
29 | fastembed = "^0.5.0"
30 | bs4 = "^0.0.2"
31 | faiss-cpu = "^1.9.0.post1"
32 | ipykernel = "^6.29.5"
33 |
34 | [tool.poetry.scripts]
35 | demo = "dsa_agent.demo:main"
--------------------------------------------------------------------------------
/frontend-interface/components/StarComponent.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Button } from "@/components/ui/button";
3 | import { Github } from "lucide-react";
4 |
5 | const GitHubStarButtons = () => {
6 | return (
7 |
8 | window.open('https://github.com/CopilotKit/CopilotKit', '_blank')}
11 | >
12 |
13 | Star CopilotKit
14 |
15 | window.open('https://github.com/ARYPROGRAMMER/Learn-Coding-with-Copilotkit', '_blank')}
18 | >
19 |
20 | Star Us
21 |
22 |
23 | );
24 | };
25 |
26 | export default GitHubStarButtons;
--------------------------------------------------------------------------------
/agent/dsa_agent/state.py:
--------------------------------------------------------------------------------
1 | from typing import List, Annotated, Sequence, Dict, Optional
2 | from typing_extensions import TypedDict
3 | from langchain_core.messages import BaseMessage
4 | from langgraph.graph.message import add_messages
5 |
6 | class AgentState(TypedDict):
7 | """
8 | Represents the state of our graph.
9 |
10 | Attributes:
11 | question: str
12 | # testCases: List[str]
13 | code: Optional[str]
14 | explanation: Optional[str]
15 | time_complexity: Optional[str]
16 | space_complexity: Optional[str]
17 | visualization: Optional[str]
18 | # messages: list of messages
19 | """
20 |
21 | question: str
22 |
23 | code: Optional[str]
24 | explanation: Optional[str]
25 | time_complexity: Optional[str]
26 | space_complexity: Optional[str]
27 | visualization: Optional[str]
28 | # testCases: Optional[List[str]] # type: ignore
29 | # messages: Annotated[Sequence[BaseMessage], add_messages]
--------------------------------------------------------------------------------
/frontend-interface/public/globe.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/backend/tools/visualisation_generator.py:
--------------------------------------------------------------------------------
1 | from base import BaseTool
2 | from langchain_core.messages import AIMessage, HumanMessage
3 |
4 | class VisualizationGenerator(BaseTool):
5 | def generate_mermaid_visualization(self, code: str) -> str:
6 | prompt = f"""For the following code, create a well labelled Mermaid CODE FOR THE diagram that visualizes the algorithm's flow:
7 | {code}
8 |
9 | Create a flowchart using Mermaid syntax. Focus on key steps and decision points.
10 | The diagram should start with 'flowchart TD' and use proper Mermaid syntax.
11 | Include clear labels and connections between nodes. Ensure the diagram is easy to understand and follow.
12 |
13 | DO NOT INCLUDE ANYTHING ELSE JUST THE MERMAID CODE FOR THE FLOWCHART AND MAKE IT WELL STRUCTURED AND LABELLED AND ONLY AND ONLY RETURN THE MERMAID CODE.
14 | """
15 |
16 | response = self.model.invoke([HumanMessage(content=prompt)]) # type: ignore
17 | return self.output_parser.invoke(response.content)
18 |
--------------------------------------------------------------------------------
/agent/dsa_agent/edges/code_verify.py:
--------------------------------------------------------------------------------
1 | from pydantic import BaseModel, Field
2 | from langchain_groq import ChatGroq
3 | from langchain_core.prompts import ChatPromptTemplate
4 | from dotenv import load_dotenv
5 |
6 | load_dotenv()
7 |
8 | class VerifyCode(BaseModel):
9 | """Binary ouput to assess code solves the question."""
10 |
11 | binary_score: str = Field(
12 | description="Code solves the question, 'yes' or 'no'"
13 | )
14 |
15 | llm = ChatGroq(model="llama-3.3-70b-versatile", temperature=0)
16 | code_verification = llm.with_structured_output(VerifyCode)
17 |
18 | system = """You a 4000 rated Competitive Programmer that writes optimised and fully detailed working code in python \n
19 | Given a question you are expected to write a working code in python that is generic and well optimised \n"""
20 |
21 |
22 | code_prompt = ChatPromptTemplate.from_messages(
23 | [
24 | ("system", system),
25 | ("human", "User question: \n\n {question} \n\n Code Generated: \n\n {code} \n\n"),
26 | ]
27 | )
28 |
29 | code_verify = code_prompt | code_verification
--------------------------------------------------------------------------------
/frontend-interface/components/ui/slider.tsx:
--------------------------------------------------------------------------------
1 | "use client"
2 |
3 | import * as React from "react"
4 | import * as SliderPrimitive from "@radix-ui/react-slider"
5 |
6 | import { cn } from "@/lib/utils"
7 |
8 | const Slider = React.forwardRef<
9 | React.ElementRef,
10 | React.ComponentPropsWithoutRef
11 | >(({ className, ...props }, ref) => (
12 |
20 |
21 |
22 |
23 |
24 |
25 | ))
26 | Slider.displayName = SliderPrimitive.Root.displayName
27 |
28 | export { Slider }
29 |
--------------------------------------------------------------------------------
/agent/dsa_agent/edges/visualisation_verify.py:
--------------------------------------------------------------------------------
1 | from pydantic import BaseModel, Field
2 | from langchain_groq import ChatGroq
3 | from langchain_core.prompts import ChatPromptTemplate
4 | from dotenv import load_dotenv
5 |
6 | load_dotenv()
7 |
8 | class VerifyVisualisation(BaseModel):
9 | """Binary output to verify the mermaid code generated to visualise the python code."""
10 |
11 | binary_score: str = Field(
12 | description="Mermaid Code generated is correct, 'yes' or 'no'"
13 | )
14 |
15 | llm = ChatGroq(model="llama-3.3-70b-versatile", temperature=0)
16 | viusalisation_verification = llm.with_structured_output(VerifyVisualisation)
17 |
18 | system = """You provide visualisation of a complex problem by generating corresponding mermaid code\n
19 | Given the question\n
20 | You have to provide the appropriate mermaid code to visualise the solution\n
21 | Make sure that your output contains only mermaid flowchart code in the format ```mermaid\nFLOWCHART...```\n"""
22 |
23 | visualisation_prompt = ChatPromptTemplate.from_messages(
24 | [
25 | ("system", system),
26 | ("human", "question: \n\n {question}"),
27 | ]
28 | )
29 |
30 | visualisation_verify = visualisation_prompt | viusalisation_verification
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | This is free and unencumbered software released into the public domain.
2 |
3 | Anyone is free to copy, modify, publish, use, compile, sell, or
4 | distribute this software, either in source code form or as a compiled
5 | binary, for any purpose, commercial or non-commercial, and by any
6 | means.
7 |
8 | In jurisdictions that recognize copyright laws, the author or authors
9 | of this software dedicate any and all copyright interest in the
10 | software to the public domain. We make this dedication for the benefit
11 | of the public at large and to the detriment of our heirs and
12 | successors. We intend this dedication to be an overt act of
13 | relinquishment in perpetuity of all present and future rights to this
14 | software under copyright law.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 | OTHER DEALINGS IN THE SOFTWARE.
23 |
24 | For more information, please refer to
--------------------------------------------------------------------------------
/agent/dsa_agent/edges/explanation_verify.py:
--------------------------------------------------------------------------------
1 | from pydantic import BaseModel, Field
2 | from langchain_groq import ChatGroq
3 | from langchain_core.prompts import ChatPromptTemplate
4 | from dotenv import load_dotenv
5 |
6 | load_dotenv()
7 |
8 | class VerifyExplanation(BaseModel):
9 | """Binary output to verify the explanation of the python code provided."""
10 |
11 | binary_score: str = Field(
12 | description="Python Code provided is correctly explained for the question asked 'yes' or 'no'"
13 | )
14 |
15 | llm = ChatGroq(model="llama-3.3-70b-versatile", temperature=0)
16 | explanation_verification = llm.with_structured_output(VerifyExplanation)
17 |
18 | system = """You a 4000 rated Competitive Programmer that explains an optimised and fully detailed working code in python \n
19 | Given a question and the generated code for it \n
20 | You have to provide the explanation in markdown of the code to solve the question and of the approach generated \n
21 | Make sure that your output contains only markdown code"""
22 |
23 | explaination_prompt = ChatPromptTemplate.from_messages(
24 | [
25 | ("system", system),
26 | ("human", "Python Code Generated: \n\n {code} \n\n Initially Question Asked: {question}"),
27 | ]
28 | )
29 |
30 | explaination_verify = explaination_prompt | explanation_verification
--------------------------------------------------------------------------------
/frontend-interface/public/next.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/frontend-interface/components/ProblemInput.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Textarea } from "@/components/ui/textarea";
3 |
4 | const ProblemInput = ({ question, setQuestion }: { question: string, setQuestion: React.Dispatch> }) => {
5 | const formatQuestion = (input: string): string => {
6 | return input
7 | .replace(/\s+/g, " ")
8 | .replace(/\n+/g, " ")
9 | .trim()
10 | .replace(/\s*([.,?!])\s*/g, "$1 ")
11 | .replace(/\s+([.,?!])/g, "$1")
12 | .replace(/\s+/g, " ");
13 | };
14 |
15 | return (
16 |
17 |
18 | Describe Your Problem
19 |
20 |
31 | );
32 | };
33 |
34 | export default ProblemInput;
35 |
36 |
--------------------------------------------------------------------------------
/frontend-interface/components/StepNavigation.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Button } from "@/components/ui/button";
3 | import { Brain, PlayCircle, Lightbulb } from 'lucide-react';
4 |
5 | const steps = [
6 | { title: "Problem", icon: Brain },
7 | { title: "Test Cases", icon: PlayCircle },
8 | { title: "Expected Complexity", icon: Lightbulb },
9 | ];
10 |
11 | interface StepNavigationProps {
12 | activeStep: number;
13 | setActiveStep: (step: number) => void;
14 | }
15 |
16 | const StepNavigation = ({ activeStep, setActiveStep }: StepNavigationProps) => {
17 | return (
18 |
19 | {steps.map((step, index) => (
20 | setActiveStep(index)}
25 | className={`flex items-center gap-2 flex-1 ${
26 | activeStep === index
27 | ? "bg-blue-500 text-white"
28 | : "text-gray-600 dark:text-gray-300"
29 | } transition-all duration-300 ease-in-out transform hover:scale-105`}
30 | >
31 |
32 | {step.title}
33 |
34 | ))}
35 |
36 | );
37 | };
38 |
39 | export default StepNavigation;
40 |
41 |
--------------------------------------------------------------------------------
/agent/dsa_agent/edges/complexity_verify.py:
--------------------------------------------------------------------------------
1 | from pydantic import BaseModel, Field
2 | from langchain_groq import ChatGroq
3 | from langchain_core.prompts import ChatPromptTemplate
4 | from dotenv import load_dotenv
5 |
6 | load_dotenv()
7 |
8 | class VerifyComplexity(BaseModel):
9 | """Binary output to verify the time and space complexity generated of the python code provided."""
10 |
11 | binary_score: str = Field(
12 | description="Python Code provided has the same time and space complexity as generated, 'yes' or 'no'"
13 | )
14 |
15 | llm = ChatGroq(model="llama-3.3-70b-versatile", temperature=0)
16 | complexity_verification = llm.with_structured_output(VerifyComplexity)
17 |
18 | system = """You a 4000 rated Competitive Programmer that analyzes optimised and fully detailed working code in python \n
19 | Given a code in python \n
20 | You have to provide the appropriate List of 2 string elements first being time complexity of code and second being space complexity of the code \n
21 | Make sure that your output contains list of 2 string only"""
22 |
23 | complexity_prompt = ChatPromptTemplate.from_messages(
24 | [
25 | ("system", system),
26 | ("human", "Python Code: \n\n {code} \n\n Time Complexity of Code Generated: {time_complexity} \n Space Complexity of Code Generated: {space_complexity}"),
27 | ]
28 | )
29 |
30 | complexity_verify = complexity_prompt | complexity_verification
--------------------------------------------------------------------------------
/frontend-interface/components/ui/avatar.tsx:
--------------------------------------------------------------------------------
1 | "use client"
2 |
3 | import * as React from "react"
4 | import * as AvatarPrimitive from "@radix-ui/react-avatar"
5 |
6 | import { cn } from "@/lib/utils"
7 |
8 | const Avatar = React.forwardRef<
9 | React.ElementRef,
10 | React.ComponentPropsWithoutRef
11 | >(({ className, ...props }, ref) => (
12 |
20 | ))
21 | Avatar.displayName = AvatarPrimitive.Root.displayName
22 |
23 | const AvatarImage = React.forwardRef<
24 | React.ElementRef,
25 | React.ComponentPropsWithoutRef
26 | >(({ className, ...props }, ref) => (
27 |
32 | ))
33 | AvatarImage.displayName = AvatarPrimitive.Image.displayName
34 |
35 | const AvatarFallback = React.forwardRef<
36 | React.ElementRef,
37 | React.ComponentPropsWithoutRef
38 | >(({ className, ...props }, ref) => (
39 |
47 | ))
48 | AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName
49 |
50 | export { Avatar, AvatarImage, AvatarFallback }
51 |
--------------------------------------------------------------------------------
/frontend-interface/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "frontend-interface",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "dev": "next dev --port 3000",
7 | "build": "next build",
8 | "start": "next start",
9 | "lint": "next lint"
10 | },
11 | "dependencies": {
12 | "@copilotkit/react-core": "1.4.7",
13 | "@copilotkit/react-ui": "1.4.7",
14 | "@copilotkit/runtime": "1.4.7",
15 | "@copilotkit/runtime-client-gql": "1.4.7",
16 | "@monaco-editor/react": "^4.6.0",
17 | "@radix-ui/react-accordion": "^1.2.0",
18 | "@radix-ui/react-avatar": "^1.1.2",
19 | "@radix-ui/react-dialog": "^1.1.4",
20 | "@radix-ui/react-icons": "^1.3.2",
21 | "@radix-ui/react-select": "^2.1.4",
22 | "@radix-ui/react-separator": "^1.1.1",
23 | "@radix-ui/react-slider": "^1.2.2",
24 | "@radix-ui/react-slot": "^1.1.0",
25 | "@radix-ui/react-tabs": "^1.1.2",
26 | "class-variance-authority": "^0.7.0",
27 | "clsx": "^2.1.1",
28 | "framer-motion": "^11.3.31",
29 | "lucide-react": "^0.436.0",
30 | "mermaid": "^11.4.1",
31 | "next": "15.1.0",
32 | "react": "19.0.0",
33 | "react-dom": "19.0.0",
34 | "react-markdown": "^9.0.1",
35 | "tailwind-merge": "^2.5.2",
36 | "tailwindcss-animate": "^1.0.7"
37 | },
38 | "devDependencies": {
39 | "@types/node": "^22.0.0",
40 | "@types/react": "19.0.1",
41 | "@types/react-dom": "19.0.2",
42 | "eslint": "^9.0.0",
43 | "eslint-config-next": "15.1.0",
44 | "postcss": "^8",
45 | "tailwindcss": "^3.4.1",
46 | "typescript": "^5"
47 | },
48 | "pnpm": {
49 | "overrides": {
50 | "@types/react": "19.0.1",
51 | "@types/react-dom": "19.0.2"
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/frontend-interface/components/ui/alert.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import { cva, type VariantProps } from "class-variance-authority"
3 |
4 | import { cn } from "@/lib/utils"
5 |
6 | const alertVariants = cva(
7 | "relative w-full rounded-lg border px-4 py-3 text-sm [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground [&>svg~*]:pl-7",
8 | {
9 | variants: {
10 | variant: {
11 | default: "bg-background text-foreground",
12 | destructive:
13 | "border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive",
14 | },
15 | },
16 | defaultVariants: {
17 | variant: "default",
18 | },
19 | }
20 | )
21 |
22 | const Alert = React.forwardRef<
23 | HTMLDivElement,
24 | React.HTMLAttributes & VariantProps
25 | >(({ className, variant, ...props }, ref) => (
26 |
32 | ))
33 | Alert.displayName = "Alert"
34 |
35 | const AlertTitle = React.forwardRef<
36 | HTMLParagraphElement,
37 | React.HTMLAttributes
38 | >(({ className, ...props }, ref) => (
39 |
44 | ))
45 | AlertTitle.displayName = "AlertTitle"
46 |
47 | const AlertDescription = React.forwardRef<
48 | HTMLParagraphElement,
49 | React.HTMLAttributes
50 | >(({ className, ...props }, ref) => (
51 |
56 | ))
57 | AlertDescription.displayName = "AlertDescription"
58 |
59 | export { Alert, AlertTitle, AlertDescription }
60 |
--------------------------------------------------------------------------------
/frontend-interface/components/ComplexityInput.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Input } from "@/components/ui/input";
3 |
4 | const ComplexityInput = ({
5 | timeComplexity,
6 | setTimeComplexity,
7 | spaceComplexity,
8 | setSpaceComplexity,
9 | }: {
10 | timeComplexity: string;
11 | setTimeComplexity: (value: string) => void;
12 | spaceComplexity: string;
13 | setSpaceComplexity: (value: string) => void;
14 | }) => {
15 | return (
16 |
17 |
18 | Expected Complexity
19 |
20 |
44 |
45 | );
46 | };
47 |
48 | export default ComplexityInput;
49 |
50 |
--------------------------------------------------------------------------------
/frontend-interface/tailwind.config.ts:
--------------------------------------------------------------------------------
1 | import type { Config } from "tailwindcss";
2 |
3 | export default {
4 | darkMode: ["class"],
5 | content: [
6 | "./pages/**/*.{js,ts,jsx,tsx,mdx}",
7 | "./components/**/*.{js,ts,jsx,tsx,mdx}",
8 | "./app/**/*.{js,ts,jsx,tsx,mdx}",
9 | ],
10 | theme: {
11 | extend: {
12 | colors: {
13 | background: 'hsl(var(--background))',
14 | foreground: 'hsl(var(--foreground))',
15 | card: {
16 | DEFAULT: 'hsl(var(--card))',
17 | foreground: 'hsl(var(--card-foreground))'
18 | },
19 | popover: {
20 | DEFAULT: 'hsl(var(--popover))',
21 | foreground: 'hsl(var(--popover-foreground))'
22 | },
23 | primary: {
24 | DEFAULT: 'hsl(var(--primary))',
25 | foreground: 'hsl(var(--primary-foreground))'
26 | },
27 | secondary: {
28 | DEFAULT: 'hsl(var(--secondary))',
29 | foreground: 'hsl(var(--secondary-foreground))'
30 | },
31 | muted: {
32 | DEFAULT: 'hsl(var(--muted))',
33 | foreground: 'hsl(var(--muted-foreground))'
34 | },
35 | accent: {
36 | DEFAULT: 'hsl(var(--accent))',
37 | foreground: 'hsl(var(--accent-foreground))'
38 | },
39 | destructive: {
40 | DEFAULT: 'hsl(var(--destructive))',
41 | foreground: 'hsl(var(--destructive-foreground))'
42 | },
43 | border: 'hsl(var(--border))',
44 | input: 'hsl(var(--input))',
45 | ring: 'hsl(var(--ring))',
46 | chart: {
47 | '1': 'hsl(var(--chart-1))',
48 | '2': 'hsl(var(--chart-2))',
49 | '3': 'hsl(var(--chart-3))',
50 | '4': 'hsl(var(--chart-4))',
51 | '5': 'hsl(var(--chart-5))'
52 | }
53 | },
54 | borderRadius: {
55 | lg: 'var(--radius)',
56 | md: 'calc(var(--radius) - 2px)',
57 | sm: 'calc(var(--radius) - 4px)'
58 | }
59 | }
60 | },
61 | plugins: [require("tailwindcss-animate")],
62 | } satisfies Config;
63 |
--------------------------------------------------------------------------------
/frontend-interface/components/ui/tabs.tsx:
--------------------------------------------------------------------------------
1 | "use client"
2 |
3 | import * as React from "react"
4 | import * as TabsPrimitive from "@radix-ui/react-tabs"
5 |
6 | import { cn } from "@/lib/utils"
7 |
8 | const Tabs = TabsPrimitive.Root
9 |
10 | const TabsList = React.forwardRef<
11 | React.ElementRef,
12 | React.ComponentPropsWithoutRef
13 | >(({ className, ...props }, ref) => (
14 |
22 | ))
23 | TabsList.displayName = TabsPrimitive.List.displayName
24 |
25 | const TabsTrigger = React.forwardRef<
26 | React.ElementRef,
27 | React.ComponentPropsWithoutRef
28 | >(({ className, ...props }, ref) => (
29 |
37 | ))
38 | TabsTrigger.displayName = TabsPrimitive.Trigger.displayName
39 |
40 | const TabsContent = React.forwardRef<
41 | React.ElementRef,
42 | React.ComponentPropsWithoutRef
43 | >(({ className, ...props }, ref) => (
44 |
52 | ))
53 | TabsContent.displayName = TabsPrimitive.Content.displayName
54 |
55 | export { Tabs, TabsList, TabsTrigger, TabsContent }
56 |
--------------------------------------------------------------------------------
/frontend-interface/components/ui/button.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import { Slot } from "@radix-ui/react-slot"
3 | import { cva, type VariantProps } from "class-variance-authority"
4 |
5 | import { cn } from "@/lib/utils"
6 |
7 | const buttonVariants = cva(
8 | "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
9 | {
10 | variants: {
11 | variant: {
12 | default:
13 | "bg-primary text-primary-foreground shadow hover:bg-primary/90",
14 | destructive:
15 | "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
16 | outline:
17 | "border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
18 | secondary:
19 | "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
20 | ghost: "hover:bg-accent hover:text-accent-foreground",
21 | link: "text-primary underline-offset-4 hover:underline",
22 | },
23 | size: {
24 | default: "h-9 px-4 py-2",
25 | sm: "h-8 rounded-md px-3 text-xs",
26 | lg: "h-10 rounded-md px-8",
27 | icon: "h-9 w-9",
28 | },
29 | },
30 | defaultVariants: {
31 | variant: "default",
32 | size: "default",
33 | },
34 | }
35 | )
36 |
37 | export interface ButtonProps
38 | extends React.ButtonHTMLAttributes,
39 | VariantProps {
40 | asChild?: boolean
41 | }
42 |
43 | const Button = React.forwardRef(
44 | ({ className, variant, size, asChild = false, ...props }, ref) => {
45 | const Comp = asChild ? Slot : "button"
46 | return (
47 |
52 | )
53 | }
54 | )
55 | Button.displayName = "Button"
56 |
57 | export { Button, buttonVariants }
58 |
--------------------------------------------------------------------------------
/frontend-interface/components/ui/card.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 |
3 | import { cn } from "@/lib/utils"
4 |
5 | const Card = React.forwardRef<
6 | HTMLDivElement,
7 | React.HTMLAttributes
8 | >(({ className, ...props }, ref) => (
9 |
17 | ))
18 | Card.displayName = "Card"
19 |
20 | const CardHeader = React.forwardRef<
21 | HTMLDivElement,
22 | React.HTMLAttributes
23 | >(({ className, ...props }, ref) => (
24 |
29 | ))
30 | CardHeader.displayName = "CardHeader"
31 |
32 | const CardTitle = React.forwardRef<
33 | HTMLDivElement,
34 | React.HTMLAttributes
35 | >(({ className, ...props }, ref) => (
36 |
41 | ))
42 | CardTitle.displayName = "CardTitle"
43 |
44 | const CardDescription = React.forwardRef<
45 | HTMLDivElement,
46 | React.HTMLAttributes
47 | >(({ className, ...props }, ref) => (
48 |
53 | ))
54 | CardDescription.displayName = "CardDescription"
55 |
56 | const CardContent = React.forwardRef<
57 | HTMLDivElement,
58 | React.HTMLAttributes
59 | >(({ className, ...props }, ref) => (
60 |
61 | ))
62 | CardContent.displayName = "CardContent"
63 |
64 | const CardFooter = React.forwardRef<
65 | HTMLDivElement,
66 | React.HTMLAttributes
67 | >(({ className, ...props }, ref) => (
68 |
73 | ))
74 | CardFooter.displayName = "CardFooter"
75 |
76 | export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent }
77 |
--------------------------------------------------------------------------------
/backend/run_agent.py:
--------------------------------------------------------------------------------
1 | # demo.py
2 | from fastapi import FastAPI, HTTPException
3 | from pydantic import BaseModel
4 | from typing import List, Optional
5 | import uvicorn
6 | from graph import AgentState, create_graph
7 | import logging
8 | from fastapi.middleware.cors import CORSMiddleware
9 |
10 | logging.basicConfig(level=logging.INFO)
11 | logger = logging.getLogger(__name__)
12 |
13 | app = FastAPI()
14 | app.add_middleware(
15 | CORSMiddleware,
16 | allow_origins=["http://localhost:3000","https://learn-coding-with-copilotkit.vercel.app"],
17 | allow_credentials=True,
18 | allow_methods=["*"],
19 | allow_headers=["*"],
20 | )
21 | class CopilotRequest(BaseModel):
22 | question: str
23 | testCases: List[str]
24 |
25 | class CopilotResponse(BaseModel):
26 | code: Optional[str]
27 | explanation: Optional[str]
28 | time_complexity: Optional[str]
29 | space_complexity: Optional[str]
30 | visualization: Optional[str]
31 |
32 | @app.post("/copilotkit")
33 | async def process_request(request: CopilotRequest) -> CopilotResponse:
34 | logger.info(f"Received request with question: {request.question}")
35 |
36 | try:
37 | # Create initial state
38 | initial_state: AgentState = {
39 | "question": request.question,
40 | "testCases": request.testCases,
41 | "code": None,
42 | "explanation": None,
43 | "time_complexity": None,
44 | "space_complexity": None,
45 | "visualization": None
46 | }
47 |
48 | logger.info("Creating graph...")
49 | graph = create_graph()
50 |
51 | logger.info("Running graph...")
52 | final_state = graph.invoke(initial_state)
53 |
54 | logger.info("Processing completed successfully")
55 | return CopilotResponse(
56 | code=final_state["code"],
57 | explanation=final_state["explanation"],
58 | time_complexity=final_state["time_complexity"],
59 | space_complexity=final_state["space_complexity"],
60 | visualization=final_state["visualization"],
61 | )
62 | except Exception as e:
63 | logger.error(f"Error processing request: {str(e)}")
64 | raise HTTPException(status_code=500, detail=str(e))
65 |
66 | if __name__ == "__main__":
67 | logger.info("Starting Copilot API server...")
68 | uvicorn.run(app, host="0.0.0.0", port=8000)
69 |
--------------------------------------------------------------------------------
/frontend-interface/app/globals.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
5 | :root {
6 | --foreground-rgb: 0, 0, 0;
7 | --background-start-rgb: 214, 219, 220;
8 | --background-end-rgb: 255, 255, 255;
9 | }
10 |
11 | @media (prefers-color-scheme: dark) {
12 | :root {
13 | --foreground-rgb: 255, 255, 255;
14 | --background-start-rgb: 0, 0, 0;
15 | --background-end-rgb: 0, 0, 0;
16 | }
17 | }
18 |
19 | /* Ensure Comfortaa is used for all text */
20 | body, input, textarea, button {
21 | font-family: 'Comfortaa', sans-serif;
22 | }
23 | @layer base {
24 | :root {
25 | --background: 0 0% 100%;
26 | --foreground: 0 0% 3.9%;
27 | --card: 0 0% 100%;
28 | --card-foreground: 0 0% 3.9%;
29 | --popover: 0 0% 100%;
30 | --popover-foreground: 0 0% 3.9%;
31 | --primary: 0 0% 9%;
32 | --primary-foreground: 0 0% 98%;
33 | --secondary: 0 0% 96.1%;
34 | --secondary-foreground: 0 0% 9%;
35 | --muted: 0 0% 96.1%;
36 | --muted-foreground: 0 0% 45.1%;
37 | --accent: 0 0% 96.1%;
38 | --accent-foreground: 0 0% 9%;
39 | --destructive: 0 84.2% 60.2%;
40 | --destructive-foreground: 0 0% 98%;
41 | --border: 0 0% 89.8%;
42 | --input: 0 0% 89.8%;
43 | --ring: 0 0% 3.9%;
44 | --chart-1: 12 76% 61%;
45 | --chart-2: 173 58% 39%;
46 | --chart-3: 197 37% 24%;
47 | --chart-4: 43 74% 66%;
48 | --chart-5: 27 87% 67%;
49 | --radius: 0.5rem;
50 | }
51 | .dark {
52 | --background: 0 0% 3.9%;
53 | --foreground: 0 0% 98%;
54 | --card: 0 0% 3.9%;
55 | --card-foreground: 0 0% 98%;
56 | --popover: 0 0% 3.9%;
57 | --popover-foreground: 0 0% 98%;
58 | --primary: 0 0% 98%;
59 | --primary-foreground: 0 0% 9%;
60 | --secondary: 0 0% 14.9%;
61 | --secondary-foreground: 0 0% 98%;
62 | --muted: 0 0% 14.9%;
63 | --muted-foreground: 0 0% 63.9%;
64 | --accent: 0 0% 14.9%;
65 | --accent-foreground: 0 0% 98%;
66 | --destructive: 0 62.8% 30.6%;
67 | --destructive-foreground: 0 0% 98%;
68 | --border: 0 0% 14.9%;
69 | --input: 0 0% 14.9%;
70 | --ring: 0 0% 83.1%;
71 | --chart-1: 220 70% 50%;
72 | --chart-2: 160 60% 45%;
73 | --chart-3: 30 80% 55%;
74 | --chart-4: 280 65% 60%;
75 | --chart-5: 340 75% 55%;
76 | }
77 | }
78 | @layer base {
79 | * {
80 | @apply border-border;
81 | }
82 | body {
83 | @apply bg-background text-foreground;
84 | }
85 | }
86 |
87 |
--------------------------------------------------------------------------------
/agent/dsa_agent/agent.py:
--------------------------------------------------------------------------------
1 | from langgraph.graph import END, StateGraph, START
2 | from dsa_agent.state import AgentState
3 | from dsa_agent.nodes import (
4 | retrieve_question,
5 | code_generation_in_node,
6 | visualize_code,
7 | complexity_analysis,
8 | explaination_code,
9 | no_context
10 | )
11 | from dsa_agent.edges import (
12 | new_question,
13 | decide_to_generate_code,
14 | decide_to_generate_visualisation,
15 | decide_to_generate_complexity,
16 | decide_to_generate_explanation
17 | )
18 | from langgraph.checkpoint.memory import MemorySaver
19 |
20 |
21 | workflow = StateGraph(AgentState)
22 |
23 | # workflow.add_node("update_question", update_question)
24 | workflow.add_node("retrieve_question", retrieve_question)
25 | workflow.add_node("code_generation_in_node", code_generation_in_node)
26 | workflow.add_node("visualize_code", visualize_code)
27 | workflow.add_node("complexity_analysis", complexity_analysis)
28 | workflow.add_node("explaination_code", explaination_code)
29 | workflow.add_node("no_context", no_context)
30 |
31 | workflow.add_conditional_edges(
32 | START,
33 | new_question,
34 | {"retrieve_question": "retrieve_question", "no_context": "no_context"},
35 |
36 | )
37 |
38 |
39 | workflow.add_edge("retrieve_question", "code_generation_in_node")
40 |
41 |
42 | workflow.add_conditional_edges(
43 | "code_generation_in_node",
44 | decide_to_generate_code,
45 | {
46 | "useful": "visualize_code",
47 | "no_context": "no_context",
48 | },
49 | )
50 |
51 |
52 |
53 | # workflow.add_edge("visualize_code", "retrieve_question")
54 |
55 |
56 | workflow.add_conditional_edges(
57 | "visualize_code",
58 | decide_to_generate_visualisation,
59 | {
60 | "useful": "complexity_analysis",
61 | "no_context": "no_context",
62 | },
63 | )
64 |
65 | # workflow.add_edge("complexity_analysis", "retrieve_question")
66 |
67 |
68 | workflow.add_conditional_edges(
69 | "complexity_analysis",
70 | decide_to_generate_complexity,
71 | {
72 | "useful": "explaination_code",
73 | "no_context": "no_context",
74 | },
75 | )
76 |
77 | # workflow.add_edge("explaination_code", "retrieve_question")
78 |
79 |
80 | workflow.add_conditional_edges(
81 | "explaination_code",
82 | decide_to_generate_explanation,
83 | {
84 | "useful": END,
85 | "no_context": "no_context",
86 | },
87 | )
88 |
89 | workflow.add_edge("no_context", END)
90 |
91 | graph = workflow.compile(checkpointer=MemorySaver())
--------------------------------------------------------------------------------
/frontend-interface/components/TestCases.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Button } from "@/components/ui/button";
3 | import { Input } from "@/components/ui/input";
4 | import { Plus, Trash2 } from 'lucide-react';
5 |
6 | interface TestCase {
7 | input: string;
8 | output: string;
9 | }
10 |
11 | interface TestCasesProps {
12 | testCases: TestCase[];
13 | setTestCases: React.Dispatch>;
14 | }
15 |
16 | const TestCases = ({ testCases, setTestCases }: TestCasesProps) => {
17 | const handleAddTestCase = () => {
18 | setTestCases([...testCases, { input: "", output: "" }]);
19 | };
20 |
21 | const handleRemoveTestCase = (index: number) => {
22 | setTestCases(testCases.filter((_, i) => i !== index));
23 | };
24 |
25 | const updateTestCase = (
26 | index: number,
27 | field: "input" | "output",
28 | value: string
29 | ) => {
30 | const newTestCases = [...testCases];
31 | newTestCases[index][field] = value;
32 | setTestCases(newTestCases);
33 | };
34 |
35 | return (
36 |
37 |
38 | Test Cases
39 |
40 | {testCases.map((testCase, index) => (
41 |
42 |
43 | updateTestCase(index, "input", e.target.value)}
47 | className="bg-gray-50 dark:bg-gray-700 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-2 focus:ring-blue-500 dark:focus:ring-blue-400 transition duration-300 ease-in-out"
48 | />
49 |
50 |
51 | updateTestCase(index, "output", e.target.value)}
55 | className="bg-gray-50 dark:bg-gray-700 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-2 focus:ring-blue-500 dark:focus:ring-blue-400 transition duration-300 ease-in-out"
56 | />
57 |
58 |
handleRemoveTestCase(index)}
62 | disabled={testCases.length === 1}
63 | className="text-red-500 hover:text-red-600 dark:text-red-400 dark:hover:text-red-300"
64 | >
65 |
66 |
67 |
68 | ))}
69 |
74 | Add Test Case
75 |
76 |
77 | );
78 | };
79 |
80 | export default TestCases;
81 |
82 |
--------------------------------------------------------------------------------
/backend/graph.py:
--------------------------------------------------------------------------------
1 | # dsa_agent.py
2 |
3 | from typing import Dict, List, Annotated, TypedDict,Optional
4 | from langgraph.graph import Graph, StateGraph
5 | from langchain_core.messages import AIMessage, HumanMessage
6 |
7 | from tools.code_generator import CodeGenerator
8 | from tools.explanation_generator import ExplanationGenerator
9 | from tools.complexity_analyser import ComplexityAnalyzer # type: ignore
10 | from tools.visualisation_generator import VisualizationGenerator# type: ignore
11 |
12 | class AgentState(TypedDict):
13 | question: str
14 | testCases: List[str]
15 | code: Optional[str] # type: ignore
16 | explanation: Optional[str] # type: ignore
17 | time_complexity: Optional[str] # type: ignore
18 | space_complexity: Optional[str] # type: ignore
19 | visualization: Optional[str] # type: ignore
20 |
21 |
22 | def create_graph():
23 | # Initialize tools
24 | code_gen = CodeGenerator()
25 | explain_gen = ExplanationGenerator()
26 | complexity = ComplexityAnalyzer()
27 | viz_gen = VisualizationGenerator()
28 |
29 | # Define nodes
30 | def generation_of_code(state: AgentState) -> AgentState:
31 | result = code_gen.generate_code(state["question"],state["testCases"])
32 | state["code"] = result
33 | return state
34 |
35 | def generate_explanation(state: AgentState) -> AgentState:
36 | explanation = explain_gen.generate_explanation(state["question"],state["testCases"],state["code"])
37 | state["explanation"] = explanation
38 | return state
39 |
40 | def analyze_complexity(state: AgentState) -> AgentState:
41 | input_string = complexity.analyze_complexity(state["code"])
42 | complexities = []
43 | current_complexity = ""
44 | inside_complexity = False
45 |
46 | for char in input_string:
47 | if char == "O": # Start of a complexity
48 | inside_complexity = True
49 | current_complexity += char
50 | elif inside_complexity:
51 | current_complexity += char
52 | if char == ")": # End of a complexity
53 | complexities.append(current_complexity)
54 | current_complexity = ""
55 | inside_complexity = False
56 |
57 | state["time_complexity"] = complexities[0]
58 | state["space_complexity"] = complexities[1]
59 | return state
60 |
61 | def generate_viz(state: AgentState) -> AgentState:
62 | state["visualization"] = viz_gen.generate_mermaid_visualization(state["code"])
63 | return state
64 |
65 | # Create graph
66 | workflow = StateGraph(AgentState)
67 |
68 | # Add nodes
69 | workflow.add_node("generate_code", generation_of_code)
70 | workflow.add_node("generate_explanation", generate_explanation)
71 | workflow.add_node("analyze_complexity", analyze_complexity)
72 | workflow.add_node("generate_viz", generate_viz)
73 |
74 | # Define edges
75 | workflow.add_edge("generate_code", "generate_explanation")
76 | workflow.add_edge("generate_explanation", "analyze_complexity")
77 | workflow.add_edge("analyze_complexity", "generate_viz")
78 |
79 | # Set entry point
80 | workflow.set_entry_point("generate_code")
81 |
82 | return workflow.compile()
--------------------------------------------------------------------------------
/frontend-interface/app/not-found.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Link from 'next/link';
3 | import { Terminal, Code2, ArrowLeft, Server } from 'lucide-react';
4 |
5 | const NotFound = () => {
6 | return (
7 |
8 | {/* Floating Code Particles */}
9 |
10 | {[...Array(20)].map((_, i) => (
11 |
21 | {'{'}
22 |
23 | ))}
24 |
25 |
26 |
27 | {/* Main Content */}
28 |
29 | {/* Animated Terminal Icon */}
30 |
31 |
35 |
39 |
40 |
41 | {/* Error Message */}
42 |
43 | 404
44 |
45 |
46 | Under Maintenance
47 |
48 |
49 |
50 |
51 | We're currently optimizing this section for Quira to bring you an even better coding experience.
52 |
53 |
54 |
55 | System Upgrade in Progress
56 |
57 |
58 |
59 |
60 |
64 |
65 |
Return to Dashboard
66 |
67 |
68 | {/* Status Indicator */}
69 |
70 |
71 |
Systems Operating Normally
72 |
73 |
74 |
75 |
76 | {/* Background Grid */}
77 |
78 |
79 | );
80 | };
81 |
82 | export default NotFound;
--------------------------------------------------------------------------------
/agent/dsa_agent/nodes/__init__.py:
--------------------------------------------------------------------------------
1 | from dsa_agent.nodes.visualiser import visualization_generated
2 | from dsa_agent.nodes.complexity_finder import complexity_generated
3 | from dsa_agent.nodes.explainer import explanation_generated
4 | from dsa_agent.nodes.coding import code_writer
5 | from dsa_agent.nodes.question import question_instance
6 | from langchain_core.messages import HumanMessage
7 |
8 | def retrieve_question(state):
9 | """
10 | Retrieve Question
11 |
12 | Args:
13 | state (dict): The current graph state
14 |
15 | Returns:
16 | state (dict): New key added to state, documents, that contains retrieved documents
17 | """
18 | print("---GETTING QUESTION---")
19 | question = state["question"]
20 | print(f"---nodes new QUESTION DETECTED: {question}---")
21 | return {
22 | **state,
23 | "question": question,
24 | }
25 |
26 | def update_question(state):
27 | print("---UPDATE QUESTION---")
28 |
29 | new_question = state["question"]
30 | print(f"---NEW QUESTION DETECTED: {new_question}---")
31 |
32 | question_instance.update_question(new_question)
33 |
34 | print("---QUESTION UPDATED---")
35 |
36 | return {**state, "question": new_question , "messages": []}
37 |
38 | def code_generation_in_node(state):
39 | """
40 | Writes the code for the question
41 |
42 | Args:
43 | state (dict): The current graph state
44 |
45 | Returns:
46 | state (dict): Updates code key with a generated code
47 | """
48 |
49 | print("---TRANSFORM QUERY---")
50 | question = state["question"]
51 | # testCases = state["testCases"]
52 | # print(testCases)
53 | # if testCases == []:
54 | # testCases = ["X RETURNS Y"]
55 |
56 | code_generated = code_writer.invoke({"question": question })
57 | return {**state, "code": code_generated}
58 |
59 | def visualize_code(state):
60 | '''
61 | Visualizes the code generated
62 | Args:
63 | state (dict): The current graph state
64 |
65 | Returns:
66 | state (dict): Updates documents key with only filtered relevant documents
67 | '''
68 |
69 | print("---VISUALIZE CODE---")
70 | code = state["code"]
71 | question = state["question"]
72 |
73 | visualization = visualization_generated.invoke({"code": code, "question": question})
74 | return {**state, "visualization": visualization}
75 |
76 | def complexity_analysis(state):
77 | '''
78 | Analyzes the complexity of the code generated
79 | Args:
80 | state (dict): The current graph state
81 |
82 | Returns:
83 | state (dict): Updates documents key with only filtered relevant documents
84 | '''
85 |
86 | print("---ANALYZE COMPLEXITY---")
87 | code = state["code"]
88 |
89 | complexity = complexity_generated.invoke({"code": code})
90 | return {**state, "time_complexity": complexity, "space_complexity": complexity}
91 |
92 | def explaination_code(state):
93 | '''
94 | Explains the code generated
95 | Args:
96 | state (dict): The current graph state
97 |
98 | Returns:
99 | state (dict): Updates documents key with only filtered relevant documents
100 | '''
101 |
102 | print("---EXPLAIN CODE---")
103 | question = state["question"]
104 | code = state["code"]
105 |
106 | explanation = explanation_generated.invoke({"code": code, "question": question})
107 | return {**state, "explanation": explanation}
108 |
109 | def no_context(state):
110 | print("---NO CONTEXT---")
111 |
112 | messages = state["question"]
113 | messages.append(HumanMessage("I'm sorry, I can't find any relevant information."))
114 |
115 | return state
--------------------------------------------------------------------------------
/agent/dsa_agent/edges/__init__.py:
--------------------------------------------------------------------------------
1 |
2 | from langchain_core.messages import SystemMessage, HumanMessage
3 | from dsa_agent.edges.code_verify import code_verify
4 | from dsa_agent.edges.visualisation_verify import visualisation_verify
5 | from dsa_agent.edges.complexity_verify import complexity_verify
6 | from dsa_agent.edges.explanation_verify import explaination_verify
7 |
8 | def new_question(state):
9 | question = state["question"]
10 | if (
11 | isinstance(question, SystemMessage)
12 | and "QUESTION UPDATED" in question.content
13 | ):
14 | return "update_question"
15 |
16 | print("init edges new question : ", question)
17 |
18 | return "retrieve_question"
19 |
20 |
21 | def decide_to_generate_code(state):
22 | """
23 | Determines whether to re-generate the code or not.
24 |
25 | Args:
26 | state (dict): The current graph state
27 |
28 | Returns:
29 | str: Binary decision for next node to call
30 | """
31 |
32 | print("---ASSESS GENERATED CODE---")
33 | code = state["code"]
34 | question = state["question"]
35 | # testCases = state["testCases"]
36 |
37 | print("---GRADE CODE---")
38 | score = code_verify.invoke({"question": question, "code": code})
39 | grade = score.binary_score
40 |
41 | if grade == "yes":
42 | print("---DECISION: CODE IS CORRECT---")
43 | return "useful"
44 | else:
45 | print("---DECISION: CODE IS INCORRECT---")
46 | return "code_generation_in_node"
47 |
48 |
49 | def decide_to_generate_visualisation(state):
50 | """
51 | Determines whether to re-generate the visualization or not.
52 |
53 | Args:
54 | state (dict): The current graph state
55 |
56 | Returns:
57 | str: Binary decision for next node to call
58 | """
59 |
60 | print("---ASSESS MERMAID VISUALISATION CODE---")
61 | question = state["question"]
62 |
63 | print("---GRADE CODE---")
64 | score = visualisation_verify.invoke({"question": question})
65 | grade = score.binary_score
66 |
67 | if grade == "yes":
68 | print("---DECISION: CODE IS CORRECT---")
69 | return "useful"
70 | else:
71 | print("---DECISION: VISUALISATION IS INCORRECT---")
72 | return "visualize_code"
73 |
74 |
75 | def decide_to_generate_complexity(state):
76 | """
77 | Determines whether to re-generate the complexity.
78 |
79 | Args:
80 | state (dict): The current graph state
81 |
82 | Returns:
83 | str: Binary decision for next node to call
84 | """
85 |
86 |
87 | print("---ASSESS GENERATED COMPLEXITY---")
88 | code = state["code"]
89 | time_complexity = state["time_complexity"]
90 | space_complexity = state["space_complexity"]
91 |
92 | print("---GRADE CODE---")
93 | score = complexity_verify.invoke({"code": code,"time_complexity": time_complexity, "space_complexity": space_complexity})
94 | grade = score.binary_score
95 |
96 | if grade == "yes":
97 | print("---DECISION: CODE IS CORRECT---")
98 | return "useful"
99 | else:
100 | print("---DECISION: COMPLEXITY IS INCORRECT---")
101 | return "complexity_analysis"
102 |
103 |
104 | def decide_to_generate_explanation(state):
105 | """
106 | Determines whether to re-generate the explanation or not.
107 |
108 | Args:
109 | state (dict): The current graph state
110 |
111 | Returns:
112 | str: Binary decision for next node to call
113 | """
114 |
115 | print("---ASSESS EXPLANATION OF CODE---")
116 | code = state["code"]
117 | question = state["question"]
118 |
119 | print("---GRADE EXPLANATION---")
120 | score = explaination_verify.invoke({"code": code, "question": question})
121 | grade = score.binary_score
122 |
123 | if grade == "yes":
124 | print("---DECISION: CODE IS CORRECT---")
125 | return "useful"
126 | else:
127 | print("---DECISION: EXPLANATION IS INCORRECT---")
128 | return "explaination_code"
129 |
--------------------------------------------------------------------------------
/frontend-interface/components/VideoSection.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { motion } from "framer-motion";
3 | import { Button } from "@/components/ui/button";
4 | import { Play } from "lucide-react";
5 | import Image from "next/image";
6 |
7 | const VideoSection = () => {
8 | const [isPlaying1, setIsPlaying1] = React.useState(false);
9 | const [isPlaying2, setIsPlaying2] = React.useState(false);
10 |
11 | const videos = [
12 | {
13 | id: 1,
14 | videoUrl: "https://vimeo.com/1044157863",
15 | thumbnail: "/thumbnail.png",
16 | title: "See A Full Fledged Demonstration",
17 | subtitle: "Watch the demo insight during development",
18 | isPlaying: isPlaying1,
19 | setIsPlaying: setIsPlaying1
20 | },
21 | {
22 | id: 2,
23 | videoUrl: "https://vimeo.com/1044282090",
24 | thumbnail: "/thumbnail.png",
25 | title: "Recent Deployed Demonstration",
26 | subtitle: "See Near Release Demonstration of the Project",
27 | isPlaying: isPlaying2,
28 | setIsPlaying: setIsPlaying2
29 | }
30 | ];
31 |
32 | const getVimeoEmbedUrl = (url: string) => {
33 | const videoId = url.split("vimeo.com/")[1];
34 | return `https://player.vimeo.com/video/${videoId}`;
35 | };
36 |
37 | return (
38 |
44 | {videos.map((video) => (
45 |
52 |
53 | {video.isPlaying ? (
54 |
62 | ) : (
63 | <>
64 |
72 |
73 |
74 |
75 |
video.setIsPlaying(true)}
78 | >
79 |
80 |
81 |
82 |
{video.title}
83 |
{video.subtitle}
84 |
85 |
86 |
video.setIsPlaying(!video.isPlaying)}
91 | >
92 | Learn More
93 |
94 |
95 |
96 | >
97 | )}
98 |
99 |
100 | ))}
101 |
102 | );
103 | };
104 |
105 | export default VideoSection;
--------------------------------------------------------------------------------
/frontend-interface/components/ChatInterface.tsx:
--------------------------------------------------------------------------------
1 | // "use client"
2 |
3 | import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
4 | import { Button } from "@/components/ui/button"
5 | import { Card, CardContent, CardFooter } from "@/components/ui/card"
6 | import { Input } from "@/components/ui/input"
7 | import { cn } from "@/lib/utils"
8 | import { Role, TextMessage } from "@copilotkit/runtime-client-gql"
9 | import { Loader2, Send } from 'lucide-react'
10 | import { useEffect, useRef, useState } from "react"
11 |
12 | export default function ChatInterface({
13 | isLoading,
14 | appendMessage,
15 | visibleMessages,
16 |
17 | }: {
18 | isLoading: boolean
19 | appendMessage: (message: TextMessage) => void
20 | visibleMessages: TextMessage[]
21 |
22 | }) {
23 | const messagesEndRef = useRef(null)
24 | const chatContainerRef = useRef(null)
25 |
26 | const scrollToBottom = () => {
27 | if (chatContainerRef.current) {
28 | const { scrollHeight, clientHeight } = chatContainerRef.current
29 | chatContainerRef.current.scrollTop = scrollHeight - clientHeight
30 | }
31 | }
32 |
33 | useEffect(() => {
34 | scrollToBottom()
35 | }, [visibleMessages])
36 |
37 | useEffect(() => {
38 | // Parse messages for solution content
39 | const lastMessage = visibleMessages[visibleMessages.length - 1];
40 | if (lastMessage?.role === Role.Assistant) {
41 | try {
42 | const content = lastMessage.content;
43 | if (typeof content === 'string' && content.includes('```python')) {
44 |
45 | // eslint-disable-next-line @typescript-eslint/no-unused-vars
46 | const solution = {
47 | code: content.match(/```python\n([\s\S]*?)```/)?.[1] || '',
48 | explanation: content.split('```')[0].trim(),
49 | timeComplexity: content.match(/Time Complexity: (O\([^)]+\))/)?.[1] || '',
50 | spaceComplexity: content.match(/Space Complexity: (O\([^)]+\))/)?.[1] || ''
51 | };
52 | }
53 | } catch (error) {
54 | console.error('Error parsing solution:', error);
55 | }
56 | }
57 | }, [visibleMessages]);
58 |
59 | const [inputValue, setInputValue] = useState("")
60 |
61 | const handleSendMessage = () => {
62 | if (inputValue.trim()) {
63 | const message = new TextMessage({
64 | content: inputValue,
65 | role: Role.User,
66 | id: Date.now().toString()
67 | });
68 | appendMessage(message)
69 | setInputValue("")
70 | }
71 | }
72 |
73 | return (
74 |
75 |
79 | {visibleMessages.map((message, index) => (
80 |
86 | {message.role === Role.Assistant && (
87 |
88 |
89 | AI
90 |
91 | )}
92 |
98 | {typeof message.content === 'string' ? message.content : ''}
99 |
100 | {message.role === Role.User && (
101 |
102 |
103 | ME
104 |
105 | )}
106 |
107 | ))}
108 | {isLoading && (
109 |
110 |
111 |
112 | AI
113 |
114 |
115 |
116 |
117 |
118 | )}
119 |
120 |
121 |
122 |
123 | setInputValue(e.target.value)}
127 | onKeyDown={(e) => e.key === 'Enter' && !e.shiftKey && handleSendMessage()}
128 | className="flex-1"
129 | />
130 |
135 |
136 |
137 |
138 |
139 |
140 | )
141 | }
--------------------------------------------------------------------------------
/frontend-interface/components/SolutionDisplay.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
3 | import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
4 | import { Alert, AlertDescription } from "@/components/ui/alert";
5 | import { Code2, Clock, Box, PlayCircle } from 'lucide-react';
6 | import ReactMarkdown from "react-markdown";
7 | import VisualizationTab from "@/components/MermaidRenderer";
8 |
9 | interface Solution {
10 | code: string;
11 | explanation: string;
12 | visualization?: string;
13 | }
14 |
15 | interface SolutionDisplayProps {
16 | solution: Solution;
17 | timeComplexity?: string;
18 | spaceComplexity?: string;
19 | }
20 |
21 | const SolutionDisplay = ({ solution, timeComplexity, spaceComplexity }: SolutionDisplayProps) => {
22 | return (
23 |
24 |
25 |
29 | Code
30 |
31 |
35 | Explanation
36 |
37 |
41 | Complexity
42 |
43 |
47 | Visualization
48 |
49 |
50 |
51 |
52 |
53 |
54 | Python Code
55 |
56 |
57 |
58 | {solution.code}
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 | Approach Explanation
68 |
69 |
70 |
71 | {solution.explanation}
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 | Complexity Analysis
81 |
82 |
83 |
84 |
85 |
86 |
87 | Time Complexity: {timeComplexity || "Not specified"}
88 |
89 |
90 |
91 |
92 |
93 | Space Complexity: {spaceComplexity || "Not specified"}
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 | Visual Representation
105 |
106 |
107 |
108 | {solution.visualization && (
109 |
110 | )}
111 |
112 |
113 |
114 |
115 |
116 | );
117 | };
118 |
119 | export default SolutionDisplay;
120 |
121 |
--------------------------------------------------------------------------------
/frontend-interface/components/ui/select.tsx:
--------------------------------------------------------------------------------
1 | "use client"
2 |
3 | import * as React from "react"
4 | import * as SelectPrimitive from "@radix-ui/react-select"
5 | import { Check, ChevronDown, ChevronUp } from "lucide-react"
6 |
7 | import { cn } from "@/lib/utils"
8 |
9 | const Select = SelectPrimitive.Root
10 |
11 | const SelectGroup = SelectPrimitive.Group
12 |
13 | const SelectValue = SelectPrimitive.Value
14 |
15 | const SelectTrigger = React.forwardRef<
16 | React.ElementRef,
17 | React.ComponentPropsWithoutRef
18 | >(({ className, children, ...props }, ref) => (
19 | span]:line-clamp-1",
23 | className
24 | )}
25 | {...props}
26 | >
27 | {children}
28 |
29 |
30 |
31 |
32 | ))
33 | SelectTrigger.displayName = SelectPrimitive.Trigger.displayName
34 |
35 | const SelectScrollUpButton = React.forwardRef<
36 | React.ElementRef,
37 | React.ComponentPropsWithoutRef
38 | >(({ className, ...props }, ref) => (
39 |
47 |
48 |
49 | ))
50 | SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName
51 |
52 | const SelectScrollDownButton = React.forwardRef<
53 | React.ElementRef,
54 | React.ComponentPropsWithoutRef
55 | >(({ className, ...props }, ref) => (
56 |
64 |
65 |
66 | ))
67 | SelectScrollDownButton.displayName =
68 | SelectPrimitive.ScrollDownButton.displayName
69 |
70 | const SelectContent = React.forwardRef<
71 | React.ElementRef,
72 | React.ComponentPropsWithoutRef
73 | >(({ className, children, position = "popper", ...props }, ref) => (
74 |
75 |
86 |
87 |
94 | {children}
95 |
96 |
97 |
98 |
99 | ))
100 | SelectContent.displayName = SelectPrimitive.Content.displayName
101 |
102 | const SelectLabel = React.forwardRef<
103 | React.ElementRef,
104 | React.ComponentPropsWithoutRef
105 | >(({ className, ...props }, ref) => (
106 |
111 | ))
112 | SelectLabel.displayName = SelectPrimitive.Label.displayName
113 |
114 | const SelectItem = React.forwardRef<
115 | React.ElementRef,
116 | React.ComponentPropsWithoutRef
117 | >(({ className, children, ...props }, ref) => (
118 |
126 |
127 |
128 |
129 |
130 |
131 | {children}
132 |
133 | ))
134 | SelectItem.displayName = SelectPrimitive.Item.displayName
135 |
136 | const SelectSeparator = React.forwardRef<
137 | React.ElementRef,
138 | React.ComponentPropsWithoutRef
139 | >(({ className, ...props }, ref) => (
140 |
145 | ))
146 | SelectSeparator.displayName = SelectPrimitive.Separator.displayName
147 |
148 | export {
149 | Select,
150 | SelectGroup,
151 | SelectValue,
152 | SelectTrigger,
153 | SelectContent,
154 | SelectLabel,
155 | SelectItem,
156 | SelectSeparator,
157 | SelectScrollUpButton,
158 | SelectScrollDownButton,
159 | }
160 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # [Vote this Project Here](https://quira.sh/repo/ARYPROGRAMMER-Learn-Coding-with-Copilotkit-910783830)
2 |
3 | **Note : Running Locally is the Best Option as the API Keys might get exhausted after some time and the app would not work as expected.**
4 |
5 |
6 |
7 | # Learn Coding with CopilotKit, CoAgents, and LangGraphs🚀
8 |
9 |
10 |
11 |
34 |
35 | ---
36 |
37 | ## 📖 **About**
38 |
39 | **Not everyone can code, but everyone can learn.**
40 |
41 | This project is an AI-powered **DSA/Competitive Programming Helper** with an inbuilt editor to help you:
42 | - Prepare for **coding interviews**
43 | - Start learning how to code from scratch
44 | - **Visualize everything** with intuitive representations
45 |
46 | **Experience the future of coding education!**
47 |
48 | 🌐 Live Demo: [learn-coding-with-copilotkit.vercel.app](https://learn-coding-with-copilotkit.vercel.app/)
49 |
50 | ---
51 |
52 | ## 🌟 **Why CopilotKit?**
53 |
54 | - **Seamless Integration**: Build AI copilots that enhance user experiences effortlessly.
55 | - **Open Source**: Join a thriving community of developers using and contributing to CopilotKit.
56 | - **Future-Ready**: Perfect for in-app AI agents, context-aware chatbots, shared state and beyond!
57 |
58 | Learn more about [CopilotKit](https://github.com/copilotkit).
59 |
60 | ---
61 |
62 |
63 | ## 🛠️ **Project Description**
64 |
65 | Learn coding in a revolutionary way using **CopilotKit**, **CoAgents**, and **LangGraphs**! This project showcases how cutting-edge tools can simplify coding education through interactive UI and AI-driven technologies.
66 |
67 | ### Key Features:
68 | - **🌐 CopilotKit**: Effortlessly integrate AI copilots into your apps, enabling in-app chatbots, context-aware interactions, and more.
69 | - **🤖 CoAgents**: A robust infrastructure for connecting LangGraph agents to humans in the loop, enabling seamless collaboration.
70 | - **📊 LangGraphs**: Visual representations of programming languages to simplify understanding of their structure and syntax.
71 | - **🖥️ Inbuilt Editor**: A powerful coding editor designed to boost productivity and learning.
72 |
73 | ---
74 |
75 |
76 | ## Screenshots
77 |
78 |
79 | View Achieved Accuracy
80 |
81 |
87 |
88 |
89 |
90 |
91 | ## 🏗️ **Tech Stack**
92 |
93 | ### Frontend:
94 | - [Next.js](https://nextjs.org/)
95 | - [ShadCN UI](https://shadcn.dev/)
96 | - [Tailwind CSS](https://tailwindcss.com/)
97 | - [CopilotKit-UI](https://github.com/copilotkit)
98 |
99 | ### Backend:
100 | - [Python](https://www.python.org/)
101 | - [FastAPI](https://fastapi.tiangolo.com/)
102 | - [LangGraphs](https://langgraphs.example)
103 | - [CopilotKit](https://github.com/copilotkit)
104 |
105 | ### APIs:
106 | - [Groq](https://groq.com/)
107 | - [Llama-70B](https://example.com/)
108 |
109 | ---
110 |
111 | ## 📚 **Topics Covered**
112 |
113 | - **TypeScript**
114 | - **Next.js**
115 | - **Competitive Programming**
116 | - **Tailwind CSS**
117 | - **Render Deployment**
118 | - **Koyeb API**
119 | - **ShadCN-UI**
120 | - **Llama-70B**
121 | - **Groq AI**
122 | - **CopilotKit**
123 | - **LangGraph (Python)**
124 | - **CoAgents**
125 |
126 | ---
127 |
128 | ## ⚙️ **Installation**
129 |
130 | Clone the repository:
131 |
132 | ```bash
133 | git clone https://github.com/.git
134 | ```
135 |
136 | ---
137 |
138 | ### 🧩 **Configuration**
139 |
140 | 1. Install the dependencies for the backend:
141 |
142 | ```bash
143 | cd agent
144 | poetry install
145 | ```
146 |
147 | 2. Create a `.env` file in the `./agent` directory:
148 |
149 | ```plaintext
150 | GROQ_API_KEY=your_groq_api_key_here
151 | ```
152 |
153 | 3. Run the demo:
154 |
155 | ```bash
156 | poetry run demo
157 | ```
158 |
159 | ---
160 |
161 | ### 🖥️ **Running the UI**
162 |
163 | 1. Install the dependencies for the frontend:
164 |
165 | ```bash
166 | cd ./frontend-interface
167 | npm i --legacy-peer-deps
168 | ```
169 |
170 | 2. Create a `.env` file in the `./frontend-interface` directory:
171 |
172 | ```plaintext
173 | GROQ_API_KEY=your_groq_api_key_here
174 | ```
175 |
176 | 3. Run the Next.js project:
177 |
178 | ```bash
179 | npm run dev
180 | ```
181 |
182 | 4. Navigate to [http://localhost:3000](http://localhost:3000).
183 |
184 | ---
185 |
186 | ### 🖥️ **Running the Backend**
187 |
188 | 1. Install the dependencies for the backend:
189 |
190 | ```bash
191 | cd ./backend
192 | pip install -r -requirements.txt
193 | ```
194 |
195 | 2. Create a `.env` file in the `./frontend-interface` directory:
196 |
197 | ```plaintext
198 | GROQ_API_KEY=your_groq_api_key_here
199 | ```
200 |
201 | 3. Run the FAST API server:
202 |
203 | ```bash
204 | python run_agent.py
205 | ```
206 |
207 | ---
208 |
209 |
210 | ## 🧑💻 **Usage**
211 |
212 | 1. **Launch LangGraph Studio**:
213 | Run LangGraph Studio and load the `./agent` folder into it.
214 |
215 | 2. **Ensure proper configuration**: Make sure the `.env` file is properly configured as mentioned in the setup steps.
216 |
217 | ---
218 |
219 | ## 🔧 **Troubleshooting**
220 |
221 | If you encounter any issues, try the following:
222 |
223 | 1. Ensure no other application is running on port `8000`.
224 | 2. In `/agent/dsa_agent/demo.py`, change `0.0.0.0` to `127.0.0.1` or `localhost`.
225 |
226 | ---
227 |
228 | ## 📜 **License**
229 |
230 | This project is [UN Licensed](LICENSE).
231 |
232 | ---
233 |
234 | Give CopilotKit a ⭐ on [GitHub](https://github.com/copilotkit) if you love it!
235 |
236 |
--------------------------------------------------------------------------------
/frontend-interface/components/Editor.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import React, { useState } from 'react';
4 | import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card";
5 | import { Button } from "@/components/ui/button";
6 | import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
7 | import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
8 | import { X, Settings, Play, Loader2 } from "lucide-react";
9 | import Editor from '@monaco-editor/react';
10 |
11 | interface CodeEditorProps {
12 | code: string;
13 | language?: string;
14 | theme?: string;
15 | onClose: () => void;
16 | onChange?: (value: string | undefined) => void;
17 | }
18 |
19 | interface ExecutionResult {
20 | output: string;
21 | error?: string;
22 | language: string;
23 | version: string;
24 | }
25 |
26 | const LANGUAGE_TO_PISTON = {
27 | javascript: "javascript",
28 | typescript: "typescript",
29 | python: "python3",
30 | java: "java",
31 | cpp: "c++",
32 | csharp: "c#",
33 | };
34 |
35 | const CodeEditor: React.FC = ({
36 | code,
37 | language: initialLanguage = "python",
38 | theme: initialTheme = "vs-dark",
39 | onClose,
40 | onChange
41 | }) => {
42 | const [language, setLanguage] = useState(initialLanguage);
43 | const [theme, setTheme] = useState(initialTheme);
44 | const [showSettings, setShowSettings] = useState(false);
45 | const [isExecuting, setIsExecuting] = useState(false);
46 | const [executionResult, setExecutionResult] = useState(null);
47 | const [activeTab, setActiveTab] = useState("editor");
48 |
49 | const languages = [
50 | { value: "javascript", label: "JavaScript" },
51 | { value: "typescript", label: "TypeScript" },
52 | { value: "python", label: "Python" },
53 | { value: "java", label: "Java" },
54 | { value: "cpp", label: "C++" },
55 | { value: "csharp", label: "C#" },
56 | ];
57 |
58 | const themes = [
59 | { value: "vs-dark", label: "Dark" },
60 | { value: "light", label: "Light" },
61 | { value: "hc-black", label: "High Contrast Dark" },
62 | { value: "hc-light", label: "High Contrast Light" },
63 | ];
64 |
65 | const handleEditorChange = (value: string | undefined) => {
66 | if (onChange) {
67 | onChange(value);
68 | }
69 | };
70 |
71 | const executeCode = async () => {
72 | setIsExecuting(true);
73 | setActiveTab("output");
74 |
75 | try {
76 | const response = await fetch('https://emkc.org/api/v2/piston/execute', {
77 | method: 'POST',
78 | headers: {
79 | 'Content-Type': 'application/json',
80 | },
81 | body: JSON.stringify({
82 | language: LANGUAGE_TO_PISTON[language as keyof typeof LANGUAGE_TO_PISTON],
83 | version: '*',
84 | files: [
85 | {
86 | content: code
87 | }
88 | ]
89 | })
90 | });
91 |
92 | const data = await response.json();
93 |
94 | setExecutionResult({
95 | output: data.run.output || 'No output',
96 | error: data.run.stderr,
97 | language: data.language,
98 | version: data.version
99 | });
100 | } catch (error) {
101 | setExecutionResult({
102 | output: '',
103 | error: 'Execution failed: ' + (error as Error).message,
104 | language,
105 | version: 'unknown'
106 | });
107 | } finally {
108 | setIsExecuting(false);
109 | }
110 | };
111 |
112 | return (
113 |
114 |
115 |
116 | Code Editor
117 | setShowSettings(!showSettings)}
121 | className="h-8 w-8"
122 | >
123 |
124 |
125 |
126 |
127 |
133 | {isExecuting ? (
134 |
135 | ) : (
136 |
137 | )}
138 | Run Code
139 |
140 |
146 |
147 |
148 |
149 |
150 |
151 | {showSettings && (
152 |
153 |
154 |
155 | Language
156 | setLanguage(value)}
159 | >
160 |
161 |
162 |
163 |
164 | {languages.map((lang) => (
165 |
166 | {lang.label}
167 |
168 | ))}
169 |
170 |
171 |
172 |
173 | Theme
174 | setTheme(value)}
177 | >
178 |
179 |
180 |
181 |
182 | {themes.map((themeOption) => (
183 |
184 | {themeOption.label}
185 |
186 | ))}
187 |
188 |
189 |
190 |
191 |
192 | )}
193 |
194 |
195 |
196 |
197 | Editor
198 | Output
199 |
200 |
201 |
202 |
221 |
222 |
223 |
224 | {executionResult && (
225 |
226 |
227 | Executed using {executionResult.language} v{executionResult.version}
228 |
229 | {executionResult.error ? (
230 |
{executionResult.error}
231 | ) : (
232 |
{executionResult.output}
233 | )}
234 |
235 | )}
236 |
237 |
238 |
239 |
240 | );
241 | };
242 |
243 | export default CodeEditor;
--------------------------------------------------------------------------------
/frontend-interface/components/MermaidRenderer.tsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState, useRef } from 'react';
2 | import { Card, CardContent } from '@/components/ui/card';
3 | import { TabsContent } from '@/components/ui/tabs';
4 | import { Button } from '@/components/ui/button';
5 | import { Slider } from '@/components/ui/slider';
6 | import mermaid from 'mermaid';
7 | import {
8 | Loader2,
9 | ZoomIn,
10 | ZoomOut,
11 | Download,
12 | RotateCw,
13 | Maximize2,
14 | Copy,
15 | Move
16 | } from 'lucide-react';
17 |
18 | interface Transform {
19 | scale: number;
20 | translateX: number;
21 | translateY: number;
22 | }
23 |
24 | const MermaidRenderer = ({ value }: { value: string }) => {
25 | const [isLoading, setIsLoading] = useState(true);
26 | // eslint-disable-next-line @typescript-eslint/no-unused-vars
27 | const [isFullscreen, setIsFullscreen] = useState(false);
28 | const [isPanning, setIsPanning] = useState(false);
29 | const [transform, setTransform] = useState({ scale: 1, translateX: 0, translateY: 0 });
30 | const containerRef = useRef(null);
31 | const contentRef = useRef(null);
32 | const isDragging = useRef(false);
33 | const lastPosition = useRef({ x: 0, y: 0 });
34 |
35 | useEffect(() => {
36 | mermaid.initialize({
37 | startOnLoad: true,
38 | theme: 'neutral',
39 | securityLevel: 'loose',
40 | themeVariables: {
41 | fontFamily: 'ui-sans-serif, system-ui, sans-serif',
42 | fontSize: '16px',
43 | primaryColor: '#2563eb',
44 | primaryTextColor: '#1e293b',
45 | primaryBorderColor: '#94a3b8',
46 | lineColor: '#64748b',
47 | secondaryColor: '#3b82f6',
48 | tertiaryColor: '#60a5fa'
49 | }
50 | });
51 |
52 | const renderDiagram = async () => {
53 | try {
54 | await mermaid.contentLoaded();
55 | setIsLoading(false);
56 | // Center after initial render
57 | requestAnimationFrame(centerContent);
58 | } catch (error) {
59 | console.error('Mermaid rendering error:', error);
60 | setIsLoading(false);
61 | }
62 | };
63 |
64 | renderDiagram();
65 | }, [value]);
66 |
67 | const centerContent = () => {
68 | if (!containerRef.current || !contentRef.current) return;
69 |
70 | const container = containerRef.current.getBoundingClientRect();
71 | const content = contentRef.current.getBoundingClientRect();
72 |
73 | const translateX = (container.width - content.width) / 2;
74 | const translateY = (container.height - content.height) / 2;
75 |
76 | setTransform(prev => ({
77 | ...prev,
78 | translateX,
79 | translateY
80 | }));
81 | };
82 |
83 | const handleMouseDown = (e: React.MouseEvent) => {
84 | if (!isPanning) return;
85 |
86 | isDragging.current = true;
87 | lastPosition.current = { x: e.clientX, y: e.clientY };
88 |
89 | const handleMouseMove = (e: MouseEvent) => {
90 | if (!isDragging.current) return;
91 |
92 | const deltaX = e.clientX - lastPosition.current.x;
93 | const deltaY = e.clientY - lastPosition.current.y;
94 |
95 | setTransform(prev => ({
96 | ...prev,
97 | translateX: prev.translateX + deltaX,
98 | translateY: prev.translateY + deltaY
99 | }));
100 |
101 | lastPosition.current = { x: e.clientX, y: e.clientY };
102 | };
103 |
104 | const handleMouseUp = () => {
105 | isDragging.current = false;
106 | window.removeEventListener('mousemove', handleMouseMove);
107 | window.removeEventListener('mouseup', handleMouseUp);
108 | };
109 |
110 | window.addEventListener('mousemove', handleMouseMove);
111 | window.addEventListener('mouseup', handleMouseUp);
112 | };
113 |
114 | const handleZoom = (delta: number) => {
115 | setTransform(prev => {
116 | const newScale = Math.max(0.25, Math.min(2, prev.scale + delta));
117 | return { ...prev, scale: newScale };
118 | });
119 | };
120 |
121 | const resetView = () => {
122 | setTransform({ scale: 1, translateX: 0, translateY: 0 });
123 | requestAnimationFrame(centerContent);
124 | };
125 |
126 | const handleDownload = async () => {
127 | if (!containerRef.current) return;
128 | try {
129 | const svgElement = containerRef.current.querySelector('svg');
130 | if (!svgElement) return;
131 |
132 | const svgData = new XMLSerializer().serializeToString(svgElement);
133 | const canvas = document.createElement('canvas');
134 | const ctx = canvas.getContext('2d');
135 | const img = new Image();
136 |
137 | img.onload = () => {
138 | canvas.width = img.width * transform.scale;
139 | canvas.height = img.height * transform.scale;
140 | ctx?.drawImage(img, 0, 0, canvas.width, canvas.height);
141 |
142 | const a = document.createElement('a');
143 | a.download = 'diagram.png';
144 | a.href = canvas.toDataURL('image/png');
145 | a.click();
146 | };
147 |
148 | img.src = 'data:image/svg+xml;base64,' + btoa(svgData);
149 | } catch (error) {
150 | console.error('Download error:', error);
151 | }
152 | };
153 |
154 | const handleCopy = async () => {
155 | if (!containerRef.current) return;
156 | try {
157 | const svgElement = containerRef.current.querySelector('svg');
158 | if (svgElement) {
159 | const svgString = new XMLSerializer().serializeToString(svgElement);
160 | await navigator.clipboard.writeText(svgString);
161 | }
162 | } catch (error) {
163 | console.error('Copy error:', error);
164 | }
165 | };
166 |
167 | const toggleFullscreen = () => {
168 | if (!document.fullscreenElement) {
169 | containerRef.current?.requestFullscreen();
170 | setIsFullscreen(true);
171 | } else {
172 | document.exitFullscreen();
173 | setIsFullscreen(false);
174 | }
175 | };
176 |
177 | if (!value) return null;
178 |
179 | return (
180 |
181 |
182 |
183 | handleZoom(-0.25)}
187 | >
188 |
189 |
190 |
191 | setTransform(prev => ({ ...prev, scale: value[0] / 100 }))}
194 | min={25}
195 | max={200}
196 | step={25}
197 | className="w-32"
198 | />
199 |
200 | handleZoom(0.25)}
204 | >
205 |
206 |
207 |
208 | setIsPanning(!isPanning)}
212 | >
213 |
214 |
215 |
216 |
221 |
222 |
223 |
224 |
225 |
226 |
231 |
232 | Copy SVG
233 |
234 |
235 |
240 |
241 | Download
242 |
243 |
244 |
249 |
250 |
251 |
252 |
253 |
254 |
260 | {isLoading && (
261 |
262 |
263 |
264 | )}
265 |
274 | {value}
275 |
276 |
277 |
278 | );
279 | };
280 |
281 | const VisualizationTab = ({ visualization }: { visualization: string }) => {
282 | return (
283 |
287 |
288 |
289 | {visualization ? (
290 |
291 | ) : (
292 |
293 | No visualization available
294 |
295 | )}
296 |
297 |
298 |
299 | );
300 | };
301 |
302 | export default VisualizationTab;
--------------------------------------------------------------------------------
/frontend-interface/app/page.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import React, { useEffect, useState } from "react";
4 | import { motion, AnimatePresence } from "framer-motion";
5 | import dynamic from "next/dynamic";
6 | import { Loader2, ExternalLink, Cpu, MessageSquare } from "lucide-react";
7 | import { Button } from "@/components/ui/button";
8 | import { Role, TextMessage } from "@copilotkit/runtime-client-gql";
9 | import ChatInterface from "@/components/ChatInterface";
10 | import StepNavigation from "@/components/StepNavigation";
11 | import ProblemInput from "@/components/ProblemInput";
12 | import TestCases from "@/components/TestCases";
13 | import ComplexityInput from "@/components/ComplexityInput";
14 | import SolutionDisplay from "@/components/SolutionDisplay";
15 | import { CopilotKit, useCoAgent, useCopilotChat } from "@copilotkit/react-core";
16 | import GitHubStarButtons from "@/components/StarComponent";
17 | import Image from "next/image";
18 | import { CopilotSidebar } from "@copilotkit/react-ui";
19 | import "@copilotkit/react-ui/styles.css";
20 | import VideoSection from "@/components/VideoSection";
21 |
22 | interface AgentState {
23 | question: string;
24 | testCases: { input: string; output: string }[];
25 | timeComplexity: string;
26 | spaceComplexity: string;
27 | code: string;
28 | explanation: string;
29 | visualization?: string;
30 | }
31 |
32 | interface Solution {
33 | code: string;
34 | explanation: string;
35 | visualization?: string;
36 | }
37 | const CodeEditor = dynamic(() => import("../components/Editor"), {
38 | ssr: false,
39 | });
40 |
41 | const DSASolutionInterface = () => {
42 | const [question, setQuestion] = useState("");
43 | const [loading, setLoading] = useState(false);
44 | const [showEditor, setShowEditor] = useState(false);
45 | const [showChat, setShowChat] = useState(false);
46 | const [editorCode, setEditorCode] = useState("");
47 | const [solution, setSolution] = useState(null);
48 | const [testCases, setTestCases] = useState([{ input: "", output: "" }]);
49 | const [timeComplexity, setTimeComplexity] = useState("");
50 | const [spaceComplexity, setSpaceComplexity] = useState("");
51 | const [activeStep, setActiveStep] = useState(0);
52 |
53 | const handleOpenEditor = () => {
54 | if (solution?.code) {
55 | setEditorCode(solution.code);
56 | }
57 | setShowEditor(true);
58 | };
59 |
60 | const handleCloseEditor = () => {
61 | setShowEditor(false);
62 | };
63 |
64 | const handleSubmit = async () => {
65 | if (!question.trim()) return;
66 |
67 | setLoading(true);
68 | try {
69 | const response = await fetch(
70 | "https://novel-tasia-arya007-ab53373f.koyeb.app/copilotkit",
71 | {
72 | method: "POST",
73 | headers: {
74 | "Content-Type": "application/json",
75 | Accept: "application/json",
76 | },
77 | credentials: "include",
78 | body: JSON.stringify({
79 | question,
80 | testCases: testCases.map((tc) => tc.input),
81 | }),
82 | }
83 | );
84 |
85 | if (!response.ok) {
86 | throw new Error(`HTTP error! status: ${response.status}`);
87 | }
88 |
89 | const data = await response.json();
90 |
91 | const cleanCode = (data.code || "").replace(/```python\n?|\n?```/g, "");
92 | const cleanVisualization = (data.visualization || "").replace(
93 | /```mermaid\n?|\n?```/g,
94 | ""
95 | );
96 |
97 | setSolution({
98 | code: cleanCode,
99 | explanation: data.explanation || "",
100 | visualization: cleanVisualization,
101 | });
102 |
103 | setTimeComplexity(data.time_complexity || "O(1)");
104 | setSpaceComplexity(data.space_complexity || "O(1)");
105 | setEditorCode(cleanCode);
106 | } catch (error) {
107 | console.error(error);
108 | try {
109 | const response = await fetch(
110 | "https://learn-coding-with-copilotkit.onrender.com/copilotkit",
111 | {
112 | method: "POST",
113 | headers: {
114 | "Content-Type": "application/json",
115 | Accept: "application/json",
116 | },
117 | credentials: "include",
118 | body: JSON.stringify({
119 | question,
120 | testCases: testCases.map((tc) => tc.input),
121 | }),
122 | }
123 | );
124 |
125 | if (!response.ok) {
126 | throw new Error(`HTTP error! status: ${response.status}`);
127 | }
128 |
129 | const data = await response.json();
130 |
131 | const cleanCode = (data.code || "").replace(/```python\n?|\n?```/g, "");
132 | const cleanVisualization = (data.visualization || "").replace(
133 | /```mermaid\n?|\n?```/g,
134 | ""
135 | );
136 |
137 | setSolution({
138 | code: cleanCode,
139 | explanation: data.explanation || "",
140 | visualization: cleanVisualization,
141 | });
142 |
143 | setTimeComplexity(data.time_complexity || "O(1)");
144 | setSpaceComplexity(data.space_complexity || "O(1)");
145 | setEditorCode(cleanCode);
146 | } catch (error) {
147 | console.error(error);
148 | }
149 | } finally {
150 | setLoading(false);
151 | }
152 | };
153 |
154 |
155 | const { state, setState } = useCoAgent({
156 | name: "dsa_agent",
157 | initialState: {
158 | question: "",
159 | timeComplexity: "",
160 | spaceComplexity: "",
161 | code: "",
162 | explanation: "",
163 | visualization: "",
164 | },
165 | });
166 |
167 | const { isLoading, appendMessage, visibleMessages } = useCopilotChat();
168 |
169 |
170 |
171 | const isStateEqual = (prevState: AgentState, newState: Partial) => {
172 | return (
173 | prevState.question === newState.question &&
174 | JSON.stringify(prevState.testCases) === JSON.stringify(newState.testCases) &&
175 | prevState.timeComplexity === newState.timeComplexity &&
176 | prevState.spaceComplexity === newState.spaceComplexity
177 | );
178 | };
179 |
180 | useEffect(() => {
181 | const newState = {
182 | question,
183 | testCases,
184 | timeComplexity,
185 | spaceComplexity,
186 | };
187 |
188 | if (!isStateEqual(state, newState)) {
189 | setState((prevState = state) => ({
190 | ...prevState,
191 | ...newState,
192 |
193 | code: prevState.code,
194 | explanation: prevState.explanation,
195 | visualization: prevState.visualization,
196 | }));
197 | }
198 | }, [question, testCases, timeComplexity, spaceComplexity]);
199 |
200 | const handleRetry = () => {
201 | if (!question.trim()) {
202 | console.error("Question is empty");
203 | return;
204 | }
205 |
206 | setShowChat(true);
207 |
208 | const contextMessage = new TextMessage({
209 | id: "context-" + Date.now().toString(),
210 | role: Role.System,
211 | content: `
212 | Language: Python
213 | Status: New Problem
214 |
215 | Question:
216 | ${question}
217 | `,
218 | });
219 |
220 |
221 | const userMessage = new TextMessage({
222 | id: "user-" + Date.now().toString(),
223 | role: Role.User,
224 | content: question,
225 | });
226 |
227 |
228 | setTimeout(() => {
229 | appendMessage(contextMessage);
230 | setTimeout(() => {
231 | appendMessage(userMessage);
232 | }, 100);
233 | }, 100);
234 | };
235 |
236 | const handleSolutionUpdate = (content: string) => {
237 | try {
238 |
239 | const codeMatch = content.match(/```python\n([\s\S]*?)```/);
240 | const code = codeMatch ? codeMatch[1].trim() : "";
241 |
242 |
243 | const explanation = content.split("```")[0].trim();
244 |
245 | const timeMatch = content.match(/[Tt]ime [Cc]omplexity:?\s*(O\([^)]+\))/);
246 | const spaceMatch = content.match(
247 | /[Ss]pace [Cc]omplexity:?\s*(O\([^)]+\))/
248 | );
249 |
250 |
251 | setSolution(prevSolution => ({
252 | code: code,
253 | explanation: explanation,
254 | visualization: prevSolution?.visualization
255 | }));
256 |
257 | if (timeMatch) setTimeComplexity(timeMatch[1]);
258 | if (spaceMatch) setSpaceComplexity(spaceMatch[1]);
259 | if (code) setEditorCode(code);
260 |
261 | setState({
262 | ...state,
263 | code: code,
264 | explanation: explanation,
265 | visualization: state.visualization, // Preserve existing visualization
266 | timeComplexity: timeMatch ? timeMatch[1] : state.timeComplexity,
267 | spaceComplexity: spaceMatch ? spaceMatch[1] : state.spaceComplexity,
268 | });
269 | } catch (error) {
270 | console.error("Error parsing solution:", error);
271 | }
272 | };
273 |
274 | useEffect(() => {
275 | const lastMessage = visibleMessages[visibleMessages.length - 1];
276 | const textMessage = lastMessage as TextMessage;
277 | if (
278 | textMessage?.role === Role.Assistant &&
279 | typeof textMessage.content === "string"
280 | ) {
281 | handleSolutionUpdate((lastMessage as TextMessage).content);
282 | }
283 | }, [visibleMessages]);
284 |
285 |
286 | return (
287 |
288 |
289 |
290 |
293 |
294 |
295 |
300 |
301 |
307 |
308 | Learn Coding with
309 |
310 |
311 |
318 |
319 |
320 |
321 |
325 |
326 |
327 |
334 | {activeStep === 0 && (
335 |
336 | )}
337 | {activeStep === 1 && (
338 |
339 | )}
340 | {activeStep === 2 && (
341 |
347 | )}
348 |
349 |
350 |
351 |
356 | {loading ? (
357 | <>
358 |
359 | Analyzing Problem...
360 | >
361 | ) : (
362 | "Generate Solution"
363 | )}
364 |
365 |
366 | {solution && (
367 | <>
368 |
369 |
373 |
374 | Retry with Chat
375 |
376 |
380 |
381 | Open in Editor
382 |
383 |
384 |
385 |
390 | >
391 | )}
392 |
393 |
394 |
395 | Powered by CopilotKit CoAgents and Langgraphs
396 |
397 |
398 |
399 |
400 |
401 |
402 | {!showChat && (
403 |
404 |
412 |
413 |
414 |
415 | )}
416 |
417 |
418 |
419 |
420 | {showChat && (
421 |
428 |
429 |
430 |
Chat with AI
431 | setShowChat(false)} variant="ghost">
432 | Close
433 |
434 |
435 |
436 |
441 |
442 |
443 |
444 | )}
445 |
446 |
447 |
448 | {showEditor && (
449 |
456 | value !== undefined && setEditorCode(value)}
460 | />
461 |
462 | )}
463 |
464 |
465 |
466 |
467 |
468 | );
469 | };
470 |
471 | export default DSASolutionInterface;
472 |
--------------------------------------------------------------------------------