Compare commits

..

No commits in common. "v0.1.7" and "main" have entirely different histories.
v0.1.7 ... main

3 changed files with 13 additions and 53 deletions

1
.gitignore vendored
View File

@ -1 +0,0 @@
*.swp

View File

@ -9,8 +9,6 @@ Go package for automated evaluation of academic papers using LLM-based criteria
- Rate limiting with request delay configuration
- File-based processing (JSON input/output)
- Customizable evaluation criteria
- Robust error handling with failure tracking
- Automatic dump file for failed analyses
## Installation
@ -21,7 +19,7 @@ go get gitea.r8z.us/stwhite/paperprocessor
## API Reference
### ProcessFile
`func ProcessFile(inputPath, outputPath, criteriaPath string, config Config) error`
`func ProcessFile(inputPath, outputPath, criteriaPath string, config Config, debug bool) error`
Processes papers from input JSON file and writes results to output JSON file
@ -30,6 +28,7 @@ Parameters:
- outputPath: Path to write processing results JSON
- criteriaPath: Path to text file with evaluation criteria
- config: Configuration settings for API and processing
- debug: Enable debug logging when true
Returns:
- error: Processing error or nil if successful
@ -55,6 +54,7 @@ err := paperprocessor.ProcessFile(
"output/results.json",
"criteria.txt",
config,
true, // debug mode
)
if err != nil {
log.Fatal("Processing failed:", err)
@ -106,23 +106,10 @@ Evaluation criteria:
"decision": "REJECT",
"explanation": "Doesn't meet novelty requirements..."
}
],
"failed": [
{
"paper": {
"title": "Problematic Paper",
"abstract": "...",
"arxiv_id": "2301.11111"
},
"error": "invalid decision format",
"output": ""
}
]
}
```
When papers fail processing, they are added to the "failed" list in the output JSON and also written to a `dump.json` file for detailed review.
## Configuration Options
| Parameter | Description | Default |

View File

@ -8,6 +8,7 @@ import (
"net/http"
"strings"
"time"
"unicode"
)
// Paper represents a single academic paper
@ -28,11 +29,6 @@ type PaperResult struct {
type ProcessingResult struct {
Accepted []PaperResult `json:"accepted"`
Rejected []PaperResult `json:"rejected"`
Failed []struct {
Paper Paper `json:"paper"`
Error string `json:"error"`
Output string `json:"output"`
} `json:"failed"`
}
// Config holds the configuration for the processor
@ -84,17 +80,7 @@ func (p *Processor) ProcessPapers(papers []Paper, criteria string) (*ProcessingR
}
decision, err := p.evaluatePaper(paper, criteria)
if err != nil {
// Instead of returning error, add to failed list
result.Failed = append(result.Failed, struct {
Paper Paper `json:"paper"`
Error string `json:"error"`
Output string `json:"output"`
}{
Paper: paper,
Error: err.Error(),
Output: "", // We could potentially add the raw LLM output here if needed
})
continue
return nil, fmt.Errorf("error processing paper %s: %v", paper.ArxivID, err)
}
paperResult := PaperResult{
@ -110,14 +96,6 @@ func (p *Processor) ProcessPapers(papers []Paper, criteria string) (*ProcessingR
}
}
// Write failed analyses to dump file if any exist
if len(result.Failed) > 0 {
dumpData, err := json.MarshalIndent(result.Failed, "", " ")
if err == nil { // Only try to write if marshaling succeeded
ioutil.WriteFile("dump.json", dumpData, 0644)
}
}
return result, nil
}
@ -146,9 +124,8 @@ type decisionResult struct {
func (p *Processor) evaluatePaper(paper Paper, criteria string) (*decisionResult, error) {
prompt := fmt.Sprintf(`Please evaluate the following academic paper against the provided criteria.
Respond with either "ACCEPT" or "REJECT" followed by an explanation of your decision.
For ACCEPT decisions, provide a thorough explanation. For REJECT decisions, keep the explanation brief and focused on the key reason.
Do not use markdown, bullet points, or quotes in your response. Keep your response clear and concise.
Respond with either "ACCEPT" or "REJECT" followed by a brief explanation of your decision.
Do not use markdown emphasis in your response. Keep your response clear and concise.
Your response should be in the format:
DECISION
Explanation
@ -223,16 +200,13 @@ Abstract: %s`, criteria, paper.Title, paper.Abstract)
// Clean and normalize decision
rawDecision := strings.TrimSpace(decisionLine)
// Handle common prefixes and clean the decision text
cleanDecision := rawDecision
for _, prefix := range []string{"DECISION:", "Decision:", "-", "\"", "*"} {
cleanDecision = strings.TrimPrefix(cleanDecision, prefix)
}
cleanDecision = strings.TrimSpace(cleanDecision)
// Remove any remaining quotes
cleanDecision = strings.Trim(cleanDecision, "\"")
// Remove "DECISION:" prefix if present and trim non-alphabetic characters
cleanDecision := strings.TrimPrefix(rawDecision, "DECISION:")
cleanDecision = strings.TrimFunc(cleanDecision, func(r rune) bool {
return !unicode.IsLetter(r) && !unicode.IsNumber(r)
})
// Normalize case
// Normalize case and check for valid decision
upperDecision := strings.ToUpper(cleanDecision)
var decision string
switch {