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 @@
|
|
|
1
|
+
#!/usr/bin/python3
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# about.py
|
|
2
|
+
|
|
3
|
+
__version__ = "0.1.0"
|
|
4
|
+
__package__ = "article_introduction_generator"
|
|
5
|
+
__program_name__ = "article-introduction-generator"
|
|
6
|
+
__author__ = "Fernando Pujaico Rivera"
|
|
7
|
+
__email__ = "fernando.pujaico.rivera@gmail.com"
|
|
8
|
+
__description__ = "Program to generate an introduction from a JSON File"
|
|
9
|
+
__url_source__ = "https://github.com/trucomanx/ArticleIntroductionGenerator"
|
|
10
|
+
__url_doc__ = "https://github.com/trucomanx/ArticleIntroductionGenerator/tree/main/doc"
|
|
11
|
+
__url_funding__ = "https://trucomanx.github.io/en/funding.html"
|
|
12
|
+
__url_bugs__ = "https://github.com/trucomanx/ArticleIntroductionGenerator/issues"
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import article_introduction_generator.about as about
|
|
3
|
+
import subprocess
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def update_desktop_database(desktop_path):
|
|
7
|
+
applications_dir = os.path.expanduser(desktop_path)
|
|
8
|
+
try:
|
|
9
|
+
subprocess.run(
|
|
10
|
+
["update-desktop-database", applications_dir],
|
|
11
|
+
check=True
|
|
12
|
+
)
|
|
13
|
+
print("Shortcut database updated successfully.")
|
|
14
|
+
except subprocess.CalledProcessError as e:
|
|
15
|
+
print(f"Error updating the database: {e}")
|
|
16
|
+
except FileNotFoundError:
|
|
17
|
+
print("The command 'update-desktop-database' was not found. Verify that the package 'desktop-file-utils' is installed.")
|
|
18
|
+
|
|
19
|
+
def create_desktop_file(desktop_path, overwrite=False, program_name=None):
|
|
20
|
+
base_dir_path = os.path.dirname(os.path.abspath(__file__))
|
|
21
|
+
icon_path = os.path.join(base_dir_path, 'icons', 'logo.png')
|
|
22
|
+
|
|
23
|
+
if program_name is None:
|
|
24
|
+
__program_name = about.__program_name__
|
|
25
|
+
else:
|
|
26
|
+
__program_name = program_name
|
|
27
|
+
|
|
28
|
+
script_path = os.path.expanduser(f"~/.local/bin/{__program_name}")
|
|
29
|
+
|
|
30
|
+
desktop_entry = f"""[Desktop Entry]
|
|
31
|
+
Name={__program_name}
|
|
32
|
+
Comment={about.__description__}
|
|
33
|
+
Exec={script_path}
|
|
34
|
+
Terminal=false
|
|
35
|
+
Type=Application
|
|
36
|
+
Icon={icon_path}
|
|
37
|
+
StartupNotify=true
|
|
38
|
+
Categories=Education;ResearchTools;
|
|
39
|
+
Keywords=organizer;python;
|
|
40
|
+
Encoding=UTF-8
|
|
41
|
+
StartupWMClass={about.__package__}
|
|
42
|
+
"""
|
|
43
|
+
path = os.path.expanduser(os.path.join(desktop_path,f"{__program_name}.desktop"))
|
|
44
|
+
|
|
45
|
+
if not os.path.exists(path) or overwrite == True:
|
|
46
|
+
os.makedirs(os.path.dirname(path), exist_ok=True)
|
|
47
|
+
with open(path, "w") as f:
|
|
48
|
+
f.write(desktop_entry)
|
|
49
|
+
os.chmod(path, 0o755)
|
|
50
|
+
print(f"File {__program_name}.desktop created in {path}.")
|
|
51
|
+
update_desktop_database(desktop_path)
|
|
52
|
+
|
|
53
|
+
def create_desktop_directory( directory_name = "ResearchTools",
|
|
54
|
+
long_name = "Scientific research",
|
|
55
|
+
comment = "Tools for Writing and Research Support",
|
|
56
|
+
icon = "accessories-text-editor",
|
|
57
|
+
overwrite = False):
|
|
58
|
+
|
|
59
|
+
desktop_entry = f"""[Desktop Entry]
|
|
60
|
+
Version=1.0
|
|
61
|
+
Type=Directory
|
|
62
|
+
Name={long_name}
|
|
63
|
+
Comment={comment}
|
|
64
|
+
Icon={icon}
|
|
65
|
+
"""
|
|
66
|
+
path = os.path.expanduser(f"~/.local/share/desktop-directories/{directory_name}.directory")
|
|
67
|
+
|
|
68
|
+
if not os.path.exists(path) or overwrite == True: # Evita sobrescrever
|
|
69
|
+
os.makedirs(os.path.dirname(path), exist_ok=True)
|
|
70
|
+
with open(path, "w") as f:
|
|
71
|
+
f.write(desktop_entry)
|
|
72
|
+
os.chmod(path, 0o755)
|
|
73
|
+
print(f"File {path} created.")
|
|
74
|
+
|
|
75
|
+
def create_desktop_menu(directory_name = "ResearchTools",
|
|
76
|
+
basename = "research-tools",
|
|
77
|
+
overwrite = False):
|
|
78
|
+
|
|
79
|
+
desktop_entry = f"""<!-- ~/.config/menus/applications-merged/{basename}.menu -->
|
|
80
|
+
<Menu>
|
|
81
|
+
<Name>Applications</Name>
|
|
82
|
+
<Menu>
|
|
83
|
+
<Name>{directory_name}</Name>
|
|
84
|
+
<Directory>{directory_name}.directory</Directory>
|
|
85
|
+
<Include>
|
|
86
|
+
<Category>{directory_name}</Category>
|
|
87
|
+
</Include>
|
|
88
|
+
</Menu>
|
|
89
|
+
</Menu>
|
|
90
|
+
"""
|
|
91
|
+
path = os.path.expanduser(f"~/.config/menus/applications-merged/{basename}.menu")
|
|
92
|
+
|
|
93
|
+
if not os.path.exists(path) or overwrite == True: # Evita sobrescrever
|
|
94
|
+
os.makedirs(os.path.dirname(path), exist_ok=True)
|
|
95
|
+
with open(path, "w") as f:
|
|
96
|
+
f.write(desktop_entry)
|
|
97
|
+
print(f"File {path} created.")
|
|
98
|
+
|
|
99
|
+
if __name__ == '__main__':
|
|
100
|
+
create_desktop_menu()
|
|
101
|
+
create_desktop_directory()
|
|
102
|
+
create_desktop_file()
|
|
103
|
+
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/python3
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import json
|
|
3
|
+
|
|
4
|
+
def verify_default_config(path,default_content={}):
|
|
5
|
+
"""
|
|
6
|
+
Cria o arquivo JSON no caminho especificado com conteúdo padrão,
|
|
7
|
+
criando diretórios intermediários se necessário.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
# Se o arquivo não existir, cria com o conteúdo padrão
|
|
11
|
+
if not os.path.exists(path):
|
|
12
|
+
# Garante que os diretórios existam
|
|
13
|
+
os.makedirs(os.path.dirname(path), exist_ok=True)
|
|
14
|
+
with open(path, 'w', encoding='utf-8') as f:
|
|
15
|
+
json.dump(default_content, f, ensure_ascii=False, indent=4)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def merge_defaults(config, defaults):
|
|
19
|
+
"""
|
|
20
|
+
Adiciona valores de defaults que não existam em config.
|
|
21
|
+
Funciona recursivamente para dicionários aninhados.
|
|
22
|
+
"""
|
|
23
|
+
for key, value in defaults.items():
|
|
24
|
+
if key not in config:
|
|
25
|
+
config[key] = value
|
|
26
|
+
elif isinstance(value, dict) and isinstance(config[key], dict):
|
|
27
|
+
merge_defaults(config[key], value)
|
|
28
|
+
return config
|
|
29
|
+
|
|
30
|
+
# Lê o JSON no início do programa
|
|
31
|
+
def load_config(config_path, default_content=None):
|
|
32
|
+
"""
|
|
33
|
+
Carrega o JSON de configuração e preenche com valores padrão se necessário.
|
|
34
|
+
"""
|
|
35
|
+
config = {}
|
|
36
|
+
if os.path.exists(config_path):
|
|
37
|
+
with open(config_path, 'r', encoding='utf-8') as f:
|
|
38
|
+
try:
|
|
39
|
+
config = json.load(f)
|
|
40
|
+
except json.JSONDecodeError:
|
|
41
|
+
print("Erro ao ler config, usando defaults")
|
|
42
|
+
config = {}
|
|
43
|
+
|
|
44
|
+
if default_content:
|
|
45
|
+
config = merge_defaults(config, default_content)
|
|
46
|
+
|
|
47
|
+
return config
|
|
48
|
+
|
|
49
|
+
def save_config(path,content):
|
|
50
|
+
"""
|
|
51
|
+
Cria o arquivo JSON no caminho especificado com conteúdo padrão,
|
|
52
|
+
criando diretórios intermediários se necessário.
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
# Garante que os diretórios existam
|
|
56
|
+
os.makedirs(os.path.dirname(path), exist_ok=True)
|
|
57
|
+
with open(path, 'w', encoding='utf-8') as f:
|
|
58
|
+
json.dump(content, f, ensure_ascii=False, indent=4)
|
|
59
|
+
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
|
|
2
|
+
import json
|
|
3
|
+
from deep_consultation.core import consult_with_deepchat
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
SYSTEM_PROMPT = """
|
|
7
|
+
You are an expert scientific writer specialized in Q1 Computer Science journals
|
|
8
|
+
(e.g., IEEE TPAMI, CVPR, ICCV, NeurIPS, Elsevier Pattern Recognition).
|
|
9
|
+
|
|
10
|
+
Your task is to generate the INTRODUCTION section of a research paper.
|
|
11
|
+
|
|
12
|
+
Strict rules:
|
|
13
|
+
1. You must rely exclusively on the information provided in the user input JSON.
|
|
14
|
+
2. You must NOT invent citations, methods, datasets, claims, or results.
|
|
15
|
+
3. All mentions of prior work must be grounded in the provided
|
|
16
|
+
related_work.references entries.
|
|
17
|
+
4. The introduction must seamlessly integrate background, state of the art,
|
|
18
|
+
critical analysis, and motivation.
|
|
19
|
+
5. The tone must match a top-tier Q1 journal: formal, precise, and concise.
|
|
20
|
+
6. No bullet points. No section headers. Only well-structured academic paragraphs.
|
|
21
|
+
7. Do NOT describe the JSON or its structure in the output.
|
|
22
|
+
8. Follow all instructions contained in the "writing_guidelines" field if present.
|
|
23
|
+
9. Do not use exactly the same text sent in JSON, try to use your own words to avoid plagiarism problems.
|
|
24
|
+
|
|
25
|
+
You must write as a human researcher, not as an assistant.
|
|
26
|
+
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
USER_PROMPT = """
|
|
30
|
+
Using the JSON below, write the complete INTRODUCTION section of the paper.
|
|
31
|
+
|
|
32
|
+
Structural requirements:
|
|
33
|
+
- Paragraph 1: General context of the topic.
|
|
34
|
+
Broad research domain overview and importance
|
|
35
|
+
(use research_problem.research_domain_overview).
|
|
36
|
+
- Paragraph 2: Specific problem within the topic that the text focuses on.
|
|
37
|
+
Narrow down to the specific problem and practical challenges
|
|
38
|
+
(use research_problem.specific_problem and practical_challenges).
|
|
39
|
+
- Paragraphs 3–4: Integrated state of the art discussion.
|
|
40
|
+
Organize cited works according to their introduction_paragraph_role
|
|
41
|
+
(foundational → early_state_of_art → recent_advances).
|
|
42
|
+
Highlight limitations where relevant.
|
|
43
|
+
Use LaTeX-style bibliographic formatting for citations in the bibliography.
|
|
44
|
+
- Paragraph 5: Synthesize common trends and open problems using
|
|
45
|
+
related_work.human_curated_synthesis.
|
|
46
|
+
- Final paragraph: Proposed solution of paper.
|
|
47
|
+
Explicitly state the research gap and position the paper’s
|
|
48
|
+
contributions as a response to this gap.
|
|
49
|
+
|
|
50
|
+
Use the author_intended_summary to guide emphasis and narrative flow.
|
|
51
|
+
Integrate the contributions naturally into the motivation, not as a list.
|
|
52
|
+
|
|
53
|
+
Here is the JSON input:
|
|
54
|
+
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
def consultation_in_depth(system_data, json_data):
|
|
58
|
+
|
|
59
|
+
json_data_string = json.dumps(
|
|
60
|
+
json_data,
|
|
61
|
+
ensure_ascii=False, # mantém acentos
|
|
62
|
+
indent=2 # deixa bonito e legível
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
msg = USER_PROMPT + "```json\n" + json_data_string + "\n```"
|
|
66
|
+
|
|
67
|
+
OUT=consult_with_deepchat( system_data["base_url"],
|
|
68
|
+
system_data["api_key"],
|
|
69
|
+
system_data["model"],
|
|
70
|
+
msg,
|
|
71
|
+
SYSTEM_PROMPT)
|
|
72
|
+
return OUT
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
from PyQt5.QtWidgets import QDialog, QLabel, QPushButton, QVBoxLayout
|
|
2
|
+
from PyQt5.QtGui import QPixmap
|
|
3
|
+
from PyQt5.QtCore import Qt
|
|
4
|
+
|
|
5
|
+
class AboutWindow(QDialog):
|
|
6
|
+
"""About dialog window"""
|
|
7
|
+
def __init__(self, data, logo_path, parent=None):
|
|
8
|
+
super().__init__(parent)
|
|
9
|
+
self.setWindowTitle("About")
|
|
10
|
+
self.setMinimumSize(500, 300)
|
|
11
|
+
|
|
12
|
+
# Create layout
|
|
13
|
+
layout = QVBoxLayout(self)
|
|
14
|
+
|
|
15
|
+
# Logo
|
|
16
|
+
logo_label = QLabel()
|
|
17
|
+
pixmap = QPixmap(logo_path)
|
|
18
|
+
pixmap = pixmap.scaled(100, 100, Qt.KeepAspectRatio, Qt.SmoothTransformation)
|
|
19
|
+
logo_label.setPixmap(pixmap)
|
|
20
|
+
logo_label.setAlignment(Qt.AlignCenter)
|
|
21
|
+
layout.addWidget(logo_label)
|
|
22
|
+
|
|
23
|
+
# Description
|
|
24
|
+
description_label = QLabel(f"<b>{data['description']}</b>")
|
|
25
|
+
description_label.setWordWrap(True)
|
|
26
|
+
description_label.setTextInteractionFlags(Qt.TextSelectableByMouse)
|
|
27
|
+
layout.addWidget(description_label)
|
|
28
|
+
|
|
29
|
+
# Add separator
|
|
30
|
+
separator = QLabel()
|
|
31
|
+
separator.setFrameShape(QLabel.HLine)
|
|
32
|
+
separator.setFrameShadow(QLabel.Sunken)
|
|
33
|
+
layout.addWidget(separator)
|
|
34
|
+
|
|
35
|
+
# Package info
|
|
36
|
+
package_label = QLabel(f"Package: {data['package']}")
|
|
37
|
+
package_label.setTextInteractionFlags(Qt.TextSelectableByMouse)
|
|
38
|
+
package_label.setAlignment(Qt.AlignLeft)
|
|
39
|
+
layout.addWidget(package_label)
|
|
40
|
+
|
|
41
|
+
# Program info
|
|
42
|
+
program_label = QLabel(f"Program: {data['program_name']}")
|
|
43
|
+
program_label.setTextInteractionFlags(Qt.TextSelectableByMouse)
|
|
44
|
+
program_label.setAlignment(Qt.AlignLeft)
|
|
45
|
+
layout.addWidget(program_label)
|
|
46
|
+
|
|
47
|
+
# Version info
|
|
48
|
+
version_label = QLabel(f"Version: {data['version']}")
|
|
49
|
+
version_label.setTextInteractionFlags(Qt.TextSelectableByMouse)
|
|
50
|
+
version_label.setAlignment(Qt.AlignLeft)
|
|
51
|
+
layout.addWidget(version_label)
|
|
52
|
+
|
|
53
|
+
# Author info
|
|
54
|
+
author_label = QLabel(f"Author: {data['author']}")
|
|
55
|
+
author_label.setTextInteractionFlags(Qt.TextSelectableByMouse)
|
|
56
|
+
author_label.setAlignment(Qt.AlignLeft)
|
|
57
|
+
layout.addWidget(author_label)
|
|
58
|
+
|
|
59
|
+
# Email info
|
|
60
|
+
email_label = QLabel(f"Email: <a href=\"mailto:{data['email']}\">{data['email']}</a>")
|
|
61
|
+
email_label.setTextInteractionFlags(Qt.TextSelectableByMouse| Qt.LinksAccessibleByMouse)
|
|
62
|
+
email_label.setOpenExternalLinks(True)
|
|
63
|
+
email_label.setAlignment(Qt.AlignLeft)
|
|
64
|
+
layout.addWidget(email_label)
|
|
65
|
+
|
|
66
|
+
# Add another separator
|
|
67
|
+
separator2 = QLabel()
|
|
68
|
+
separator2.setFrameShape(QLabel.HLine)
|
|
69
|
+
separator2.setFrameShadow(QLabel.Sunken)
|
|
70
|
+
layout.addWidget(separator2)
|
|
71
|
+
|
|
72
|
+
# Source URL
|
|
73
|
+
source_label = QLabel(f"Source: <a href=\"{data['url_source']}\">{data['url_source']}</a>")
|
|
74
|
+
source_label.setTextInteractionFlags(Qt.TextSelectableByMouse| Qt.LinksAccessibleByMouse)
|
|
75
|
+
source_label.setOpenExternalLinks(True)
|
|
76
|
+
source_label.setAlignment(Qt.AlignLeft)
|
|
77
|
+
layout.addWidget(source_label)
|
|
78
|
+
|
|
79
|
+
# Doc URL
|
|
80
|
+
doc_label = QLabel(f"Documentation: <a href=\"{data['url_doc']}\">{data['url_doc']}</a>")
|
|
81
|
+
doc_label.setTextInteractionFlags(Qt.TextSelectableByMouse| Qt.LinksAccessibleByMouse)
|
|
82
|
+
doc_label.setOpenExternalLinks(True)
|
|
83
|
+
doc_label.setAlignment(Qt.AlignLeft)
|
|
84
|
+
layout.addWidget(doc_label)
|
|
85
|
+
|
|
86
|
+
# Funding URL
|
|
87
|
+
funding_label = QLabel(f"Funding: <a href=\"{data['url_funding']}\">{data['url_funding']}</a>")
|
|
88
|
+
funding_label.setTextInteractionFlags(Qt.TextSelectableByMouse| Qt.LinksAccessibleByMouse)
|
|
89
|
+
funding_label.setOpenExternalLinks(True)
|
|
90
|
+
funding_label.setAlignment(Qt.AlignLeft)
|
|
91
|
+
layout.addWidget(funding_label)
|
|
92
|
+
|
|
93
|
+
# Bugs URL
|
|
94
|
+
bugs_label = QLabel(f"Bugs: <a href=\"{data['url_bugs']}\">{data['url_bugs']}</a>")
|
|
95
|
+
bugs_label.setTextInteractionFlags(Qt.TextSelectableByMouse| Qt.LinksAccessibleByMouse)
|
|
96
|
+
bugs_label.setOpenExternalLinks(True)
|
|
97
|
+
bugs_label.setAlignment(Qt.AlignLeft)
|
|
98
|
+
layout.addWidget(bugs_label)
|
|
99
|
+
|
|
100
|
+
# OK Button
|
|
101
|
+
ok_button = QPushButton("OK")
|
|
102
|
+
ok_button.clicked.connect(self.accept)
|
|
103
|
+
layout.addWidget(ok_button)
|
|
104
|
+
|
|
105
|
+
def show_about_window(data, logo_path):
|
|
106
|
+
dialog = AboutWindow(data, logo_path)
|
|
107
|
+
dialog.exec_()
|
|
108
|
+
|