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.methods_draft import MethodsDraft
|
||||||
from custom_nodes.research.consistency_check import ConsistencyCheck
|
from custom_nodes.research.consistency_check import ConsistencyCheck
|
||||||
from custom_nodes.research.export_manuscript import ExportManuscript
|
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:
|
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