mirror of
https://github.com/suitenumerique/meet.git
synced 2026-07-27 20:29:09 +00:00
Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| fdb5d447b0 | |||
| 8ac4c2409d | |||
| e47ad42656 | |||
| 2509452c52 | |||
| 1022780027 | |||
| 4a1a04f86e | |||
| 8702638cf3 | |||
| f88c0307ea | |||
| e7f15b50ff | |||
| 75ba2ff146 | |||
| bbe2a32efc | |||
| 86fff16eed | |||
| 195d2b5006 | |||
| 30cf264276 | |||
| 945d779b45 |
@@ -82,7 +82,7 @@ jobs:
|
|||||||
- name: Install Node.js
|
- name: Install Node.js
|
||||||
uses: actions/setup-node@v6
|
uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version: "18"
|
node-version: "22"
|
||||||
|
|
||||||
- name: Restore the mail templates
|
- name: Restore the mail templates
|
||||||
uses: actions/cache@v5
|
uses: actions/cache@v5
|
||||||
|
|||||||
@@ -8,6 +8,17 @@ and this project adheres to
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- 🗑️(settings) deprecate SUMMARY_SERVICE_VERSION=1
|
||||||
|
- ⬆️(mail) update mjml to v5 and @html-to/text-cli
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- 🩹(backend) identify externally provisioned users to PostHog
|
||||||
|
|
||||||
|
## [1.23.0] - 2026-07-08
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- ✨(backend) extend analytics module to support feature flags
|
- ✨(backend) extend analytics module to support feature flags
|
||||||
@@ -22,6 +33,13 @@ and this project adheres to
|
|||||||
- ✨(meet) use compatible with summary v2 #1362
|
- ✨(meet) use compatible with summary v2 #1362
|
||||||
- ♻️(backend) refactor analytics backend from Protocol to abstract class
|
- ♻️(backend) refactor analytics backend from Protocol to abstract class
|
||||||
- 🔥(summary) remove call to summary enabled feature flag
|
- 🔥(summary) remove call to summary enabled feature flag
|
||||||
|
- ♻️(frontend) wrap MuteEveryoneButton with AdminOrOwnerOnly
|
||||||
|
- ⬆️(frontend) upgrade livekit-client from 2.19.0 to 2.19.2
|
||||||
|
- ⬆️(frontend) upgrade posthog-js from 1.386.5 to 1.387.0
|
||||||
|
- ⬆️(frontend) upgrade @tanstack/react-query from 5.100.14 to 5.101.0
|
||||||
|
- ⬆️(frontend) update the frontend build image to Node 22
|
||||||
|
- 🔒️(frontend) update docker image to nginx-unprivileged:1.30.3-alpine3.23
|
||||||
|
- ✨(summary) more precise analytics events
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
|
|||||||
+12
@@ -15,3 +15,15 @@ the following command inside your docker container:
|
|||||||
(Note : in your development environment, you can `make migrate`.)
|
(Note : in your development environment, you can `make migrate`.)
|
||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
## v1.23.0
|
||||||
|
|
||||||
|
As part of the 1.23.0 release, the legacy `api/v1` implementation has been removed from the _experimental_ Summary service and Meet has been migrated to the new `api/v2`.
|
||||||
|
|
||||||
|
**To avoid a breaking change, the Meet backend continues to use the Summary service's v1-compatible API format by default (`SUMMARY_SERVICE_VERSION` setting defaults to `1`).**
|
||||||
|
|
||||||
|
If you are deploying both Meet and Summary from this repository, you must configure the Meet backend to use the v2 API by setting the following environment variable `SUMMARY_SERVICE_VERSION=2`.
|
||||||
|
|
||||||
|
If you are upgrading only the Meet deployment while keeping an older Summary v1 compatible deployment, no action is required, as the v1-compatible API remains the default.
|
||||||
|
|
||||||
|
Note that we plan on removing the legacy `v1` summary compatibility in a future major version. If you have your own implementation for the summary service, we recommend updating its API contract and setting `SUMMARY_SERVICE_VERSION=2`.
|
||||||
|
|||||||
@@ -113,6 +113,12 @@ update_python_version "summary"
|
|||||||
# Update agents pyproject.toml
|
# Update agents pyproject.toml
|
||||||
update_python_version "agents"
|
update_python_version "agents"
|
||||||
|
|
||||||
|
# Run uv lock in agents
|
||||||
|
print_info "Running uv lock in agents..."
|
||||||
|
cd "src/agents"
|
||||||
|
uv lock
|
||||||
|
cd -
|
||||||
|
|
||||||
# Update CHANGELOG
|
# Update CHANGELOG
|
||||||
print_info "Updating CHANGELOG..."
|
print_info "Updating CHANGELOG..."
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# ---- Front-end image ----
|
# ---- Front-end image ----
|
||||||
FROM node:20-alpine AS frontend-deps
|
FROM node:22-alpine AS frontend-deps
|
||||||
|
|
||||||
WORKDIR /home/frontend/
|
WORKDIR /home/frontend/
|
||||||
|
|
||||||
@@ -54,7 +54,7 @@ RUN npx webpack --mode production
|
|||||||
|
|
||||||
|
|
||||||
# ---- Front-end image ----
|
# ---- Front-end image ----
|
||||||
FROM nginxinc/nginx-unprivileged:alpine3.23 AS frontend-production
|
FROM nginxinc/nginx-unprivileged:1.30.3-alpine3.23 AS frontend-production
|
||||||
|
|
||||||
USER root
|
USER root
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "agents"
|
name = "agents"
|
||||||
version = "1.22.0"
|
version = "1.23.0"
|
||||||
requires-python = ">=3.12"
|
requires-python = ">=3.12"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"livekit-agents==1.6.4",
|
"livekit-agents==1.6.4",
|
||||||
|
|||||||
Generated
+1
-1
@@ -9,7 +9,7 @@ resolution-markers = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "agents"
|
name = "agents"
|
||||||
version = "1.22.0"
|
version = "1.23.0"
|
||||||
source = { virtual = "." }
|
source = { virtual = "." }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "livekit-agents" },
|
{ name = "livekit-agents" },
|
||||||
|
|||||||
@@ -215,5 +215,6 @@ class RoomViewSet(
|
|||||||
"client_id": client_id,
|
"client_id": client_id,
|
||||||
"external_api": True,
|
"external_api": True,
|
||||||
"auth_method": auth_method,
|
"auth_method": auth_method,
|
||||||
|
"$set": {"email": self.request.user.email},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ https://docs.djangoproject.com/en/3.1/ref/settings/
|
|||||||
# pylint: disable=too-many-lines
|
# pylint: disable=too-many-lines
|
||||||
|
|
||||||
import json
|
import json
|
||||||
|
import warnings
|
||||||
from os import path
|
from os import path
|
||||||
from socket import gethostbyname, gethostname
|
from socket import gethostbyname, gethostname
|
||||||
|
|
||||||
@@ -1128,6 +1129,20 @@ class Base(Configuration):
|
|||||||
"FILE_UPLOAD_TMP_PATH cannot be the same as FILE_UPLOAD_PATH"
|
"FILE_UPLOAD_TMP_PATH cannot be the same as FILE_UPLOAD_PATH"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (
|
||||||
|
cls.SUMMARY_SERVICE_VERSION == 1
|
||||||
|
and cls.SUMMARY_SERVICE_ENDPOINT is not None
|
||||||
|
):
|
||||||
|
warnings.warn(
|
||||||
|
"SUMMARY_SERVICE_VERSION=1 is deprecated. "
|
||||||
|
"The legacy v1 API has been removed from the experimental "
|
||||||
|
"Summary service. Please update your Summary service deployment to "
|
||||||
|
"the v2 API and set SUMMARY_SERVICE_VERSION=2.",
|
||||||
|
# We use UserWarning to make sure it shows up in production deployment
|
||||||
|
UserWarning,
|
||||||
|
stacklevel=2,
|
||||||
|
)
|
||||||
|
|
||||||
# The SENTRY_DSN setting should be available to activate sentry for an environment
|
# The SENTRY_DSN setting should be available to activate sentry for an environment
|
||||||
if cls.SENTRY_DSN is not None:
|
if cls.SENTRY_DSN is not None:
|
||||||
sentry_sdk.init(
|
sentry_sdk.init(
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ build-backend = "uv_build"
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "meet"
|
name = "meet"
|
||||||
version = "1.22.0"
|
version = "1.23.0"
|
||||||
authors = [{ "name" = "DINUM", "email" = "dev@mail.numerique.gouv.fr" }]
|
authors = [{ "name" = "DINUM", "email" = "dev@mail.numerique.gouv.fr" }]
|
||||||
classifiers = [
|
classifiers = [
|
||||||
"Development Status :: 5 - Production/Stable",
|
"Development Status :: 5 - Production/Stable",
|
||||||
|
|||||||
Generated
+1
-1
@@ -1187,7 +1187,7 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "meet"
|
name = "meet"
|
||||||
version = "1.22.0"
|
version = "1.23.0"
|
||||||
source = { editable = "." }
|
source = { editable = "." }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "aiohttp" },
|
{ name = "aiohttp" },
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM node:20-alpine AS frontend-deps
|
FROM node:22-alpine AS frontend-deps
|
||||||
|
|
||||||
USER node
|
USER node
|
||||||
|
|
||||||
@@ -39,7 +39,7 @@ ENV VITE_API_BASE_URL=${VITE_API_BASE_URL}
|
|||||||
RUN npm run build
|
RUN npm run build
|
||||||
|
|
||||||
# ---- Front-end image ----
|
# ---- Front-end image ----
|
||||||
FROM nginxinc/nginx-unprivileged:alpine3.23 AS frontend-production
|
FROM nginxinc/nginx-unprivileged:1.30.3-alpine3.23 AS frontend-production
|
||||||
|
|
||||||
USER root
|
USER root
|
||||||
|
|
||||||
|
|||||||
Generated
+20
-20
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "meet",
|
"name": "meet",
|
||||||
"version": "1.22.0",
|
"version": "1.23.0",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "meet",
|
"name": "meet",
|
||||||
"version": "1.22.0",
|
"version": "1.23.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fontsource-variable/atkinson-hyperlegible-next": "5.2.6",
|
"@fontsource-variable/atkinson-hyperlegible-next": "5.2.6",
|
||||||
"@fontsource-variable/lexend": "5.2.11",
|
"@fontsource-variable/lexend": "5.2.11",
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
"@pandacss/preset-panda": "1.11.3",
|
"@pandacss/preset-panda": "1.11.3",
|
||||||
"@react-types/overlays": "3.10.0",
|
"@react-types/overlays": "3.10.0",
|
||||||
"@remixicon/react": "4.9.0",
|
"@remixicon/react": "4.9.0",
|
||||||
"@tanstack/react-query": "5.100.14",
|
"@tanstack/react-query": "5.101.0",
|
||||||
"@timephy/rnnoise-wasm": "1.0.0",
|
"@timephy/rnnoise-wasm": "1.0.0",
|
||||||
"crisp-sdk-web": "1.1.2",
|
"crisp-sdk-web": "1.1.2",
|
||||||
"derive-valtio": "0.2.0",
|
"derive-valtio": "0.2.0",
|
||||||
@@ -28,8 +28,8 @@
|
|||||||
"i18next-browser-languagedetector": "8.2.1",
|
"i18next-browser-languagedetector": "8.2.1",
|
||||||
"i18next-parser": "9.4.0",
|
"i18next-parser": "9.4.0",
|
||||||
"i18next-resources-to-backend": "1.2.1",
|
"i18next-resources-to-backend": "1.2.1",
|
||||||
"livekit-client": "2.19.0",
|
"livekit-client": "2.19.2",
|
||||||
"posthog-js": "1.386.5",
|
"posthog-js": "1.387.0",
|
||||||
"react": "18.3.1",
|
"react": "18.3.1",
|
||||||
"react-aria": "3.49.0",
|
"react-aria": "3.49.0",
|
||||||
"react-aria-components": "1.18.0",
|
"react-aria-components": "1.18.0",
|
||||||
@@ -2357,9 +2357,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tanstack/query-core": {
|
"node_modules/@tanstack/query-core": {
|
||||||
"version": "5.100.14",
|
"version": "5.101.0",
|
||||||
"resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.100.14.tgz",
|
"resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.101.0.tgz",
|
||||||
"integrity": "sha512-5X41dGpxgeaHISCRW2oYwcSycZeULZzAunaudXT9ov1KOTj9xwt0CH6hbwqP1/z74ZWF7rYFnDpyYH07XFcZew==",
|
"integrity": "sha512-cQetA74EB+seWySv1TTKr828TnP0u39m6LykwDXIo84SNortpDkp30TMEjkqtYCNP9c40uT/iwl6MLiufEt0Ow==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"funding": {
|
"funding": {
|
||||||
"type": "github",
|
"type": "github",
|
||||||
@@ -2378,12 +2378,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tanstack/react-query": {
|
"node_modules/@tanstack/react-query": {
|
||||||
"version": "5.100.14",
|
"version": "5.101.0",
|
||||||
"resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.100.14.tgz",
|
"resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.101.0.tgz",
|
||||||
"integrity": "sha512-oOr6aRdSFEwWhzxEkD/9ZcItM3+LjBSkeVmadWKwUssAHTsqd/7bOjWrX4AbvEkoEhgAxzN0Xk6H/aYzXiYBAw==",
|
"integrity": "sha512-rLlJXSpkqfizLWgkR5+eLeIk0MvTx/meEIR7LRjxic+qxiQP8zVjq7BqQkiCMNLQBlLfuOLqqr6KO5GtrDlmSg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tanstack/query-core": "5.100.14"
|
"@tanstack/query-core": "5.101.0"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"type": "github",
|
"type": "github",
|
||||||
@@ -8035,9 +8035,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/livekit-client": {
|
"node_modules/livekit-client": {
|
||||||
"version": "2.19.0",
|
"version": "2.19.2",
|
||||||
"resolved": "https://registry.npmjs.org/livekit-client/-/livekit-client-2.19.0.tgz",
|
"resolved": "https://registry.npmjs.org/livekit-client/-/livekit-client-2.19.2.tgz",
|
||||||
"integrity": "sha512-aolY1XDAtx0nHKBNm29W9OhzBnSz1CP5kq3phvRhFfi1NbvMXs8tcACjAkZTnIKgihkp+BiJScZZ3tZv0Gz8sA==",
|
"integrity": "sha512-Kvk07QYDWRAbmYNLRll04ZIuxMQobW/oLPYnmR1kCy8GGHpU0gqyHf704Rz+29zfy8IJZRjKqeVbzGSKn9sumw==",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@livekit/mutex": "1.1.1",
|
"@livekit/mutex": "1.1.1",
|
||||||
@@ -9033,13 +9033,13 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/posthog-js": {
|
"node_modules/posthog-js": {
|
||||||
"version": "1.386.5",
|
"version": "1.387.0",
|
||||||
"resolved": "https://registry.npmjs.org/posthog-js/-/posthog-js-1.386.5.tgz",
|
"resolved": "https://registry.npmjs.org/posthog-js/-/posthog-js-1.387.0.tgz",
|
||||||
"integrity": "sha512-ASejQQf5Xw0XolMwH/KCLZlZtoyLK6VsvORwGagAtfa8/ElIOF76BMQspkDsRTybEI+uzHqRDm2m/na1Dki2mA==",
|
"integrity": "sha512-Pv1jUMySMN62zoAxdJBJPV8n62lkHdjuWhpeU7izczc5Dqbx3hhqO2hkrNTI8Yx1ezmWk2qUHZs03FuOBubdFQ==",
|
||||||
"license": "SEE LICENSE IN LICENSE",
|
"license": "SEE LICENSE IN LICENSE",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@posthog/core": "^1.32.3",
|
"@posthog/core": "^1.33.0",
|
||||||
"@posthog/types": "^1.386.3",
|
"@posthog/types": "^1.387.0",
|
||||||
"core-js": "^3.38.1",
|
"core-js": "^3.38.1",
|
||||||
"dompurify": "^3.3.2",
|
"dompurify": "^3.3.2",
|
||||||
"fflate": "^0.4.8",
|
"fflate": "^0.4.8",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "meet",
|
"name": "meet",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "1.22.0",
|
"version": "1.23.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "panda codegen && vite",
|
"dev": "panda codegen && vite",
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
"@pandacss/preset-panda": "1.11.3",
|
"@pandacss/preset-panda": "1.11.3",
|
||||||
"@react-types/overlays": "3.10.0",
|
"@react-types/overlays": "3.10.0",
|
||||||
"@remixicon/react": "4.9.0",
|
"@remixicon/react": "4.9.0",
|
||||||
"@tanstack/react-query": "5.100.14",
|
"@tanstack/react-query": "5.101.0",
|
||||||
"@timephy/rnnoise-wasm": "1.0.0",
|
"@timephy/rnnoise-wasm": "1.0.0",
|
||||||
"crisp-sdk-web": "1.1.2",
|
"crisp-sdk-web": "1.1.2",
|
||||||
"derive-valtio": "0.2.0",
|
"derive-valtio": "0.2.0",
|
||||||
@@ -35,8 +35,8 @@
|
|||||||
"i18next-browser-languagedetector": "8.2.1",
|
"i18next-browser-languagedetector": "8.2.1",
|
||||||
"i18next-parser": "9.4.0",
|
"i18next-parser": "9.4.0",
|
||||||
"i18next-resources-to-backend": "1.2.1",
|
"i18next-resources-to-backend": "1.2.1",
|
||||||
"livekit-client": "2.19.0",
|
"livekit-client": "2.19.2",
|
||||||
"posthog-js": "1.386.5",
|
"posthog-js": "1.387.0",
|
||||||
"react": "18.3.1",
|
"react": "18.3.1",
|
||||||
"react-aria": "3.49.0",
|
"react-aria": "3.49.0",
|
||||||
"react-aria-components": "1.18.0",
|
"react-aria-components": "1.18.0",
|
||||||
|
|||||||
+13
-6
@@ -1,23 +1,20 @@
|
|||||||
import { Button } from '@/primitives'
|
import { Button } from '@/primitives'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import type { Participant } from 'livekit-client'
|
import type { Participant } from 'livekit-client'
|
||||||
import { useIsAdminOrOwner } from '@/features/rooms/livekit/hooks/useIsAdminOrOwner'
|
|
||||||
import { useMuteParticipants } from '@/features/rooms/api/muteParticipants'
|
import { useMuteParticipants } from '@/features/rooms/api/muteParticipants'
|
||||||
import { RiMicOffLine } from '@remixicon/react'
|
import { RiMicOffLine } from '@remixicon/react'
|
||||||
import { css } from '@/styled-system/css'
|
import { css } from '@/styled-system/css'
|
||||||
|
import { AdminOrOwnerOnly } from '@/features/rooms/components/AdminOrOwnerOnly'
|
||||||
|
|
||||||
type MuteEveryoneButtonProps = {
|
type MuteEveryoneButtonProps = {
|
||||||
participants: Array<Participant>
|
participants: Array<Participant>
|
||||||
}
|
}
|
||||||
|
|
||||||
export const MuteEveryoneButton = ({
|
const MuteEveryoneButtonInner = ({ participants }: MuteEveryoneButtonProps) => {
|
||||||
participants,
|
|
||||||
}: MuteEveryoneButtonProps) => {
|
|
||||||
const { muteParticipants } = useMuteParticipants()
|
const { muteParticipants } = useMuteParticipants()
|
||||||
const { t } = useTranslation('rooms')
|
const { t } = useTranslation('rooms')
|
||||||
|
|
||||||
const isAdminOrOwner = useIsAdminOrOwner()
|
if (!participants.length) return null
|
||||||
if (!isAdminOrOwner || !participants.length) return null
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
@@ -36,3 +33,13 @@ export const MuteEveryoneButton = ({
|
|||||||
</Button>
|
</Button>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const MuteEveryoneButton = ({
|
||||||
|
participants,
|
||||||
|
}: MuteEveryoneButtonProps) => {
|
||||||
|
return (
|
||||||
|
<AdminOrOwnerOnly>
|
||||||
|
<MuteEveryoneButtonInner participants={participants} />
|
||||||
|
</AdminOrOwnerOnly>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,4 +6,4 @@ DIR_MAILS="../backend/core/templates/mail/html/"
|
|||||||
if [ ! -d "${DIR_MAILS}" ]; then
|
if [ ! -d "${DIR_MAILS}" ]; then
|
||||||
mkdir -p "${DIR_MAILS}";
|
mkdir -p "${DIR_MAILS}";
|
||||||
fi
|
fi
|
||||||
mjml mjml/*.mjml -o "${DIR_MAILS}";
|
mjml mjml/*.mjml -o "${DIR_MAILS}" --config.allowIncludes true;
|
||||||
|
|||||||
@@ -2,6 +2,11 @@
|
|||||||
<mj-include path="./partial/header.mjml" />
|
<mj-include path="./partial/header.mjml" />
|
||||||
|
|
||||||
<mj-body mj-class="bg--blue-100">
|
<mj-body mj-class="bg--blue-100">
|
||||||
|
<!--
|
||||||
|
We load django tags here so they appear in the body of the HTML output.
|
||||||
|
This ensures html-to-text also includes them in the plain text template.
|
||||||
|
-->
|
||||||
|
<mj-raw>{% load i18n static extra_tags %}</mj-raw>
|
||||||
<mj-wrapper css-class="wrapper" padding="0 40px 40px 40px">
|
<mj-wrapper css-class="wrapper" padding="0 40px 40px 40px">
|
||||||
<mj-section css-class="wrapper-logo">
|
<mj-section css-class="wrapper-logo">
|
||||||
<mj-column>
|
<mj-column>
|
||||||
@@ -59,7 +64,7 @@
|
|||||||
</mj-column>
|
</mj-column>
|
||||||
</mj-section>
|
</mj-section>
|
||||||
</mj-wrapper>
|
</mj-wrapper>
|
||||||
</mj-body>
|
|
||||||
|
|
||||||
<mj-include path="./partial/footer.mjml" />
|
<mj-include path="./partial/footer.mjml" />
|
||||||
|
</mj-body>
|
||||||
</mjml>
|
</mjml>
|
||||||
|
|||||||
@@ -1,21 +1,16 @@
|
|||||||
<mj-head>
|
<mj-head>
|
||||||
<mj-title>{{ title }}</mj-title>
|
<mj-title>{{ title }}</mj-title>
|
||||||
<mj-preview>
|
<mj-preview>{{ title }}</mj-preview>
|
||||||
<!--
|
<mj-font name="Roboto" href="https://fonts.bunny.net/css?family=roboto:400,700,900" />
|
||||||
We load django tags here, in this way there are put within the body in html output
|
|
||||||
so the html-to-text command includes it within its output
|
|
||||||
-->
|
|
||||||
{% load i18n static extra_tags %}
|
|
||||||
{{ title }}
|
|
||||||
</mj-preview>
|
|
||||||
<mj-attributes>
|
<mj-attributes>
|
||||||
<mj-font name="Roboto" href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;700;900&display=swap" />
|
|
||||||
<mj-all
|
<mj-all
|
||||||
font-family="Roboto, -apple-system, BlinkMacSystemFont, 'Segoe UI', Oxygen, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif"
|
font-family="Roboto, -apple-system, BlinkMacSystemFont, 'Segoe UI', Oxygen, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif"
|
||||||
font-size="16px"
|
font-size="16px"
|
||||||
line-height="1.5em"
|
line-height="1.5em"
|
||||||
color="#3A3A3A"
|
color="#3A3A3A"
|
||||||
/>
|
/>
|
||||||
|
<mj-text font-family="Roboto, sans-serif" />
|
||||||
|
<mj-button font-family="Roboto, sans-serif" />
|
||||||
</mj-attributes>
|
</mj-attributes>
|
||||||
<mj-style>
|
<mj-style>
|
||||||
/* Reset */
|
/* Reset */
|
||||||
|
|||||||
@@ -2,6 +2,11 @@
|
|||||||
<mj-include path="./partial/header.mjml" />
|
<mj-include path="./partial/header.mjml" />
|
||||||
|
|
||||||
<mj-body mj-class="bg--blue-100">
|
<mj-body mj-class="bg--blue-100">
|
||||||
|
<!--
|
||||||
|
We load django tags here so they appear in the body of the HTML output.
|
||||||
|
This ensures html-to-text also includes them in the plain text template.
|
||||||
|
-->
|
||||||
|
<mj-raw>{% load i18n static extra_tags %}</mj-raw>
|
||||||
<mj-wrapper css-class="wrapper" padding="5px 25px 0px 25px">
|
<mj-wrapper css-class="wrapper" padding="5px 25px 0px 25px">
|
||||||
<mj-section css-class="wrapper-logo">
|
<mj-section css-class="wrapper-logo">
|
||||||
<mj-column>
|
<mj-column>
|
||||||
|
|||||||
Generated
+1904
-942
File diff suppressed because it is too large
Load Diff
@@ -1,11 +1,11 @@
|
|||||||
{
|
{
|
||||||
"name": "mail_mjml",
|
"name": "mail_mjml",
|
||||||
"version": "1.22.0",
|
"version": "1.23.0",
|
||||||
"description": "An util to generate html and text django's templates from mjml templates",
|
"description": "An util to generate html and text django's templates from mjml templates",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@html-to/text-cli": "0.5.4",
|
"@html-to/text-cli": "0.6.0",
|
||||||
"mjml": "4.18.0"
|
"mjml": "5.4.0"
|
||||||
},
|
},
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "sdk",
|
"name": "sdk",
|
||||||
"version": "1.22.0",
|
"version": "1.23.0",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "sdk",
|
"name": "sdk",
|
||||||
"version": "1.22.0",
|
"version": "1.23.0",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"./library",
|
"./library",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "sdk",
|
"name": "sdk",
|
||||||
"version": "1.22.0",
|
"version": "1.23.0",
|
||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"description": "",
|
"description": "",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "summary"
|
name = "summary"
|
||||||
version = "1.22.0"
|
version = "1.23.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"fastapi[standard]>=0.105.0",
|
"fastapi[standard]>=0.105.0",
|
||||||
"uvicorn>=0.24.0",
|
"uvicorn>=0.24.0",
|
||||||
|
|||||||
@@ -59,17 +59,16 @@ async def create_transcribe_task_v2(
|
|||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
properties = {}
|
||||||
|
if request.user_email:
|
||||||
|
properties["$set"] = {"email": request.user_email}
|
||||||
|
|
||||||
# We track the request, this also properly initializes the user in the
|
# We track the request, this also properly initializes the user in the
|
||||||
# analytics system, so that later feature flags work properly
|
# analytics system, so that later feature flags work properly
|
||||||
analytics.capture(
|
analytics.capture(
|
||||||
settings.posthog_event_request,
|
settings.posthog_transcript_request,
|
||||||
request.user_sub,
|
request.user_sub,
|
||||||
properties={
|
properties=properties,
|
||||||
"kind": "transcribe",
|
|
||||||
"$set": {
|
|
||||||
"email": request.user_email,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
|
|
||||||
return TranscribeWebhookPendingPayload(job_id=task.id).model_dump()
|
return TranscribeWebhookPendingPayload(job_id=task.id).model_dump()
|
||||||
@@ -93,15 +92,15 @@ async def create_summarize_task_v2(
|
|||||||
|
|
||||||
# We track the request, this also properly initializes the user in the
|
# We track the request, this also properly initializes the user in the
|
||||||
# analytics system, so that later feature flags work properly
|
# analytics system, so that later feature flags work properly
|
||||||
|
|
||||||
|
properties = {}
|
||||||
|
if request.user_email:
|
||||||
|
properties["$set"] = {"email": request.user_email}
|
||||||
|
|
||||||
analytics.capture(
|
analytics.capture(
|
||||||
settings.posthog_event_request,
|
settings.posthog_summary_request,
|
||||||
request.user_sub,
|
request.user_sub,
|
||||||
properties={
|
properties=properties,
|
||||||
"kind": "summarize",
|
|
||||||
"$set": {
|
|
||||||
"email": request.user_email,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
return SummarizeWebhookPendingPayload(job_id=task.id).model_dump()
|
return SummarizeWebhookPendingPayload(job_id=task.id).model_dump()
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ from celery.utils.log import get_task_logger
|
|||||||
from posthog import Posthog
|
from posthog import Posthog
|
||||||
|
|
||||||
from summary.core.config import get_settings
|
from summary.core.config import get_settings
|
||||||
from summary.core.models import TranscribeTaskJob
|
from summary.core.models import SummarizeTaskJob, TranscribeTaskJob
|
||||||
|
|
||||||
logger = get_task_logger(__name__)
|
logger = get_task_logger(__name__)
|
||||||
settings = get_settings()
|
settings = get_settings()
|
||||||
@@ -109,19 +109,15 @@ class MetadataManager:
|
|||||||
"""Check if task_id exists in tasks metadata cache."""
|
"""Check if task_id exists in tasks metadata cache."""
|
||||||
return self._redis.exists(self._get_redis_key(task_id))
|
return self._redis.exists(self._get_redis_key(task_id))
|
||||||
|
|
||||||
def create(self, task_id: str, task_payload: TranscribeTaskJob):
|
def create(self, task_id: str, task_payload: TranscribeTaskJob | SummarizeTaskJob):
|
||||||
"""Create initial metadata entry for a new task."""
|
"""Create initial metadata entry for a new task."""
|
||||||
if self._is_disabled or self.has_task_id(task_id):
|
if self._is_disabled or self.has_task_id(task_id):
|
||||||
return
|
return
|
||||||
|
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
parts = urlsplit(task_payload.cloud_storage_url)
|
|
||||||
clean_url = urlunsplit((parts.scheme, parts.netloc, parts.path, "", ""))
|
|
||||||
initial_metadata = {
|
initial_metadata = {
|
||||||
"start_time": start_time,
|
"start_time": start_time,
|
||||||
"asr_model": settings.whisperx_asr_model,
|
|
||||||
"retries": 0,
|
"retries": 0,
|
||||||
"filename": clean_url,
|
|
||||||
"sub": task_payload.user_sub,
|
"sub": task_payload.user_sub,
|
||||||
# avoid None in redis, it shouldn't happen anyway in prod
|
# avoid None in redis, it shouldn't happen anyway in prod
|
||||||
"email": task_payload.user_email or "",
|
"email": task_payload.user_email or "",
|
||||||
@@ -129,6 +125,15 @@ class MetadataManager:
|
|||||||
"queuing_time": round(start_time - task_payload.received_at.timestamp(), 2),
|
"queuing_time": round(start_time - task_payload.received_at.timestamp(), 2),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if isinstance(task_payload, TranscribeTaskJob):
|
||||||
|
parts = urlsplit(task_payload.cloud_storage_url)
|
||||||
|
clean_url = urlunsplit((parts.scheme, parts.netloc, parts.path, "", ""))
|
||||||
|
initial_metadata["source_url"] = clean_url
|
||||||
|
initial_metadata["asr_model"] = settings.whisperx_asr_model
|
||||||
|
elif isinstance(task_payload, SummarizeTaskJob):
|
||||||
|
initial_metadata["content_length"] = len(task_payload.content)
|
||||||
|
initial_metadata["llm_model"] = settings.llm_model
|
||||||
|
|
||||||
self._save_metadata(task_id, initial_metadata)
|
self._save_metadata(task_id, initial_metadata)
|
||||||
|
|
||||||
def retry(self, task_id):
|
def retry(self, task_id):
|
||||||
|
|||||||
@@ -542,28 +542,28 @@ def process_audio_transcribe_v2_task(
|
|||||||
call_webhook_v2_task.apply_async(
|
call_webhook_v2_task.apply_async(
|
||||||
args=[success_payload.model_dump(), payload.tenant_id]
|
args=[success_payload.model_dump(), payload.tenant_id]
|
||||||
)
|
)
|
||||||
metadata_manager.capture(job_id, settings.posthog_event_success)
|
metadata_manager.capture(job_id, settings.posthog_transcript_success)
|
||||||
|
|
||||||
return success_payload.model_dump()
|
return success_payload.model_dump()
|
||||||
|
|
||||||
|
|
||||||
@signals.task_prerun.connect(sender=process_audio_transcribe_v2_task)
|
@signals.task_prerun.connect(sender=process_audio_transcribe_v2_task)
|
||||||
def task_started(task_id=None, task=None, args=None, **kwargs):
|
def task_started_transcript(task_id=None, task=None, args=None, **kwargs):
|
||||||
"""Signal handler called before task execution begins."""
|
"""Signal handler called before task execution begins."""
|
||||||
if args:
|
if args:
|
||||||
metadata_manager.create(task_id, TranscribeTaskJob.model_validate(args[0]))
|
metadata_manager.create(task_id, TranscribeTaskJob.model_validate(args[0]))
|
||||||
|
|
||||||
|
|
||||||
@signals.task_retry.connect(sender=process_audio_transcribe_v2_task)
|
@signals.task_retry.connect(sender=process_audio_transcribe_v2_task)
|
||||||
def task_retry_handler(request=None, reason=None, einfo=None, **kwargs):
|
def task_retry_handler_transcript(request=None, reason=None, einfo=None, **kwargs):
|
||||||
"""Signal handler called when task execution retries."""
|
"""Signal handler called when task execution retries."""
|
||||||
metadata_manager.retry(request.id)
|
metadata_manager.retry(request.id)
|
||||||
|
|
||||||
|
|
||||||
@signals.task_failure.connect(sender=process_audio_transcribe_v2_task)
|
@signals.task_failure.connect(sender=process_audio_transcribe_v2_task)
|
||||||
def task_failure_handler(task_id, exception=None, **kwargs):
|
def task_failure_handler_transcript(task_id, exception=None, **kwargs):
|
||||||
"""Signal handler called when task execution fails permanently."""
|
"""Signal handler called when task execution fails permanently."""
|
||||||
metadata_manager.capture(task_id, settings.posthog_event_failure)
|
metadata_manager.capture(task_id, settings.posthog_transcript_failure)
|
||||||
|
|
||||||
|
|
||||||
@signals.task_failure.connect(sender=process_audio_transcribe_v2_task)
|
@signals.task_failure.connect(sender=process_audio_transcribe_v2_task)
|
||||||
@@ -648,9 +648,30 @@ def summarize_v2_task(
|
|||||||
call_webhook_v2_task.apply_async(
|
call_webhook_v2_task.apply_async(
|
||||||
args=[success_payload.model_dump(), payload.tenant_id]
|
args=[success_payload.model_dump(), payload.tenant_id]
|
||||||
)
|
)
|
||||||
|
metadata_manager.capture(job_id, settings.posthog_summary_success)
|
||||||
|
|
||||||
return success_payload.model_dump()
|
return success_payload.model_dump()
|
||||||
|
|
||||||
|
|
||||||
|
@signals.task_prerun.connect(sender=summarize_v2_task)
|
||||||
|
def task_started_summary(task_id=None, task=None, args=None, **kwargs):
|
||||||
|
"""Signal handler called before task execution begins."""
|
||||||
|
if args:
|
||||||
|
metadata_manager.create(task_id, SummarizeTaskJob.model_validate(args[0]))
|
||||||
|
|
||||||
|
|
||||||
|
@signals.task_retry.connect(sender=summarize_v2_task)
|
||||||
|
def task_retry_handler_summary(request=None, reason=None, einfo=None, **kwargs):
|
||||||
|
"""Signal handler called when task execution retries."""
|
||||||
|
metadata_manager.retry(request.id)
|
||||||
|
|
||||||
|
|
||||||
|
@signals.task_failure.connect(sender=summarize_v2_task)
|
||||||
|
def task_failure_handler_summary(task_id, exception=None, **kwargs):
|
||||||
|
"""Signal handler called when task execution fails permanently."""
|
||||||
|
metadata_manager.capture(task_id, settings.posthog_summary_failure)
|
||||||
|
|
||||||
|
|
||||||
@signals.task_failure.connect(sender=summarize_v2_task)
|
@signals.task_failure.connect(sender=summarize_v2_task)
|
||||||
def handle_summarize_v2_failed(
|
def handle_summarize_v2_failed(
|
||||||
sender,
|
sender,
|
||||||
|
|||||||
@@ -130,9 +130,12 @@ class Settings(BaseSettings):
|
|||||||
posthog_enabled: bool = False
|
posthog_enabled: bool = False
|
||||||
posthog_api_key: Optional[str] = None
|
posthog_api_key: Optional[str] = None
|
||||||
posthog_api_host: Optional[str] = "https://eu.i.posthog.com"
|
posthog_api_host: Optional[str] = "https://eu.i.posthog.com"
|
||||||
posthog_event_failure: str = "transcript-failure"
|
posthog_transcript_request: str = "transcript-request"
|
||||||
posthog_event_success: str = "transcript-success"
|
posthog_transcript_failure: str = "transcript-failure"
|
||||||
posthog_event_request: str = "transcript-request"
|
posthog_transcript_success: str = "transcript-success"
|
||||||
|
posthog_summary_request: str = "summary-request"
|
||||||
|
posthog_summary_failure: str = "summary-failure"
|
||||||
|
posthog_summary_success: str = "summary-success"
|
||||||
|
|
||||||
# Langfuse (LLM Observability)
|
# Langfuse (LLM Observability)
|
||||||
langfuse_enabled: bool = False
|
langfuse_enabled: bool = False
|
||||||
|
|||||||
Reference in New Issue
Block a user