Repository: SpikeInterface/spikeinterface

Issue:
curation_dict from sortingview doesn't have 'mergeGroups' key 
Hello, 
I just updated Spikeinterface from 0.100.2 to 0.101.0 and am making the transition to using sorting analyzer class which has been pretty smooth for the most part but I'm getting an error related to sortingview_curation. 
Here's my code:

```
save_folder = Path(data_folder) / "batch_sort"
analyzer = si.load_sorting_analyzer(
    folder=save_folder / "stage1/stage1_analyzer.zarr")

analyzer.compute("random_spikes") 
analyzer.compute("waveforms", ms_before=1.0, ms_after=2.0)
analyzer.compute("templates")
analyzer.compute("template_similarity")
analyzer.compute("correlograms")
analyzer.compute("spike_amplitudes")
analyzer.compute("unit_locations")

si.plot_sorting_summary(analyzer, curation=True, backend="sortingview")
uri = input("\nPlease enter uri: ")
manual_curation_sorting = si.apply_sortingview_curation(
    analyzer.sorting, uri_or_json=uri)
```
However, apply_sortingview_curation throws me a KeyValue error. 

```
si.apply_sortingview_curation(
    analyzer.sorting, uri_or_json=uri)
Traceback (most recent call last):

  Cell In[59], line 1
    si.apply_sortingview_curation(

  File ~\anaconda3\envs\si_env3\Lib\site-packages\spikeinterface\curation\sortingview_curation.py:74 in apply_sortingview_curation
    curation_dict = convert_from_sortingview_curation_format_v0(curation_dict)

  File ~\anaconda3\envs\si_env3\Lib\site-packages\spikeinterface\curation\curation_format.py:96 in convert_from_sortingview_curation_format_v0
    merge_groups = sortingview_dict["mergeGroups"]

KeyError: 'mergeGroups'
```

Printing sortingview_dict returns this:
```
{'labelsByUnit': {'12': ['reject'], '13': ['accept'], '14': ['accept'], '15': ['accept'], '16': ['accept'], '17': ['accept'], '22': ['accept'], '23': ['accept'], '24': ['accept'], '25': ['reject'], '26': ['accept'], '30': ['accept'], '31': ['accept'], '32': ['accept'], '37': ['accept'], '40': ['accept'], '41': ['accept'], '48': ['accept'], '49': ['accept'], '50': ['accept'], '51': ['accept'], '52': ['accept'], '54': ['reject'], '55': ['accept'], '56': ['accept'], '57': ['accept'], '58': ['accept'], '59': ['accept'], '67': ['accept'], '68': ['accept'], '69': ['reject'], '7': ['accept'], '72': ['reject'], '76': ['accept'], '77': ['accept']}}
```
The curation dict is returned from kcl.load_json function from sortingview_curation.py:
```
# download
if Path(uri_or_json).suffix == ".json" and not str(uri_or_json).startswith("gh://"):
    with open(uri_or_json, "r") as f:
        curation_dict = json.load(f)
else:
    try:
        import kachery_cloud as kcl
    except ImportError:
        raise ImportError(
            "To apply a SortingView manual curation, you need to have sortingview installed: "
            ">>> pip install sortingview"
        )

    try:
        curation_dict = kcl.load_json(uri=uri_or_json)
    except:
        raise Exception(f"Could not retrieve curation from SortingView uri: {uri_or_json}")

# convert to new format
if "format_version" not in curation_dict:
    curation_dict = convert_from_sortingview_curation_format_v0(curation_dict)
```

Is there a reason why kcl.load_json isn't returning a curation_dict with the correct format? 

Also, thank you guys for doing a great job with SpikeInterface. It's been a pleasure working with it. 


Discussion:

Patch:
diff --git a/src/spikeinterface/curation/curation_format.py b/src/spikeinterface/curation/curation_format.py
index babe7aac4..511abb780 100644
--- a/src/spikeinterface/curation/curation_format.py
+++ b/src/spikeinterface/curation/curation_format.py
@@ -92,13 +92,17 @@ def convert_from_sortingview_curation_format_v0(sortingview_dict, destination_fo
     """
 
     assert destination_format == "1"
-
+    if "mergeGroups" not in sortingview_dict.keys():
+        sortingview_dict["mergeGroups"] = []
     merge_groups = sortingview_dict["mergeGroups"]
     merged_units = sum(merge_groups, [])
-    if len(merged_units) > 0:
-        unit_id_type = int if isinstance(merged_units[0], int) else str
+
+    first_unit_id = next(iter(sortingview_dict["labelsByUnit"].keys()))
+    if str.isdigit(first_unit_id):
+        unit_id_type = int
     else:
         unit_id_type = str
+
     all_units = []
     all_labels = []
     manual_labels = []


Test patch:
diff --git a/src/spikeinterface/curation/tests/sv-sorting-curation-no-merge.json b/src/spikeinterface/curation/tests/sv-sorting-curation-no-merge.json
new file mode 100644
index 000000000..2a350340f
--- /dev/null
+++ b/src/spikeinterface/curation/tests/sv-sorting-curation-no-merge.json
@@ -0,0 +1,1 @@
+{"labelsByUnit":{"2":["mua"],"3":["mua"],"4":["mua"],"5":["accept"],"6":["accept"],"7":["accept"],"8":["artifact"],"9":["artifact"]}}
diff --git a/src/spikeinterface/curation/tests/test_sortingview_curation.py b/src/spikeinterface/curation/tests/test_sortingview_curation.py
index bb152e7f7..945aca793 100644
--- a/src/spikeinterface/curation/tests/test_sortingview_curation.py
+++ b/src/spikeinterface/curation/tests/test_sortingview_curation.py
@@ -243,11 +243,23 @@ def test_label_inheritance_str():
     assert np.all(sorting_include_accept.get_property("accept"))
 
 
+def test_json_no_merge_curation():
+    """
+    Test curation with no merges using a JSON file.
+    """
+    sorting = generate_sorting(num_units=10)
+
+    json_file = parent_folder / "sv-sorting-curation-no-merge.json"
+    sorting_curated = apply_sortingview_curation(sorting, uri_or_json=json_file)
+
+
 if __name__ == "__main__":
     # generate_sortingview_curation_dataset()
     # test_sha1_curation()
+
     test_gh_curation()
     test_json_curation()
     test_false_positive_curation()
     test_label_inheritance_int()
     test_label_inheritance_str()
+    test_json_no_merge_curation()