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 - Rate limiting with request delay configuration
- File-based processing (JSON input/output) - File-based processing (JSON input/output)
- Customizable evaluation criteria - Customizable evaluation criteria
- Robust error handling with failure tracking
- Automatic dump file for failed analyses
## Installation ## Installation
@ -21,7 +19,7 @@ go get gitea.r8z.us/stwhite/paperprocessor
## API Reference ## API Reference
### ProcessFile ### 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 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 - outputPath: Path to write processing results JSON
- criteriaPath: Path to text file with evaluation criteria - criteriaPath: Path to text file with evaluation criteria
- config: Configuration settings for API and processing - config: Configuration settings for API and processing
- debug: Enable debug logging when true
Returns: Returns:
- error: Processing error or nil if successful - error: Processing error or nil if successful
@ -55,6 +54,7 @@ err := paperprocessor.ProcessFile(
"output/results.json", "output/results.json",
"criteria.txt", "criteria.txt",
config, config,
true, // debug mode
) )
if err != nil { if err != nil {
log.Fatal("Processing failed:", err) log.Fatal("Processing failed:", err)
@ -106,23 +106,10 @@ Evaluation criteria:
"decision": "REJECT", "decision": "REJECT",
"explanation": "Doesn't meet novelty requirements..." "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 ## Configuration Options
| Parameter | Description | Default | | Parameter | Description | Default |

View File

@ -8,6 +8,7 @@ import (
"net/http" "net/http"
"strings" "strings"
"time" "time"
"unicode"
) )
// Paper represents a single academic paper // Paper represents a single academic paper
@ -28,11 +29,6 @@ type PaperResult struct {
type ProcessingResult struct { type ProcessingResult struct {
Accepted []PaperResult `json:"accepted"` Accepted []PaperResult `json:"accepted"`
Rejected []PaperResult `json:"rejected"` 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 // 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) decision, err := p.evaluatePaper(paper, criteria)
if err != nil { if err != nil {
// Instead of returning error, add to failed list return nil, fmt.Errorf("error processing paper %s: %v", paper.ArxivID, err)
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
} }
paperResult := PaperResult{ 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 return result, nil
} }
@ -146,9 +124,8 @@ type decisionResult struct {
func (p *Processor) evaluatePaper(paper Paper, criteria string) (*decisionResult, error) { func (p *Processor) evaluatePaper(paper Paper, criteria string) (*decisionResult, error) {
prompt := fmt.Sprintf(`Please evaluate the following academic paper against the provided criteria. 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. Respond with either "ACCEPT" or "REJECT" followed by a brief 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 emphasis in your response. Keep your response clear and concise.
Do not use markdown, bullet points, or quotes in your response. Keep your response clear and concise.
Your response should be in the format: Your response should be in the format:
DECISION DECISION
Explanation Explanation
@ -223,16 +200,13 @@ Abstract: %s`, criteria, paper.Title, paper.Abstract)
// Clean and normalize decision // Clean and normalize decision
rawDecision := strings.TrimSpace(decisionLine) rawDecision := strings.TrimSpace(decisionLine)
// Handle common prefixes and clean the decision text // Remove "DECISION:" prefix if present and trim non-alphabetic characters
cleanDecision := rawDecision cleanDecision := strings.TrimPrefix(rawDecision, "DECISION:")
for _, prefix := range []string{"DECISION:", "Decision:", "-", "\"", "*"} { cleanDecision = strings.TrimFunc(cleanDecision, func(r rune) bool {
cleanDecision = strings.TrimPrefix(cleanDecision, prefix) return !unicode.IsLetter(r) && !unicode.IsNumber(r)
} })
cleanDecision = strings.TrimSpace(cleanDecision)
// Remove any remaining quotes
cleanDecision = strings.Trim(cleanDecision, "\"")
// Normalize case // Normalize case and check for valid decision
upperDecision := strings.ToUpper(cleanDecision) upperDecision := strings.ToUpper(cleanDecision)
var decision string var decision string
switch { switch {