BibexPy 2.0.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.
Files changed (171) hide show
  1. bibex_core/MergeDB.py +1189 -0
  2. bibex_core/__init__.py +13 -0
  3. bibex_core/modules/__init__.py +35 -0
  4. bibex_core/modules/api_utils.py +1172 -0
  5. bibex_core/modules/c1_utils.py +423 -0
  6. bibex_core/modules/file_utils.py +71 -0
  7. bibex_core/modules/ml_utils.py +332 -0
  8. bibex_core/modules/post_process.py +50 -0
  9. bibex_core/modules/stats_utils.py +216 -0
  10. bibex_core/scp2xlsx.py +235 -0
  11. bibex_core/wos2xlsx.py +159 -0
  12. bibex_core/xlsx2vos.py +185 -0
  13. bibexpy/__init__.py +9 -0
  14. bibexpy/__main__.py +6 -0
  15. bibexpy/_server/__init__.py +1 -0
  16. bibexpy/_server/config.py +92 -0
  17. bibexpy/_server/jobs/__init__.py +3 -0
  18. bibexpy/_server/jobs/runner.py +301 -0
  19. bibexpy/_server/main.py +211 -0
  20. bibexpy/_server/models/__init__.py +0 -0
  21. bibexpy/_server/models/project.py +25 -0
  22. bibexpy/_server/routers/__init__.py +0 -0
  23. bibexpy/_server/routers/audit.py +65 -0
  24. bibexpy/_server/routers/convert.py +101 -0
  25. bibexpy/_server/routers/disambiguate.py +177 -0
  26. bibexpy/_server/routers/downloads.py +26 -0
  27. bibexpy/_server/routers/enrich.py +42 -0
  28. bibexpy/_server/routers/export.py +116 -0
  29. bibexpy/_server/routers/export_folder.py +97 -0
  30. bibexpy/_server/routers/filter.py +131 -0
  31. bibexpy/_server/routers/jobs.py +72 -0
  32. bibexpy/_server/routers/merge.py +437 -0
  33. bibexpy/_server/routers/prepare.py +241 -0
  34. bibexpy/_server/routers/projects.py +49 -0
  35. bibexpy/_server/routers/quality.py +288 -0
  36. bibexpy/_server/routers/records.py +204 -0
  37. bibexpy/_server/routers/report.py +111 -0
  38. bibexpy/_server/routers/settings.py +383 -0
  39. bibexpy/_server/routers/system.py +209 -0
  40. bibexpy/_server/routers/tools.py +257 -0
  41. bibexpy/_server/routers/upload.py +110 -0
  42. bibexpy/_server/services/__init__.py +0 -0
  43. bibexpy/_server/services/analyses.py +364 -0
  44. bibexpy/_server/services/audit.py +340 -0
  45. bibexpy/_server/services/bibex_adapter.py +47 -0
  46. bibexpy/_server/services/bibtex_writer.py +104 -0
  47. bibexpy/_server/services/converter.py +205 -0
  48. bibexpy/_server/services/disambiguation/__init__.py +19 -0
  49. bibexpy/_server/services/disambiguation/blocking.py +581 -0
  50. bibexpy/_server/services/disambiguation/cache.py +47 -0
  51. bibexpy/_server/services/disambiguation/deepseek_client.py +203 -0
  52. bibexpy/_server/services/disambiguation/orcid.py +261 -0
  53. bibexpy/_server/services/disambiguation/pipeline.py +985 -0
  54. bibexpy/_server/services/disambiguation/similarity.py +91 -0
  55. bibexpy/_server/services/enricher.py +338 -0
  56. bibexpy/_server/services/exporter.py +112 -0
  57. bibexpy/_server/services/filter_engine.py +300 -0
  58. bibexpy/_server/services/merger.py +202 -0
  59. bibexpy/_server/services/methodology.py +102 -0
  60. bibexpy/_server/services/report_export.py +300 -0
  61. bibexpy/_server/services/ris_writer.py +62 -0
  62. bibexpy/_server/services/smart_merger.py +967 -0
  63. bibexpy/_server/services/storage.py +165 -0
  64. bibexpy/_web/404/index.html +1 -0
  65. bibexpy/_web/404.html +1 -0
  66. bibexpy/_web/_next/static/chunks/117-7ad5186126fa076d.js +2 -0
  67. bibexpy/_web/_next/static/chunks/156-75beffb8ae92a7f3.js +1 -0
  68. bibexpy/_web/_next/static/chunks/169-301c04fcec22686f.js +4 -0
  69. bibexpy/_web/_next/static/chunks/2-ecc1c36a5632ac61.js +1 -0
  70. bibexpy/_web/_next/static/chunks/244-be343e0f8aa00fb5.js +1 -0
  71. bibexpy/_web/_next/static/chunks/367-b7457c2b95f6932b.js +1 -0
  72. bibexpy/_web/_next/static/chunks/382-9cd163eed632e241.js +1 -0
  73. bibexpy/_web/_next/static/chunks/392-afa8bfa4c1a9893d.js +1 -0
  74. bibexpy/_web/_next/static/chunks/507-63607ded9f83c1aa.js +1 -0
  75. bibexpy/_web/_next/static/chunks/624-cae565632f47217d.js +1 -0
  76. bibexpy/_web/_next/static/chunks/739-a00c6b9c0f11813e.js +1 -0
  77. bibexpy/_web/_next/static/chunks/862-8e1bd5f93c082c02.js +1 -0
  78. bibexpy/_web/_next/static/chunks/app/_not-found/page-873ba59b5eb7c342.js +1 -0
  79. bibexpy/_web/_next/static/chunks/app/layout-0d5fc68ac8971a04.js +1 -0
  80. bibexpy/_web/_next/static/chunks/app/page-cf2bea5edc74459a.js +1 -0
  81. bibexpy/_web/_next/static/chunks/app/projects/[id]/convert/page-ab6dd645ae113b64.js +1 -0
  82. bibexpy/_web/_next/static/chunks/app/projects/[id]/disambiguate/page-dd98482cc47344e9.js +1 -0
  83. bibexpy/_web/_next/static/chunks/app/projects/[id]/enrich/page-4727e431468514e9.js +1 -0
  84. bibexpy/_web/_next/static/chunks/app/projects/[id]/export/page-f9005d164bb22cb0.js +1 -0
  85. bibexpy/_web/_next/static/chunks/app/projects/[id]/layout-07755fda55b3ae1f.js +1 -0
  86. bibexpy/_web/_next/static/chunks/app/projects/[id]/merge/page-45b95318ea7beccf.js +1 -0
  87. bibexpy/_web/_next/static/chunks/app/projects/[id]/records/page-bfad80457da9eb0b.js +1 -0
  88. bibexpy/_web/_next/static/chunks/app/projects/[id]/report/page-f05767e74158e995.js +1 -0
  89. bibexpy/_web/_next/static/chunks/app/projects/[id]/upload/page-8df78ca9cdecbcb8.js +1 -0
  90. bibexpy/_web/_next/static/chunks/app/projects/page-99960711ac6a13e9.js +1 -0
  91. bibexpy/_web/_next/static/chunks/app/settings/page-002df809d6c5a227.js +1 -0
  92. bibexpy/_web/_next/static/chunks/app/tools/page-27eee1c6a590859f.js +1 -0
  93. bibexpy/_web/_next/static/chunks/fd9d1056-f2718be92181f426.js +1 -0
  94. bibexpy/_web/_next/static/chunks/framework-f66176bb897dc684.js +1 -0
  95. bibexpy/_web/_next/static/chunks/main-app-d138a6e2f8c847f6.js +1 -0
  96. bibexpy/_web/_next/static/chunks/main-c4b9ddbf514503ef.js +1 -0
  97. bibexpy/_web/_next/static/chunks/pages/_app-72b849fbd24ac258.js +1 -0
  98. bibexpy/_web/_next/static/chunks/pages/_error-7ba65e1336b92748.js +1 -0
  99. bibexpy/_web/_next/static/chunks/polyfills-42372ed130431b0a.js +1 -0
  100. bibexpy/_web/_next/static/chunks/webpack-c81f7fd28659d64f.js +1 -0
  101. bibexpy/_web/_next/static/css/1c4638f3e39cf127.css +3 -0
  102. bibexpy/_web/_next/static/ypx2IQAkZiSaFiKWnzZGB/_buildManifest.js +1 -0
  103. bibexpy/_web/_next/static/ypx2IQAkZiSaFiKWnzZGB/_ssgManifest.js +1 -0
  104. bibexpy/_web/images/PROMPTS.md +83 -0
  105. bibexpy/_web/images/about-illustration.png +0 -0
  106. bibexpy/_web/images/authors/alperen-sahin.jpg +0 -0
  107. bibexpy/_web/images/authors/burak-can-kara.jpg +0 -0
  108. bibexpy/_web/images/authors/taskin-dirsehan.jpg +0 -0
  109. bibexpy/_web/images/bibexpy-logo-full.png +0 -0
  110. bibexpy/_web/images/bibexpy-logo-header.png +0 -0
  111. bibexpy/_web/images/bibexpy-logo-in.png +0 -0
  112. bibexpy/_web/images/bibexpy-logo.webp +0 -0
  113. bibexpy/_web/images/hero-illustration.png +0 -0
  114. bibexpy/_web/images/loader.gif +0 -0
  115. bibexpy/_web/images/workflow-diagram.png +0 -0
  116. bibexpy/_web/index.html +1 -0
  117. bibexpy/_web/index.txt +11 -0
  118. bibexpy/_web/projects/_/convert/index.html +1 -0
  119. bibexpy/_web/projects/_/convert/index.txt +12 -0
  120. bibexpy/_web/projects/_/disambiguate/index.html +1 -0
  121. bibexpy/_web/projects/_/disambiguate/index.txt +12 -0
  122. bibexpy/_web/projects/_/enrich/index.html +1 -0
  123. bibexpy/_web/projects/_/enrich/index.txt +12 -0
  124. bibexpy/_web/projects/_/export/index.html +1 -0
  125. bibexpy/_web/projects/_/export/index.txt +12 -0
  126. bibexpy/_web/projects/_/merge/index.html +1 -0
  127. bibexpy/_web/projects/_/merge/index.txt +12 -0
  128. bibexpy/_web/projects/_/records/index.html +1 -0
  129. bibexpy/_web/projects/_/records/index.txt +12 -0
  130. bibexpy/_web/projects/_/report/index.html +1 -0
  131. bibexpy/_web/projects/_/report/index.txt +12 -0
  132. bibexpy/_web/projects/_/upload/index.html +1 -0
  133. bibexpy/_web/projects/_/upload/index.txt +12 -0
  134. bibexpy/_web/projects/index.html +1 -0
  135. bibexpy/_web/projects/index.txt +11 -0
  136. bibexpy/_web/settings/index.html +1 -0
  137. bibexpy/_web/settings/index.txt +11 -0
  138. bibexpy/_web/tools/README.md +65 -0
  139. bibexpy/_web/tools/bibexcel.svg +6 -0
  140. bibexpy/_web/tools/bibliometrix.png +0 -0
  141. bibexpy/_web/tools/biblioshiny.svg +12 -0
  142. bibexpy/_web/tools/citavi.svg +6 -0
  143. bibexpy/_web/tools/citespace.svg +7 -0
  144. bibexpy/_web/tools/citnetexplorer.svg +8 -0
  145. bibexpy/_web/tools/endnote.svg +6 -0
  146. bibexpy/_web/tools/excel.svg +1 -0
  147. bibexpy/_web/tools/gephi.svg +66 -0
  148. bibexpy/_web/tools/histcite.svg +7 -0
  149. bibexpy/_web/tools/index.html +1 -0
  150. bibexpy/_web/tools/index.txt +11 -0
  151. bibexpy/_web/tools/jabref.svg +122 -0
  152. bibexpy/_web/tools/latex.svg +1 -0
  153. bibexpy/_web/tools/mendeley.svg +1 -0
  154. bibexpy/_web/tools/openrefine.svg +15 -0
  155. bibexpy/_web/tools/overleaf.svg +1 -0
  156. bibexpy/_web/tools/papers.svg +7 -0
  157. bibexpy/_web/tools/powerbi.svg +1 -0
  158. bibexpy/_web/tools/python.svg +1 -0
  159. bibexpy/_web/tools/r.svg +1 -0
  160. bibexpy/_web/tools/refworks.svg +5 -0
  161. bibexpy/_web/tools/scite.svg +5 -0
  162. bibexpy/_web/tools/tableau.svg +1 -0
  163. bibexpy/_web/tools/vosviewer.png +0 -0
  164. bibexpy/_web/tools/zotero.svg +1 -0
  165. bibexpy/cli.py +242 -0
  166. bibexpy-2.0.0.dist-info/METADATA +105 -0
  167. bibexpy-2.0.0.dist-info/RECORD +171 -0
  168. bibexpy-2.0.0.dist-info/WHEEL +5 -0
  169. bibexpy-2.0.0.dist-info/entry_points.txt +2 -0
  170. bibexpy-2.0.0.dist-info/licenses/LICENSE +674 -0
  171. bibexpy-2.0.0.dist-info/top_level.txt +2 -0
