Asks GPT to list its fixes

Signed-off-by: Mihovil Ilakovac <mihovil@ilakovac.com>
This commit is contained in:
Mihovil Ilakovac 2023-07-05 16:08:18 +02:00
parent 03c2f685fb
commit 8dba4f163f
6 changed files with 80 additions and 20 deletions

View File

@ -65,19 +65,19 @@ generateNewProject newProjectDetails waspProjectSkeletonFiles = do
-- do it blindly though, some of them are relevant only to plan (e.g. not generating login /
-- signup page), we would have to do some adapting.
writeToLog "Fixing any mistakes in Wasp file..."
fixWaspFile newProjectDetails waspFilePath plan
writeToLog "Wasp file fixed."
listOfWaspFileFixes <- fixWaspFile newProjectDetails waspFilePath plan
writeToLog $ appendFixes "Wasp file fixed." listOfWaspFileFixes
writeToLog "Fixing any mistakes in NodeJS operations files..."
forM_ (nub $ getOperationJsFilePath <$> (queries <> actions)) $ \opFp -> do
fixOperationsJsFile newProjectDetails waspFilePath opFp
writeToLog $ T.pack $ "Fixed NodeJS operations file '" <> opFp <> "'."
listOfFixes <- fixOperationsJsFile newProjectDetails waspFilePath opFp
writeToLog $ appendFixes ("Fixed NodeJS operations file '" <> T.pack opFp <> "'.") listOfFixes
writeToLog "NodeJS operations files fixed."
writeToLog "Fixing any mistakes in pages..."
forM_ (getPageComponentPath <$> pages) $ \pageFp -> do
fixPageComponent newProjectDetails waspFilePath pageFp
writeToLog $ T.pack $ "Fixed '" <> pageFp <> "' page."
listOfFixes <- fixPageComponent newProjectDetails waspFilePath pageFp
writeToLog $ appendFixes ("Fixed '" <> T.pack pageFp <> "' page.") listOfFixes
writeToLog "Pages fixed."
(promptTokensUsed, completionTokensUsed) <- getTotalTokensUsage
@ -106,3 +106,9 @@ generateNewProject newProjectDetails waspProjectSkeletonFiles = do
showT :: Show a => a -> Text
showT = T.pack . show
appendFixes :: Text -> Text -> Text
appendFixes text fixesText =
if T.null text
then fixesText
else text <> "\n" <> fixesText

View File

