mirror of
https://github.com/comfyanonymous/ComfyUI.git
synced 2026-04-15 04:52:31 +08:00
feat: add ReviewImport and ReviewAtomize nodes
This commit is contained in:
parent
8140dac594
commit
dc952f6daf
@ -18,7 +18,11 @@ class ResearchExtension(ComfyExtension):
|
||||
from custom_nodes.research.methods_draft import MethodsDraft
|
||||
from custom_nodes.research.consistency_check import ConsistencyCheck
|
||||
from custom_nodes.research.export_manuscript import ExportManuscript
|
||||
return [PaperSearch, PaperClaimExtract, ClaimEvidenceAssemble, StyleProfileExtract, ReferencePaperSelect, SectionPlan, AbstractDraft, IntroductionDraft, MethodsDraft, ConsistencyCheck, ExportManuscript]
|
||||
from custom_nodes.research.review_import import ReviewImport
|
||||
from custom_nodes.research.review_atomize import ReviewAtomize
|
||||
from custom_nodes.research.review_classify import ReviewClassify
|
||||
from custom_nodes.research.review_map import ReviewMap
|
||||
return [PaperSearch, PaperClaimExtract, ClaimEvidenceAssemble, StyleProfileExtract, ReferencePaperSelect, SectionPlan, AbstractDraft, IntroductionDraft, MethodsDraft, ConsistencyCheck, ExportManuscript, ReviewImport, ReviewAtomize, ReviewClassify, ReviewMap]
|
||||
|
||||
|
||||
async def comfy_entrypoint() -> ComfyExtension:
|
||||
|
||||
109
custom_nodes/research/review_atomize.py
Normal file
109
custom_nodes/research/review_atomize.py
Normal file
@ -0,0 +1,109 @@
|
||||
# custom_nodes/research/review_atomize.py
|
||||
"""ReviewAtomize node - split review into atomic items."""
|
||||
import json
|
||||
import re
|
||||
from typing_extensions import override
|
||||
from comfy_api.latest import ComfyNode, io
|
||||
|
||||
|
||||
class ReviewAtomize(io.ComfyNode):
|
||||
"""Split review text into atomic feedback items."""
|
||||
|
||||
@classmethod
|
||||
def define_schema(cls) -> io.Schema:
|
||||
return io.Schema(
|
||||
node_id="ReviewAtomize",
|
||||
display_name="Atomize Review",
|
||||
category="Research",
|
||||
inputs=[
|
||||
io.String.Input(
|
||||
"raw_review",
|
||||
display_name="Raw Review (JSON)",
|
||||
default="{}",
|
||||
multiline=True,
|
||||
),
|
||||
io.Int.Input(
|
||||
"min_severity",
|
||||
display_name="Min Severity to Extract",
|
||||
default=1,
|
||||
min=1,
|
||||
max=3,
|
||||
step=1,
|
||||
),
|
||||
],
|
||||
outputs=[
|
||||
io.String.Output(display_name="Review Items (JSON)"),
|
||||
],
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def execute(cls, raw_review: str, min_severity: int) -> io.NodeOutput:
|
||||
try:
|
||||
review = json.loads(raw_review) if raw_review else {}
|
||||
except json.JSONDecodeError:
|
||||
review = {"original_text": raw_review}
|
||||
|
||||
original_text = review.get("original_text", "")
|
||||
paragraphs = review.get("paragraphs", [])
|
||||
|
||||
items = []
|
||||
item_id = 1
|
||||
|
||||
# Common reviewer phrases that indicate feedback
|
||||
feedback_patterns = [
|
||||
(r"the (?:paper|method|approach|model|results?|experiments?) (?:is|are|should|could|may|might) (.+)", "methodology"),
|
||||
(r"(?:it is|this is|there is) (?:not|rarely|insufficiently) (.+)", "gap"),
|
||||
(r"(?:more|additional|further) (.+) (?:is|are) needed", "missing"),
|
||||
(r"(?:unclear|confusing|vague|ambiguous) (.+)", "clarity"),
|
||||
(r"(?:incorrect|inaccurate|wrong|error) (.+)", "error"),
|
||||
(r"(?:major|significant|critical|important) (.+)", "major"),
|
||||
(r"(?:minor|small|small) (.+)", "minor"),
|
||||
(r"see (?:Section|Figure|Table) (\d+)", "reference"),
|
||||
]
|
||||
|
||||
# Split by sentence and extract items
|
||||
sentences = re.split(r'(?<=[.!?])\s+', original_text)
|
||||
|
||||
for sentence in sentences:
|
||||
sentence = sentence.strip()
|
||||
if len(sentence) < 20: # Skip very short sentences
|
||||
continue
|
||||
|
||||
# Classify the item
|
||||
item_type = "general"
|
||||
severity = 1
|
||||
|
||||
sentence_lower = sentence.lower()
|
||||
|
||||
if any(w in sentence_lower for w in ["major", "significant", "critical", "important", "must"]):
|
||||
severity = 3
|
||||
item_type = "major_concern"
|
||||
elif any(w in sentence_lower for w in ["minor", "small", "suggestion"]):
|
||||
severity = 1
|
||||
item_type = "suggestion"
|
||||
elif any(w in sentence_lower for w in ["unclear", "confusing", "vague", "ambiguous"]):
|
||||
severity = 2
|
||||
item_type = "clarity"
|
||||
elif any(w in sentence_lower for w in ["error", "incorrect", "wrong", "mistake"]):
|
||||
severity = 3
|
||||
item_type = "error"
|
||||
elif any(w in sentence_lower for w in ["missing", "lacking", "insufficient", "not enough"]):
|
||||
severity = 2
|
||||
item_type = "missing_info"
|
||||
|
||||
if severity >= min_severity:
|
||||
items.append({
|
||||
"id": f"item_{item_id}",
|
||||
"text": sentence,
|
||||
"type": item_type,
|
||||
"severity": severity,
|
||||
"quoted_claims": [],
|
||||
})
|
||||
item_id += 1
|
||||
|
||||
result = {
|
||||
"total_items": len(items),
|
||||
"items": items,
|
||||
}
|
||||
|
||||
return io.NodeOutput(review_items=json.dumps(result, indent=2))
|
||||
48
custom_nodes/research/review_import.py
Normal file
48
custom_nodes/research/review_import.py
Normal file
@ -0,0 +1,48 @@
|
||||
# custom_nodes/research/review_import.py
|
||||
"""ReviewImport node - import review text."""
|
||||
import json
|
||||
from typing_extensions import override
|
||||
from comfy_api.latest import ComfyNode, io
|
||||
|
||||
|
||||
class ReviewImport(io.ComfyNode):
|
||||
"""Import reviewer feedback text for analysis."""
|
||||
|
||||
@classmethod
|
||||
def define_schema(cls) -> io.Schema:
|
||||
return io.Schema(
|
||||
node_id="ReviewImport",
|
||||
display_name="Import Review",
|
||||
category="Research",
|
||||
inputs=[
|
||||
io.String.Input(
|
||||
"review_text",
|
||||
display_name="Review Text",
|
||||
default="",
|
||||
multiline=True,
|
||||
),
|
||||
io.String.Input(
|
||||
"reviewer_role",
|
||||
display_name="Reviewer Role",
|
||||
default="reviewer",
|
||||
),
|
||||
],
|
||||
outputs=[
|
||||
io.String.Output(display_name="Raw Review (JSON)"),
|
||||
],
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def execute(cls, review_text: str, reviewer_role: str) -> io.NodeOutput:
|
||||
if not review_text.strip():
|
||||
return io.NodeOutput(raw_review=json.dumps({"error": "No review text provided"}))
|
||||
|
||||
# Parse the review into structured format
|
||||
raw_review = {
|
||||
"reviewer_role": reviewer_role,
|
||||
"original_text": review_text,
|
||||
"paragraphs": [p.strip() for p in review_text.split("\n\n") if p.strip()],
|
||||
"word_count": len(review_text.split()),
|
||||
}
|
||||
|
||||
return io.NodeOutput(raw_review=json.dumps(raw_review, indent=2))
|
||||
Loading…
Reference in New Issue
Block a user