File size: 7,934 Bytes
7de6e4d
 
 
 
 
 
 
4505501
7de6e4d
 
1561d5f
7de6e4d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1561d5f
 
7de6e4d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1561d5f
7de6e4d
 
 
 
 
 
 
 
 
1561d5f
 
7de6e4d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
# agents/draft_writer.py

from typing import Any, Dict, Generator

from langchain.callbacks.base import BaseCallbackHandler
from langchain.chains import LLMChain
from langchain.prompts import PromptTemplate
from langchain_openai import OpenAI

from streaming_config import get_chunk_size, is_yield_enabled
import os

"""
LangChain LLMChain for writing a draft based on the outline and research notes with yield support.
"""
DRAFT_WRITER_PROMPT = """
You are an expert academic writer. Given a research paper outline and research notes, write a comprehensive draft of the paper. Use clear academic language and expand on each section of the outline.

Outline:
{outline}

Research notes:
{research_notes}

Instructions:
- Write a comprehensive draft that fully develops each section of the outline
- Use section headings and include inline citations like [1], [2] where appropriate
- Do not include a bibliography section
- Ensure the draft is complete and covers all points from the outline


Draft:
"""

def get_draft_writer_chain():
    """
    Returns a LangChain LLMChain for draft writing.
    """
    prompt = PromptTemplate(
        input_variables=["outline", "research_notes"],
        template=DRAFT_WRITER_PROMPT
    )
    
    # Always enable streaming in the LLM - callbacks will be passed during execution
    llm = OpenAI(
        temperature=0.3,
        openai_api_key=os.getenv("OPENAI_API_KEY"),
        streaming=True  # Always enable streaming
    )
    
    return LLMChain(llm=llm, prompt=prompt, output_key="draft")

def yield_draft_writing(outline: str, research_notes: str, preset: str = None) -> Generator[str, None, None]:
    """
    Yield draft writing results progressively
    
    Args:
        outline: The research paper outline
        research_notes: The research notes
        preset: Optional streaming preset
        
    Yields:
        str: Progressive draft content
    """
    if not is_yield_enabled(preset):
        # Fallback to non-yield processing
        chain = get_draft_writer_chain()
        result = chain.run(outline=outline, research_notes=research_notes)
        yield result
        return
    
    try:
        # Import required modules
        from langchain.prompts import PromptTemplate
        from langchain_openai import ChatOpenAI

        import os

        # Create prompt template
        prompt = PromptTemplate(
            input_variables=["outline", "research_notes"],
            template=DRAFT_WRITER_PROMPT
        )
        
        # Create LLM with streaming
        llm = ChatOpenAI(
            temperature=0.3,
            openai_api_key=os.getenv("OPENAI_API_KEY"),
            streaming=True
        )
        
        # Format the prompt
        formatted_prompt = prompt.format(outline=outline, research_notes=research_notes)
        
        # Get chunk size for this step
        chunk_size = get_chunk_size("draft_writer", preset)
        
        # Call LLM and yield results progressively
        result = llm.invoke(formatted_prompt)
        content = result.content
        
        # Yield content in chunks
        for i in range(0, len(content), chunk_size):
            chunk = content[i:i + chunk_size]
            yield chunk
            
    except Exception as e:
        yield f"Error in draft writing: {str(e)}"

def yield_draft_by_sections(outline: str, research_notes: str) -> Generator[str, None, None]:
    """
    Yield draft writing organized by sections
    
    Args:
        outline: The research paper outline
        research_notes: The research notes
        
    Yields:
        str: Progressive draft content by section
    """
    # Parse outline to extract sections
    sections = []
    lines = outline.split('\n')
    current_section = ""
    
    for line in lines:
        line = line.strip()
        if line and (line.startswith('#') or line.startswith('1.') or line.startswith('2.') or 
                    line.startswith('3.') or line.startswith('4.') or line.startswith('5.')):
            current_section = line
            sections.append(current_section)
    
    if not sections:
        # Fallback to single section
        yield "Writing complete draft..."
        for chunk in yield_draft_writing(outline, research_notes):
            yield chunk
        return
    
    yield f"Writing draft with {len(sections)} sections..."
    
    for i, section in enumerate(sections, 1):
        yield f"\n--- Section {i}: {section} ---"
        
        # Create section-specific prompt
        section_prompt = f"""
        Write the content for this specific section of the research paper:
        
        Section: {section}
        Full Outline: {outline}
        Research Notes: {research_notes}
        
        Focus on developing this section comprehensively.
        """
        
        # Process section with yield
        for chunk in yield_draft_writing(section_prompt, research_notes):
            yield chunk
        
        yield f"\n--- Section {i} Complete ---\n"

def yield_draft_with_style(outline: str, research_notes: str, style: str = "academic") -> Generator[str, None, None]:
    """
    Yield draft writing with specific style using yield generators
    
    Args:
        outline: The research paper outline
        research_notes: The research notes
        style: Writing style (academic, technical, accessible, etc.)
        
    Yields:
        str: Progressive draft content with specified style
    """
    style_instructions = {
        "academic": "Use formal academic language with proper citations and scholarly tone.",
        "technical": "Focus on technical details and methodology with precise terminology.",
        "accessible": "Use clear, accessible language suitable for broader audiences.",
        "concise": "Write in a concise, direct manner with minimal elaboration."
    }
    
    style_instruction = style_instructions.get(style, style_instructions["academic"])
    
    yield f"Writing draft in {style} style..."
    
    # Create style-enhanced prompt
    enhanced_prompt = f"""
    You are an expert academic writer. Given a research paper outline and research notes, write a comprehensive draft of the paper.
    
    Style requirement: {style_instruction}
    
    Outline:
    {outline}
    
    Research notes:
    {research_notes}
    
    Instructions:
    - Write a comprehensive draft that fully develops each section of the outline
    - Use section headings and include inline citations like [1], [2] where appropriate
    - Do not include a bibliography section
    - Ensure the draft is complete and covers all points from the outline
    - Follow the specified style: {style}
    
    Draft:
    """
    
    # Yield the enhanced draft writing
    for chunk in yield_draft_writing(enhanced_prompt, ""):
        yield chunk

def process_draft_with_revisions(outline: str, research_notes: str, revisions: list = None) -> Generator[str, None, None]:
    """
    Process draft writing with optional revision requests using yield generators
    
    Args:
        outline: The research paper outline
        research_notes: The research notes
        revisions: Optional list of revision requests
        
    Yields:
        str: Progressive draft content with revisions
    """
    if revisions:
        yield f"Applying {len(revisions)} revision requests..."
        
        # Apply revisions to the prompt
        revision_text = "\n".join([f"- {rev}" for rev in revisions])
        enhanced_prompt = f"""
        Outline: {outline}
        Research notes: {research_notes}
        
        Revision requests:
        {revision_text}
        
        Please incorporate these revision requests into the draft.
        """
    else:
        enhanced_prompt = f"Outline: {outline}\nResearch notes: {research_notes}"
    
    # Yield the enhanced draft writing
    for chunk in yield_draft_writing(enhanced_prompt, ""):
        yield chunk