DanielSwift commited on
Commit
53b8615
·
1 Parent(s): 8992f8c

Import ~2000 common concepts

Browse files
concepts_to_import.json ADDED
The diff for this file is too large to render. See raw diff
 
manage_concepts.py ADDED
@@ -0,0 +1,87 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ Script for managing SFOSR concepts (export/import).
4
+ """
5
+
6
+ import argparse
7
+ import sys
8
+ import os
9
+
10
+ # Ensure the script can find the sfosr_core module
11
+ script_dir = os.path.dirname(os.path.abspath(__file__))
12
+ project_root = script_dir # Assumes script is in the root
13
+ sys.path.insert(0, project_root)
14
+
15
+ try:
16
+ from sfosr_core.sfosr_database import SFOSRDatabase
17
+ except ImportError as e:
18
+ print(f"Error: Could not import SFOSRDatabase. Make sure sfosr_core is accessible.")
19
+ print(f"PYTHONPATH: {sys.path}")
20
+ sys.exit(1)
21
+
22
+ DEFAULT_DB_PATH = "sfosr.db"
23
+ DEFAULT_JSON_PATH_EXPORT = "concepts_export.json" # Default for export
24
+ DEFAULT_JSON_PATH_IMPORT = "concepts_to_import.json" # Default for import
25
+
26
+ def main():
27
+ parser = argparse.ArgumentParser(description="Manage SFOSR concepts.")
28
+ subparsers = parser.add_subparsers(dest='action', help='Action to perform', required=True)
29
+
30
+ # Export command
31
+ parser_export = subparsers.add_parser('export', help='Export concepts to JSON')
32
+ parser_export.add_argument(
33
+ '--db-path',
34
+ default=DEFAULT_DB_PATH,
35
+ help=f"Path to the SFOSR database file (default: {DEFAULT_DB_PATH})"
36
+ )
37
+ parser_export.add_argument(
38
+ '--json-path',
39
+ default=DEFAULT_JSON_PATH_EXPORT,
40
+ help=f"Path to the output JSON file (default: {DEFAULT_JSON_PATH_EXPORT})"
41
+ )
42
+
43
+ # Import command
44
+ parser_import = subparsers.add_parser('import', help='Import concepts from JSON (adds only new concepts)')
45
+ parser_import.add_argument(
46
+ '--db-path',
47
+ default=DEFAULT_DB_PATH,
48
+ help=f"Path to the SFOSR database file (default: {DEFAULT_DB_PATH})"
49
+ )
50
+ parser_import.add_argument(
51
+ '--json-path',
52
+ default=DEFAULT_JSON_PATH_IMPORT,
53
+ help=f"Path to the input JSON file (default: {DEFAULT_JSON_PATH_IMPORT})"
54
+ )
55
+
56
+ args = parser.parse_args()
57
+
58
+ if not os.path.exists(args.db_path):
59
+ print(f"Error: Database file not found at {args.db_path}")
60
+ sys.exit(1)
61
+
62
+ db = SFOSRDatabase(db_path=args.db_path)
63
+
64
+ if args.action == 'export':
65
+ print(f"Exporting concepts from {args.db_path} to {args.json_path}...")
66
+ db.export_concepts_to_json(args.json_path)
67
+
68
+ elif args.action == 'import':
69
+ if not os.path.exists(args.json_path):
70
+ print(f"Error: Import JSON file not found at {args.json_path}")
71
+ sys.exit(1)
72
+
73
+ print(f"Importing concepts from {args.json_path} to {args.db_path}...")
74
+ try:
75
+ added, skipped = db.import_concepts_from_json(args.json_path)
76
+ # Optional: Add more feedback based on counts
77
+ except AttributeError:
78
+ print(f"Error: import_concepts_from_json method not found in SFOSRDatabase class in {db.__class__.__module__}.")
79
+ sys.exit(1)
80
+ except Exception as e:
81
+ print(f"An unexpected error occurred during import: {e}")
82
+ import traceback
83
+ traceback.print_exc() # Print stack trace for unexpected errors
84
+ sys.exit(1)
85
+
86
+ if __name__ == "__main__":
87
+ main()
sfosr.db CHANGED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:3ab8d2f8291292b3d49448099b3b085e72a83825fd8b20a37e534355495777a8
3
- size 118784
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:2dced7d5030004004ac3532c01117075552aa621e9caa6396e7f6b8ea45bf248
3
+ size 319488
sfosr_core/sfosr_database.py CHANGED
@@ -449,4 +449,89 @@ class SFOSRDatabase:
449
  }
450
  vectors.append(vector)
451
 
452
- return vectors
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
449
  }
450
  vectors.append(vector)
451
 
452
+ return vectors
453
+
454
+ def export_concepts_to_json(self, filepath: str) -> None:
455
+ """
456
+ Экспортирует все концепты из БД в JSON файл.
457
+
458
+ Args:
459
+ filepath: Путь к файлу для сохранения JSON.
460
+ """
461
+ concepts = self.get_all_concepts() # Reuse existing method
462
+ try:
463
+ with open(filepath, 'w', encoding='utf-8') as f:
464
+ json.dump(concepts, f, ensure_ascii=False, indent=2)
465
+ print(f"Concepts successfully exported to {filepath}")
466
+ except IOError as e:
467
+ print(f"Error writing to file {filepath}: {e}")
468
+ except Exception as e:
469
+ print(f"An unexpected error occurred during export: {e}")
470
+
471
+ def import_concepts_from_json(self, filepath: str) -> Tuple[int, int]:
472
+ """
473
+ Импортирует концепты из JSON файла, добавляя только те, которых нет в БД.
474
+
475
+ Args:
476
+ filepath: Путь к JSON файлу со списком концептов.
477
+ Каждый концепт должен быть словарем с ключами
478
+ 'name', 'description', 'domain', 'level'. 'id' игнорируется.
479
+
480
+ Returns:
481
+ Кортеж (added_count, skipped_count): Количество добавленных и пропущенных концептов.
482
+ """
483
+ added_count = 0
484
+ skipped_count = 0
485
+ try:
486
+ with open(filepath, 'r', encoding='utf-8') as f:
487
+ concepts_to_import = json.load(f)
488
+
489
+ if not isinstance(concepts_to_import, list):
490
+ print(f"Error: JSON file {filepath} should contain a list of concepts.")
491
+ return 0, 0
492
+
493
+ existing_names = self.get_all_concept_names() # Получаем существующие имена
494
+
495
+ with self as conn: # Используем одно соединение для всех вставок
496
+ cursor = conn.cursor()
497
+ for concept in concepts_to_import:
498
+ name = concept.get('name')
499
+ description = concept.get('description')
500
+ domain = concept.get('domain')
501
+ level = concept.get('level')
502
+
503
+ if not all([name, description, domain, level]):
504
+ print(f"Warning: Skipping concept due to missing fields: {concept}")
505
+ skipped_count += 1
506
+ continue
507
+
508
+ if name in existing_names:
509
+ # print(f"Skipping existing concept: {name}") # Optional: uncomment for verbose logging
510
+ skipped_count += 1
511
+ else:
512
+ try:
513
+ cursor.execute("""
514
+ INSERT INTO concepts (name, description, domain, level)
515
+ VALUES (?, ?, ?, ?)
516
+ """, (name, description, domain, level))
517
+ added_count += 1
518
+ existing_names.add(name) # Добавляем в сет, чтобы не добавить дубль из самого файла
519
+ except sqlite3.Error as e:
520
+ print(f"Error inserting concept {name}: {e}")
521
+ skipped_count += 1
522
+ # Optionally rollback or handle error differently
523
+
524
+ conn.commit() # Коммитим все изменения разом
525
+
526
+ print(f"Import finished. Added: {added_count}, Skipped (existing or invalid): {skipped_count}")
527
+ return added_count, skipped_count
528
+
529
+ except FileNotFoundError:
530
+ print(f"Error: Import file not found at {filepath}")
531
+ return 0, 0
532
+ except json.JSONDecodeError as e:
533
+ print(f"Error decoding JSON from {filepath}: {e}")
534
+ return 0, 0
535
+ except Exception as e:
536
+ print(f"An unexpected error occurred during import: {e}")
537
+ return 0, 0