@ -5,11 +5,13 @@ module Wasp.AI.GenerateNewProject.OperationsJsFile
)
where
import Control.Monad (when)
import Data.Aeson (FromJSON)
import Data.Aeson.Types (ToJSON)
import Data.Maybe (fromMaybe)
import Data.Text (Text)
import qualified Data.Text as T
import Debug.Trace (trace)
import GHC.Generics (Generic)
import NeatInterpolation (trimming)
import Wasp.AI.CodeAgent (CodeAgent, getFile, writeToFile)
@ -22,8 +24,9 @@ import Wasp.AI.GenerateNewProject.Common.Prompts (appDescriptionBlock)
import qualified Wasp.AI.GenerateNewProject.Common.Prompts as Prompts
import Wasp.AI.GenerateNewProject.Operation (actionDocPrompt, queryDocPrompt)
import Wasp.AI.OpenAI.ChatGPT (ChatMessage (..), ChatRole (..))
import Wasp.Util.StringDiff (printTwoFiles)
fixOperationsJsFile :: NewProjectDetails -> FilePath -> FilePath -> CodeAgent ()
fixOperationsJsFile :: NewProjectDetails -> FilePath -> FilePath -> CodeAgent Text
fixOperationsJsFile newProjectDetails waspFilePath opJsFilePath = do
currentWaspFileContent <- fromMaybe (error "couldn't find wasp file") <$> getFile waspFilePath
currentOpJsFileContent <- fromMaybe (error "couldn't find operation js file to fix") <$> getFile opJsFilePath
@ -37,6 +40,17 @@ fixOperationsJsFile newProjectDetails waspFilePath opJsFilePath = do
ChatMessage {role = User, content = fixOpJsFilePrompt currentWaspFileContent currentOpJsFileContent}
]
writeToFile opJsFilePath (const $ opJsFileContent fixedOpJsFile)
when True
$ trace
( "=== Diff between old and new "
<> opJsFilePath
<> " operation: ===\n"
<> printTwoFiles (T.unpack currentOpJsFileContent) (T.unpack $ opJsFileContent fixedOpJsFile)
)
$ return ()
return $ listOfFixes fixedOpJsFile
where
fixOpJsFilePrompt currentWaspFileContent currentOpJsFileContent =
[trimming|
@ -81,11 +95,12 @@ fixOperationsJsFile newProjectDetails waspFilePath opJsFilePath = do
const { name, description } = arg;
```
With this in mind, generate a new, fixed NodeJS file with operations (${opJsFilePathText}).
List all of the fixes first and then generate a new, fixed NodeJS file with operations (${opJsFilePathText}).
The fixes should be a - prefixed list of lines, each line being a fix.
Don't do too big changes, like deleting or adding whole functions, focus on smaller things and those listed above.
DO NOT add new queries / actions to the file, or delete existing ones!
Do actual fixes, don't leave comments with "TODO"!
Please respond ONLY with a valid JSON of the format { opJsFileContent: string }.
Please respond ONLY with a valid JSON of the format { opJsFileContent: string, listOfFixes: string }.
There should be no other text in your response. Don't wrap content with the "```" code delimiters.
${appDescriptionBlockText}
@ -95,7 +110,8 @@ fixOperationsJsFile newProjectDetails waspFilePath opJsFilePath = do
opJsFilePathText = T.pack opJsFilePath
data OperationsJsFile = OperationsJsFile
{ opJsFileContent :: Text
{ opJsFileContent :: Text,
listOfFixes :: Text
}
deriving (Generic, Show)

View File

@ -5,10 +5,12 @@ module Wasp.AI.GenerateNewProject.PageComponentFile
)
where
import Control.Monad (when)
import Data.Aeson (FromJSON)
import Data.Maybe (fromMaybe)
import Data.Text (Text)
import qualified Data.Text as T
import Debug.Trace (trace)
import GHC.Generics (Generic)
import NeatInterpolation (trimming)
import Wasp.AI.CodeAgent (CodeAgent, getFile, writeToFile)
@ -21,8 +23,9 @@ import Wasp.AI.GenerateNewProject.Common.Prompts (appDescriptionBlock)
import qualified Wasp.AI.GenerateNewProject.Common.Prompts as Prompts
import Wasp.AI.GenerateNewProject.Page (pageDocPrompt)
import Wasp.AI.OpenAI.ChatGPT (ChatMessage (..), ChatRole (..))
import Wasp.Util.StringDiff (printTwoFiles)
fixPageComponent :: NewProjectDetails -> FilePath -> FilePath -> CodeAgent ()
fixPageComponent :: NewProjectDetails -> FilePath -> FilePath -> CodeAgent Text
fixPageComponent newProjectDetails waspFilePath pageComponentPath = do
currentWaspFileContent <- fromMaybe (error "couldn't find wasp file") <$> getFile waspFilePath
currentPageComponentContent <- fromMaybe (error "couldn't find page file to fix") <$> getFile pageComponentPath
@ -33,6 +36,17 @@ fixPageComponent newProjectDetails waspFilePath pageComponentPath = do
ChatMessage {role = User, content = fixPageComponentPrompt currentWaspFileContent currentPageComponentContent}
]
writeToFile pageComponentPath (const $ pageComponentImpl fixedPageComponent)
when True
$ trace
( "=== Diff between old and new "
<> pageComponentPath
<> " page component: ===\n"
<> printTwoFiles (T.unpack currentPageComponentContent) (T.unpack $ pageComponentImpl fixedPageComponent)
)
$ return ()
return $ listOfFixes fixedPageComponent
where
fixPageComponentPrompt currentWaspFileContent currentPageContent =
[trimming|
@ -70,9 +84,10 @@ fixPageComponent newProjectDetails waspFilePath pageComponentPath = do
- If there are any duplicate imports, make sure to remove them.
- There might be some invalid JS or JSX syntax -> fix it if there is any.
With this in mind, generate a new, fixed React component (${pageComponentPathText}).
List all of the fixes first and then generate a new, fixed React component (${pageComponentPathText}).
The fixes should be a - prefixed list of lines, each line being a fix.
Do actual fixes, don't leave comments with "TODO"!
Please respond ONLY with a valid JSON of the format { pageComponentImpl: string }.
Please respond ONLY with a valid JSON of the format { pageComponentImpl: string, listOfFixes: string }.
There should be no other text in your response. Don't wrap content with the "```" code delimiters.
${appDescriptionBlockText}
@ -82,7 +97,8 @@ fixPageComponent newProjectDetails waspFilePath pageComponentPath = do
pageComponentPathText = T.pack pageComponentPath
data PageComponent = PageComponent
{ pageComponentImpl :: Text
{ pageComponentImpl :: Text,
listOfFixes :: Text
}
deriving (Generic, Show)

View File

@ -5,6 +5,7 @@ module Wasp.AI.GenerateNewProject.WaspFile
)
where
import Control.Monad (when)
import Control.Monad.IO.Class (liftIO)
import Data.Aeson (FromJSON)
import Data.Aeson.Types (ToJSON)
@ -13,6 +14,7 @@ import Data.List (intercalate)
import Data.Maybe (fromMaybe)
import Data.Text (Text)
import qualified Data.Text as T
import Debug.Trace (trace)
import GHC.Generics (Generic)
import NeatInterpolation (trimming)
import Wasp.AI.CodeAgent (CodeAgent, getFile, writeToFile)
@ -28,8 +30,9 @@ import Wasp.AI.OpenAI.ChatGPT (ChatMessage (..), ChatRole (..))
import Wasp.Analyzer.Parser.Ctx (Ctx (..))
import Wasp.Project.Analyze (analyzeWaspFileContent)
import qualified Wasp.Util.Aeson as Utils.Aeson
import Wasp.Util.StringDiff (printTwoFiles)
fixWaspFile :: NewProjectDetails -> FilePath -> Plan -> CodeAgent ()
fixWaspFile :: NewProjectDetails -> FilePath -> Plan -> CodeAgent Text
fixWaspFile newProjectDetails waspFilePath plan = do
currentWaspFileContent <- getFile waspFilePath <&> fromMaybe (error "couldn't find wasp file to fix")
@ -37,18 +40,28 @@ fixWaspFile newProjectDetails waspFilePath plan = do
-- to give chatGPT opportunity to fix some other stuff we mention in the prompt.
-- Then, we do two more attempts at fixing, but only if there are compiler errors.
fixedWaspFile <-
pure (WaspFile {waspFileContent = currentWaspFileContent})
pure (WaspFile {waspFileContent = currentWaspFileContent, listOfFixes = ""})
>>= askChatGptToFixWaspFile EvenIfNoCompileErrors
>>= askChatGptToFixWaspFile OnlyIfCompileErrors
>>= askChatGptToFixWaspFile OnlyIfCompileErrors
writeToFile waspFilePath (const $ waspFileContent fixedWaspFile)
when True
$ trace
( "=== Diff between old and new "
<> "main.wasp ===\n"
<> printTwoFiles (T.unpack currentWaspFileContent) (T.unpack $ waspFileContent fixedWaspFile)
)
$ return ()
return $ listOfFixes fixedWaspFile
where
askChatGptToFixWaspFile :: ShouldContinueIfCompileErrors -> WaspFile -> CodeAgent WaspFile
askChatGptToFixWaspFile shouldContinueIfCompileErrors WaspFile {waspFileContent = wfContent} = do
compileErrors <- liftIO $ getWaspFileCompileErrors wfContent
case shouldContinueIfCompileErrors of
OnlyIfCompileErrors | null compileErrors -> return $ WaspFile {waspFileContent = wfContent}
OnlyIfCompileErrors | null compileErrors -> return $ WaspFile {waspFileContent = wfContent, listOfFixes = ""}
_otherwise ->
queryChatGPTForJSON
defaultChatGPTParamsForFixing
@ -125,12 +138,13 @@ fixWaspFile newProjectDetails waspFilePath plan = do
- I noticed that you sometimes by accident add redundant "}" at the end of the Wasp file while fixing it.
Be careful not to do that.
With this in mind, generate a new, fixed wasp file.
List all of the fixes first and then generate a new, fixed wasp file.
The fixes should be a - prefixed list of lines, each line being a fix.
Try not to do big changes like changing names, removing/adding declarations and similar, those are usually correct, focus more on obvious, smaller errors.
Don't touch `app` declaration, `Login` page, and `Signup` page.
Do actual fixes, don't leave comments with "TODO"!
Make extra sure to fix compiler errors, if there are any.
Please respond ONLY with a valid JSON of the format { waspFileContent: string }.
Please respond ONLY with a valid JSON of the format { waspFileContent: string, listOfFixes: string }.
There should be no other text in your response. Don't wrap content with the "```" code delimiters.
${appDescriptionBlockText}
@ -150,7 +164,8 @@ getWaspFileCompileErrors waspSource =
showCompileError (errMsg, Ctx {ctxSourceRegion = loc}) = show loc <> ": " <> errMsg
data WaspFile = WaspFile
{ waspFileContent :: Text
{ waspFileContent :: Text,
listOfFixes :: Text
}
deriving (Generic, Show)

View File

@ -0,0 +1,6 @@
module Wasp.Util.StringDiff where
data DiffType = Same | Different
printTwoFiles :: String -> String -> String
printTwoFiles text1 text2 = "=== First ===\n" ++ text1 ++ "\n=== Second ===\n" ++ text2 ++ "\n=== End ===\n"

View File

@ -353,6 +353,7 @@ library
Wasp.Util.Network.HTTP
Wasp.Util.Network.Socket
Wasp.Util.Terminal
Wasp.Util.StringDiff
Wasp.Version
Wasp.WaspignoreFile