bibex_core/scp2xlsx.py ADDED
@@ -0,0 +1,235 @@
1
+ import pandas as pd
2
+ import re
3
+ import os
4
+ from typing import List, Union
5
+
6
+
7
+ def abbrev_title(title: str) -> str:
8
+ # This function can be used to abbreviate journal names
9
+ # Simple version for now
10
+ return title.replace('.', '').upper()
11
+
12
+
13
+ def labelling(data: pd.DataFrame) -> pd.DataFrame:
14
+ """Converts column labels to standard format"""
15
+
16
+ df_tag = pd.DataFrame([
17
+ ["Abbreviated Source Title", "JI"],
18
+ ["Affiliations", "C1"],
19
+ ["Authors", "AU"],
20
+ ["Author Names", "AU"],
21
+ ["Author full names", "AF"],
22
+ ["Source title", "SO"],
23
+ ["Titles", "TI"],
24
+ ["Title", "TI"],
25
+ ["Publication Year", "PY"],
26
+ ["Year", "PY"],
27
+ ["Volume", "VL"],
28
+ ["Issue", "IS"],
29
+ ["Page count", "PP"],
30
+ ["Cited by", "TC"],
31
+ ["DOI", "DI"],
32
+ ["Link", "URL"],
33
+ ["Abstract", "AB"],
34
+ ["Author Keywords", "DE"],
35
+ ["Indexed Keywords", "ID"],
36
+ ["Index Keywords", "ID"],
37
+ ["Funding Details", "FU"],
38
+ ["Funding Texts", "FX"],
39
+ ["Funding Text 1", "FX"],
40
+ ["References", "CR"],
41
+ ["Correspondence Address", "RP"],
42
+ ["Publisher", "PU"],
43
+ ["Open Access", "OA"],
44
+ ["Language of Original Document", "LA"],
45
+ ["Document Type", "DT"],
46
+ ["Source", "DB"],
47
+ ["EID", "UT"]
48
+ ], columns=['orig', 'tag'])
49
+
50
+ # Mevcut sütun isimlerini al
51
+ label = pd.DataFrame({'orig': data.columns})
52
+
53
+ # Eşleştirme yap
54
+ label = label.merge(df_tag, on='orig', how='left')
55
+
56
+ # Eşleşmeyen sütunlar için orijinal ismi kullan
57
+ label['tag'] = label['tag'].fillna(label['orig'])
58
+
59
+ # Sütun isimlerini güncelle
60
+ data.columns = label['tag']
61
+
62
+ return data
63
+
64
+
65
+ def csvScopus2df(files: Union[str, List[str]]) -> pd.DataFrame:
66
+ """
67
+ Reads and processes Scopus CSV files
68
+
69
+ Parameters:
70
+ -----------
71
+ files : str or list of str
72
+ Path to CSV files to process
73
+
74
+ Returns:
75
+ --------
76
+ pd.DataFrame
77
+ Processed data frame
78
+ """
79
+
80
+ if isinstance(files, str):
81
+ files = [files]
82
+
83
+ all_data = []
84
+
85
+ for i, file in enumerate(files):
86
+ try:
87
+ # Read CSV file
88
+ df = pd.read_csv(file,
89
+ dtype=str, # Read all columns as string
90
+ na_values='', # Mark empty values as NA
91
+ keep_default_na=False, # Don't use default NA values
92
+ encoding='utf-8') # Use UTF-8 encoding
93
+
94
+ # Replace NA values with empty string
95
+ df = df.fillna('')
96
+
97
+ if i > 0:
98
+ # Find common columns
99
+ common_cols = list(set(df.columns) & set(all_data[0].columns))
100
+ # Merge using only common columns
101
+ all_data.append(df[common_cols])
102
+ else:
103
+ all_data.append(df)
104
+
105
+ except Exception as e:
106
+ print(f"Error: Failed to read file {file}: {str(e)}")
107
+ continue
108
+
109
+ if not all_data:
110
+ raise ValueError("No files could be read!")
111
+
112
+ # Merge all dataframes
113
+ DATA = pd.concat(all_data, ignore_index=True)
114
+
115
+ # Organize column labels
116
+ DATA = labelling(DATA)
117
+
118
+ # Clean author names
119
+ if 'AU' in DATA.columns:
120
+ DATA['AU'] = DATA['AU'].str.replace('.', '', regex=False)
121
+ DATA['AU'] = DATA['AU'].str.replace(',', ';', regex=False)
122
+
123
+ # Store raw institution information
124
+ if 'C1' not in DATA.columns:
125
+ DATA['C1'] = ''
126
+
127
+ # Process journal abbreviations
128
+ if 'JI' in DATA.columns:
129
+ DATA['J9'] = DATA['JI'].str.replace('.', '', regex=False)
130
+ else:
131
+ if 'SO' in DATA.columns:
132
+ DATA['J9'] = DATA['SO'].apply(abbrev_title)
133
+ DATA['JI'] = DATA['J9']
134
+
135
+ # Store DI and URL values (before converting to uppercase)
136
+ di_values = DATA.get('DI', None)
137
+ url_values = DATA.get('URL', None)
138
+
139
+ # Convert all string columns to uppercase
140
+ for col in DATA.columns:
141
+ if DATA[col].dtype == 'object':
142
+ DATA[col] = DATA[col].str.upper()
143
+
144
+ # Restore DI and URL values
145
+ if di_values is not None:
146
+ DATA['DI'] = di_values
147
+ if url_values is not None:
148
+ DATA['URL'] = url_values
149
+
150
+ return DATA
151
+
152
+
153
+ def save_to_excel(file_paths: Union[str, List[str]], output_path: str) -> bool:
154
+ """
155
+ Processes Scopus CSV files and saves as Excel file
156
+
157
+ Parameters:
158
+ -----------
159
+ file_paths : str or list of str
160
+ Path to CSV files to process
161
+ output_path : str
162
+ Path to output Excel file
163
+
164
+ Returns:
165
+ --------
166
+ bool
167
+ Whether the operation was successful
168
+ """
169
+ try:
170
+ # Convert data
171
+ df = csvScopus2df(file_paths)
172
+
173
+ # Save as Excel
174
+ df.to_excel(output_path, index=False)
175
+ print(f"Data successfully saved to {output_path}")
176
+ return True
177
+ except Exception as e:
178
+ print(f"Error occurred: {str(e)}")
179
+ return False
180
+
181
+
182
+ if __name__ == "__main__":
183
+ try:
184
+ # Show current working directory
185
+ print(f"Current working directory: {os.getcwd()}")
186
+
187
+ while True:
188
+ # Get file names from user
189
+ print("\nEnter the full path or file names of Scopus CSV files separated by commas")
190
+ print("Example 1: data1.csv,data2.csv")
191
+ print("Example 2: C:/Users/data1.csv,D:/Data/data2.csv")
192
+ print("(Type 'q' to quit)")
193
+
194
+ input_str = input().strip()
195
+ if input_str.lower() == 'q':
196
+ print("Program terminating...")
197
+ break
198
+
199
+ input_files = [f.strip() for f in input_str.split(',')]
200
+
201
+ # Get output file name
202
+ print("\nEnter the name or full path of the output Excel file")
203
+ print("Example 1: output.xlsx")
204
+ print("Example 2: C:/Users/output.xlsx")
205
+ output_file = input().strip()
206
+
207
+ # Check file extensions
208
+ input_files = [f if f.endswith('.csv') else f + '.csv' for f in input_files]
209
+ if not output_file.endswith('.xlsx'):
210
+ output_file += '.xlsx'
211
+
212
+ # Check if files exist
213
+ missing_files = [f for f in input_files if not os.path.exists(f)]
214
+ if missing_files:
215
+ print("\nError: The following files were not found:")
216
+ for f in missing_files:
217
+ print(f"- {f}")
218
+ print("\nPlease check the file names and try again.")
219
+ continue
220
+
221
+ # Process files and save to Excel
222
+ print("\nProcessing files...")
223
+ success = save_to_excel(input_files, output_file)
224
+ if success:
225
+ print("\nOperation completed successfully!")
226
+ print(f"Result file: {os.path.abspath(output_file)}")
227
+
228
+ # Ask if user wants to continue
229
+ print("\nDo you want to process more files? (Y/N)")
230
+ if input().strip().upper() != 'Y':
231
+ print("Program terminating...")
232
+ break
233
+
234
+ except Exception as e:
235
+ print(f"\nAn unexpected error occurred: {str(e)}")
bibex_core/wos2xlsx.py ADDED
@@ -0,0 +1,159 @@
1
+ import pandas as pd
2
+ import re
3
+ import os
4
+
5
+
6
+ def remove_strange_char(text):
7
+ # Remove strange characters
8
+ return re.sub(r'[^\x00-\x7F]+', '', text)
9
+
10
+
11
+ def safe_str_replace(x, old, new):
12
+ # Safe string replacement operation
13
+ if pd.isna(x):
14
+ return x
15
+ try:
16
+ return str(x).replace(old, new)
17
+ except:
18
+ return x
19
+
20
+
21
+ def isi2df(D):
22
+ # Remove empty lines and strange characters
23
+ D = [line for line in D if len(line.strip()) > 1]
24
+ D = [remove_strange_char(line) for line in D]
25
+
26
+ # Remove lines starting with FN and VR
27
+ D = [line for line in D if not line.startswith(('FN ', 'VR '))]
28
+
29
+ # Combine lines starting with spaces with the label of the previous line
30
+ for i in range(1, len(D)):
31
+ if D[i].startswith(' '):
32
+ D[i] = D[i - 1][:3] + D[i][3:]
33
+
34
+ # Find starting indices of documents
35
+ papers = [i for i, line in enumerate(D) if line.startswith('PT ')]
36
+ nP = len(papers)
37
+
38
+ if nP == 0:
39
+ raise ValueError("No valid ISI format found. Please check your file.")
40
+
41
+ # Calculate number of lines for each document
42
+ row_papers = []
43
+ for i in range(len(papers) - 1):
44
+ row_papers.append(papers[i + 1] - papers[i])
45
+ row_papers.append(len(D) - papers[-1])
46
+
47
+ # Create document number for each line
48
+ num_papers = []
49
+ for i, count in enumerate(row_papers):
50
+ num_papers.extend([i + 1] * count)
51
+
52
+ # Create DataFrame
53
+ data = {
54
+ 'Tag': [line[:3].strip() for line in D],
55
+ 'content': [line[3:].strip() for line in D],
56
+ 'Paper': num_papers
57
+ }
58
+ df = pd.DataFrame(data)
59
+
60
+ # Combine Tag and content
61
+ df = df.groupby(['Paper', 'Tag'])['content'].apply('---'.join).reset_index()
62
+
63
+ # Pivot operation
64
+ df = df.pivot(index='Paper', columns='Tag', values='content').reset_index()
65
+
66
+ # Check mandatory fields
67
+ mandatory_tags = ['AU', 'DE', 'C1', 'RP', 'CR', 'PY', 'SO', 'TI', 'TC']
68
+ missing_tags = [tag for tag in mandatory_tags if tag not in df.columns]
69
+ if missing_tags:
70
+ print("\nWarning: Some mandatory metadata fields are missing. Bibliometrix functions may not work properly!")
71
+ print("Missing fields:", missing_tags)
72
+
73
+ # Fields that should be separated by commas
74
+ comma_tags = ['AU', 'AF', 'CR']
75
+ for tag in comma_tags:
76
+ if tag in df.columns:
77
+ df[tag] = df[tag].apply(lambda x: safe_str_replace(x, '---', ';'))
78
+
79
+ # Replace --- with space for other fields
80
+ other_tags = [col for col in df.columns if col not in comma_tags]
81
+ for tag in other_tags:
82
+ if tag in df.columns:
83
+ df[tag] = df[tag].apply(lambda x: safe_str_replace(x, '---', ' ').strip() if pd.notnull(x) else x)
84
+
85
+ # Add C1raw column
86
+ if 'C1' in df.columns:
87
+ df['C1raw'] = df['C1'].copy()
88
+ # Remove author information in square brackets
89
+ df['C1'] = df['C1'].apply(lambda x: re.sub(r'\[.*?\]', '', str(x)) if pd.notnull(x) else x)
90
+ df['C1'] = df['C1'].apply(lambda x: safe_str_replace(x, '.', '.;') if pd.notnull(x) else x)
91
+
92
+ # Add database information
93
+ df['DB'] = 'ISI'
94
+
95
+ # Clean commas in author names
96
+ if 'AU' in df.columns:
97
+ df['AU'] = df['AU'].apply(lambda x: safe_str_replace(x, ',', ' ').strip() if pd.notnull(x) else x)
98
+
99
+ # Convert all string columns to uppercase except DI
100
+ di_col = None
101
+ if 'DI' in df.columns:
102
+ di_col = df['DI'].copy()
103
+
104
+ for col in df.columns:
105
+ if df[col].dtype == 'object':
106
+ df[col] = df[col].apply(lambda x: str(x).upper() if pd.notnull(x) else x)
107
+
108
+ if di_col is not None:
109
+ df['DI'] = di_col
110
+
111
+ # Remove Paper column
112
+ df = df.drop('Paper', axis=1)
113
+
114
+ return df
115
+
116
+
117
+ def save_to_excel(file_path, output_path):
118
+ try:
119
+ # Read file
120
+ with open(file_path, 'r', encoding='utf-8') as file:
121
+ lines = file.readlines()
122
+
123
+ if not lines:
124
+ raise ValueError("File is empty!")
125
+
126
+ # Convert data
127
+ df = isi2df(lines)
128
+
129
+ # Save as Excel
130
+ df.to_excel(output_path, index=False)
131
+ print(f"Data successfully saved to {output_path}")
132
+ return True
133
+ except Exception as e:
134
+ print(f"Error occurred: {str(e)}")
135
+ return False
136
+
137
+
138
+ if __name__ == "__main__":
139
+ # Get file names from user
140
+ print("Enter the name of the ISI format file (e.g., data.txt):")
141
+ input_file = input().strip()
142
+
143
+ print("Enter the name of the output Excel file (e.g., output.xlsx):")
144
+ output_file = input().strip()
145
+
146
+ # Check file extensions
147
+ if not input_file.endswith(('.txt', '.isi')):
148
+ input_file += '.txt'
149
+ if not output_file.endswith('.xlsx'):
150
+ output_file += '.xlsx'
151
+
152
+ # Check if file exists
153
+ if not os.path.exists(input_file):
154
+ print(f"Error: File {input_file} not found!")
155
+ else:
156
+ # Process file and save to Excel
157
+ success = save_to_excel(input_file, output_file)
158
+ if success:
159
+ print("\nOperation completed successfully!")
bibex_core/xlsx2vos.py ADDED
@@ -0,0 +1,185 @@
1
+ import pandas as pd
2
+ from tqdm import tqdm # İlerleme çubuğu için tqdm kütüphanesi
3
+
4
+ def convert_excel_to_wos(input_excel_path, output_txt_path):
5
+ # Excel dosyasını pandas kullanarak aç
6
+ df = pd.read_excel(input_excel_path)
7
+
8
+ # Başlıklara göre sütun isimlerini eşleştir
9
+ desired_columns = {
10
+ "PT": "PT", # Publication Type
11
+ "AU": "AU", # Authors
12
+ "AF": "AF", # Author Full Names
13
+ "TI": "TI", # Title
14
+ "SO": "SO", # Source
15
+ "LA": "LA", # Language
16
+ "DT": "DT", # Document Type
17
+ "DE": "DE", # Keywords
18
+ "ID": "ID", # Keywords Plus
19
+ "AB": "AB", # Abstract
20
+ "C1": "C1", # Author Address
21
+ "C3": "C3", # Additional Address
22
+ "RP": "RP", # Reprint Address
23
+ "EM": "EM", # Email
24
+ "FU": "FU", # Funding
25
+ "FX": "FX", # Funding Text
26
+ "CR": "CR", # Cited References
27
+ "NR": "NR", # Number of References
28
+ "TC": "TC", # Times Cited
29
+ "Z9": "Z9", # Total Times Cited
30
+ "U1": "U1", # Usage Count (Last 180 Days)
31
+ "U2": "U2", # Usage Count (Since 2013)
32
+ "PU": "PU", # Publisher
33
+ "PI": "PI", # Publisher City
34
+ "PA": "PA", # Publisher Address
35
+ "SN": "SN", # ISSN
36
+ "EI": "ISSN", # Electronic ISSN
37
+ "J9": "J9", # 29-Character Source Abbreviation
38
+ "JI": "JI", # ISO Source Abbreviation
39
+ "PD": "PD", # Publication Date
40
+ "PY": "PY", # Year Published
41
+ "VL": "VL", # Volume
42
+ "AR": "Art. No.", # Article Number
43
+ "DI": "DI", # DOI
44
+ "EA": "EA", # Early Access Date
45
+ "PG": "PG", # Page Count
46
+ "WC": "WC", # Web of Science Categories
47
+ "WE": "WE", # Web of Science Index
48
+ "SC": "SC", # Research Areas
49
+ "GA": "GA", # Document Delivery Number
50
+ "UT": "UT", # Accession Number
51
+ "DA": "DA" # Date of Export
52
+ }
53
+
54
+ # Değerleri saklamak için boş listeler oluştur
55
+ values_dict = {column: [] for column in desired_columns}
56
+
57
+ # Verileri başlıklara göre al
58
+ for idx, row in df.iterrows():
59
+ for key, header_name in desired_columns.items():
60
+ cell_value = row.get(header_name, "")
61
+ values_dict[key].append(cell_value if pd.notna(cell_value) else "")
62
+
63
+ with open(output_txt_path, 'w', encoding='utf-8') as file:
64
+ # Dosya başlangıcı (bir kere)
65
+ file.write("FN Clarivate Analytics Web of Science\n")
66
+ file.write("VR 1.0\n\n")
67
+
68
+ # Her kayıt için bilgileri dosyaya yaz
69
+ for idx in range(len(df)):
70
+ # Her kayıt PT ile başlar
71
+ pt_value = values_dict["PT"][idx] if values_dict["PT"][idx] else "J"
72
+ file.write(f"PT {pt_value}\n")
73
+
74
+ # AU (Author) bilgisi
75
+ au = values_dict["AU"][idx]
76
+ if au:
77
+ au_list = au.split(';') # Yazarları ayır
78
+ formatted_au_list = [author.strip() for author in au_list if author.strip()]
79
+ file.write(f"AU {formatted_au_list[0]}\n") # AU belirtecinin ilk satırını AU satırına yaz
80
+ for author in formatted_au_list[1:]:
81
+ file.write(f" {author}\n") # Diğer yazarları alt satırlara yaz ve önde üç boşluk bırak
82
+ else:
83
+ file.write("AU \n")
84
+
85
+ # AF (Author Full Name) bilgisi
86
+ af = values_dict["AF"][idx]
87
+ if af:
88
+ af_list = af.split(';') # Yazar tam isimlerini ayır
89
+ file.write(f"AF {af_list[0].strip()}\n") # AF belirtecinin ilk satırını AF satırına yaz
90
+ for author_full in af_list[1:]:
91
+ file.write(f" {author_full.strip()}\n") # Diğer isimleri alt satırlara yaz ve önde üç boşluk bırak
92
+ else:
93
+ file.write("AF \n")
94
+
95
+ # Diğer makale bilgilerini yaz
96
+ file.write(f"TI {values_dict['TI'][idx]}\n") # Makale başlığı
97
+ file.write(f"SO {values_dict['SO'][idx]}\n") # Kaynak başlık (Source)
98
+ file.write(f"LA {values_dict['LA'][idx]}\n") # Dil bilgisi (Language)
99
+ file.write(f"DT {values_dict['DT'][idx]}\n") # Belge türü (Document Type)
100
+ file.write(f"DE {values_dict['DE'][idx]}\n") # Anahtar kelimeler (Keywords)
101
+ file.write(f"ID {values_dict['ID'][idx]}\n") # Keywords Plus
102
+ file.write(f"AB {values_dict['AB'][idx]}\n") # Özet (Abstract)
103
+
104
+ # C1 (Author Address) information - Each address on a new line
105
+ c1 = values_dict['C1'][idx]
106
+ af = values_dict['AF'][idx]
107
+
108
+ if c1 and af:
109
+ # Split authors and addresses
110
+ authors = [a.strip() for a in af.split(';') if a.strip()]
111
+ addresses = [addr.strip() for addr in c1.split(';') if addr.strip()]
112
+
113
+ # If we have both authors and addresses
114
+ if authors and addresses:
115
+ # İlk satır için "C1" kullan
116
+ file.write(f"C1 [{authors[0]}] {addresses[0]}\n")
117
+
118
+ # Diğer satırlar için " " ile başla
119
+ current_addr_idx = 1
120
+
121
+ # Normal eşleşmeleri yaz
122
+ for i in range(1, min(len(authors), len(addresses))):
123
+ file.write(f" [{authors[i]}] {addresses[i]}\n")
124
+ current_addr_idx = i + 1
125
+
126
+ # Eğer fazla yazar varsa, son adresle eşleştir
127
+ if len(authors) > len(addresses):
128
+ last_address = addresses[-1]
129
+ for i in range(current_addr_idx, len(authors)):
130
+ file.write(f" [{authors[i]}] {last_address}\n")
131
+ else:
132
+ file.write("C1 \n")
133
+
134
+ file.write(f"C3 {values_dict['C3'][idx]}\n") # Other address information
135
+ file.write(f"RP {values_dict['RP'][idx]}\n") # Reprint Address
136
+ file.write(f"EM {values_dict['EM'][idx]}\n") # Email Address
137
+ file.write(f"FU {values_dict['FU'][idx]}\n") # Funding Information
138
+ file.write(f"FX {values_dict['FX'][idx]}\n") # Funding Text
139
+
140
+ # CR (Cited References) information - from CR_raw column
141
+ cr = values_dict['CR'][idx]
142
+ if cr:
143
+ cr_list = [ref.strip() for ref in cr.split(';') if ref.strip()] # Filter empty references
144
+ if cr_list:
145
+ # Writing process
146
+ file.write(f"CR {cr_list[0]}\n") # First reference
147
+ for ref in cr_list[1:]:
148
+ file.write(f" {ref}\n") # Other references start with 3 spaces
149
+ else:
150
+ file.write("CR \n")
151
+
152
+ # Diğer gerekli bilgileri yaz
153
+ file.write(f"NR {values_dict['NR'][idx]}\n") # Atıf sayısı (Number of References)
154
+ file.write(f"TC {values_dict['TC'][idx]}\n") # Toplam atıf sayısı (Times Cited)
155
+ file.write(f"Z9 {values_dict['Z9'][idx]}\n") # Total Times Cited
156
+ file.write(f"U1 {values_dict['U1'][idx]}\n") # Usage Count (Last 180 Days)
157
+ file.write(f"U2 {values_dict['U2'][idx]}\n") # Usage Count (Since 2013)
158
+ file.write(f"PU {values_dict['PU'][idx]}\n") # Publisher
159
+ file.write(f"PI {values_dict['PI'][idx]}\n") # Publisher City
160
+ file.write(f"PA {values_dict['PA'][idx]}\n") # Publisher Address
161
+ file.write(f"SN {values_dict['SN'][idx]}\n") # ISSN
162
+ file.write(f"EI {values_dict['EI'][idx]}\n") # Electronic ISSN
163
+ file.write(f"J9 {values_dict['J9'][idx]}\n") # 29-Character Source Abbreviation
164
+ file.write(f"JI {values_dict['JI'][idx]}\n") # ISO Source Abbreviation
165
+ file.write(f"PD {values_dict['PD'][idx]}\n") # Publication Date
166
+ file.write(f"PY {values_dict['PY'][idx]}\n") # Year Published
167
+ file.write(f"VL {values_dict['VL'][idx]}\n") # Volume
168
+ file.write(f"AR {values_dict['AR'][idx]}\n") # Article Number
169
+ file.write(f"DI {values_dict['DI'][idx]}\n") # DOI
170
+ file.write(f"EA {values_dict['EA'][idx]}\n") # Early Access Date
171
+ file.write(f"PG {values_dict['PG'][idx]}\n") # Page Count
172
+ file.write(f"WC {values_dict['WC'][idx]}\n") # Web of Science Categories
173
+ file.write(f"WE {values_dict['WE'][idx]}\n") # Web of Science Index
174
+ file.write(f"SC {values_dict['SC'][idx]}\n") # Research Areas
175
+ file.write(f"GA {values_dict['GA'][idx]}\n") # Document Delivery Number
176
+ file.write(f"UT {values_dict['UT'][idx]}\n") # Accession Number
177
+ file.write(f"DA {values_dict['DA'][idx]}\n") # Date of Export
178
+
179
+ # Her kayıt ER ile biter
180
+ file.write("ER\n\n")
181
+
182
+ # Dosya sonu
183
+ file.write("EF\n")
184
+
185
+ print(f"Successfully converted file to WoS format: '{output_txt_path}'")
bibexpy/__init__.py ADDED
@@ -0,0 +1,9 @@
1
+ """BibexPy v2 — self-hosted bibliometric data preparation tool.
2
+
3
+ Son kullanıcı bu paketi `pip install bibexpy` ile kurar ve `bibexpy` komutuyla
4
+ çalıştırır. Gömülü FastAPI sunucusu + Next.js static UI tek pakette gelir;
5
+ Node.js / npm gerektirmez.
6
+ """
7
+
8
+ __version__ = "2.0.0"
9
+ __all__ = ["__version__"]
bibexpy/__main__.py ADDED
@@ -0,0 +1,6 @@
1
+ """`python -m bibexpy` desteği — cli.main()'e yönlendirir."""
2
+
3
+ from bibexpy.cli import main
4
+
5
+ if __name__ == "__main__":
6
+ raise SystemExit(main())
@@ -0,0 +1 @@
1
+ """BibexPy gömülü FastAPI sunucusu (build-time kopya). Runtime sys.path'e eklenir."""