Skip to content

Commit 0760158

Browse files
committed
Merge remote-tracking branch 'origin/develop' into fix/7761-spectrogram-initial-render
2 parents 820fa79 + 9b06605 commit 0760158

File tree

36 files changed

+1388
-140
lines changed

36 files changed

+1388
-140
lines changed

.github/workflows/fm-command.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ concurrency:
99

1010
jobs:
1111
sync:
12-
name: "Update: Update Feature Flags"
12+
name: "Follow Merge: Sync Upstream PRs"
1313
if: github.event.client_payload.slash_command.args.unnamed.arg1 == 'sync'
1414
uses: ./.github/workflows/follow-merge-upstream-repo-sync-v2.yml
1515
with:

.github/workflows/follow-merge-upstream-repo-sync-v2.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,13 +145,12 @@ jobs:
145145
upstream_prs_urls: "${{ steps.upstream-prs.outputs.upstream_prs_urls }}"
146146

147147
- name: Add PR Assignees
148-
if: steps.upstream-prs.outputs.assignees
149148
uses: ./.github/actions-hub/actions/github-add-pull-request-assignees
150149
continue-on-error: true
151150
with:
152151
github_token: ${{ secrets.GIT_PAT }}
153152
pullrequest_number: "${{ steps.get-pr.outputs.number }}"
154-
assignees: "${{ steps.upstream-prs.outputs.assignees }}"
153+
assignees: "${{ steps.upstream-prs.outputs.assignees }},${{ github.event.client_payload.github.actor }}"
155154

156155
- name: Add PR state Labels
157156
if: steps.upstream-prs.outputs.status == 'stale'

docs/source/guide/manage_data.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,36 @@ When you filter or sort the data before you label it, you modify which tasks and
4242

4343
<img src="/images/data-manager-filters.png" class="gif-border">
4444

