Compare commits

..

1 Commits

Author SHA1 Message Date
lebaudantoine af214d582d 🐛(frontend) fix unclickable fullscreen warning buttons
Adjust z-index values to restore button interactivity broken by previous
z-index changes in commit 53e68b7, ensuring fullscreen warning dismiss
controls remain accessible to users instead of being blocked
by overlay layering.
2025-12-10 12:44:57 +01:00
22 changed files with 133 additions and 252 deletions
-26
View File
@@ -34,32 +34,6 @@ jobs:
if: always()
run: ~/.local/bin/gitlint --commits origin/${{ github.event.pull_request.base.ref }}..HEAD
check-changelog:
runs-on: ubuntu-latest
if: |
contains(github.event.pull_request.labels.*.name, 'noChangeLog') == false &&
github.event_name == 'pull_request'
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 50
- name: Check that the CHANGELOG has been modified in the current branch
run: git diff --name-only ${{ github.event.pull_request.base.sha }} ${{ github.event.after }} | grep 'CHANGELOG.md'
lint-changelog:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Check CHANGELOG max line length
run: |
max_line_length=$(cat CHANGELOG.md | grep -Ev "^\[.*\]: https://github.com" | wc -L)
if [ $max_line_length -ge 80 ]; then
echo "ERROR: CHANGELOG has lines longer than 80 characters."
exit 1
fi
build-mails:
runs-on: ubuntu-latest
defaults:
+1 -1
View File
@@ -9,4 +9,4 @@ and this project adheres to
## [Unreleased]
-
- 🔧(backend) support `_FILE` for secret environment variables #566
+1 -1
View File
@@ -1,7 +1,7 @@
[project]
name = "agents"
version = "1.0.0"
version = "0.1.42"
requires-python = ">=3.12"
dependencies = [
"livekit-agents==1.2.18",
-2
View File
@@ -159,8 +159,6 @@ class RoomSerializer(serializers.ModelSerializer):
configuration=configuration,
is_admin_or_owner=is_admin_or_owner,
)
else:
del output["pin_code"]
output["is_administrable"] = is_admin_or_owner
@@ -3,8 +3,6 @@
import logging
from typing import Dict
from django.conf import settings
from rest_framework import exceptions, permissions
from .. import models
@@ -57,12 +55,6 @@ class BaseScopePermission(permissions.BasePermission):
if isinstance(token_scopes, str):
token_scopes = token_scopes.split()
if settings.OIDC_RS_SCOPES_PREFIX:
token_scopes = [
scope.replace(f"{settings.OIDC_RS_SCOPES_PREFIX}:", "")
for scope in token_scopes
]
if required_scope not in token_scopes:
raise exceptions.PermissionDenied(
f"Insufficient permissions. Required scope: {required_scope}"
@@ -32,6 +32,7 @@ def test_api_rooms_retrieve_anonymous_private_pk():
"id": str(room.id),
"is_administrable": False,
"name": room.name,
"pin_code": room.pin_code,
"slug": room.slug,
}
@@ -51,6 +52,7 @@ def test_api_rooms_retrieve_anonymous_trusted_pk():
"id": str(room.id),
"is_administrable": False,
"name": room.name,
"pin_code": room.pin_code,
"slug": room.slug,
}
@@ -69,6 +71,7 @@ def test_api_rooms_retrieve_anonymous_private_pk_no_dashes():
"id": str(room.id),
"is_administrable": False,
"name": room.name,
"pin_code": room.pin_code,
"slug": room.slug,
}
@@ -85,6 +88,7 @@ def test_api_rooms_retrieve_anonymous_private_slug():
"id": str(room.id),
"is_administrable": False,
"name": room.name,
"pin_code": room.pin_code,
"slug": room.slug,
}
@@ -101,6 +105,7 @@ def test_api_rooms_retrieve_anonymous_private_slug_not_normalized():
"id": str(room.id),
"is_administrable": False,
"name": room.name,
"pin_code": room.pin_code,
"slug": room.slug,
}
@@ -342,6 +347,7 @@ def test_api_rooms_retrieve_authenticated():
"id": str(room.id),
"is_administrable": False,
"name": room.name,
"pin_code": room.pin_code,
"slug": room.slug,
}
@@ -373,7 +373,6 @@ def test_resource_server_creates_user_on_first_authentication(settings):
settings.OIDC_RS_CLIENT_ID = "some_client_id"
settings.OIDC_RS_CLIENT_SECRET = "some_client_secret"
settings.OIDC_RS_SCOPES_PREFIX = "lasuite_meet"
settings.OIDC_OP_URL = "https://oidc.example.com"
settings.OIDC_VERIFY_SSL = False
@@ -390,7 +389,7 @@ def test_resource_server_creates_user_on_first_authentication(settings):
"aud": "some_client_id", # settings.OIDC_RS_CLIENT_ID
"sub": "very-specific-sub",
"client_id": "some_service_provider",
"scope": "openid lasuite_meet lasuite_meet:rooms:list",
"scope": "openid lasuite_meet rooms:list",
"active": True,
},
)
@@ -490,7 +489,6 @@ def test_resource_server_authentication_successful(settings):
settings.OIDC_RS_CLIENT_ID = "some_client_id"
settings.OIDC_RS_CLIENT_SECRET = "some_client_secret"
settings.OIDC_RS_SCOPES_PREFIX = "lasuite_meet"
settings.OIDC_OP_URL = "https://oidc.example.com"
settings.OIDC_VERIFY_SSL = False
@@ -507,7 +505,7 @@ def test_resource_server_authentication_successful(settings):
"aud": "some_client_id", # settings.OIDC_RS_CLIENT_ID
"sub": "very-specific-sub",
"client_id": "some_service_provider",
"scope": "openid lasuite_meet lasuite_meet:rooms:list",
"scope": "openid lasuite_meet rooms:list",
"active": True,
},
)
-3
View File
@@ -538,9 +538,6 @@ class Base(Configuration):
OIDC_RS_ENCRYPTION_KEY_TYPE = values.Value(
default="RSA", environ_name="OIDC_RS_ENCRYPTION_KEY_TYPE", environ_prefix=None
)
OIDC_RS_SCOPES_PREFIX = values.Value(
default=None, environ_name="OIDC_RS_SCOPES_PREFIX", environ_prefix=None
)
# Video conference configuration
LIVEKIT_CONFIGURATION = {
+1 -1
View File
@@ -7,7 +7,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "meet"
version = "1.0.0"
version = "0.1.42"
authors = [{ "name" = "DINUM", "email" = "dev@mail.numerique.gouv.fr" }]
classifiers = [
"Development Status :: 5 - Production/Stable",
+30 -39
View File
@@ -1,12 +1,12 @@
{
"name": "meet",
"version": "1.0.0",
"version": "0.1.42",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "meet",
"version": "1.0.0",
"version": "0.1.42",
"dependencies": {
"@livekit/components-react": "2.9.13",
"@livekit/components-styles": "1.1.6",
@@ -55,7 +55,7 @@
"postcss": "8.5.6",
"prettier": "3.6.2",
"typescript": "5.8.3",
"vite": "7.0.8",
"vite": "7.0.2",
"vite-tsconfig-paths": "5.1.4"
}
},
@@ -104,7 +104,6 @@
"integrity": "sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@ampproject/remapping": "^2.2.0",
"@babel/code-frame": "^7.27.1",
@@ -3819,6 +3818,17 @@
"win32"
]
},
"node_modules/@rrweb/types": {
"version": "2.0.0-alpha.17",
"resolved": "https://registry.npmjs.org/@rrweb/types/-/types-2.0.0-alpha.17.tgz",
"integrity": "sha512-AfDTVUuCyCaIG0lTSqYtrZqJX39ZEYzs4fYKnexhQ+id+kbZIpIJtaut5cto6dWZbB3SEe4fW0o90Po3LvTmfg==",
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"rrweb-snapshot": "^2.0.0-alpha.17"
}
},
"node_modules/@swc/helpers": {
"version": "0.5.13",
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.13.tgz",
@@ -3870,7 +3880,6 @@
"resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.81.5.tgz",
"integrity": "sha512-lOf2KqRRiYWpQT86eeeftAGnjuTR35myTP8MXyvHa81VlomoAWNEd8x5vkcAfQefu0qtYCvyqLropFZqgI2EQw==",
"license": "MIT",
"peer": true,
"dependencies": {
"@tanstack/query-core": "5.81.5"
},
@@ -3962,7 +3971,8 @@
"version": "1.0.22",
"resolved": "https://registry.npmjs.org/@types/dom-mediacapture-record/-/dom-mediacapture-record-1.0.22.tgz",
"integrity": "sha512-mUMZLK3NvwRLcAAT9qmcK+9p7tpU2FHdDsntR3YI4+GY88XrgG4XiE7u1Q2LAN2/FZOz/tdMDC3GQCR4T8nFuw==",
"license": "MIT"
"license": "MIT",
"peer": true
},
"node_modules/@types/dom-mediacapture-transform": {
"version": "0.1.11",
@@ -3978,7 +3988,8 @@
"version": "0.1.15",
"resolved": "https://registry.npmjs.org/@types/dom-webcodecs/-/dom-webcodecs-0.1.15.tgz",
"integrity": "sha512-omOlCPvTWyPm4ZE5bZUhlSvnHM2ZWM2U+1cPiYFL/e8aV5O9MouELp+L4dMKNTON0nTeHqEg+KWDfFQMY5Wkaw==",
"license": "MIT"
"license": "MIT",
"peer": true
},
"node_modules/@types/estree": {
"version": "1.0.8",
@@ -4005,7 +4016,6 @@
"integrity": "sha512-B2egV9wALML1JCpv3VQoQ+yesQKAmNMBIAY7OteVrikcOcAkWm+dGL6qpeCktPjAv6N1JLnhbNiqS35UpFyBsQ==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"undici-types": "~6.21.0"
}
@@ -4023,7 +4033,6 @@
"integrity": "sha512-D2wOSq/d6Agt28q7rSI3jhU7G6aiuzljDGZ2hTZHIkrTLUI+AF3WMeKkEZ9nN2fkBAlcktT6vcZjDFiIhMYEQw==",
"devOptional": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@types/prop-types": "*",
"csstype": "^3.0.2"
@@ -4090,7 +4099,6 @@
"integrity": "sha512-3MyiDfrfLeK06bi/g9DqJxP5pV74LNv4rFTyvGDmT3x2p1yp1lOd+qYZfiRPIOf/oON+WRZR5wxxuF85qOar+w==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@typescript-eslint/scope-manager": "8.35.1",
"@typescript-eslint/types": "8.35.1",
@@ -4382,7 +4390,6 @@
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz",
"integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==",
"dev": true,
"peer": true,
"bin": {
"acorn": "bin/acorn"
},
@@ -4797,7 +4804,6 @@
"url": "https://github.com/sponsors/ai"
}
],
"peer": true,
"dependencies": {
"caniuse-lite": "^1.0.30001646",
"electron-to-chromium": "^1.5.4",
@@ -5607,7 +5613,6 @@
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz",
"integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==",
"dev": true,
"peer": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.6.1",
@@ -6575,7 +6580,6 @@
}
],
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/runtime": "^7.27.6"
},
@@ -7460,7 +7464,6 @@
"resolved": "https://registry.npmjs.org/livekit-client/-/livekit-client-2.15.7.tgz",
"integrity": "sha512-19m8Q1cvRl5PslRawDUgWXeP8vL8584tX8kiZEJaPZo83U/L6VPS/O7pP06phfJaBWeeV8sAOVtEPlQiZEHtpg==",
"license": "Apache-2.0",
"peer": true,
"dependencies": {
"@livekit/mutex": "1.1.1",
"@livekit/protocol": "1.39.3",
@@ -8120,7 +8123,6 @@
}
],
"license": "MIT",
"peer": true,
"dependencies": {
"nanoid": "^3.3.11",
"picocolors": "^1.1.1",
@@ -8234,7 +8236,6 @@
"integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"cssesc": "^3.0.0",
"util-deprecate": "^1.0.2"
@@ -8388,7 +8389,6 @@
"resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
"integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"loose-envify": "^1.1.0"
},
@@ -8495,7 +8495,6 @@
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
"integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
"license": "MIT",
"peer": true,
"dependencies": {
"loose-envify": "^1.1.0",
"scheduler": "^0.23.2"
@@ -8745,6 +8744,7 @@
"integrity": "sha512-GBg5pV8LHOTbeVmH2VHLEFR0mc2QpQMzAvcoxEGfPNWgWHc8UvKCyq7pqN1vA+fDZ+yXXbixeO0kB2pzVvFCBw==",
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"postcss": "^8.4.38"
}
@@ -9248,7 +9248,6 @@
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
"dev": true,
"license": "MIT",
"peer": true,
"engines": {
"node": ">=12"
},
@@ -9367,8 +9366,7 @@
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
"license": "0BSD",
"peer": true
"license": "0BSD"
},
"node_modules/type-check": {
"version": "0.4.0",
@@ -9480,7 +9478,6 @@
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz",
"integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
"license": "Apache-2.0",
"peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@@ -9641,7 +9638,6 @@
"resolved": "https://registry.npmjs.org/valtio/-/valtio-2.1.5.tgz",
"integrity": "sha512-vsh1Ixu5mT0pJFZm+Jspvhga5GzHUTYv0/+Th203pLfh3/wbHwxhu/Z2OkZDXIgHfjnjBns7SN9HNcbDvPmaGw==",
"license": "MIT",
"peer": true,
"dependencies": {
"proxy-compare": "^3.0.1"
},
@@ -9737,16 +9733,15 @@
}
},
"node_modules/vite": {
"version": "7.0.8",
"resolved": "https://registry.npmjs.org/vite/-/vite-7.0.8.tgz",
"integrity": "sha512-cJBdq0/u+8rgstg9t7UkBilf8ipLmeXJO30NxD5HAHOivnj10ocV8YtR/XBvd2wQpN3TmcaxNKaHX3tN7o5F5A==",
"version": "7.0.2",
"resolved": "https://registry.npmjs.org/vite/-/vite-7.0.2.tgz",
"integrity": "sha512-hxdyZDY1CM6SNpKI4w4lcUc3Mtkd9ej4ECWVHSMrOdSinVc2zYOAppHeGc/hzmRo3pxM5blMzkuWHOJA/3NiFw==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"esbuild": "^0.25.0",
"fdir": "^6.4.6",
"picomatch": "^4.0.3",
"picomatch": "^4.0.2",
"postcss": "^8.5.6",
"rollup": "^4.40.0",
"tinyglobby": "^0.2.14"
@@ -9854,14 +9849,11 @@
}
},
"node_modules/vite/node_modules/fdir": {
"version": "6.5.0",
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
"integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
"version": "6.4.6",
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz",
"integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=12.0.0"
},
"peerDependencies": {
"picomatch": "^3 || ^4"
},
@@ -9872,12 +9864,11 @@
}
},
"node_modules/vite/node_modules/picomatch": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
"dev": true,
"license": "MIT",
"peer": true,
"engines": {
"node": ">=12"
},
+2 -2
View File
@@ -1,7 +1,7 @@
{
"name": "meet",
"private": true,
"version": "1.0.0",
"version": "0.1.42",
"type": "module",
"scripts": {
"dev": "panda codegen && vite",
@@ -60,7 +60,7 @@
"postcss": "8.5.6",
"prettier": "3.6.2",
"typescript": "5.8.3",
"vite": "7.0.8",
"vite": "7.0.2",
"vite-tsconfig-paths": "5.1.4"
}
}
@@ -30,7 +30,6 @@ import { MediaDeviceErrorAlert } from './MediaDeviceErrorAlert'
import { usePostHog } from 'posthog-js/react'
import { useConfig } from '@/api/useConfig'
import { isFireFox } from '@/utils/livekit'
import { useIsMobile } from '@/utils/useIsMobile'
export const Conference = ({
roomId,
@@ -170,8 +169,6 @@ export const Conference = ({
kind: null,
})
const isMobile = useIsMobile()
/*
* Ensure stable WebSocket connection URL. This is critical for legacy browser compatibility
* (Firefox <124, Chrome <125, Edge <125) where HTTPS URLs in WebSocket() constructor
@@ -241,7 +238,7 @@ export const Conference = ({
}}
>
<VideoConference />
{showInviteDialog && !isMobile && (
{showInviteDialog && (
<InviteDialog
isOpen={showInviteDialog}
onOpenChange={setShowInviteDialog}
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "mail_mjml",
"version": "1.0.0",
"version": "0.1.42",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "mail_mjml",
"version": "1.0.0",
"version": "0.1.42",
"license": "MIT",
"dependencies": {
"@html-to/text-cli": "0.5.4",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "mail_mjml",
"version": "1.0.0",
"version": "0.1.42",
"description": "An util to generate html and text django's templates from mjml templates",
"type": "module",
"dependencies": {
+1 -1
View File
@@ -24,6 +24,6 @@
"globals": "16.3.0",
"typescript": "5.8.3",
"typescript-eslint": "8.35.1",
"vite": "7.0.8"
"vite": "7.0.2"
}
}
+1 -1
View File
@@ -46,7 +46,7 @@
"sass": "1.89.2",
"prettier": "3.6.2",
"typescript": "5.8.3",
"vite": "7.0.8",
"vite": "7.0.2",
"vite-plugin-dts": "4.5.4"
}
}
+14 -17
View File
@@ -1,12 +1,12 @@
{
"name": "sdk",
"version": "1.0.0",
"version": "0.1.42",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "sdk",
"version": "1.0.0",
"version": "0.1.42",
"license": "ISC",
"workspaces": [
"./library",
@@ -30,7 +30,7 @@
"globals": "16.3.0",
"typescript": "5.8.3",
"typescript-eslint": "8.35.1",
"vite": "7.0.8"
"vite": "7.0.2"
}
},
"consumer/node_modules/@eslint/js": {
@@ -103,7 +103,7 @@
"prettier": "3.6.2",
"sass": "1.89.2",
"typescript": "5.8.3",
"vite": "7.0.8",
"vite": "7.0.2",
"vite-plugin-dts": "4.5.4"
}
},
@@ -6677,15 +6677,15 @@
}
},
"node_modules/vite": {
"version": "7.0.8",
"resolved": "https://registry.npmjs.org/vite/-/vite-7.0.8.tgz",
"integrity": "sha512-cJBdq0/u+8rgstg9t7UkBilf8ipLmeXJO30NxD5HAHOivnj10ocV8YtR/XBvd2wQpN3TmcaxNKaHX3tN7o5F5A==",
"version": "7.0.2",
"resolved": "https://registry.npmjs.org/vite/-/vite-7.0.2.tgz",
"integrity": "sha512-hxdyZDY1CM6SNpKI4w4lcUc3Mtkd9ej4ECWVHSMrOdSinVc2zYOAppHeGc/hzmRo3pxM5blMzkuWHOJA/3NiFw==",
"dev": true,
"license": "MIT",
"dependencies": {
"esbuild": "^0.25.0",
"fdir": "^6.4.6",
"picomatch": "^4.0.3",
"picomatch": "^4.0.2",
"postcss": "^8.5.6",
"rollup": "^4.40.0",
"tinyglobby": "^0.2.14"
@@ -6779,14 +6779,11 @@
}
},
"node_modules/vite/node_modules/fdir": {
"version": "6.5.0",
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
"integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
"version": "6.4.6",
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz",
"integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=12.0.0"
},
"peerDependencies": {
"picomatch": "^3 || ^4"
},
@@ -6797,9 +6794,9 @@
}
},
"node_modules/vite/node_modules/picomatch": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
"dev": true,
"license": "MIT",
"engines": {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "sdk",
"version": "1.0.0",
"version": "0.1.42",
"author": "",
"license": "ISC",
"description": "",
+1 -1
View File
@@ -1,7 +1,7 @@
[project]
name = "summary"
version = "1.0.0"
version = "0.1.42"
dependencies = [
"fastapi[standard]>=0.105.0",
"uvicorn>=0.24.0",
+68 -12
View File
@@ -31,7 +31,6 @@ from summary.core.prompt import (
PROMPT_SYSTEM_TLDR,
PROMPT_USER_PART,
)
from summary.core.transcript_formatter import TranscriptFormatter
settings = get_settings()
analytics = get_analytics()
@@ -57,6 +56,28 @@ if settings.sentry_dsn and settings.sentry_is_enabled:
sentry_sdk.init(dsn=settings.sentry_dsn, enable_tracing=True)
DEFAULT_EMPTY_TRANSCRIPTION = """
**Aucun contenu audio na été détecté dans votre transcription.**
*Si vous pensez quil sagit dune erreur, nhésitez pas à contacter
notre support technique : visio@numerique.gouv.fr*
.
.
.
Quelques points que nous vous conseillons de vérifier :
- Un micro était-il activé ?
- Étiez-vous suffisamment proche ?
- Le micro est-il de bonne qualité ?
- Lenregistrement dure-t-il plus de 30 secondes ?
"""
class AudioValidationError(Exception):
"""Custom exception for audio validation errors."""
@@ -145,6 +166,36 @@ def format_actions(llm_output: dict) -> str:
return ""
def format_segments(transcription_data):
"""Format transcription segments from WhisperX into a readable conversation format.
Processes transcription data with segments containing speaker information and text,
combining consecutive segments from the same speaker and formatting them as a
conversation with speaker labels.
"""
formatted_output = ""
if not transcription_data or not hasattr(transcription_data, "segments"):
if isinstance(transcription_data, dict) and "segments" in transcription_data:
segments = transcription_data["segments"]
else:
return "Error: Invalid transcription data format"
else:
segments = transcription_data.segments
previous_speaker = None
for segment in segments:
speaker = segment.get("speaker", "UNKNOWN_SPEAKER")
text = segment.get("text", "")
if text:
if speaker != previous_speaker:
formatted_output += f"\n\n **{speaker}**: {text}"
else:
formatted_output += f" {text}"
previous_speaker = speaker
return formatted_output
def post_with_retries(url, data):
"""Send POST request with automatic retries."""
session = create_retry_session()
@@ -255,20 +306,25 @@ def process_audio_transcribe_summarize_v2(
os.remove(temp_file_path)
logger.debug("Temporary file removed: %s", temp_file_path)
metadata_manager.track_transcription_metadata(task_id, transcription)
formatter = TranscriptFormatter()
content, title = formatter.format(
transcription,
room=room,
recording_date=recording_date,
recording_time=recording_time,
formatted_transcription = (
DEFAULT_EMPTY_TRANSCRIPTION
if not transcription.segments
else format_segments(transcription)
)
metadata_manager.track_transcription_metadata(task_id, transcription)
if not room or not recording_date or not recording_time:
title = settings.document_default_title
else:
title = settings.document_title_template.format(
room=room,
room_recording_date=recording_date,
room_recording_time=recording_time,
)
data = {
"title": title,
"content": content,
"content": formatted_transcription,
"email": email,
"sub": sub,
}
@@ -300,7 +356,7 @@ def process_audio_transcribe_summarize_v2(
):
logger.info("Queuing summary generation task.")
summarize_transcription.apply_async(
args=[content, email, sub, title],
args=[formatted_transcription, email, sub, title],
queue=settings.summarize_queue,
)
else:
-4
View File
@@ -45,10 +45,6 @@ class Settings(BaseSettings):
llm_api_key: str
llm_model: str
# Transcription processing
hallucination_patterns: List[str] = ["Vap'n'Roll Thierry"]
hallucination_replacement_text: str = "[Texte impossible à transcrire]"
# Webhook-related settings
webhook_max_retries: int = 2
webhook_status_forcelist: List[int] = [502, 503, 504]
@@ -1,121 +0,0 @@
"""Transcript formatting into readable conversation format with speaker labels."""
import logging
from typing import Optional, Tuple
from summary.core.config import get_settings
settings = get_settings()
logger = logging.getLogger(__name__)
DEFAULT_EMPTY_TRANSCRIPTION = """
**Aucun contenu audio na été détecté dans votre transcription.**
*Si vous pensez quil sagit dune erreur, nhésitez pas à contacter
notre support technique : visio@numerique.gouv.fr*
.
.
.
Quelques points que nous vous conseillons de vérifier :
- Un micro était-il activé ?
- Étiez-vous suffisamment proche ?
- Le micro est-il de bonne qualité ?
- Lenregistrement dure-t-il plus de 30 secondes ?
"""
class TranscriptFormatter:
"""Formats WhisperX transcription output into readable conversation format.
Handles:
- Extracting segments from transcription objects or dictionaries
- Combining consecutive segments from the same speaker
- Removing hallucination patterns from content
- Generating descriptive titles from context
"""
def __init__(self):
"""Initialize formatter with settings."""
self.hallucination_patterns = settings.hallucination_patterns
self.hallucination_replacement_text = settings.hallucination_replacement_text
self.default_title = settings.document_default_title
self.default_empty_transcription = DEFAULT_EMPTY_TRANSCRIPTION
def _get_segments(self, transcription):
"""Extract segments from transcription object or dictionary."""
if hasattr(transcription, "segments"):
return transcription.segments
if isinstance(transcription, dict):
return transcription.get("segments", None)
return None
def format(
self,
transcription,
room: Optional[str] = None,
recording_date: Optional[str] = None,
recording_time: Optional[str] = None,
) -> Tuple[str, str]:
"""Format transcription into the final document and its title."""
segments = self._get_segments(transcription)
if not segments:
content = self.default_empty_transcription
else:
content = self._format_speaker(segments)
content = self._remove_hallucinations(content)
title = self._generate_title(room, recording_date, recording_time)
return content, title
def _remove_hallucinations(self, content: str) -> str:
"""Remove hallucination patterns from content."""
replacement = self.hallucination_replacement_text or ""
for pattern in self.hallucination_patterns:
content = content.replace(pattern, replacement)
return content
def _format_speaker(self, segments) -> str:
"""Format segments with speaker labels, combining consecutive speakers."""
formatted_output = ""
previous_speaker = None
for segment in segments:
speaker = segment.get("speaker", "UNKNOWN_SPEAKER")
text = segment.get("text", "")
if text:
if speaker != previous_speaker:
formatted_output += f"\n\n **{speaker}**: {text}"
else:
formatted_output += f" {text}"
previous_speaker = speaker
return formatted_output
def _generate_title(
self,
room: Optional[str] = None,
recording_date: Optional[str] = None,
recording_time: Optional[str] = None,
) -> str:
"""Generate title from context or return default."""
if not room or not recording_date or not recording_time:
return self.default_title
return settings.document_title_template.format(
room=room,
room_recording_date=recording_date,
room_recording_time=recording_time,
)