article-introduction-generator 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- article_introduction_generator/__init__.py +1 -0
- article_introduction_generator/about.py +12 -0
- article_introduction_generator/desktop.py +103 -0
- article_introduction_generator/icons/logo.png +0 -0
- article_introduction_generator/modules/__init__.py +1 -0
- article_introduction_generator/modules/configure.py +59 -0
- article_introduction_generator/modules/consult.py +72 -0
- article_introduction_generator/modules/wabout.py +108 -0
- article_introduction_generator/program.py +993 -0
- article_introduction_generator/program_old.py +624 -0
- article_introduction_generator-0.1.0.dist-info/METADATA +59 -0
- article_introduction_generator-0.1.0.dist-info/RECORD +16 -0
- article_introduction_generator-0.1.0.dist-info/WHEEL +5 -0
- article_introduction_generator-0.1.0.dist-info/entry_points.txt +2 -0
- article_introduction_generator-0.1.0.dist-info/licenses/LICENSE +674 -0
- article_introduction_generator-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,624 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import sys
|
|
3
|
+
from PyQt5.QtWidgets import (
|
|
4
|
+
QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
|
|
5
|
+
QLabel, QTextEdit, QLineEdit, QPushButton, QFileDialog,
|
|
6
|
+
QTabWidget, QListWidget, QMessageBox, QStatusBar, QToolBar,
|
|
7
|
+
QComboBox, QScrollArea, QListWidgetItem
|
|
8
|
+
)
|
|
9
|
+
from PyQt5.QtCore import Qt
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
# ---------- Reusable Widgets ----------
|
|
13
|
+
|
|
14
|
+
class LabeledTextEdit(QWidget):
|
|
15
|
+
def __init__(self, label, tooltip=""):
|
|
16
|
+
super().__init__()
|
|
17
|
+
layout = QHBoxLayout()
|
|
18
|
+
self.label = QLabel(label)
|
|
19
|
+
self.text = QTextEdit()
|
|
20
|
+
self.text.setToolTip(tooltip)
|
|
21
|
+
self.text.setMinimumHeight(80)
|
|
22
|
+
layout.addWidget(self.label, 1)
|
|
23
|
+
layout.addWidget(self.text, 4)
|
|
24
|
+
self.setLayout(layout)
|
|
25
|
+
|
|
26
|
+
def get(self):
|
|
27
|
+
return self.text.toPlainText().strip()
|
|
28
|
+
|
|
29
|
+
def set(self, value):
|
|
30
|
+
self.text.setPlainText(value or "")
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class LabeledLineEdit(QWidget):
|
|
34
|
+
def __init__(self, label, tooltip=""):
|
|
35
|
+
super().__init__()
|
|
36
|
+
layout = QHBoxLayout()
|
|
37
|
+
self.label = QLabel(label)
|
|
38
|
+
self.line = QLineEdit()
|
|
39
|
+
self.line.setToolTip(tooltip)
|
|
40
|
+
layout.addWidget(self.label, 1)
|
|
41
|
+
layout.addWidget(self.line, 4)
|
|
42
|
+
self.setLayout(layout)
|
|
43
|
+
|
|
44
|
+
def get(self):
|
|
45
|
+
return self.line.text().strip()
|
|
46
|
+
|
|
47
|
+
def set(self, value):
|
|
48
|
+
self.line.setText(value or "")
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class StringListEditor(QWidget):
|
|
52
|
+
def __init__(self, label, tooltip=""):
|
|
53
|
+
super().__init__()
|
|
54
|
+
layout = QVBoxLayout()
|
|
55
|
+
title = QLabel(label)
|
|
56
|
+
title.setToolTip(tooltip)
|
|
57
|
+
self.list = QListWidget()
|
|
58
|
+
|
|
59
|
+
placeholder = QListWidgetItem("Click 'Add' to insert a new entry")
|
|
60
|
+
placeholder.setFlags(Qt.NoItemFlags) # não selecionável / não editável
|
|
61
|
+
placeholder.setForeground(Qt.gray)
|
|
62
|
+
self.list.addItem(placeholder)
|
|
63
|
+
|
|
64
|
+
self.list.setToolTip(tooltip)
|
|
65
|
+
|
|
66
|
+
btn_layout = QHBoxLayout()
|
|
67
|
+
add_btn = QPushButton("Add")
|
|
68
|
+
remove_btn = QPushButton("Remove")
|
|
69
|
+
btn_layout.addWidget(add_btn)
|
|
70
|
+
btn_layout.addWidget(remove_btn)
|
|
71
|
+
|
|
72
|
+
add_btn.clicked.connect(self.add_item)
|
|
73
|
+
remove_btn.clicked.connect(self.remove_item)
|
|
74
|
+
|
|
75
|
+
layout.addWidget(title)
|
|
76
|
+
layout.addWidget(self.list)
|
|
77
|
+
layout.addLayout(btn_layout)
|
|
78
|
+
self.setLayout(layout)
|
|
79
|
+
|
|
80
|
+
self.list.setEditTriggers(
|
|
81
|
+
self.list.DoubleClicked | self.list.SelectedClicked
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
def add_item(self, text=None):
|
|
85
|
+
from PyQt5.QtWidgets import QListWidgetItem
|
|
86
|
+
|
|
87
|
+
# Se o primeiro item for placeholder, remove
|
|
88
|
+
if self.list.count() == 1:
|
|
89
|
+
item0 = self.list.item(0)
|
|
90
|
+
if item0.flags() == Qt.NoItemFlags:
|
|
91
|
+
self.list.clear()
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
if not isinstance(text, str):
|
|
95
|
+
text = ""
|
|
96
|
+
|
|
97
|
+
item = QListWidgetItem(text)
|
|
98
|
+
item.setFlags(item.flags() | Qt.ItemIsEditable)
|
|
99
|
+
self.list.addItem(item)
|
|
100
|
+
self.list.editItem(item)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def remove_item(self):
|
|
104
|
+
for item in self.list.selectedItems():
|
|
105
|
+
self.list.takeItem(self.list.row(item))
|
|
106
|
+
|
|
107
|
+
if self.list.count() == 0:
|
|
108
|
+
self._add_placeholder()
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def get(self):
|
|
112
|
+
values = []
|
|
113
|
+
for i in range(self.list.count()):
|
|
114
|
+
item = self.list.item(i)
|
|
115
|
+
if not (item.flags() & Qt.ItemIsEditable):
|
|
116
|
+
continue
|
|
117
|
+
text = item.text().strip()
|
|
118
|
+
if text:
|
|
119
|
+
values.append(text)
|
|
120
|
+
return values
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def set(self, values):
|
|
124
|
+
self.list.clear()
|
|
125
|
+
|
|
126
|
+
if not values:
|
|
127
|
+
self._add_placeholder()
|
|
128
|
+
return
|
|
129
|
+
|
|
130
|
+
for v in values:
|
|
131
|
+
item = QListWidgetItem(v)
|
|
132
|
+
item.setFlags(item.flags() | Qt.ItemIsEditable)
|
|
133
|
+
self.list.addItem(item)
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def _add_placeholder(self):
|
|
137
|
+
placeholder = QListWidgetItem("Click 'Add' to insert a new entry")
|
|
138
|
+
placeholder.setFlags(Qt.NoItemFlags)
|
|
139
|
+
placeholder.setForeground(Qt.gray)
|
|
140
|
+
self.list.addItem(placeholder)
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
# ---------- Main Window ----------
|
|
145
|
+
|
|
146
|
+
class JsonIntroductionEditor(QMainWindow):
|
|
147
|
+
def __init__(self):
|
|
148
|
+
super().__init__()
|
|
149
|
+
self.setWindowTitle("Q1 Introduction JSON Editor")
|
|
150
|
+
self.resize(1100, 800)
|
|
151
|
+
|
|
152
|
+
self.current_path = None
|
|
153
|
+
|
|
154
|
+
self.references_data = {}
|
|
155
|
+
|
|
156
|
+
self.current_reference_key = None
|
|
157
|
+
|
|
158
|
+
self.tabs = QTabWidget()
|
|
159
|
+
self.setCentralWidget(self.tabs)
|
|
160
|
+
|
|
161
|
+
self._create_toolbar()
|
|
162
|
+
self._create_status_bar()
|
|
163
|
+
|
|
164
|
+
self._create_tabs()
|
|
165
|
+
self._apply_styles()
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
# ---------- UI ----------
|
|
169
|
+
def _apply_styles(self):
|
|
170
|
+
self.setStyleSheet("""
|
|
171
|
+
QListWidget {
|
|
172
|
+
border: 1px solid #999;
|
|
173
|
+
border-radius: 4px;
|
|
174
|
+
background-color: #f9f9f9;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
QListWidget::item {
|
|
178
|
+
padding: 4px;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
QListWidget::item:selected {
|
|
182
|
+
background-color: #cce5ff;
|
|
183
|
+
color: black;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
QTextEdit {
|
|
187
|
+
border: 1px solid #bbb;
|
|
188
|
+
border-radius: 4px;
|
|
189
|
+
background-color: #ffffff;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
QLineEdit {
|
|
193
|
+
border: 1px solid #bbb;
|
|
194
|
+
border-radius: 4px;
|
|
195
|
+
background-color: #ffffff;
|
|
196
|
+
padding: 2px;
|
|
197
|
+
}
|
|
198
|
+
QListWidget:empty {
|
|
199
|
+
background-color: #f9f9f9;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
QListWidget:empty::item {
|
|
203
|
+
color: #999;
|
|
204
|
+
}
|
|
205
|
+
""")
|
|
206
|
+
|
|
207
|
+
def _create_toolbar(self):
|
|
208
|
+
toolbar = QToolBar("Main Toolbar")
|
|
209
|
+
self.addToolBar(toolbar)
|
|
210
|
+
|
|
211
|
+
load_btn = QPushButton("Load JSON")
|
|
212
|
+
save_btn = QPushButton("Save JSON")
|
|
213
|
+
|
|
214
|
+
load_btn.clicked.connect(self.load_json)
|
|
215
|
+
save_btn.clicked.connect(self.save_json)
|
|
216
|
+
|
|
217
|
+
toolbar.addWidget(load_btn)
|
|
218
|
+
toolbar.addWidget(save_btn)
|
|
219
|
+
|
|
220
|
+
def _create_status_bar(self):
|
|
221
|
+
self.status = QStatusBar()
|
|
222
|
+
self.setStatusBar(self.status)
|
|
223
|
+
|
|
224
|
+
def _wrap_scroll(self, widget):
|
|
225
|
+
scroll = QScrollArea()
|
|
226
|
+
scroll.setWidgetResizable(True)
|
|
227
|
+
scroll.setWidget(widget)
|
|
228
|
+
return scroll
|
|
229
|
+
|
|
230
|
+
def _create_tabs(self):
|
|
231
|
+
self.tabs.addTab(self._wrap_scroll(self._paper_profile_tab()), "Paper Profile")
|
|
232
|
+
self.tabs.addTab(self._wrap_scroll(self._research_problem_tab()), "Research Problem")
|
|
233
|
+
self.tabs.addTab(self._wrap_scroll(self._contributions_tab()), "Contributions")
|
|
234
|
+
self.tabs.addTab(self._related_work_tab(), "Related Work")
|
|
235
|
+
self.tabs.addTab(self._wrap_scroll(self._writing_guidelines_tab()), "Writing Guidelines")
|
|
236
|
+
|
|
237
|
+
# ---------- Tabs ----------
|
|
238
|
+
|
|
239
|
+
def _paper_profile_tab(self):
|
|
240
|
+
w = QWidget()
|
|
241
|
+
layout = QVBoxLayout()
|
|
242
|
+
|
|
243
|
+
self.pp_title = LabeledLineEdit(
|
|
244
|
+
"Title",
|
|
245
|
+
"Full paper title."
|
|
246
|
+
)
|
|
247
|
+
self.pp_domain = LabeledLineEdit(
|
|
248
|
+
"Domain",
|
|
249
|
+
"Research domain, e.g., Computer Vision, NLP, Systems."
|
|
250
|
+
)
|
|
251
|
+
self.pp_journal = LabeledLineEdit(
|
|
252
|
+
"Target Journal",
|
|
253
|
+
"Intended journal (IEEE, Elsevier, ACM, etc.)."
|
|
254
|
+
)
|
|
255
|
+
self.pp_keywords = StringListEditor(
|
|
256
|
+
"Keywords",
|
|
257
|
+
"High-level keywords describing the paper."
|
|
258
|
+
)
|
|
259
|
+
self.pp_summary = LabeledTextEdit(
|
|
260
|
+
"Author Intended Summary",
|
|
261
|
+
"Human-written summary describing what the paper does and why."
|
|
262
|
+
)
|
|
263
|
+
|
|
264
|
+
for wdg in [self.pp_title, self.pp_domain, self.pp_journal, self.pp_keywords, self.pp_summary]:
|
|
265
|
+
layout.addWidget(wdg)
|
|
266
|
+
|
|
267
|
+
w.setLayout(layout)
|
|
268
|
+
return w
|
|
269
|
+
|
|
270
|
+
def _research_problem_tab(self):
|
|
271
|
+
w = QWidget()
|
|
272
|
+
layout = QVBoxLayout()
|
|
273
|
+
|
|
274
|
+
self.rp_overview = LabeledTextEdit(
|
|
275
|
+
"Research Domain Overview",
|
|
276
|
+
"General overview of the research domain and its importance."
|
|
277
|
+
)
|
|
278
|
+
self.rp_specific = LabeledTextEdit(
|
|
279
|
+
"Specific Problem",
|
|
280
|
+
"Precise formulation of the problem addressed."
|
|
281
|
+
)
|
|
282
|
+
self.rp_challenges = StringListEditor(
|
|
283
|
+
"Practical Challenges",
|
|
284
|
+
"Key practical or theoretical challenges."
|
|
285
|
+
)
|
|
286
|
+
self.rp_insufficient = LabeledTextEdit(
|
|
287
|
+
"Why Existing Solutions Are Insufficient",
|
|
288
|
+
"High-level human assessment without citing specific papers."
|
|
289
|
+
)
|
|
290
|
+
|
|
291
|
+
for wdg in [self.rp_overview, self.rp_specific, self.rp_challenges, self.rp_insufficient]:
|
|
292
|
+
layout.addWidget(wdg)
|
|
293
|
+
|
|
294
|
+
w.setLayout(layout)
|
|
295
|
+
return w
|
|
296
|
+
|
|
297
|
+
def _contributions_tab(self):
|
|
298
|
+
w = QWidget()
|
|
299
|
+
layout = QVBoxLayout()
|
|
300
|
+
|
|
301
|
+
self.contributions = StringListEditor(
|
|
302
|
+
"Contributions",
|
|
303
|
+
"Main contributions of the paper, one per entry."
|
|
304
|
+
)
|
|
305
|
+
|
|
306
|
+
layout.addWidget(self.contributions)
|
|
307
|
+
w.setLayout(layout)
|
|
308
|
+
return w
|
|
309
|
+
|
|
310
|
+
def _related_work_tab(self):
|
|
311
|
+
tabs = QTabWidget()
|
|
312
|
+
tabs.addTab(self._references_tab(), "References")
|
|
313
|
+
tabs.addTab(self._wrap_scroll(self._synthesis_tab()), "Human Curated Synthesis")
|
|
314
|
+
return tabs
|
|
315
|
+
|
|
316
|
+
def _references_tab(self):
|
|
317
|
+
w = QWidget()
|
|
318
|
+
layout = QHBoxLayout()
|
|
319
|
+
|
|
320
|
+
self.ref_list = QListWidget()
|
|
321
|
+
self.ref_list.setEditTriggers(
|
|
322
|
+
QListWidget.DoubleClicked | QListWidget.EditKeyPressed
|
|
323
|
+
)
|
|
324
|
+
self.ref_list.itemChanged.connect(self._on_reference_renamed)
|
|
325
|
+
self.ref_list.currentItemChanged.connect(self._load_reference)
|
|
326
|
+
|
|
327
|
+
# ---- Right panel (scrollable) ----
|
|
328
|
+
right_widget = QWidget()
|
|
329
|
+
right = QVBoxLayout()
|
|
330
|
+
right_widget.setLayout(right)
|
|
331
|
+
|
|
332
|
+
self.ref_bibtex = LabeledTextEdit("BibTeX", "BibTeX entry. This is the only source for citations.")
|
|
333
|
+
self.ref_abstract = LabeledTextEdit("Abstract", "Original abstract of the cited paper.")
|
|
334
|
+
self.ref_category = LabeledLineEdit("Methodological Category", "e.g., deep_learning, transformer_based, graph_based.")
|
|
335
|
+
self.ref_contribution = LabeledTextEdit("Central Technical Contribution", "Main technical idea introduced by this work.")
|
|
336
|
+
self.ref_strengths = StringListEditor("Author Reported Strengths", "Strengths explicitly claimed by the original authors.")
|
|
337
|
+
self.ref_limitations = StringListEditor("Reported Limitations", "Limitations discussed or implied by the paper.")
|
|
338
|
+
self.ref_relevance = LabeledTextEdit("Relevance to Our Work", "How this work relates to and differs from our paper.")
|
|
339
|
+
self.ref_role = LabeledLineEdit("Introduction Paragraph Role", "foundational, early_state_of_art, recent_advances, etc.")
|
|
340
|
+
|
|
341
|
+
for wdg in [
|
|
342
|
+
self.ref_bibtex, self.ref_abstract, self.ref_category,
|
|
343
|
+
self.ref_contribution, self.ref_strengths,
|
|
344
|
+
self.ref_limitations, self.ref_relevance, self.ref_role
|
|
345
|
+
]:
|
|
346
|
+
right.addWidget(wdg)
|
|
347
|
+
|
|
348
|
+
btns = QHBoxLayout()
|
|
349
|
+
add = QPushButton("Add Reference")
|
|
350
|
+
remove = QPushButton("Remove Reference")
|
|
351
|
+
btns.addWidget(add)
|
|
352
|
+
btns.addWidget(remove)
|
|
353
|
+
|
|
354
|
+
add.clicked.connect(self._add_reference)
|
|
355
|
+
remove.clicked.connect(self._remove_reference)
|
|
356
|
+
|
|
357
|
+
right.addLayout(btns)
|
|
358
|
+
|
|
359
|
+
scroll = QScrollArea()
|
|
360
|
+
scroll.setWidgetResizable(True)
|
|
361
|
+
scroll.setWidget(right_widget)
|
|
362
|
+
|
|
363
|
+
layout.addWidget(self.ref_list, 1)
|
|
364
|
+
layout.addWidget(scroll, 3)
|
|
365
|
+
|
|
366
|
+
w.setLayout(layout)
|
|
367
|
+
return w
|
|
368
|
+
|
|
369
|
+
def _on_reference_renamed(self, item: QListWidgetItem):
|
|
370
|
+
old_key = self.current_reference_key
|
|
371
|
+
new_key = item.text().strip()
|
|
372
|
+
|
|
373
|
+
if not old_key:
|
|
374
|
+
return
|
|
375
|
+
|
|
376
|
+
if not new_key:
|
|
377
|
+
QMessageBox.warning(self, "Invalid name", "Reference key cannot be empty.")
|
|
378
|
+
self.ref_list.blockSignals(True)
|
|
379
|
+
item.setText(old_key)
|
|
380
|
+
self.ref_list.blockSignals(False)
|
|
381
|
+
return
|
|
382
|
+
|
|
383
|
+
if new_key in self.references_data and new_key != old_key:
|
|
384
|
+
QMessageBox.warning(self, "Duplicate key", "This reference key already exists.")
|
|
385
|
+
self.ref_list.blockSignals(True)
|
|
386
|
+
item.setText(old_key)
|
|
387
|
+
self.ref_list.blockSignals(False)
|
|
388
|
+
return
|
|
389
|
+
|
|
390
|
+
self._save_current_reference()
|
|
391
|
+
|
|
392
|
+
self.references_data[new_key] = self.references_data.pop(old_key)
|
|
393
|
+
self.current_reference_key = new_key
|
|
394
|
+
|
|
395
|
+
|
|
396
|
+
def _synthesis_tab(self):
|
|
397
|
+
w = QWidget()
|
|
398
|
+
layout = QVBoxLayout()
|
|
399
|
+
|
|
400
|
+
self.syn_trends = StringListEditor(
|
|
401
|
+
"Common Trends",
|
|
402
|
+
"Observed trends across the literature."
|
|
403
|
+
)
|
|
404
|
+
self.syn_open = StringListEditor(
|
|
405
|
+
"Open Problems",
|
|
406
|
+
"Unresolved problems identified by the author."
|
|
407
|
+
)
|
|
408
|
+
self.syn_gap = LabeledTextEdit(
|
|
409
|
+
"Explicit Research Gap",
|
|
410
|
+
"Clear formulation of the research gap addressed by the paper."
|
|
411
|
+
)
|
|
412
|
+
|
|
413
|
+
for wdg in [self.syn_trends, self.syn_open, self.syn_gap]:
|
|
414
|
+
layout.addWidget(wdg)
|
|
415
|
+
|
|
416
|
+
w.setLayout(layout)
|
|
417
|
+
return w
|
|
418
|
+
|
|
419
|
+
def _writing_guidelines_tab(self):
|
|
420
|
+
w = QWidget()
|
|
421
|
+
layout = QVBoxLayout()
|
|
422
|
+
|
|
423
|
+
self.wg = LabeledTextEdit(
|
|
424
|
+
"Writing Guidelines",
|
|
425
|
+
"Explicit instructions to be followed by the LLM when generating text."
|
|
426
|
+
)
|
|
427
|
+
|
|
428
|
+
layout.addWidget(self.wg)
|
|
429
|
+
w.setLayout(layout)
|
|
430
|
+
return w
|
|
431
|
+
|
|
432
|
+
# ---------- Reference Helpers ----------
|
|
433
|
+
|
|
434
|
+
def _add_reference(self):
|
|
435
|
+
if self.references_data:
|
|
436
|
+
indices = []
|
|
437
|
+
for k in self.references_data.keys():
|
|
438
|
+
try:
|
|
439
|
+
indices.append(int(k.split("_")[1]))
|
|
440
|
+
except (IndexError, ValueError):
|
|
441
|
+
pass
|
|
442
|
+
next_idx = max(indices) + 1 if indices else 1
|
|
443
|
+
else:
|
|
444
|
+
next_idx = 1
|
|
445
|
+
|
|
446
|
+
key = f"ref_{next_idx}"
|
|
447
|
+
self.references_data[key] = {}
|
|
448
|
+
|
|
449
|
+
self.ref_list.blockSignals(True)
|
|
450
|
+
|
|
451
|
+
item = QListWidgetItem(key)
|
|
452
|
+
item.setFlags(item.flags() | Qt.ItemIsEditable)
|
|
453
|
+
self.ref_list.addItem(item)
|
|
454
|
+
self.ref_list.setCurrentItem(item)
|
|
455
|
+
|
|
456
|
+
self.current_reference_key = key
|
|
457
|
+
|
|
458
|
+
self.ref_list.blockSignals(False)
|
|
459
|
+
|
|
460
|
+
self._clear_reference_editor()
|
|
461
|
+
|
|
462
|
+
def _clear_reference_editor(self):
|
|
463
|
+
self.ref_bibtex.set("")
|
|
464
|
+
self.ref_abstract.set("")
|
|
465
|
+
self.ref_category.set("")
|
|
466
|
+
self.ref_contribution.set("")
|
|
467
|
+
self.ref_strengths.set([])
|
|
468
|
+
self.ref_limitations.set([])
|
|
469
|
+
self.ref_relevance.set("")
|
|
470
|
+
self.ref_role.set("")
|
|
471
|
+
|
|
472
|
+
def _remove_reference(self):
|
|
473
|
+
for item in self.ref_list.selectedItems():
|
|
474
|
+
key = item.text()
|
|
475
|
+
self.references_data.pop(key, None)
|
|
476
|
+
self.ref_list.takeItem(self.ref_list.row(item))
|
|
477
|
+
|
|
478
|
+
if key == self.current_reference_key:
|
|
479
|
+
self.current_reference_key = None
|
|
480
|
+
|
|
481
|
+
self._clear_reference_editor()
|
|
482
|
+
|
|
483
|
+
def _save_current_reference(self):
|
|
484
|
+
if not self.current_reference_key:
|
|
485
|
+
return
|
|
486
|
+
|
|
487
|
+
self.references_data[self.current_reference_key] = {
|
|
488
|
+
"bibtex": self.ref_bibtex.get(),
|
|
489
|
+
"abstract": self.ref_abstract.get(),
|
|
490
|
+
"methodological_category": self.ref_category.get(),
|
|
491
|
+
"central_technical_contribution": self.ref_contribution.get(),
|
|
492
|
+
"author_reported_strengths": self.ref_strengths.get(),
|
|
493
|
+
"reported_limitations": self.ref_limitations.get(),
|
|
494
|
+
"relevance_to_our_work": self.ref_relevance.get(),
|
|
495
|
+
"introduction_paragraph_role": self.ref_role.get(),
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
|
|
499
|
+
def _load_reference(self, current, previous):
|
|
500
|
+
if previous and self.current_reference_key:
|
|
501
|
+
self._save_current_reference()
|
|
502
|
+
|
|
503
|
+
if not current:
|
|
504
|
+
self.current_reference_key = None
|
|
505
|
+
return
|
|
506
|
+
|
|
507
|
+
self.ref_list.blockSignals(True)
|
|
508
|
+
|
|
509
|
+
self.current_reference_key = current.text()
|
|
510
|
+
ref = self.references_data.get(self.current_reference_key, {})
|
|
511
|
+
|
|
512
|
+
self.ref_bibtex.set(ref.get("bibtex"))
|
|
513
|
+
self.ref_abstract.set(ref.get("abstract"))
|
|
514
|
+
self.ref_category.set(ref.get("methodological_category"))
|
|
515
|
+
self.ref_contribution.set(ref.get("central_technical_contribution"))
|
|
516
|
+
self.ref_strengths.set(ref.get("author_reported_strengths", []))
|
|
517
|
+
self.ref_limitations.set(ref.get("reported_limitations", []))
|
|
518
|
+
self.ref_relevance.set(ref.get("relevance_to_our_work"))
|
|
519
|
+
self.ref_role.set(ref.get("introduction_paragraph_role"))
|
|
520
|
+
|
|
521
|
+
self.ref_list.blockSignals(False)
|
|
522
|
+
|
|
523
|
+
|
|
524
|
+
# ---------- Load / Save ----------
|
|
525
|
+
|
|
526
|
+
def load_json(self):
|
|
527
|
+
self._save_current_reference()
|
|
528
|
+
|
|
529
|
+
path, _ = QFileDialog.getOpenFileName(self, "Load JSON", "", "JSON Files (*.json)")
|
|
530
|
+
if not path:
|
|
531
|
+
return
|
|
532
|
+
|
|
533
|
+
with open(path, "r", encoding="utf-8") as f:
|
|
534
|
+
data = json.load(f)
|
|
535
|
+
|
|
536
|
+
self.current_path = path
|
|
537
|
+
self.status.showMessage(f"Loaded from {path}")
|
|
538
|
+
|
|
539
|
+
# ---- Paper Profile ----
|
|
540
|
+
pp = data.get("paper_profile", {})
|
|
541
|
+
self.pp_title.set(pp.get("title"))
|
|
542
|
+
self.pp_domain.set(pp.get("domain"))
|
|
543
|
+
self.pp_journal.set(pp.get("target_journal"))
|
|
544
|
+
self.pp_keywords.set(pp.get("keywords", []))
|
|
545
|
+
self.pp_summary.set(pp.get("author_intended_summary"))
|
|
546
|
+
|
|
547
|
+
# ---- Research Problem ----
|
|
548
|
+
rp = data.get("research_problem", {})
|
|
549
|
+
self.rp_overview.set(rp.get("research_domain_overview"))
|
|
550
|
+
self.rp_specific.set(rp.get("specific_problem"))
|
|
551
|
+
self.rp_challenges.set(rp.get("practical_challenges", []))
|
|
552
|
+
self.rp_insufficient.set(rp.get("why_existing_solutions_are_insufficient"))
|
|
553
|
+
|
|
554
|
+
# ---- Contributions ----
|
|
555
|
+
self.contributions.set(data.get("contributions", []))
|
|
556
|
+
|
|
557
|
+
# ---- Writing Guidelines ----
|
|
558
|
+
self.wg.set(data.get("writing_guidelines", ""))
|
|
559
|
+
|
|
560
|
+
# ---- Related Work: References ----
|
|
561
|
+
self.references_data = data.get("related_work", {}).get("references", {})
|
|
562
|
+
self.ref_list.clear()
|
|
563
|
+
|
|
564
|
+
for key in self.references_data.keys():
|
|
565
|
+
item = QListWidgetItem(key)
|
|
566
|
+
item.setFlags(item.flags() | Qt.ItemIsEditable)
|
|
567
|
+
self.ref_list.addItem(item)
|
|
568
|
+
|
|
569
|
+
# ---- Related Work: Human Curated Synthesis ----
|
|
570
|
+
synth = data.get("related_work", {}).get("human_curated_synthesis", {})
|
|
571
|
+
self.syn_trends.set(synth.get("common_trends", []))
|
|
572
|
+
self.syn_open.set(synth.get("open_problems", []))
|
|
573
|
+
self.syn_gap.set(synth.get("explicit_research_gap"))
|
|
574
|
+
|
|
575
|
+
self.current_reference_key = None
|
|
576
|
+
self._clear_reference_editor()
|
|
577
|
+
|
|
578
|
+
def save_json(self):
|
|
579
|
+
self._save_current_reference()
|
|
580
|
+
|
|
581
|
+
path, _ = QFileDialog.getSaveFileName(self, "Save JSON", "", "JSON Files (*.json)")
|
|
582
|
+
if not path:
|
|
583
|
+
return
|
|
584
|
+
|
|
585
|
+
data = {
|
|
586
|
+
"paper_profile": {
|
|
587
|
+
"title": self.pp_title.get(),
|
|
588
|
+
"domain": self.pp_domain.get(),
|
|
589
|
+
"target_journal": self.pp_journal.get(),
|
|
590
|
+
"keywords": self.pp_keywords.get(),
|
|
591
|
+
"author_intended_summary": self.pp_summary.get()
|
|
592
|
+
},
|
|
593
|
+
"research_problem": {
|
|
594
|
+
"research_domain_overview": self.rp_overview.get(),
|
|
595
|
+
"specific_problem": self.rp_specific.get(),
|
|
596
|
+
"practical_challenges": self.rp_challenges.get(),
|
|
597
|
+
"why_existing_solutions_are_insufficient": self.rp_insufficient.get()
|
|
598
|
+
},
|
|
599
|
+
"contributions": self.contributions.get(),
|
|
600
|
+
"related_work": {
|
|
601
|
+
"references": self.references_data,
|
|
602
|
+
"human_curated_synthesis": {
|
|
603
|
+
"common_trends": self.syn_trends.get(),
|
|
604
|
+
"open_problems": self.syn_open.get(),
|
|
605
|
+
"explicit_research_gap": self.syn_gap.get()
|
|
606
|
+
}
|
|
607
|
+
},
|
|
608
|
+
"writing_guidelines": self.wg.get()
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
with open(path, "w", encoding="utf-8") as f:
|
|
612
|
+
json.dump(data, f, indent=2)
|
|
613
|
+
|
|
614
|
+
self.current_path = path
|
|
615
|
+
self.status.showMessage(f"Saved to {path}")
|
|
616
|
+
|
|
617
|
+
|
|
618
|
+
# ---------- Main ----------
|
|
619
|
+
|
|
620
|
+
if __name__ == "__main__":
|
|
621
|
+
app = QApplication(sys.argv)
|
|
622
|
+
win = JsonIntroductionEditor()
|
|
623
|
+
win.show()
|
|
624
|
+
sys.exit(app.exec_())
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: article_introduction_generator
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Program to generate an introduction from a JSON File
|
|
5
|
+
Author-email: Fernando Pujaico Rivera <fernando.pujaico.rivera@gmail.com>
|
|
6
|
+
Maintainer-email: Fernando Pujaico Rivera <fernando.pujaico.rivera@gmail.com>
|
|
7
|
+
License-Expression: GPL-3.0-only WITH Classpath-exception-2.0 OR BSD-3-Clause
|
|
8
|
+
Project-URL: Bug Reports, https://github.com/trucomanx/ArticleIntroductionGenerator/issues
|
|
9
|
+
Project-URL: Funding, https://trucomanx.github.io/en/funding.html
|
|
10
|
+
Project-URL: Documentation, https://github.com/trucomanx/ArticleIntroductionGenerator/tree/main/doc
|
|
11
|
+
Project-URL: Source, https://github.com/trucomanx/ArticleIntroductionGenerator
|
|
12
|
+
Keywords: writing,article
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Requires-Python: >=3.8
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
License-File: LICENSE
|
|
18
|
+
Requires-Dist: PyQt5
|
|
19
|
+
Requires-Dist: deep-consultation
|
|
20
|
+
Dynamic: license-file
|
|
21
|
+
|
|
22
|
+
# article-introduction-generator
|
|
23
|
+
|
|
24
|
+
Program to generate an introduction from a JSON File
|
|
25
|
+
|
|
26
|
+

|
|
27
|
+
|
|
28
|
+
## 1. Installing
|
|
29
|
+
|
|
30
|
+
To install the package from [PyPI](https://pypi.org/project/article_introduction_generator/), follow the instructions below:
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
pip install --upgrade article_introduction_generator
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Execute `which article-introduction-generator` to see where it was installed, probably in `/home/USERNAME/.local/bin/article-introduction-generator`.
|
|
38
|
+
|
|
39
|
+
### Using
|
|
40
|
+
|
|
41
|
+
To start, use the command below:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
article-introduction-generator
|
|
45
|
+
```
|
|
46
|
+
## 2. More information
|
|
47
|
+
|
|
48
|
+
If you want more information go to [doc](https://github.com/trucomanx/ArticleIntroductionGenerator/blob/main/doc) directory.
|
|
49
|
+
|
|
50
|
+
## 3. Buy me a coffee
|
|
51
|
+
|
|
52
|
+
If you find this tool useful and would like to support its development, you can buy me a coffee!
|
|
53
|
+
Your donations help keep the project running and improve future updates.
|
|
54
|
+
|
|
55
|
+
[☕ Buy me a coffee](https://ko-fi.com/trucomanx)
|
|
56
|
+
|
|
57
|
+
## 4. License
|
|
58
|
+
|
|
59
|
+
This project is licensed under the GPL license. See the `LICENSE` file for more details.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
article_introduction_generator/__init__.py,sha256=ruULPQI7A5xxFhCYlc2-Yak7eGnabqCYTahYYvxbPtc,19
|
|
2
|
+
article_introduction_generator/about.py,sha256=AcHtUHiefZ0oxi2AvSjsR_hCKzh7unEql1g2JjWM9ms,611
|
|
3
|
+
article_introduction_generator/desktop.py,sha256=bpg1TeAzIKDvp5qUOs-1EogeYigir-gd7zPFVisTIZk,3528
|
|
4
|
+
article_introduction_generator/program.py,sha256=ahmioGH_riEgG7VV176vPrG2Mbf6DprKGrylO36qVyc,33863
|
|
5
|
+
article_introduction_generator/program_old.py,sha256=RqORCmqLYvTmIN0mMsXS3A3kJS-llmHXCh-vOxXkQqk,20212
|
|
6
|
+
article_introduction_generator/icons/logo.png,sha256=SE1ckm6RpcoheYDNrhxWPIszQCEwgGwe_xBfzZrVR4c,117312
|
|
7
|
+
article_introduction_generator/modules/__init__.py,sha256=ruULPQI7A5xxFhCYlc2-Yak7eGnabqCYTahYYvxbPtc,19
|
|
8
|
+
article_introduction_generator/modules/configure.py,sha256=K48SPidC_LRDXE2Q5QLGOG2-zPiMHjFgu4gv-3WWnns,1923
|
|
9
|
+
article_introduction_generator/modules/consult.py,sha256=La3Xgj9EVzIluylGggd3pzhkjLjsC-mnSdzC-Q8cOk0,2945
|
|
10
|
+
article_introduction_generator/modules/wabout.py,sha256=a8WOE9FJ9AdmbFioK17lqbR0cWavBSKhTzjrhsMJn10,4455
|
|
11
|
+
article_introduction_generator-0.1.0.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
12
|
+
article_introduction_generator-0.1.0.dist-info/METADATA,sha256=-zdxutpQfvGkr2R4zfmhgwCSIPuOUsWsGoHAkSlnxsI,2131
|
|
13
|
+
article_introduction_generator-0.1.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
14
|
+
article_introduction_generator-0.1.0.dist-info/entry_points.txt,sha256=aEZZr87sAlDrTi_6Xw26oKj2cd8uoujgov_TW_XYIqk,95
|
|
15
|
+
article_introduction_generator-0.1.0.dist-info/top_level.txt,sha256=MFgK4ElkA2Af3CwTC-IfN3XivimjUkmaobCF6Itt1o0,31
|
|
16
|
+
article_introduction_generator-0.1.0.dist-info/RECORD,,
|