first commit

This commit is contained in:
Dhruv Atreja
2024-09-13 20:56:23 +05:30
commit 22d26a3927
58 changed files with 27204 additions and 0 deletions
+3
View File
@@ -0,0 +1,3 @@
{
"path": "./node_modules/cz-conventional-changelog"
}
+1
View File
@@ -0,0 +1 @@
NEXT_PUBLIC_APP_NAME="Starter Project"
+6
View File
@@ -0,0 +1,6 @@
node_modules
out
*.css
.*.js
*.ts
*.tsx
+88
View File
@@ -0,0 +1,88 @@
{
"parser": "@typescript-eslint/parser",
"extends": ["next", "next/core-web-vitals", "airbnb", "airbnb-typescript", "plugin:sonarjs/recommended", "prettier"],
"plugins": ["@typescript-eslint", "jest", "unused-imports"],
"env": {
"es2021": true,
"browser": true,
"jest": true,
"node": true
},
"rules": {
"react/require-default-props": "off",
"import/prefer-default-export": "off",
"react/prop-types": "off",
"no-multi-assign": "off",
"import/imports-first": ["error", "absolute-first"],
"react/function-component-definition": [
1,
{
"namedComponents": "arrow-function",
"unnamedComponents": "arrow-function"
}
],
"react/jsx-filename-extension": [
1,
{
"extensions": [".js", ".jsx", ".ts", ".tsx"]
}
],
// Multiline indentation: https://stackoverflow.com/a/48906878
"indent": ["error", 2],
"react/jsx-indent": ["error", 2],
"react/jsx-indent-props": ["error", 2],
"quotes": [
2,
"single",
{
"avoidEscape": true
}
],
"semi": ["error", "never"],
"constructor-super": "error",
"no-invalid-this": "error",
"no-restricted-syntax": ["error", "ForInStatement"],
"use-isnan": "error",
"@typescript-eslint/no-unused-vars": "off",
"unused-imports/no-unused-imports": "warn",
"unused-imports/no-unused-vars": [
"warn",
{
"vars": "all",
"varsIgnorePattern": "^_",
"args": "after-used",
"argsIgnorePattern": "^_"
}
],
"@typescript-eslint/await-thenable": "error",
"@typescript-eslint/no-floating-promises": "error",
"@typescript-eslint/no-misused-new": "error",
"@typescript-eslint/no-use-before-define": "error",
"@typescript-eslint/restrict-plus-operands": "error",
"@typescript-eslint/no-unnecessary-condition": [
"error",
{
"allowConstantLoopConditions": true
}
]
},
"settings": {
"import/parsers": {
"@typescript-eslint/parser": [".js", ".jsx", ".ts", ".tsx"]
},
"import/resolver": {
"typescript": {}
},
"react": {
"version": "detect"
}
},
"parserOptions": {
// Allows for the parsing of modern ECMAScript features
"ecmaVersion": 2021,
// Allows for the use of imports
"sourceType": "module",
// https://blog.geographer.fr/eslint-parser-services, https://www.robertcooper.me/using-eslint-and-prettier-in-a-typescript-project
"project": "./tsconfig.json"
}
}
+32
View File
@@ -0,0 +1,32 @@
# dependencies
/node_modules
.next
.vscode
# testing
/coverage
# production
/dist
/build
/out
#cache
/.cache
# misc
.DS_Store
.Spotlight-V100
Thumbs.db
# Package
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Environment Variables
.env
.env.local
# Typescript
tsconfig.tsbuildinfo
+4
View File
@@ -0,0 +1,4 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npx --no -- commitlint --edit "${1}"
+4
View File
@@ -0,0 +1,4 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npx lint-staged
+4
View File
@@ -0,0 +1,4 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npm run test
+13
View File
@@ -0,0 +1,13 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
# Only run commitizen if no commit message was already provided: https://github.com/commitizen/cz-cli/issues/844#issuecomment-1035862033
if [ -z "${2-}" ]; then
export CZ_TYPE="${CZ_TYPE:-fix}"
export CZ_MAX_HEADER_WIDTH=$COMMITLINT_MAX_WIDTH
export CZ_MAX_LINE_WIDTH=$CZ_MAX_HEADER_WIDTH
# By default git hooks are not interactive. exec < /dev/tty allows a users terminal to interact with commitizen.
exec < /dev/tty && npx cz --hook && npx devmoji -e || true
else
npx devmoji -e || true
fi
+10
View File
@@ -0,0 +1,10 @@
const path = require('path')
// With `next lint`: https://nextjs.org/docs/basic-features/eslint#lint-staged
const buildEslintCommand = (filenames) =>
`yarn lint:fix --file ${filenames.map((f) => path.relative(process.cwd(), f)).join(' --file ')}`
module.exports = {
'*.{js,jsx,ts,tsx}': [buildEslintCommand],
'*.{ts,tsx}': "bash -c 'npm run typecheck'", // running this via bash https://github.com/okonet/lint-staged/issues/825#issuecomment-727185296
}
+22
View File
@@ -0,0 +1,22 @@
{
"singleQuote": true,
"jsxSingleQuote": true,
"arrowParens": "always",
"noSemi": true,
"semi": false,
"trailingComma": "all",
"tabWidth": 2,
"printWidth": 120,
"importOrderSeparation": false,
"importOrder": [
"^react",
"^next",
"<THIRD_PARTY_MODULES>",
"",
"^@/(.*)$",
"",
"^~/(.*)$",
"",
"^[./]"
]
}
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2020 Abhishek Bhardwaj
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+3
View File
@@ -0,0 +1,3 @@
module.exports = {
extends: ['@commitlint/config-conventional'],
}
+30
View File
@@ -0,0 +1,30 @@
const nextJest = require('next/jest')
const createJestConfig = nextJest({
// Provide the path to your Next.js app to load next.config.js and .env files in your test environment
dir: './',
})
// Add any custom config to be passed to Jest
/** @type {import('jest').Config} */
const customJestConfig = {
setupFilesAfterEnv: ['<rootDir>/jest.setup.ts'],
moduleFileExtensions: ['js', 'jsx', 'ts', 'tsx'],
// if using TypeScript with a baseUrl set to the root directory then you need the snippet below for alias' to work
moduleDirectories: ['node_modules', '<rootDir>/'],
testEnvironment: 'jest-environment-jsdom',
testMatch: ['**/*.(test|spec).(js|jsx|ts|tsx)'],
coveragePathIgnorePatterns: ['/node_modules/'],
/**
* Absolute imports and module path aliases
*/
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/src/$1',
'^~/(.*)$': '<rootDir>/public/$1',
},
}
// createJestConfig is exported this way to ensure that next/jest can load the Next.js config which is async
module.exports = createJestConfig(customJestConfig)
+5
View File
@@ -0,0 +1,5 @@
import '@testing-library/jest-dom/jest-globals'
// Allow router mocks.
// eslint-disable-next-line no-undef, global-require
jest.mock('next/router', () => require('next-router-mock'))
+5
View File
@@ -0,0 +1,5 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
// NOTE: This file should not be edited
// see https://nextjs.org/docs/basic-features/typescript for more information.
+7
View File
@@ -0,0 +1,7 @@
/** @type {import('next').NextConfig} */
module.exports = {
poweredByHeader: false,
generateEtags: false,
reactStrictMode: true,
swcMinify: true,
}
+16923
View File
File diff suppressed because it is too large Load Diff
+82
View File
@@ -0,0 +1,82 @@
{
"name": "next-boilerplate-typescript-jest",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"export": "yarpm run build && next export",
"lint": "next lint",
"lint:fix": "next lint --fix",
"update-all-dependencies": "npx npm-check-updates -u",
"test:coverage": "yarpm run test --coverage",
"test:debug": "yarpm run test --debug --detectOpenHandles",
"test:ci": "yarpm run test --runInBand --no-cache --ci",
"test": "NODE_ENV=test jest --passWithNoTests",
"typecheck": "tsc --noEmit",
"clean": "rimraf out/",
"prepare": "is-ci || husky install",
"commit": "cz"
},
"dependencies": {
"@vercel/speed-insights": "^1.0.10",
"@xyflow/react": "^12.2.0",
"clsx": "^2.0.0",
"file-saver": "^2.0.5",
"is-ci": "^3.0.1",
"jszip": "^3.10.1",
"next": "^13.4.11",
"openai": "^4.57.0",
"posthog-js": "^1.120.2",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"uuid": "^10.0.0"
},
"devDependencies": {
"@commitlint/cli": "^17.7.1",
"@commitlint/config-conventional": "^17.7.0",
"@ianvs/prettier-plugin-sort-imports": "^4.1.0",
"@testing-library/jest-dom": "^6.1.2",
"@testing-library/react": "^14.0.0",
"@types/file-saver": "^2.0.7",
"@types/jest": "^29.5.4",
"@types/node": "^20.5.7",
"@types/react": "^18.2.21",
"@types/react-dom": "^18.2.7",
"@typescript-eslint/eslint-plugin": "^6.5.0",
"@typescript-eslint/parser": "^6.5.0",
"autoprefixer": "^10.4.15",
"commitizen": "^4.3.0",
"cssnano": "^6.0.1",
"cz-conventional-changelog": "^3.3.0",
"devmoji": "^2.3.0",
"eslint": "^8.48.0",
"eslint-config-airbnb": "19.0.4",
"eslint-config-airbnb-typescript": "^17.1.0",
"eslint-config-next": "^13.4.19",
"eslint-config-prettier": "^9.0.0",
"eslint-config-react-app": "^7.0.1",
"eslint-import-resolver-typescript": "^3.6.0",
"eslint-plugin-import": "^2.28.1",
"eslint-plugin-jest": "^27.2.3",
"eslint-plugin-jsx-a11y": "^6.7.1",
"eslint-plugin-prettier": "^5.0.0",
"eslint-plugin-react": "^7.33.2",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-sonarjs": "^0.21.0",
"eslint-plugin-unused-imports": "^3.0.0",
"husky": "^8.0.3",
"jest": "^29.6.4",
"jest-environment-jsdom": "^29.6.4",
"lint-staged": "^14.0.1",
"next-router-mock": "^0.9.9",
"npm-run-all": "^4.1.5",
"postcss": "^8.4.28",
"prettier": "^3.0.2",
"prettier-plugin-tailwindcss": "^0.5.3",
"rimraf": "^5.0.1",
"tailwindcss": "^3.3.3",
"typescript": "^5.2.2",
"yarpm": "^1.2.0"
}
}
+7
View File
@@ -0,0 +1,7 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
cssnano: {},
},
}
+1
View File
@@ -0,0 +1 @@
OPENAI_API_KEY=your_openai_api_key_here
+4
View File
@@ -0,0 +1,4 @@
{
"nodes": [],
"edges": []
}
+8
View File
@@ -0,0 +1,8 @@
from langchain.llms import OpenAI
class LLMManager:
def __init__(self):
self.llm = OpenAI()
def generate_response(self, prompt):
return self.llm(prompt)
+11
View File
@@ -0,0 +1,11 @@
from langgraph.graph import StateGraph
from langgraph.graph import END
from typing_extensions import TypedDict
# Function definitions will be generated based on the nodes
# Conditional functions will be generated based on the animated edges
# State class will be defined
# create_workflow function will be implemented
# Utility functions like returnGraph and run_sql_agent will be included
# The actual content will be generated when the user clicks the "Generate Code" button
+18
View File
@@ -0,0 +1,18 @@
from WorkFlow import create_workflow, run_sql_agent
def main():
# Initialize the workflow
workflow = create_workflow()
# Example input
input_data = {
# Add your input data here
}
# Run the workflow
result = run_sql_agent(input_data)
print("Workflow result:", result)
if __name__ == "__main__":
main()
+4
View File
@@ -0,0 +1,4 @@
langgraph
langchain
openai
python-dotenv
Binary file not shown.