45+
<div class="opensource-only">
46+
47+
!!! error Enterprise
48+
In Label Studio Enterprise, you can use advanced filters against annotation results. For more information, see our [Enterprise documentation](https://docs.humansignal.com/guide/manage_data#Filter-annotation-results).
49+
50+
</div>
51+
52+
<div class="enterprise-only">
53+
54+
### Filter annotation results
55+
56+
You can also filter on individual annotation results within a task:
57+
58+
<img src="/images/data-manager-filters-lse.png" class="gif-border" >
59+
60+
!!! note
61+
In Label Studio Community and Starter Cloud, the `Annotation results` filter is an unstructured text search across all annotations for the task, and the example above would not be achievable.
62+
63+
The following tags are supported:
64+
- All `Labels` tags (ex. `Labels`, `ParagraphLabels`, ...)
65+
- `Choices`
66+
- `Taxonomy`
67+
- `Rating`
68+
69+
**Known limitations:**
70+
- [Taxonomies loaded using `apiUrl`](/templates/taxonomy) will not be detected.
71+
72+
73+
</div>
74+
4575
### Example: Label new data first
4676
Sort the data in your project by date to focus on labeling the newest data first.
4777

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
---
2+
hide_sidebar: true
3+
---
4+
5+
## Label Studio Enterprise 2.25.0
6+
7+
<div class="onprem-highlight">Prompts on-prem availability, storage proxies, PDF tag, KeyPointLabels support, multi-task JSON imports for cloud</div>
8+
9+
*Jun 17, 2025*
10+
11+
Helm Chart version: [1.9.15](https://github.com/HumanSignal/charts/blob/master/heartex/label-studio/Chart.yaml)
12+
13+
### New features
14+
15+
#### Prompts availability for on-prem deployments
16+
17+
You can now configure your on-prem environment to use Prompts!
18+
19+
Prompts is an interface to easily integrate LLMs into your own Label Studio deployment. Leading teams use it to pre-label data, compare models, and generate synthetic samples.
20+
21+
You can find out more here:
22+
23+
* [Prompts overview](prompts_overview)
24+
* [Prompts product page](https://humansignal.com/platform/prompts/)
25+
* [Blog - How to Generate Synthetic Data with Prompts in Label Studio](https://humansignal.com/blog/how-to-generate-synthetic-data-with-prompts-in-label-studio/)
26+
27+
28+
Installing Prompts requires license enablement and [additional install steps](install_prompts). Reach out to your CSM to enable a free trial!
29+
30+
![Stylized image of Prompts](/images/releases/dog-prompts.png)
31+
32+
#### Storage proxies for cloud files
33+
34+
Label Studio now uses a proxy when accessing media files in connect cloud storages. For more information, see [Pre-signed URLs vs. storage proxies](https://docs.humansignal.com/guide/storage#Pre-signed-URLs-vs-Storage-proxies).
35+
36+
Proxy mode is only used when the **Use pre-signed URLs** option is disabled in source storage.
37+
38+
Storage proxies offer secure media access, simplified configuration, and improved performance.
39+
40+
- Keeps data access within Label Studio's network boundary, ideal for on-premise environments
41+
- Enforces strict task-level access control, even for cached files
42+
- Eliminates the need for presigned URLs and CORS configuration
43+
- Solves performance and reliability issues for large files, videos, and audio
44+
- Media is now streamed via proxy, improving compatibility and scalability
45+
46+
#### New PDF tag
47+
48+
[new PDF tag](/tags/pdf) lets you directly ingest PDF URLs for classification without needing to use hypertext tags.
49+
50+
This also simplifies the process for using PDFs with Prompts for summarization and classification tasks.
51+
52+
53+
54+
### Enhancements
55+
56+
#### KeyPointLabels exports for COCO and YOLO
57+
58+
COCO and YOLO export formats now available for `KeyPointLabels`. For more information, see [our docs](https://docs.humansignal.com/guide/export#COCO).
59+
60+
#### Multi-task JSON imports for cloud
61+
62+
Previously, if you loaded JSON tasks from source storage, you could only configure one task per JSON file.
63+
64+
This restriction has been removed, and you can now specify multiple tasks per JSON file as long as all tasks follow the same format.
65+
66+
For more information, see the examples in our [our docs](https://docs.humansignal.com/guide/storage#Off).
67+
68+
69+
#### Miscellaneous
70+
71+
- The **Export Underlying Data** option was recently introduced and is available from the Annotations chart in the [annotator performance dashboard](dashboard_annotator). This allows you to export information about the tasks that the selected users have annotated.
72+
73+
Previously, users were only identified by user ID within the CSV. With this update, you can also identify users by email.
74+
75+
- User interface enhancements for the AI Assistant, including a new icon.
76+
77+
78+
### Bug fixes
79+
80+
- Fixed various user interface issues associated with the new dark mode feature.
81+
82+
- Fixed an issue where the **Not Activated** role was hidden by default on the Organization page.
83+
84+
- Fixed several small issues related to the annotator agreement score popover.
85+
86+
- Fixed an issue where when moving around panels in the labeling interface, groups were not sticking in place.
87+
88+
- Fixed an issue where the token refresh function was not using the user-supplied `httpx_client`.
89+
90+
- Fixed an issue with cloud storage in which tasks would not resolve correctly if they referenced data in different buckets.
91+
92+
- Fixed an issue where the drop-down menu to select a user role was overflowing past the page edge.
93+
94+
12.3 KB
Loading
6.09 KB
Loading
658 KB
Loading

label_studio/core/utils/common.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -630,6 +630,24 @@ def batch(iterable, n=1):
630630
yield iterable[ndx : min(ndx + n, l)]
631631

632632

633+
def batched_iterator(iterable, n):
634+
"""
635+
TODO: replace with itertools.batched when we drop support for Python < 3.12
636+
"""
637+
638+
iterator = iter(iterable)
639+
while True:
640+
batch = []
641+
for _ in range(n):
642+
try:
643+
batch.append(next(iterator))
644+
except StopIteration:
645+
if batch:
646+
yield batch
647+
return
648+
yield batch
649+
650+
633651
def round_floats(o):
634652
if isinstance(o, float):
635653
return round(o, 2)

label_studio/feature_flags.json

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2229,6 +2229,33 @@
22292229
"version": 3,
22302230
"deleted": false
22312231
},
2232+
"fflag_feat_front_bros_98_projects_infinite_loop_short": {
2233+
"key": "fflag_feat_front_bros_98_projects_infinite_loop_short",
2234+
"on": false,
2235+
"prerequisites": [],
2236+
"targets": [],
2237+
"contextTargets": [],
2238+
"rules": [],
2239+
"fallthrough": {
2240+
"variation": 0
2241+
},
2242+
"offVariation": 1,
2243+
"variations": [
2244+
true,
2245+
false
2246+
],
2247+
"clientSideAvailability": {
2248+
"usingMobileKey": false,
2249+
"usingEnvironmentId": false
2250+
},
2251+
"clientSide": false,
2252+
"salt": "ad2d4421af2b481382acee1ace4c5428",
2253+
"trackEvents": false,
2254+
"trackEventsFallthrough": false,
2255+
"debugEventsUntilDate": null,
2256+
"version": 2,
2257+
"deleted": false
2258+
},
22322259
"fflag_feat_front_dev-2536_comment_notifications_short": {
22332260
"key": "fflag_feat_front_dev-2536_comment_notifications_short",
22342261
"on": false,
@@ -3986,7 +4013,7 @@
39864013
},
39874014
"fflag_fix_front_dev_3391_interactive_view_all": {
39884015
"key": "fflag_fix_front_dev_3391_interactive_view_all",
3989-
"on": false,
4016+
"on": true,
39904017
"prerequisites": [],
39914018
"targets": [],
39924019
"contextTargets": [],
@@ -4008,7 +4035,7 @@
40084035
"trackEvents": false,
40094036
"trackEventsFallthrough": false,
40104037
"debugEventsUntilDate": null,
4011-
"version": 3,
4038+
"version": 4,
40124039
"deleted": false
40134040
},
40144041
"fflag_fix_front_dev_3793_relative_coords_short": {
@@ -4511,6 +4538,33 @@
45114538
"version": 3,
45124539
"deleted": false
45134540
},
4541+
"fflag_front_feat_bros_87_pixel_wise_16062025_short": {
4542+
"key": "fflag_front_feat_bros_87_pixel_wise_16062025_short",
4543+
"on": false,
4544+
"prerequisites": [],
4545+
"targets": [],
4546+
"contextTargets": [],
4547+
"rules": [],
4548+
"fallthrough": {
4549+
"variation": 0
4550+
},
4551+
"offVariation": 1,
4552+
"variations": [
4553+
true,
4554+
false
4555+
],
4556+
"clientSideAvailability": {
4557+
"usingMobileKey": false,
4558+
"usingEnvironmentId": false
4559+
},
4560+
"clientSide": false,
4561+
"salt": "f769d3e1c79142c6a2480c62a3b0d44e",
4562+
"trackEvents": false,
4563+
"trackEventsFallthrough": false,
4564+
"debugEventsUntilDate": null,
4565+
"version": 2,
4566+
"deleted": false
4567+
},
45144568
"fflag_optic_all_optic_1938_storage_proxy": {
45154569
"key": "fflag_optic_all_optic_1938_storage_proxy",
45164570
"on": true,

label_studio/projects/functions/utils.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from logging import getLogger
22
from typing import TYPE_CHECKING
33

4+
from django.db.models import QuerySet
45
from tasks.models import AnnotationDraft, Task
56

67
logger = getLogger(__name__)
@@ -10,6 +11,48 @@
1011
from projects.models import Project, ProjectSummary
1112

1213

14+
def get_unique_ids_list(tasks_queryset):
15+
"""
16+
Convert various input types to a list of unique IDs.
17+
18+
:param tasks_queryset: Can be:
19+
- list of IDs (integers)
20+
- list of objects with 'id' attribute
21+
- Django QuerySet
22+
- set of IDs or objects
23+
:return: list of unique IDs
24+
"""
25+
if isinstance(tasks_queryset, (list, tuple)):
26+
if not tasks_queryset:
27+
return []
28+
29+
# Check if it's a list of IDs (integers)
30+
if isinstance(tasks_queryset[0], int):
31+
return list(set(tasks_queryset)) # Remove duplicates
32+
33+
# It's a list of objects with 'id' attribute
34+
return list(set(obj.id for obj in tasks_queryset))
35+
36+
elif isinstance(tasks_queryset, set):
37+
if not tasks_queryset:
38+
return []
39+
40+
# Check if it's a set of IDs (integers)
41+
first_item = next(iter(tasks_queryset))
42+
if isinstance(first_item, int):
43+
return list(tasks_queryset)
44+
45+
# It's a set of objects with 'id' attribute
46+
return list(obj.id for obj in tasks_queryset)
47+
48+
elif isinstance(tasks_queryset, QuerySet):
49+
# It's a Django QuerySet
50+
return list(tasks_queryset.values_list('id', flat=True))
51+
52+
else:
53+
raise ValueError(f'Unsupported type for tasks_queryset: {type(tasks_queryset)}')
54+
55+
1356
def make_queryset_from_iterable(tasks_list):
1457
"""
1558
Make queryset from list/set of int/Tasks

0 commit comments

Comments
 (0)