Compare commits
23 Commits
v0.1.9
...
optimization
| Author | SHA1 | Date | |
|---|---|---|---|
| 1333e39164 | |||
| 5931c5605a | |||
| 3a205373dd | |||
| 0b8181e5ce | |||
| 8b2365d5f9 | |||
| 2dd16d1f40 | |||
| fa9484b630 | |||
| 1e0e495cd8 | |||
| c270299179 | |||
| d9a84e5f0f | |||
| 0f64d3cf3a | |||
| d1e008a844 | |||
| 3be5a5afc6 | |||
| 31468a5e7c | |||
| b342b9d526 | |||
| f7e7c3ba22 | |||
| 3902b02691 | |||
| 7ce4390740 | |||
| 94d18cffe4 | |||
| ad0c3eea66 | |||
| 459bbf65a8 | |||
| 4b4f16e93f | |||
| 3e3f964ac5 |
+1
-1
Submodule secrets updated: 142e7a70b1...f5aea0c251
@@ -145,7 +145,7 @@ class OIDCLogoutCallbackView(MozillaOIDCOIDCLogoutView):
|
||||
|
||||
|
||||
class OIDCAuthenticationCallbackView(MozillaOIDCAuthenticationCallbackView):
|
||||
"""Custom callback view for handling the silent loging flow."""
|
||||
"""Custom callback view for handling the silent login flow."""
|
||||
|
||||
@property
|
||||
def failure_url(self):
|
||||
@@ -162,7 +162,7 @@ class OIDCAuthenticationCallbackView(MozillaOIDCAuthenticationCallbackView):
|
||||
|
||||
|
||||
class OIDCAuthenticationRequestView(MozillaOIDCAuthenticationRequestView):
|
||||
"""Custom authentication view for handling the silent loging flow."""
|
||||
"""Custom authentication view for handling the silent login flow."""
|
||||
|
||||
def get_extra_params(self, request):
|
||||
"""Handle 'prompt' extra parameter for the silent login flow
|
||||
|
||||
@@ -324,8 +324,10 @@ class Base(Configuration):
|
||||
OIDC_AUTHENTICATE_CLASS = "core.authentication.views.OIDCAuthenticationRequestView"
|
||||
OIDC_CALLBACK_CLASS = "core.authentication.views.OIDCAuthenticationCallbackView"
|
||||
OIDC_CREATE_USER = values.BooleanValue(
|
||||
default=True,
|
||||
environ_name="OIDC_CREATE_USER",
|
||||
default=True, environ_name="OIDC_CREATE_USER", environ_prefix=None
|
||||
)
|
||||
OIDC_VERIFY_SSL = values.BooleanValue(
|
||||
default=True, environ_name="OIDC_VERIFY_SSL", environ_prefix=None
|
||||
)
|
||||
OIDC_FALLBACK_TO_EMAIL_FOR_IDENTIFICATION = values.BooleanValue(
|
||||
default=False,
|
||||
|
||||
@@ -7,7 +7,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "meet"
|
||||
version = "0.1.9"
|
||||
version = "0.1.10"
|
||||
authors = [{ "name" = "DINUM", "email" = "dev@mail.numerique.gouv.fr" }]
|
||||
classifiers = [
|
||||
"Development Status :: 5 - Production/Stable",
|
||||
|
||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "meet",
|
||||
"version": "0.1.9",
|
||||
"version": "0.1.10",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "meet",
|
||||
"version": "0.1.9",
|
||||
"version": "0.1.10",
|
||||
"dependencies": {
|
||||
"@livekit/components-react": "2.6.9",
|
||||
"@livekit/components-styles": "1.1.4",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "meet",
|
||||
"private": true,
|
||||
"version": "0.1.9",
|
||||
"version": "0.1.10",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "panda codegen && vite",
|
||||
|
||||
@@ -116,10 +116,10 @@ const config: Config = {
|
||||
'80%': { transform: 'rotate(20deg)' },
|
||||
'100%': { transform: 'rotate(0)' },
|
||||
},
|
||||
pulse_mic: {
|
||||
'0%': { color: 'primary', opacity: '1' },
|
||||
'50%': { color: 'primary', opacity: '0.8' },
|
||||
'100%': { color: 'primary', opacity: '1' },
|
||||
pulse_background: {
|
||||
'0%': { opacity: '1' },
|
||||
'50%': { opacity: '0.65' },
|
||||
'100%': { opacity: '1' },
|
||||
},
|
||||
},
|
||||
tokens: defineTokens({
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
import { useConfig } from '@/api/useConfig.ts'
|
||||
|
||||
export const useIsAnalyticsEnabled = () => {
|
||||
const { data } = useConfig()
|
||||
return !!data?.analytics?.id
|
||||
}
|
||||
@@ -65,6 +65,11 @@ export const Conference = ({
|
||||
|
||||
const roomOptions = useMemo((): RoomOptions => {
|
||||
return {
|
||||
adaptiveStream: true,
|
||||
dynacast: true,
|
||||
publishDefaults: {
|
||||
videoCodec: 'vp9',
|
||||
},
|
||||
videoCaptureDefaults: {
|
||||
deviceId: userConfig.videoDeviceId ?? undefined,
|
||||
},
|
||||
|
||||
@@ -121,7 +121,13 @@ const OpenFeedback = ({
|
||||
>
|
||||
{t('submit')}
|
||||
</Button>
|
||||
<Button invisible size="sm" fullWidth onPress={onNext}>
|
||||
<Button
|
||||
invisible
|
||||
variant="secondary"
|
||||
size="sm"
|
||||
fullWidth
|
||||
onPress={onNext}
|
||||
>
|
||||
{t('skip')}
|
||||
</Button>
|
||||
</VStack>
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
import { css } from '@/styled-system/css'
|
||||
import { RiRecordCircleLine } from '@remixicon/react'
|
||||
import { Text } from '@/primitives'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useRoomContext } from '@livekit/components-react'
|
||||
|
||||
export const RecordingStateToast = () => {
|
||||
const { t } = useTranslation('rooms', { keyPrefix: 'recording' })
|
||||
|
||||
const room = useRoomContext()
|
||||
|
||||
if (!room?.isRecording) return
|
||||
|
||||
return (
|
||||
<div
|
||||
className={css({
|
||||
display: 'flex',
|
||||
position: 'fixed',
|
||||
top: '10px',
|
||||
left: '10px',
|
||||
paddingY: '0.25rem',
|
||||
paddingX: '0.25rem 0.35rem',
|
||||
backgroundColor: 'primaryDark.200',
|
||||
borderColor: 'primaryDark.400',
|
||||
border: '1px solid',
|
||||
color: 'white',
|
||||
borderRadius: '4px',
|
||||
gap: '0.5rem',
|
||||
})}
|
||||
>
|
||||
<RiRecordCircleLine
|
||||
size={20}
|
||||
className={css({
|
||||
color: 'white',
|
||||
backgroundColor: 'danger.700',
|
||||
padding: '3px',
|
||||
borderRadius: '3px',
|
||||
})}
|
||||
/>
|
||||
<Text variant={'sm'}>{t('label')}</Text>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import { useSidePanel } from '../hooks/useSidePanel'
|
||||
import { ReactNode } from 'react'
|
||||
import { Effects } from './Effects'
|
||||
import { Chat } from '../prefabs/Chat'
|
||||
import { Transcript } from './Transcript'
|
||||
|
||||
type StyledSidePanelProps = {
|
||||
title: string
|
||||
@@ -106,6 +107,7 @@ export const SidePanel = () => {
|
||||
isEffectsOpen,
|
||||
isChatOpen,
|
||||
isSidePanelOpen,
|
||||
isTranscriptOpen,
|
||||
} = useSidePanel()
|
||||
const { t } = useTranslation('rooms', { keyPrefix: 'sidePanel' })
|
||||
|
||||
@@ -127,6 +129,9 @@ export const SidePanel = () => {
|
||||
<Panel isOpen={isChatOpen}>
|
||||
<Chat />
|
||||
</Panel>
|
||||
<Panel isOpen={isTranscriptOpen}>
|
||||
<Transcript />
|
||||
</Panel>
|
||||
</StyledSidePanel>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
import { Button, Div, H, Text } from '@/primitives'
|
||||
|
||||
import thirdSlide from '@/assets/intro-slider/3_resume.png'
|
||||
import { css } from '@/styled-system/css'
|
||||
|
||||
import { useHasTranscriptAccess } from '../hooks/useHasTranscriptAccess'
|
||||
import { RiRecordCircleLine, RiStopCircleLine } from '@remixicon/react'
|
||||
import { useRoomId } from '@/features/rooms/livekit/hooks/useRoomId'
|
||||
import { useRoomContext } from '@livekit/components-react'
|
||||
import {
|
||||
RecordingMode,
|
||||
useStartRecording,
|
||||
} from '@/features/rooms/api/startRecording'
|
||||
import { useStopRecording } from '@/features/rooms/api/stopRecording'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { RoomEvent } from 'livekit-client'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
export const Transcript = () => {
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
|
||||
const { t } = useTranslation('rooms', { keyPrefix: 'transcript' })
|
||||
|
||||
const hasTranscriptAccess = useHasTranscriptAccess()
|
||||
|
||||
const roomId = useRoomId()
|
||||
|
||||
const { mutateAsync: startRecordingRoom } = useStartRecording()
|
||||
const { mutateAsync: stopRecordingRoom } = useStopRecording()
|
||||
|
||||
const room = useRoomContext()
|
||||
|
||||
useEffect(() => {
|
||||
const handleRecordingStatusChanged = () => {
|
||||
setIsLoading(false)
|
||||
}
|
||||
room.on(RoomEvent.RecordingStatusChanged, handleRecordingStatusChanged)
|
||||
return () => {
|
||||
room.off(RoomEvent.RecordingStatusChanged, handleRecordingStatusChanged)
|
||||
}
|
||||
}, [room])
|
||||
|
||||
const handleTranscript = async () => {
|
||||
if (!roomId) {
|
||||
console.warn('No room ID found')
|
||||
return
|
||||
}
|
||||
try {
|
||||
setIsLoading(true)
|
||||
if (room.isRecording) {
|
||||
await stopRecordingRoom({ id: roomId })
|
||||
} else {
|
||||
await startRecordingRoom({ id: roomId, mode: RecordingMode.Transcript })
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to handle transcript:', error)
|
||||
setIsLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasTranscriptAccess) return
|
||||
|
||||
return (
|
||||
<Div
|
||||
display="flex"
|
||||
overflowY="scroll"
|
||||
padding="0 1.5rem"
|
||||
flexGrow={1}
|
||||
flexDirection="column"
|
||||
alignItems="center"
|
||||
>
|
||||
<img src={thirdSlide} alt={'wip'} />
|
||||
{room.isRecording ? (
|
||||
<>
|
||||
<H lvl={2}>{t('stop.heading')}</H>
|
||||
<Text variant="sm" centered wrap="balance">
|
||||
{t('stop.body')}
|
||||
</Text>
|
||||
<div className={css({ height: '2rem' })} />
|
||||
<Button isDisabled={isLoading} onPress={() => handleTranscript()}>
|
||||
<RiStopCircleLine style={{ marginRight: '0.5rem' }} />{' '}
|
||||
{t('stop.button')}
|
||||
</Button>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<H lvl={2}>{t('start.heading')}</H>
|
||||
<Text variant="sm" centered wrap="balance">
|
||||
{t('start.body')}
|
||||
</Text>
|
||||
<div className={css({ height: '2rem' })} />
|
||||
<Button isDisabled={isLoading} onPress={() => handleTranscript()}>
|
||||
<RiRecordCircleLine style={{ marginRight: '0.5rem' }} />{' '}
|
||||
{t('start.button')}
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
</Div>
|
||||
)
|
||||
}
|
||||
-2
@@ -10,7 +10,6 @@ import { DialogState } from './OptionsButton'
|
||||
import { Separator } from '@/primitives/Separator'
|
||||
import { useSidePanel } from '../../../hooks/useSidePanel'
|
||||
import { menuRecipe } from '@/primitives/menuRecipe.ts'
|
||||
import { TranscriptMenuItem } from './TranscriptMenuItem'
|
||||
|
||||
// @todo try refactoring it to use MenuList component
|
||||
export const OptionsMenuItems = ({
|
||||
@@ -35,7 +34,6 @@ export const OptionsMenuItems = ({
|
||||
<RiAccountBoxLine size={20} />
|
||||
{t('effects')}
|
||||
</MenuItem>
|
||||
<TranscriptMenuItem />
|
||||
</Section>
|
||||
<Separator />
|
||||
<Section>
|
||||
|
||||
-71
@@ -1,71 +0,0 @@
|
||||
import { RiRecordCircleLine, RiStopCircleLine } from '@remixicon/react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { menuRecipe } from '@/primitives/menuRecipe'
|
||||
import { MenuItem } from 'react-aria-components'
|
||||
import {
|
||||
RecordingMode,
|
||||
useStartRecording,
|
||||
} from '@/features/rooms/api/startRecording'
|
||||
import { useStopRecording } from '@/features/rooms/api/stopRecording'
|
||||
import { useRoomContext } from '@livekit/components-react'
|
||||
import { useRoomData } from '@/features/rooms/livekit/hooks/useRoomData'
|
||||
import { useConfig } from '@/api/useConfig'
|
||||
|
||||
export const TranscriptMenuItem = () => {
|
||||
const { t } = useTranslation('rooms', { keyPrefix: 'options.items' })
|
||||
|
||||
const apiRoomData = useRoomData()
|
||||
|
||||
const { mutateAsync: startRecordingRoom } = useStartRecording()
|
||||
const { mutateAsync: stopRecordingRoom } = useStopRecording()
|
||||
|
||||
const { data } = useConfig()
|
||||
|
||||
const room = useRoomContext()
|
||||
|
||||
const handleTranscript = async () => {
|
||||
const roomId = apiRoomData?.livekit?.room
|
||||
|
||||
if (!roomId) {
|
||||
console.warn('No room ID found')
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
if (room.isRecording) {
|
||||
await stopRecordingRoom({ id: roomId })
|
||||
} else {
|
||||
await startRecordingRoom({ id: roomId, mode: RecordingMode.Transcript })
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to handle transcript:', error)
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
!data?.recording?.is_enabled ||
|
||||
!data?.recording?.available_modes?.includes(RecordingMode.Transcript) ||
|
||||
!apiRoomData?.is_administrable
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
return (
|
||||
<MenuItem
|
||||
className={menuRecipe({ icon: true }).item}
|
||||
onAction={async () => await handleTranscript()}
|
||||
>
|
||||
{room.isRecording ? (
|
||||
<>
|
||||
<RiRecordCircleLine size={20} />
|
||||
{t('transcript.stop')}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<RiStopCircleLine size={20} />
|
||||
{t('transcript.start')}
|
||||
</>
|
||||
)}
|
||||
</MenuItem>
|
||||
)
|
||||
}
|
||||
+6
-3
@@ -84,9 +84,12 @@ const MicIndicator = ({ participant }: MicIndicatorProps) => {
|
||||
<RiMicOffFill color={'gray'} />
|
||||
) : (
|
||||
<RiMicFill
|
||||
style={{
|
||||
animation: isSpeaking ? 'pulse_mic 800ms infinite' : undefined,
|
||||
}}
|
||||
className={css({
|
||||
color: isSpeaking ? 'primaryDark.300' : 'primaryDark.50',
|
||||
animation: isSpeaking
|
||||
? 'pulse_background 800ms infinite'
|
||||
: undefined,
|
||||
})}
|
||||
/>
|
||||
)}
|
||||
</Button>
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
import { ToggleButton } from '@/primitives'
|
||||
import { RiBardLine } from '@remixicon/react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useSidePanel } from '../../hooks/useSidePanel'
|
||||
import { useHasTranscriptAccess } from '../../hooks/useHasTranscriptAccess'
|
||||
import { css } from '@/styled-system/css'
|
||||
|
||||
export const TranscriptToggle = () => {
|
||||
const { t } = useTranslation('rooms', { keyPrefix: 'controls.transcript' })
|
||||
|
||||
const { isTranscriptOpen, toggleTranscript } = useSidePanel()
|
||||
const tooltipLabel = isTranscriptOpen ? 'open' : 'closed'
|
||||
|
||||
const hasTranscriptAccess = useHasTranscriptAccess()
|
||||
|
||||
if (!hasTranscriptAccess) return
|
||||
|
||||
return (
|
||||
<div
|
||||
className={css({
|
||||
position: 'relative',
|
||||
display: 'inline-block',
|
||||
})}
|
||||
>
|
||||
<ToggleButton
|
||||
square
|
||||
variant="primaryTextDark"
|
||||
aria-label={t(tooltipLabel)}
|
||||
tooltip={t(tooltipLabel)}
|
||||
isSelected={isTranscriptOpen}
|
||||
onPress={() => toggleTranscript()}
|
||||
>
|
||||
<RiBardLine />
|
||||
</ToggleButton>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import { useFeatureFlagEnabled } from 'posthog-js/react'
|
||||
import { useIsAnalyticsEnabled } from '@/features/analytics/hooks/useIsAnalyticsEnabled'
|
||||
import { useIsTranscriptEnabled } from './useIsTranscriptEnabled'
|
||||
import { useIsAdminOrOwner } from './useIsAdminOrOwner'
|
||||
|
||||
export const useHasTranscriptAccess = () => {
|
||||
const featureEnabled = useFeatureFlagEnabled('transcription-summary')
|
||||
const isAnalyticsEnabled = useIsAnalyticsEnabled()
|
||||
const isTranscriptEnabled = useIsTranscriptEnabled()
|
||||
const isAdminOrOwner = useIsAdminOrOwner()
|
||||
|
||||
return (
|
||||
(featureEnabled || !isAnalyticsEnabled) &&
|
||||
isAdminOrOwner &&
|
||||
isTranscriptEnabled
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
import { useRoomData } from './useRoomData'
|
||||
|
||||
export const useIsAdminOrOwner = () => {
|
||||
const apiRoomData = useRoomData()
|
||||
return apiRoomData?.is_administrable
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import { RecordingMode } from '@/features/rooms/api/startRecording'
|
||||
import { useConfig } from '@/api/useConfig'
|
||||
|
||||
export const useIsTranscriptEnabled = () => {
|
||||
const { data } = useConfig()
|
||||
|
||||
return (
|
||||
data?.recording?.is_enabled &&
|
||||
data?.recording?.available_modes?.includes(RecordingMode.Transcript)
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
import { useRoomData } from './useRoomData'
|
||||
|
||||
export const useRoomId = () => {
|
||||
const apiRoomData = useRoomData()
|
||||
return apiRoomData?.livekit?.room
|
||||
}
|
||||
@@ -5,6 +5,7 @@ export enum PanelId {
|
||||
PARTICIPANTS = 'participants',
|
||||
EFFECTS = 'effects',
|
||||
CHAT = 'chat',
|
||||
TRANSCRIPT = 'transcript',
|
||||
}
|
||||
|
||||
export const useSidePanel = () => {
|
||||
@@ -14,6 +15,7 @@ export const useSidePanel = () => {
|
||||
const isParticipantsOpen = activePanelId == PanelId.PARTICIPANTS
|
||||
const isEffectsOpen = activePanelId == PanelId.EFFECTS
|
||||
const isChatOpen = activePanelId == PanelId.CHAT
|
||||
const isTranscriptOpen = activePanelId == PanelId.TRANSCRIPT
|
||||
const isSidePanelOpen = !!activePanelId
|
||||
|
||||
const toggleParticipants = () => {
|
||||
@@ -28,14 +30,20 @@ export const useSidePanel = () => {
|
||||
layoutStore.activePanelId = isEffectsOpen ? null : PanelId.EFFECTS
|
||||
}
|
||||
|
||||
const toggleTranscript = () => {
|
||||
layoutStore.activePanelId = isTranscriptOpen ? null : PanelId.TRANSCRIPT
|
||||
}
|
||||
|
||||
return {
|
||||
activePanelId,
|
||||
toggleParticipants,
|
||||
toggleChat,
|
||||
toggleEffects,
|
||||
toggleTranscript,
|
||||
isChatOpen,
|
||||
isParticipantsOpen,
|
||||
isEffectsOpen,
|
||||
isSidePanelOpen,
|
||||
isTranscriptOpen,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,8 +13,10 @@ import { HandToggle } from '../components/controls/HandToggle'
|
||||
import { SelectToggleDevice } from '../components/controls/SelectToggleDevice'
|
||||
import { LeaveButton } from '../components/controls/LeaveButton'
|
||||
import { ScreenShareToggle } from '../components/controls/ScreenShareToggle'
|
||||
import { SupportToggle } from '../components/controls/SupportToggle'
|
||||
import { TranscriptToggle } from '../components/controls/TranscriptToggle'
|
||||
|
||||
import { css } from '@/styled-system/css'
|
||||
import { SupportToggle } from '@/features/rooms/livekit/components/controls/SupportToggle.tsx'
|
||||
|
||||
/** @public */
|
||||
export type ControlBarControls = {
|
||||
@@ -156,6 +158,7 @@ export function ControlBar({
|
||||
>
|
||||
<ChatToggle />
|
||||
<ParticipantsToggle />
|
||||
<TranscriptToggle />
|
||||
<SupportToggle />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -28,6 +28,7 @@ import { FocusLayout } from '../components/FocusLayout'
|
||||
import { ParticipantTile } from '../components/ParticipantTile'
|
||||
import { SidePanel } from '../components/SidePanel'
|
||||
import { useSidePanel } from '../hooks/useSidePanel'
|
||||
import { RecordingStateToast } from '../components/RecordingStateToast'
|
||||
|
||||
const LayoutWrapper = styled(
|
||||
'div',
|
||||
@@ -212,6 +213,7 @@ export function VideoConference({ ...props }: VideoConferenceProps) {
|
||||
)}
|
||||
<RoomAudioRenderer />
|
||||
<ConnectionStateToast />
|
||||
<RecordingStateToast />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -71,6 +71,10 @@
|
||||
"open": "",
|
||||
"closed": ""
|
||||
},
|
||||
"transcript": {
|
||||
"open": "",
|
||||
"closed": ""
|
||||
},
|
||||
"support": ""
|
||||
},
|
||||
"options": {
|
||||
@@ -79,11 +83,7 @@
|
||||
"feedbacks": "",
|
||||
"settings": "",
|
||||
"username": "",
|
||||
"effects": "",
|
||||
"transcript": {
|
||||
"start": "",
|
||||
"stop": ""
|
||||
}
|
||||
"effects": ""
|
||||
}
|
||||
},
|
||||
"effects": {
|
||||
@@ -102,18 +102,32 @@
|
||||
"heading": {
|
||||
"participants": "",
|
||||
"effects": "",
|
||||
"chat": ""
|
||||
"chat": "",
|
||||
"transcript": ""
|
||||
},
|
||||
"content": {
|
||||
"participants": "",
|
||||
"effects": "",
|
||||
"chat": ""
|
||||
"chat": "",
|
||||
"transcript": ""
|
||||
},
|
||||
"closeButton": ""
|
||||
},
|
||||
"chat": {
|
||||
"disclaimer": ""
|
||||
},
|
||||
"transcript": {
|
||||
"start": {
|
||||
"heading": "",
|
||||
"body": "",
|
||||
"button": ""
|
||||
},
|
||||
"stop": {
|
||||
"heading": "",
|
||||
"body": "",
|
||||
"button": ""
|
||||
}
|
||||
},
|
||||
"rating": {
|
||||
"submit": "",
|
||||
"question": "",
|
||||
@@ -150,5 +164,8 @@
|
||||
"raisedHands": "",
|
||||
"lowerParticipantHand": "",
|
||||
"lowerParticipantsHand": ""
|
||||
},
|
||||
"recording": {
|
||||
"label": ""
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,6 +70,10 @@
|
||||
"open": "Hide everyone",
|
||||
"closed": "See everyone"
|
||||
},
|
||||
"transcript": {
|
||||
"open": "Hide AI assistant",
|
||||
"closed": "Show AI assistant"
|
||||
},
|
||||
"support": "Support"
|
||||
},
|
||||
"options": {
|
||||
@@ -78,11 +82,7 @@
|
||||
"feedbacks": "Give us feedbacks",
|
||||
"settings": "Settings",
|
||||
"username": "Update Your Name",
|
||||
"effects": "Apply effects",
|
||||
"transcript": {
|
||||
"start": "Start meeting transcription",
|
||||
"stop": "Stop ongoing transcription"
|
||||
}
|
||||
"effects": "Apply effects"
|
||||
}
|
||||
},
|
||||
"effects": {
|
||||
@@ -101,18 +101,32 @@
|
||||
"heading": {
|
||||
"participants": "Participants",
|
||||
"effects": "Effects",
|
||||
"chat": "Messages in the chat"
|
||||
"chat": "Messages in the chat",
|
||||
"transcript": "AI Assistant"
|
||||
},
|
||||
"content": {
|
||||
"participants": "participants",
|
||||
"effects": "effects",
|
||||
"chat": "messages"
|
||||
"chat": "messages",
|
||||
"transcript": "AI assistant"
|
||||
},
|
||||
"closeButton": "Hide {{content}}"
|
||||
},
|
||||
"chat": {
|
||||
"disclaimer": "The messages are visible to participants only at the time they are sent. All messages are deleted at the end of the call."
|
||||
},
|
||||
"transcript": {
|
||||
"start": {
|
||||
"heading": "Start the Assistant!",
|
||||
"body": "The assistant automatically starts recording your meeting audio (limited to 1 hour). At the end, you'll receive a clear and concise summary of the discussion directly via email.",
|
||||
"button": "Start"
|
||||
},
|
||||
"stop": {
|
||||
"heading": "Recording in Progress...",
|
||||
"body": "Your meeting is currently being recorded. You will receive a summary via email once the meeting ends.",
|
||||
"button": "Stop Recording"
|
||||
}
|
||||
},
|
||||
"rating": {
|
||||
"submit": "Submit",
|
||||
"question": "What do you think about the quality of your call?",
|
||||
@@ -149,5 +163,8 @@
|
||||
"raisedHands": "Raised hands",
|
||||
"lowerParticipantHand": "Lower {{name}}'s hand",
|
||||
"lowerParticipantsHand": "Lower all hands"
|
||||
},
|
||||
"recording": {
|
||||
"label": "Recording"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,6 +70,10 @@
|
||||
"open": "Masquer les participants",
|
||||
"closed": "Afficher les participants"
|
||||
},
|
||||
"transcript": {
|
||||
"open": "Masquer l'assistant IA",
|
||||
"closed": "Afficher l'assistant IA"
|
||||
},
|
||||
"support": "Support"
|
||||
},
|
||||
"options": {
|
||||
@@ -78,11 +82,7 @@
|
||||
"feedbacks": "Partager votre avis",
|
||||
"settings": "Paramètres",
|
||||
"username": "Choisir votre nom",
|
||||
"effects": "Appliquer des effets",
|
||||
"transcript": {
|
||||
"start": "Démarrer la transcription",
|
||||
"stop": "Arrêter la transcription en cours"
|
||||
}
|
||||
"effects": "Appliquer des effets"
|
||||
}
|
||||
},
|
||||
"effects": {
|
||||
@@ -101,18 +101,32 @@
|
||||
"heading": {
|
||||
"participants": "Participants",
|
||||
"effects": "Effets",
|
||||
"chat": "Messages dans l'appel"
|
||||
"chat": "Messages dans l'appel",
|
||||
"transcript": "Assistant IA"
|
||||
},
|
||||
"content": {
|
||||
"participants": "les participants",
|
||||
"effects": "les effets",
|
||||
"chat": "les messages"
|
||||
"chat": "les messages",
|
||||
"transcript": "l'assistant IA"
|
||||
},
|
||||
"closeButton": "Masquer {{content}}"
|
||||
},
|
||||
"chat": {
|
||||
"disclaimer": "Les messages sont visibles par les participants uniquement au moment de\nleur envoi. Tous les messages sont supprimés à la fin de l'appel."
|
||||
},
|
||||
"transcript": {
|
||||
"start": {
|
||||
"heading": "Démarrer l'assistant !",
|
||||
"body": "L'assistant démarre automatiquement l'enregistrement sonore de votre réunion (limité à 1h). À la fin, vous recevrez un résumé clair et concis des échanges directement par e-mail.",
|
||||
"button": "Démarrer"
|
||||
},
|
||||
"stop": {
|
||||
"heading": "Enregistrement en cours …",
|
||||
"body": "L'enregistrement de votre réunion est en cours. Vous recevrez un compte-rendu par email une fois la réunion terminée.",
|
||||
"button": "Arrêter l'enregistrement"
|
||||
}
|
||||
},
|
||||
"rating": {
|
||||
"submit": "Envoyer",
|
||||
"question": "Que pensez-vous de la qualité de votre appel ?",
|
||||
@@ -149,5 +163,8 @@
|
||||
"raisedHands": "Mains levées",
|
||||
"lowerParticipantHand": "Baisser la main de {{name}}",
|
||||
"lowerParticipantsHand": "Baisser la main de tous les participants"
|
||||
},
|
||||
"recording": {
|
||||
"label": "Enregistrement"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,6 +55,14 @@ export const text = cva({
|
||||
textAlign: 'inherit',
|
||||
},
|
||||
},
|
||||
wrap: {
|
||||
balance: {
|
||||
textWrap: 'balance',
|
||||
},
|
||||
pretty: {
|
||||
textWrap: 'pretty',
|
||||
},
|
||||
},
|
||||
bold: {
|
||||
true: {
|
||||
fontWeight: 'bold',
|
||||
|
||||
@@ -125,6 +125,9 @@ summary:
|
||||
AWS_S3_ACCESS_KEY_ID: meet
|
||||
AWS_S3_SECRET_ACCESS_KEY: password
|
||||
OPENAI_API_KEY: password
|
||||
OPENAI_BASE_URL: https://albertine.beta.numerique.gouv.fr:32222/v1
|
||||
OPENAI_ASR_MODEL: openai/whisper-large-v3
|
||||
OPENAI_LLM_MODEL: meta-llama/Llama-3.1-8B-Instruct
|
||||
AWS_S3_SECURE_ACCESS: False
|
||||
WEBHOOK_API_TOKEN: password
|
||||
WEBHOOK_URL: https://www.mock-impress.com/webhook/
|
||||
@@ -155,6 +158,9 @@ celery:
|
||||
AWS_S3_ACCESS_KEY_ID: meet
|
||||
AWS_S3_SECRET_ACCESS_KEY: password
|
||||
OPENAI_API_KEY: password
|
||||
OPENAI_BASE_URL: https://albertine.beta.numerique.gouv.fr:32222/v1
|
||||
OPENAI_ASR_MODEL: openai/whisper-large-v3
|
||||
OPENAI_LLM_MODEL: meta-llama/Llama-3.1-8B-Instruct
|
||||
AWS_S3_SECURE_ACCESS: False
|
||||
WEBHOOK_API_TOKEN: password
|
||||
WEBHOOK_URL: https://www.mock-impress.com/webhook/
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
image:
|
||||
repository: lasuite/meet-backend
|
||||
pullPolicy: Always
|
||||
tag: "v0.1.9"
|
||||
tag: "v0.1.10"
|
||||
|
||||
backend:
|
||||
migrateJobAnnotations:
|
||||
@@ -129,7 +129,7 @@ frontend:
|
||||
image:
|
||||
repository: lasuite/meet-frontend
|
||||
pullPolicy: Always
|
||||
tag: "v0.1.9"
|
||||
tag: "v0.1.10"
|
||||
|
||||
ingress:
|
||||
enabled: true
|
||||
@@ -165,3 +165,9 @@ posthog:
|
||||
cert-manager.io/cluster-issuer: letsencrypt
|
||||
nginx.ingress.kubernetes.io/upstream-vhost: eu-assets.i.posthog.com
|
||||
nginx.ingress.kubernetes.io/backend-protocol: https
|
||||
|
||||
summary:
|
||||
replicas: 0
|
||||
|
||||
celery:
|
||||
replicas: 0
|
||||
|
||||
@@ -216,6 +216,9 @@ summary:
|
||||
secretKeyRef:
|
||||
name: summary
|
||||
key: OPENAI_API_KEY
|
||||
OPENAI_BASE_URL: https://albertine.beta.numerique.gouv.fr:32222/v1
|
||||
OPENAI_ASR_MODEL: openai/whisper-large-v3
|
||||
OPENAI_LLM_MODEL: meta-llama/Llama-3.1-8B-Instruct
|
||||
WEBHOOK_API_TOKEN:
|
||||
secretKeyRef:
|
||||
name: summary
|
||||
|
||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "mail_mjml",
|
||||
"version": "0.1.9",
|
||||
"version": "0.1.10",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "mail_mjml",
|
||||
"version": "0.1.9",
|
||||
"version": "0.1.10",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@html-to/text-cli": "0.5.4",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "mail_mjml",
|
||||
"version": "0.1.9",
|
||||
"version": "0.1.10",
|
||||
"description": "An util to generate html and text django's templates from mjml templates",
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"""Celery workers."""
|
||||
|
||||
import json
|
||||
import os
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
|
||||
@@ -28,6 +29,7 @@ celery = Celery(
|
||||
)
|
||||
|
||||
if settings.sentry_dsn and settings.sentry_is_enabled:
|
||||
|
||||
@signals.celeryd_init.connect
|
||||
def init_sentry(**_kwargs):
|
||||
"""Initialize sentry."""
|
||||
@@ -100,15 +102,20 @@ def process_audio_transcribe_summarize(filename: str, email: str, sub: str):
|
||||
api_key=settings.openai_api_key, base_url=settings.openai_base_url
|
||||
)
|
||||
|
||||
logger.debug("Querying transcription …")
|
||||
with open(temp_file_path, "rb") as audio_file:
|
||||
transcription = openai_client.audio.transcriptions.create(
|
||||
model=settings.openai_asr_model, file=audio_file
|
||||
)
|
||||
try:
|
||||
logger.debug("Querying transcription …")
|
||||
with open(temp_file_path, "rb") as audio_file:
|
||||
transcription = openai_client.audio.transcriptions.create(
|
||||
model=settings.openai_asr_model, file=audio_file
|
||||
)
|
||||
|
||||
transcription = transcription.text
|
||||
transcription = transcription.text
|
||||
|
||||
logger.debug("Transcription: \n %s", transcription)
|
||||
logger.debug("Transcription: \n %s", transcription)
|
||||
finally:
|
||||
if os.path.exists(temp_file_path):
|
||||
os.remove(temp_file_path)
|
||||
logger.debug("Temporary file removed: %s", temp_file_path)
|
||||
|
||||
instructions = get_instructions(transcription)
|
||||
summary_response = openai_client.chat.completions.create(
|
||||
|
||||
Reference in New Issue
Block a user