After

Width:  |  Height:  |  Size: 249 KiB

+51
View File
@@ -0,0 +1,51 @@
# tailwind-react-next.js-typescript-eslint-jest-starter
Starter template for building a project using React, Typescript, Next.js, Jest, TailwindCSS and ESLint.
## Setup Instructions
1. Clone or download the project.
2. `cd` in the project directory.
3. If you cloned the project, make sure you remove the remote reference to this project by running `git remote rm origin`.
4. Copy `.env.example` to `.env` as that file is used to load up all your environment variables.
4. Run `yarn install` or `npm install` to install all dependencies.
## Commands
- `yarn dev`: To start a local development server.
- `yarn test`: To run the entire unit test suite using `jest`.
- `yarn test:ci`: To run tests on CI.
- `yarn lint`: To run the ESLint based linter to find out the issues in the project.
- `yarn lint:fix`: To autoformat all the issues.
- `yarn export`: Run this after running `yarn analyze` to export a build copy.
- `yarn production`: To export a production build. Use `yarn start` to serve that.
- `yarn upgrade --latest`: To upgrade all packages to their latest versions (could include breaking changes).
## Code Structure
All source code is located in the `src/` directory.
1. All Next.js entrypoints are housed in the `src/pages` directory as a default.
- Currently has `_app.tsx` which imports TailwindCSS.
- There's also a sample `index.tsx`.
**NOTE:** Feel free to move `pages` outside of `src/` if that's what you prefer. You'll just need to restart your local development server and everything should continue working as normal.
2. `src/components` are all stateless reusable components.
3. `src/css` folder is there just to house any CSS.
- Currently contains the TailwindCSS initialization CSS file.
4. All env variables are available in `.env` files (`.env` file isn't committed). Whenever you update `.env`, please update `.env.example` and `.env.test` and `next.config.js` to proxy all environment variables properly.
- You can access these variables in the app source code anywhere using `process.env.<VAR_NAME>`.
If you feel like changing the directory structure, please change the appropriate settings in the following files:
- `jest.config.js`
- `postcss.config.js`
- `tsconfig.json`
- The `lint` and the `lint:fix` scripts in `package.json`
# bicycle
+125
View File
@@ -0,0 +1,125 @@
import { type CustomNodeType } from '@/components/nodes'
import { type CustomEdgeType } from '@/components/edges'
export function generateLanggraphCode(
nodes: CustomNodeType[],
edges: CustomEdgeType[],
buttonTexts: { [key: string]: string },
): string {
// Helper function to get node label
const getNodeLabel = (nodeId: string) => {
const node = nodes.find((n) => n.id === nodeId)
const buttonText = buttonTexts[nodeId]
return (buttonText || (node?.data?.label as string) || nodeId).replace(/\s+/g, '_')
}
// Generate imports
const imports = [
'from langgraph.graph import StateGraph',
'from langgraph.graph import END',
'from typing_extensions import TypedDict',
'\n',
]
// Generate function definitions
const functions = nodes
.filter((node) => node.type !== 'source' && node.type !== 'end')
.map((node) => `def ${(node.data.label as string).replace(/\s+/g, '_')}(self, args) -> dict:\n return args\n`)
// Generate conditional functions
const conditionalFunctions = new Map()
edges
.filter((edge) => edge.animated)
.forEach((edge) => {
const sourceLabel = getNodeLabel(edge.source)
const targetLabel = getNodeLabel(edge.target)
if (!conditionalFunctions.has(sourceLabel)) {
conditionalFunctions.set(sourceLabel, new Set())
}
conditionalFunctions.get(sourceLabel).add(targetLabel)
})
const conditionalFunctionStrings = Array.from(conditionalFunctions.entries()).map(([sourceLabel, targets]) => {
const targetStrings = Array.from(targets)
.map((target) => ` # return "${target}"`)
.join('\n')
return `def conditional_${sourceLabel}(self, args) -> str:\n${targetStrings}\n return END\n`
})
// Generate State class
const stateClass = ['class State(TypedDict):', ' # add state', ' sample_state_variable: str', '\n']
// Generate create_workflow function
const workflowFunction = [
'def create_workflow(self) -> StateGraph:',
' """Create and configure the workflow graph."""',
' workflow = StateGraph(State) # add state',
'',
' # Add nodes to the graph',
]
nodes
.filter((node) => node.type !== 'source' && node.type !== 'end')
.forEach((node) => {
workflowFunction.push(
` workflow.add_node("${(node.data.label as string).replace(/\s+/g, '_')}", ${(
node.data.label as string
).replace(/\s+/g, '_')})`,
)
})
workflowFunction.push('', ' # Define edges')
const processedConditionalEdges = new Set()
edges.forEach((edge) => {
const sourceLabel = getNodeLabel(edge.source)
const targetLabel = getNodeLabel(edge.target)
if (edge.animated) {
if (!processedConditionalEdges.has(sourceLabel)) {
workflowFunction.push(` workflow.add_conditional_edges("${sourceLabel}", conditional_${sourceLabel})`)
processedConditionalEdges.add(sourceLabel)
}
} else {
if (targetLabel === 'end') {
workflowFunction.push(` workflow.add_edge("${sourceLabel}", END)`)
} else {
if (sourceLabel != 'source') workflowFunction.push(` workflow.add_edge("${sourceLabel}", "${targetLabel}")`)
}
}
})
const startNode = nodes.find((node) => {
const sourceNode = nodes.find((n) => n.type === 'source')
return edges.some((edge) => edge.source === sourceNode?.id && edge.target === node.id)
})
if (startNode) {
workflowFunction.push(` workflow.set_entry_point("${getNodeLabel(startNode.id)}")`)
}
workflowFunction.push('\n return workflow')
// Generate additional utility functions
const utilityFunctions = [
'def returnGraph(self):',
' """Return the graph."""',
' return self.create_workflow().compile()',
'',
'def run_sql_agent(self, args) -> dict:',
' """Run the SQL agent workflow."""',
' app = self.create_workflow().compile()',
' result = app.invoke(args)',
' return result',
]
// Combine all parts
const codeParts = [
...imports,
...functions,
...conditionalFunctionStrings,
...stateClass,
...workflowFunction,
...utilityFunctions,
]
return codeParts.join('\n')
}
+131
View File
@@ -0,0 +1,131 @@
import { type CustomNodeType } from '@/components/nodes'
import { type CustomEdgeType } from '@/components/edges'
export function generateLanggraphJS(
nodes: CustomNodeType[],
edges: CustomEdgeType[],
buttonTexts: { [key: string]: string },
): string {
// Helper function to get node label
const getNodeLabel = (nodeId: string) => {
const node = nodes.find((n) => n.id === nodeId)
const buttonText = buttonTexts[nodeId]
return (buttonText || (node?.data?.label as string) || nodeId).replace(/\s+/g, '_')
}
// JavaScript code generation
// Generate imports
const imports = [
"import { StateGraph, END, Annotation } from '@langchain/langgraph';",
"import { State, StateAnnotation } from './State';",
'',
]
// Generate class definition
const classDefinition = [
'export class WorkflowManager {',
' constructor() {',
' this.create_workflow = this.create_workflow.bind(this);',
' this.returnGraph = this.returnGraph.bind(this);',
' this.run_workflow = this.run_workflow.bind(this);',
' }',
'',
]
// Generate function definitions
const functions = nodes
.filter((node) => node.type !== 'source' && node.type !== 'end')
.map((node) => {
const functionName = (node.data.label as string).replace(/\s+/g, '_')
return ` ${functionName}(args) {\n return args;\n }\n`
})
// Generate conditional functions
const conditionalFunctions = new Map()
edges
.filter((edge) => edge.animated)
.forEach((edge) => {
const sourceLabel = getNodeLabel(edge.source)
const targetLabel = getNodeLabel(edge.target)
if (!conditionalFunctions.has(sourceLabel)) {
conditionalFunctions.set(sourceLabel, new Set())
}
conditionalFunctions.get(sourceLabel).add(targetLabel)
})
const conditionalFunctionStrings = Array.from(conditionalFunctions.entries()).map(([sourceLabel, targets]) => {
const targetStrings = Array.from(targets)
.map((target) => ` // return "${target}";`)
.join('\n')
return ` conditional_${sourceLabel}(args) {\n${targetStrings}\n return END;\n }\n`
})
// Generate create_workflow function
const workflowFunction = [' create_workflow() {', ' const workflow = new StateGraph(StateAnnotation)']
nodes
.filter((node) => node.type !== 'source' && node.type !== 'end')
.forEach((node) => {
const nodeLabel = (node.data.label as string).replace(/\s+/g, '_')
workflowFunction.push(` .addNode("${nodeLabel}", this.${nodeLabel})`)
})
workflowFunction.push('')
const processedConditionalEdges = new Set()
edges.forEach((edge) => {
const sourceLabel = getNodeLabel(edge.source)
const targetLabel = getNodeLabel(edge.target)
if (edge.animated) {
if (!processedConditionalEdges.has(sourceLabel)) {
workflowFunction.push(` .addConditionalEdges("${sourceLabel}", this.conditional_${sourceLabel})`)
processedConditionalEdges.add(sourceLabel)
}
} else {
if (targetLabel === 'end') {
workflowFunction.push(` .addEdge("${sourceLabel}", END)`)
} else {
if (sourceLabel !== 'source') workflowFunction.push(` .addEdge("${sourceLabel}", "${targetLabel}")`)
}
}
})
const startNode = nodes.find((node) => {
const sourceNode = nodes.find((n) => n.type === 'source')
return edges.some((edge) => edge.source === sourceNode?.id && edge.target === node.id)
})
if (startNode) {
workflowFunction.push(` .setEntryPoint("${getNodeLabel(startNode.id)}")`)
}
workflowFunction.push('\n return workflow;', ' }')
// Generate additional utility functions
const utilityFunctions = [
' returnGraph() {',
' return this.create_workflow().compile();',
' }',
'',
' async run_workflow(args) {',
' const app = this.create_workflow().compile();',
' const result = await app.invoke(args);',
' return result;',
' }',
]
// Combine all parts
const codeParts = [
...imports,
'',
...classDefinition,
...functions,
...conditionalFunctionStrings,
...workflowFunction,
'',
...utilityFunctions,
'}',
]
return codeParts.join('\n')
}
+8
View File
@@ -0,0 +1,8 @@
import { type CustomNodeType } from '@/components/nodes'
import { type CustomEdgeType } from '@/components/edges'
export interface CodeGenerationResult {
code: string
nodes: CustomNodeType[]
edges: CustomEdgeType[]
}
+245
View File
@@ -0,0 +1,245 @@
import { useCallback, useState, useRef, useEffect } from 'react'
import {
Background,
Controls,
ReactFlow,
addEdge,
useNodesState,
useEdgesState,
OnConnectStart,
type OnConnect,
useOnSelectionChange,
applyEdgeChanges,
applyNodeChanges,
type Node,
type Edge,
} from '@xyflow/react'
import { MarkerType } from '@xyflow/react'
import '@xyflow/react/dist/style.css'
import { initialNodes, nodeTypes, type CustomNodeType } from './nodes'
import { initialEdges, edgeTypes, type CustomEdgeType } from './edges'
import { generateLanggraphCode } from '../codeGeneration/generateLanggraph'
import { generateLanggraphJS } from '../codeGeneration/generateLanggraphJS'
import { CodeGenerationResult } from '../codeGeneration/types'
import { saveAs } from 'file-saver'
import JSZip from 'jszip'
import { useButtonText } from '@/contexts/ButtonTextContext'
import Modal from './Modal'
export default function App() {
const [nodes, setNodes, onNodesChange] = useNodesState<CustomNodeType>(initialNodes)
const [edges, setEdges, onEdgesChange] = useEdgesState<CustomEdgeType>(initialEdges)
const reactFlowWrapper = useRef<any>(null)
const [reactFlowInstance, setReactFlowInstance] = useState<any>(null)
const [isConnecting, setIsConnecting] = useState(false)
const [lastClickTime, setLastClickTime] = useState(0)
const [generatedCode, setGeneratedCode] = useState<CodeGenerationResult | null>(null)
const [showModal, setShowModal] = useState(false)
const [codeType, setCodeType] = useState<'js' | 'python' | null>(null)
const onConnectStart: OnConnectStart = useCallback(
(connection) => {
console.log('onConnectStart', connection)
setIsConnecting(true)
},
[nodes, setIsConnecting],
)
const onConnect: OnConnect = useCallback(
(connection) => {
console.log('onConnect', connection)
setEdges((edges) =>
addEdge({ ...connection, markerEnd: { type: MarkerType.ArrowClosed, width: 30, height: 30 } }, edges),
)
},
[setEdges, nodes],
)
const onChange = useCallback(
({ nodes, edges }: { nodes: Node[]; edges: Edge[] }) => {
console.log('Flow changed:', nodes, edges)
if (edges.length == 0) return
const currentTime = new Date().getTime()
if (currentTime - lastClickTime < 300) {
// Double-click detected (300ms threshold)
setEdges((edgs) =>
applyEdgeChanges(
[
{
type: 'remove',
id: edges[0].id,
},
],
edgs,
),
)
} else {
setEdges((edgs) =>
applyEdgeChanges(
[
{
type: 'replace',
id: edges[0].id,
item: {
...edges[0],
source: edges[0].source,
target: edges[0].target,
animated: !edges[0].animated,
selected: false,
},
},
],
edgs,
),
)
}
setLastClickTime(currentTime)
},
[edges, setEdges, lastClickTime],
)
useOnSelectionChange({ onChange })
const addNode = useCallback(
(event: React.MouseEvent) => {
if (isConnecting) {
setIsConnecting(false)
return
}
event.preventDefault()
if (reactFlowWrapper) {
const reactFlowBounds = reactFlowWrapper.current.getBoundingClientRect()
const position = reactFlowInstance.screenToFlowPosition({
x: event.clientX - reactFlowBounds.left,
y: event.clientY - reactFlowBounds.top,
})
const newNode: CustomNodeType = {
id: `node-${nodes.length + 1}`,
type: 'custom',
position,
selected: true,
data: { label: `Node ${nodes.length + 1}` },
}
setNodes((nodes) =>
applyNodeChanges(
[
{
type: 'add',
item: newNode,
},
],
nodes,
),
)
}
},
[nodes, setNodes, reactFlowInstance, reactFlowWrapper, isConnecting, applyNodeChanges],
)
const { buttonTexts } = useButtonText()
const generateCode = useCallback(() => {
const workflowCode = generateLanggraphJS(nodes, edges, buttonTexts)
setGeneratedCode({ code: workflowCode, nodes, edges })
}, [nodes, edges, buttonTexts])
const downloadZip = useCallback(() => {
if (!generatedCode) return
const zip = new JSZip()
const myAgent = zip.folder('my_agent')
myAgent!.file('WorkFlow.py', generatedCode.code)
myAgent!.file('main.py', `# main.py content`) // Add the content for main.py
myAgent!.file('LLMManager.py', `# LLMManager.py content`) // Add the content for LLMManager.py
zip.file('.env.example', `OPENAI_API_KEY=your_openai_api_key_here`)
zip.file('langgraph.json', JSON.stringify({ nodes, edges }, null, 2))
zip.file('requirements.txt', `langgraph\nlangchain\nopenai\npython-dotenv`)
zip.generateAsync({ type: 'blob' }).then((content) => {
saveAs(content, 'project.zip')
})
}, [generatedCode, nodes, edges])
const handleGenerateCode = () => {
setShowModal(true)
}
const handleCodeTypeSelection = (type: 'js' | 'python') => {
setCodeType(type)
setShowModal(false)
let generatedCode
if (type === 'js') {
generatedCode = generateLanggraphJS(nodes, edges, buttonTexts)
} else {
generatedCode = generateLanggraphCode(nodes, edges, buttonTexts)
}
setGeneratedCode({ code: generatedCode, nodes, edges })
}
console.log(nodes)
console.log(edges)
return (
<div ref={reactFlowWrapper} className='z-10 no-scrollbar' style={{ width: '100vw', height: '100vh' }}>
<ReactFlow<CustomNodeType, CustomEdgeType>
nodes={nodes}
nodeTypes={nodeTypes}
onNodesChange={onNodesChange}
edges={edges}
edgeTypes={edgeTypes}
onEdgesChange={onEdgesChange}
onConnect={onConnect}
onInit={setReactFlowInstance}
fitView
onConnectStart={onConnectStart}
onPaneClick={addNode}
className='z-10 bg-[#1a1c24]'
style={{
backgroundColor: '#1a1c24',
}}
>
<Background />
<Controls />
</ReactFlow>
<button
onClick={handleGenerateCode}
className='absolute bottom-4 right-4 bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded'
>
Generate Code
</button>
{showModal && <Modal onClose={() => setShowModal(false)} onSelect={handleCodeTypeSelection} />}
{generatedCode && (
<div className='absolute top-4 right-4 bg-white h-full overflow-y-scroll no-scrollbar p-4 rounded shadow-lg'>
<div className='absolute top-0 right-0 p-2 flex flex-row gap-2'>
<button
onClick={downloadZip}
className='bg-green-500 hover:bg-green-700 text-white font-bold py-1 px-2 rounded'
>
Download
</button>
<button
onClick={() => setGeneratedCode(null)}
className=' bg-red-500 hover:bg-red-700 text-white font-bold py-1 px-2 rounded'
>
Hide
</button>
</div>
<h3 className='text-lg font-bold mb-2'>Generated Code:</h3>
<pre className='bg-gray-100 p-2 rounded'>
<code>{generatedCode.code}</code>
</pre>
</div>
)}
</div>
)
}
+34
View File
@@ -0,0 +1,34 @@
import React from 'react'
interface ModalProps {
onClose: () => void
onSelect: (type: 'js' | 'python') => void
}
const Modal: React.FC<ModalProps> = ({ onClose, onSelect }) => {
return (
<div className='fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50'>
<div className='bg-white p-6 rounded-lg'>
<h2 className='text-xl font-bold mb-4'>Choose Code Type</h2>
<div className='flex space-x-4'>
<button
onClick={() => onSelect('js')}
className='bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded'
>
JavaScript
</button>
<button
onClick={() => onSelect('python')}
className='bg-green-500 hover:bg-green-700 text-white font-bold py-2 px-4 rounded'
>
Python
</button>
</div>
<button onClick={onClose} className='mt-4 text-gray-600 hover:text-gray-800'>
Cancel
</button>
</div>
</div>
)
}
export default Modal
+65
View File
@@ -0,0 +1,65 @@
import { BaseEdge, EdgeLabelRenderer, getBezierPath, useReactFlow, type EdgeProps, type Edge } from '@xyflow/react'
const buttonStyle = {
width: 20,
height: 20,
background: '#eee',
border: '1px solid #fff',
cursor: 'pointer',
borderRadius: '50%',
fontSize: '12px',
lineHeight: 1,
}
type ButtonEdgeData = {}
export type ButtonEdge = Edge<ButtonEdgeData>
export default function ButtonEdge({
id,
sourceX,
sourceY,
targetX,
targetY,
sourcePosition,
targetPosition,
style = {},
markerEnd,
}: EdgeProps<ButtonEdge>) {
const { setEdges } = useReactFlow()
const [edgePath, labelX, labelY] = getBezierPath({
sourceX,
sourceY,
sourcePosition,
targetX,
targetY,
targetPosition,
})
const onEdgeClick = () => {
setEdges((edges) => edges.filter((edge) => edge.id !== id))
}
return (
<>
<BaseEdge path={edgePath} markerEnd={markerEnd} style={style} />
<EdgeLabelRenderer>
<div
style={{
position: 'absolute',
transform: `translate(-50%, -50%) translate(${labelX}px,${labelY}px)`,
fontSize: 12,
// everything inside EdgeLabelRenderer has no pointer events by default
// if you have an interactive element, set pointer-events: all
pointerEvents: 'all',
}}
className='nodrag nopan'
>
<button style={buttonStyle} onClick={onEdgeClick}>
×
</button>
</div>
</EdgeLabelRenderer>
</>
)
}
+17
View File
@@ -0,0 +1,17 @@
import type { BuiltInEdge, Edge, EdgeTypes } from '@xyflow/react'
import ButtonEdge, { type ButtonEdge as ButtonEdgeType } from './ButtonEdge'
export const initialEdges = [
// { id: 'a->c', source: 'a', target: 'c', animated: true },
// { id: 'b->d', source: 'b', target: 'd', type: 'button-edge' },
// { id: 'c->d', source: 'c', target: 'd', animated: true },
] satisfies Edge[]
export const edgeTypes = {
// Add your custom edge types here!
'button-edge': ButtonEdge,
} satisfies EdgeTypes
// Append the types of you custom edges to the BuiltInEdge type
export type CustomEdgeType = BuiltInEdge | ButtonEdgeType
+13
View File
@@ -0,0 +1,13 @@
import Flow from './Flow'
import { ReactFlowProvider } from '@xyflow/react'
import { ButtonTextProvider } from '@/contexts/ButtonTextContext'
export default function Page() {
return (
<ReactFlowProvider>
<ButtonTextProvider>
<Flow />
</ButtonTextProvider>
</ReactFlowProvider>
)
}
+51
View File
@@ -0,0 +1,51 @@
import { Handle, Position } from '@xyflow/react'
import type { Node as NodeType, NodeProps } from '@xyflow/react'
import { useCallback, useState, useMemo } from 'react'
import Modal from '../Modal'
import { useButtonText } from '@/contexts/ButtonTextContext'
export type CustomNodeData = {
label: string
}
export type CustomNode = NodeType<CustomNodeData>
export default function CustomNode({ data, id }: NodeProps<CustomNode>) {
const [showModal, setShowModal] = useState(false)
const { buttonTexts, updateButtonText } = useButtonText()
const randomBorderColor = useMemo(() => {
return `#${Math.floor(Math.random() * 16777215).toString(16)}`
}, [])
const onClick = useCallback((event: React.MouseEvent) => {
console.log('onClick', event)
setShowModal(true)
}, [])
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
updateButtonText(id, e.target.value)
}
return (
<div
className=' rounded-md '
style={{ border: `2px solid ${randomBorderColor}`, backgroundColor: randomBorderColor }}
onClick={onClick}
>
<input
type='text'
className='w-full outline-none rounded-md text-center p-2 text-white'
value={buttonTexts[id] || data.label}
onChange={handleInputChange}
style={{
backgroundColor: `rgba(26,26,36,0.8)`,
color: randomBorderColor,
}}
/>
<Handle type='source' position={Position.Bottom} />
<Handle type='target' position={Position.Top} />
</div>
)
}
+23
View File
@@ -0,0 +1,23 @@
import { Handle, Position } from '@xyflow/react'
import type { Node, NodeProps } from '@xyflow/react'
import { useMemo } from 'react'
export type EndNode = Node
export default function EndNode() {
const randomBorderColor = useMemo(() => {
return `#${Math.floor(Math.random() * 16777215).toString(16)}`
}, [])
return (
<div
className=' rounded-3xl p-[0.5px] '
style={{ border: `1px solid ${randomBorderColor}`, backgroundColor: randomBorderColor }}
>
<div className='p-3 px-8 rounded-3xl' style={{ color: randomBorderColor, backgroundColor: `rgba(26,26,36,0.8)` }}>
__end__
</div>
<Handle type='target' position={Position.Top} />
</div>
)
}
@@ -0,0 +1,30 @@
import type { Node, NodeProps } from '@xyflow/react'
import { Handle, Position } from '@xyflow/react'
export type PositionLoggerNodeData = {
label?: string
}
export type PositionLoggerNode = Node<PositionLoggerNodeData>
export default function PositionLoggerNode({
positionAbsoluteX,
positionAbsoluteY,
data,
}: NodeProps<PositionLoggerNode>) {
const x = `${Math.round(positionAbsoluteX)}px`
const y = `${Math.round(positionAbsoluteY)}px`
return (
// We add this class to use the same styles as React Flow's default nodes.
<div className='react-flow__node-default'>
{data.label && <div>{data.label}</div>}
<div>
{x} {y}
</div>
<Handle type='source' position={Position.Bottom} />
</div>
)
}
+27
View File
@@ -0,0 +1,27 @@
import { Handle, Position } from '@xyflow/react'
import type { Node, NodeProps } from '@xyflow/react'
import { useMemo } from 'react'
export type SourceNodeData = {
label: string
}
export type SourceNode = Node<SourceNodeData>
export default function SourceNode({ data }: NodeProps<SourceNode>) {
const randomBorderColor = useMemo(() => {
return `#${Math.floor(Math.random() * 16777215).toString(16)}`
}, [])
return (
<div
className=' rounded-3xl p-[0.5px] '
style={{ border: `1px solid ${randomBorderColor}`, backgroundColor: randomBorderColor }}
>
<div className='p-3 px-8 rounded-3xl' style={{ color: randomBorderColor, backgroundColor: `rgba(26,26,36,0.8)` }}>
__start__
</div>
<Handle type='source' position={Position.Bottom} />
</div>
)
}
+44
View File
@@ -0,0 +1,44 @@
import type { BuiltInNode, Node, NodeTypes } from '@xyflow/react'
import PositionLoggerNode, { type PositionLoggerNode as PositionLoggerNodeType } from './PositionLoggerNode'
import SourceNode, { type SourceNode as SourceNodeType } from './SourceNode'
import CustomNode, { type CustomNode as CustomNodeDataType } from './CustomNode'
import EndNode, { type EndNode as EndNodeType } from './EndNode'
export const initialNodes = [
// { id: 'a', type: 'input', position: { x: 0, y: 0 }, data: { label: 'wire' } },
// {
// id: 'b',
// type: 'position-logger',
// position: { x: -100, y: 100 },
// data: { label: 'drag me!' },
// },
// { id: 'c', position: { x: 100, y: 100 }, data: { label: 'your ideas' } },
// {
// id: 'd',
// type: 'output',
// position: { x: 0, y: 200 },
// data: { label: 'with React Flow' },
// },
{
id: 'source',
type: 'source',
position: { x: 0, y: 0 },
data: { label: 'source' },
},
{
id: 'end',
type: 'end',
position: { x: 0, y: 600 },
data: { label: 'end' },
},
] satisfies Node[]
export const nodeTypes = {
'position-logger': PositionLoggerNode,
source: SourceNode,
custom: CustomNode,
end: EndNode,
} satisfies NodeTypes
// Append the types of you custom edges to the BuiltInNode type
export type CustomNodeType = BuiltInNode | PositionLoggerNodeType | SourceNodeType | CustomNodeDataType | EndNodeType
+26
View File
@@ -0,0 +1,26 @@
import React, { createContext, useState, useContext } from 'react'
type ButtonTextContextType = {
buttonTexts: { [key: string]: string }
updateButtonText: (id: string, text: string) => void
}
const ButtonTextContext = createContext<ButtonTextContextType | undefined>(undefined)
export const ButtonTextProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
const [buttonTexts, setButtonTexts] = useState<{ [key: string]: string }>({})
const updateButtonText = (id: string, text: string) => {
setButtonTexts((prev) => ({ ...prev, [id]: text }))
}
return <ButtonTextContext.Provider value={{ buttonTexts, updateButtonText }}>{children}</ButtonTextContext.Provider>
}
export const useButtonText = () => {
const context = useContext(ButtonTextContext)
if (context === undefined) {
throw new Error('useButtonText must be used within a ButtonTextProvider')
}
return context
}
+10
View File
@@ -0,0 +1,10 @@
/* eslint-disable react/jsx-props-no-spreading */
import React from 'react'
import { AppProps } from 'next/app'
import '@/styles/tailwind.css'
import { SpeedInsights } from '@vercel/speed-insights/next'
const App = ({ Component, pageProps: { session, ...pageProps } }: AppProps) => <Component {...pageProps} />
export default App
+20
View File
@@ -0,0 +1,20 @@
import type { NextPage } from 'next'
import Head from 'next/head'
import Page from '@/components'
const Home: NextPage = () => {
return (
<div>
<Head>
<title>Create Next App</title>
<meta name='description' content='Generated by create next app' />
<link rel='icon' href='/favicon.ico' />
</Head>
<Page />
</div>
)
}
export default Home
+48
View File
@@ -0,0 +1,48 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
:root {
--black: rgb(12, 3, 3);
--feather-grey: rgba(250, 250, 250, 1);
--grey: rgba(224, 224, 224, 1);
--primary: rgb(230, 224, 202);
--primarylight: rgb(151, 119, 246);
--shaddow: 0px 4px 4px 0px rgba(0, 0, 0, 0.09);
--variable-collection-light-primary: rgba(155, 120, 255, 1);
--variable-collection-primary: rgba(230, 118, 50, 1);
--font-family: 'Poppins', sans-serif;
}
@layer utilities {
/* Chrome, Safari and Opera */
.no-scrollbar::-webkit-scrollbar {
display: none;
}
.no-scrollbar {
-ms-overflow-style: none; /* IE and Edge */
scrollbar-width: none; /* Firefox */
}
}
@layer components {
.scrollbar::-webkit-scrollbar {
width: 15px;
height: 15px;
}
.scrollbar::-webkit-scrollbar-track {
border-radius: 100vh;
background: #f7f4ed;
}
.scrollbar::-webkit-scrollbar-thumb {
background: #e0cbcb;
border-radius: 100vh;
border: 3px solid #f6f7ed;
}
.scrollbar::-webkit-scrollbar-thumb:hover {
background: #c0a0b9;
}
}
+55
View File
@@ -0,0 +1,55 @@
export const createproject = async (project: any) => {
// user: {
// type: String,
// },
// projectname: {
// type: String,
// },
// productname: {
// type: String,
// },
// productlink: {
// type: String,
// },
// productdescription: {
// type: String,
// },
// postfilter: {
// type: String,
// },
// subreddits: {
// type: String,
// },
// keywords: {
// type: String,
// },
// postandreplyids: {
// type: Array,
// },
// updatedat: {
// type: Date,
// default: Date.now,
// },
const proj = {
user: project.user,
projectname: project.projectname,
productname: project.productname,
productlink: project.productlink,
productdescription: project.productdescription,
postfilter: project.postfilter,
subreddits: project.subreddits,
keywords: project.keywords,
postandreplyids: [],
updatedat: Date.now(),
}
const data = await fetch(`https://buzzgenius-backend.onrender.com/createproject`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(proj),
})
const res = await data.json()
return res
}
+19
View File
@@ -0,0 +1,19 @@
export const createuser = async (email: string) => {
const user = {
email: email,
projects: [],
history: [],
payment: 'free',
postsleft: 0,
}
if (email === 'srijanjain1207@gmail.com' || email === 'andrew@unitedwebworks.com') user.payment = 'individual'
const response = await fetch(`https://buzzgenius-backend.onrender.com/createuser`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(user),
})
const data = await response.json()
return data
}
+13
View File
@@ -0,0 +1,13 @@
// app.delete("/project/:id"
export const deleteproject = async (id: string) => {
const response = await fetch(`https://buzzgenius-backend.onrender.com/project/${id}`, {
method: 'DELETE',
headers: {
'Content-Type': 'application/json',
},
})
console.log('response', response)
const data = await response.json()
return data
}
+10
View File
@@ -0,0 +1,10 @@
export const getuserprojects = async (userid: string) => {
const response = await fetch(`https://buzzgenius-backend.onrender.com/userprojects/${userid}`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
})
const data = await response.json()
return data
}
+10
View File
@@ -0,0 +1,10 @@
export const postandreplies = async (projectid: any) => {
const response = await fetch(`https://buzzgenius-backend.onrender.com/postandreplies/${projectid}`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
})
const data = await response.json()
return data
}
+20
View File
@@ -0,0 +1,20 @@
// const FeedbackSchema = new mongoose.Schema({
// // feedback
// feedback: {
// type: String,
// },
// updatedat: {
// type: Date,
// default: Date.now,
// },
// })
export const savefeedback = async (feedback: string) => {
const response = await fetch(`https://buzzgenius-backend.onrender.com/feedback`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ feedback }),
})
}
+13
View File
@@ -0,0 +1,13 @@
// send email to https://buzzgenius-backend.onrender.com/verifyemail
//api endpoint with params token and email
export const signin = async (token: string) => {
const response = await fetch(`https://buzzgenius-backend.onrender.com/signin?token=${token}`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
})
return response.json()
}
+11
View File
@@ -0,0 +1,11 @@
export const trialreplies = async (trialproject: any) => {
const response = await fetch(`https://buzzgenius-backend.onrender.com/trialreplies`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(trialproject),
})
const data = await response.json()
return data
}
+13
View File
@@ -0,0 +1,13 @@
// send email to https://buzzgenius-backend.onrender.com/verifyemail
export const verifyemail = async (email: string) => {
console.log('email', email)
const response = await fetch('https://buzzgenius-backend.onrender.com/verifyemail', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ email: email }),
})
return response.text()
}
+30
View File
@@ -0,0 +1,30 @@
/* eslint-disable import/no-extraneous-dependencies */
const defaultTheme = require('tailwindcss/defaultTheme')
/** @type {import('tailwindcss').Config} */
module.exports = {
content: ['./pages/**/*.{js,jsx,ts,tsx}', './src/**/*.{js,jsx,ts,tsx}'],
theme: {
extend: {
colors: {
primary: {
50: '#eff6ff',
100: '#dbeafe',
200: '#bfdbfe',
300: '#93c5fd',
400: '#60a5fa',
500: '#3b82f6',
600: '#2563eb',
700: '#1d4ed8',
800: '#1e40af',
900: '#1e3a8a',
950: '#172554',
},
},
},
primary: 'var(--primary)',
black: 'var(--black)',
white: 'var(--white)',
},
plugins: [],
}
+8
View File
@@ -0,0 +1,8 @@
{
"extends": "./tsconfig",
"compilerOptions": {
"module": "commonjs",
"jsx": "react",
"types": ["jest", "node", "@testing-library/jest-dom"],
}
}
+46
View File
@@ -0,0 +1,46 @@
{
"compilerOptions": {
"target": "es5",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"types": ["jest", "node", "@testing-library/jest-dom"],
"baseUrl": ".",
"paths": {
"@/*": [
"./src/*"
],
"~/*": [
"./public/*"
],
// Types error: https://stackoverflow.com/a/73019448
"react": [
"./node_modules/@types/react"
]
},
"incremental": true
},
"exclude": [
"node_modules"
],
"include": [
"next-env.d.ts",
"**/*.js",
"**/*.jsx",
"**/*.ts",
"**/*.tsx"
]
}
+8672
View File
File diff suppressed because it is too large Load Diff