melodic-vegetable-78787
02/27/2025, 2:15 PMgray-monkey-83525
02/27/2025, 2:15 PMactivation_threshold
parametresini ayarlayarak ses algılama hassasiyetini değiştirebilirsiniz. VoicePipelineAgent kullanırken, stt
ve tts
ayarlarını da gözden geçirip, uygun modelleri seçmek önemlidir. Örneğin, deepgram.STT
ve elevenlabs.TTS
için doğru dil ve model ayarlarını kontrol edin.
Daha fazla ayrıntı ister misiniz?
Sources:
- Configuring HD Voice for SIP
- VoicePipelineAgent 👍 0 button 👎 0 button 💡 Hint: Mention @runllm in the thread for followups.melodic-vegetable-78787
02/27/2025, 2:16 PMgray-monkey-83525
02/27/2025, 2:16 PMsilero.VAD
kullanıyorsanız, activation_threshold
parametresini ayarlayarak ses algılama hassasiyetini değiştirebilirsiniz. Daha düşük bir eşik değeri, daha sessiz sesleri algılamaya yardımcı olabilir, ancak bu, istenmeyen gürültülerin de algılanmasına neden olabilir. VAD parametreleri hakkında daha fazla bilgi edinebilirsiniz.
3. STT ve TTS Ayarları: deepgram.STT
ve elevenlabs.TTS
için doğru dil ve model ayarlarını kontrol edin. Örneğin, deepgram.STT
için model="nova-2-general"
ve language="tr"
ayarlarını kullanıyorsunuz. Bu ayarların doğru olduğundan emin olun ve gerekirse daha uygun bir model seçin.
4. Oda Ayarları: Oda ayarlarını optimize etmek için, `RoomOptions`'ı kullanarak ses işleme özelliklerini (örneğin, yankı iptali, gürültü bastırma) devre dışı bırakabilir veya ayarlayabilirsiniz. Bu, ses kalitesini artırabilir.
Örnek bir yapılandırma kodu:
room_options = RoomOptions(
defaultAudioCaptureOptions=AudioCaptureOptions(
echoCancellation=False,
noiseSuppression=False
),
defaultAudioPublishOptions=AudioPublishOptions(
encoding=AudioEncoding(maxBitrate=320000), # Yüksek kaliteli ses için
dtx=False
)
)
Bu ayarları deneyerek ses kalitesini artırabilirsiniz. Başka bir sorunuz var mı?
Sources:
- Configuring HD Voice for SIP
- VAD Parameters 👍 0 button 👎 0 button 💡 Hint: Mention @runllm in the thread for followups.melodic-vegetable-78787
02/27/2025, 2:22 PMgray-monkey-83525
02/27/2025, 2:22 PMroom_options = RoomOptions(
defaultAudioCaptureOptions=AudioCaptureOptions(
echoCancellation=False,
noiseSuppression=False
),
defaultAudioPublishOptions=AudioPublishOptions(
encoding=AudioEncoding(maxBitrate=320000), # Yüksek kaliteli ses için
dtx=False
)
)
3. VAD Ayarlarını Kontrol Edin: silero.VAD
kullanıyorsanız, activation_threshold
parametresini ayarlayarak ses algılama hassasiyetini değiştirebilirsiniz. Daha düşük bir eşik değeri, daha sessiz sesleri algılamaya yardımcı olabilir.
4. Ses Kaydını ve Egress Ayarlarını Kontrol Edin: Ses kaydını yaparken kullanılan ayarları kontrol edin. `RoomCompositeEgressRequest`'te audio_only=True
ve uygun dosya formatı ve codec ayarlarını kullanarak ses kalitesini artırabilirsiniz.
Kodunuza bu ayarları entegre etmek için, yukarıdaki örnekleri kullanarak RoomOptions
ve AudioCaptureOptions
ayarlarını güncelleyebilirsiniz. Ayrıca, SIP trunk sağlayıcınızın geniş bant codec'lerini desteklediğinden emin olun.
Başka bir sorunuz var mı?
Sources:
- https://livekit-users.slack.com/archives/C07FY8WHGPM/p1729300506.093409
- https://docs.livekit.io/agents/plugins/#VAD-and-StreamAdapter 👍 0 button 👎 0 button 💡 Hint: Mention @runllm in the thread for followups.melodic-vegetable-78787
02/27/2025, 2:35 PMgray-monkey-83525
02/27/2025, 2:35 PMSilero VAD
kullanarak çevredeki konuşmaları engellemek ve sadece konuşanı algılamak için activation_threshold
değerini ayarlayabilirsiniz. Daha yüksek bir activation_threshold
değeri, VAD'in daha az hassas olmasını sağlar ve sadece daha yüksek sesli konuşmaları algılar. Örneğin, activation_threshold
değerini 0.6 veya 0.7 olarak ayarlamak, daha sessiz arka plan seslerini filtrelemeye yardımcı olabilir.
vad = silero.VAD.load(activation_threshold=0.7)
Bu ayar, VAD'in sadece daha belirgin konuşmaları algılamasına yardımcı olabilir. Ancak, bu ayarın etkili olup olmadığını test etmek önemlidir, çünkü ortam gürültüsü ve konuşma dinamikleri farklılık gösterebilir. Daha fazla ayrıntı ister misiniz?
Sources:
- Silero VAD Documentation
- LiveKit Slack Discussion 👍 0 button 👎 0 button 💡 Hint: Mention @runllm in the thread for followups.melodic-vegetable-78787
02/27/2025, 2:37 PMgray-monkey-83525
02/27/2025, 2:37 PMSilero VAD
ayarlarını optimize edebilirsiniz. activation_threshold
değerini düşürmek, VAD'in daha hassas olmasını sağlar ve daha sessiz sesleri algılamasına yardımcı olabilir. Örneğin, activation_threshold
değerini 0.5 veya daha düşük bir seviyeye ayarlayarak, VAD'in daha fazla sesi algılamasını sağlayabilirsiniz.
vad = silero.VAD.load(activation_threshold=0.5)
Ayrıca, min_silence_duration
ve min_speech_duration
gibi diğer VAD parametrelerini de ayarlayarak, konuşma algılama hassasiyetini artırabilirsiniz. Bu ayarları test ederek, ortamınıza en uygun değerleri bulabilirsiniz. Daha fazla ayrıntı ister misiniz?
Sources:
- LiveKit Slack Discussion 👍 0 button 👎 0 button 💡 Hint: Mention @runllm in the thread for followups.melodic-vegetable-78787
02/27/2025, 2:43 PMmelodic-vegetable-78787
02/27/2025, 2:43 PMgray-monkey-83525
02/27/2025, 2:43 PMimport { KrispNoiseFilter } from '@livekit/krisp-noise-filter';
2. Krisp Gürültü Filtresini Etkinleştirin: Mikrofon kaynağınız için Krisp filtresini etkinleştirin.
room.on(RoomEvent.LocalTrackPublished, async (trackPublication) => {
if (trackPublication.source === Track.Source.Microphone && trackPublication.track instanceof LocalAudioTrack) {
const krispProcessor = KrispNoiseFilter();
await trackPublication.track.setProcessor(krispProcessor);
}
});
Bu adımlar, ajanın kalabalık ortamlarda daha iyi performans göstermesine yardımcı olabilir. Daha fazla ayrıntı ister misiniz?
Sources:
- Enhanced Noise Cancellation with Krisp 👍 0 button 👎 0 button 💡 Hint: Mention @runllm in the thread for followups.melodic-vegetable-78787
02/27/2025, 2:45 PMgray-monkey-83525
02/27/2025, 2:45 PMpydub
veya scipy
gibi kütüphaneleri kullanarak temel gürültü azaltma işlemleri yapabilirsiniz. Ancak, bu kütüphaneler gerçek zamanlı gürültü bastırma için sınırlı olabilir.
2. VAD Ayarlarını Optimize Etme: Silero VAD
kullanıyorsanız, activation_threshold
değerini ayarlayarak VAD'in daha az hassas olmasını sağlayabilirsiniz. Bu, arka plan gürültüsünün algılanmasını azaltabilir.
3. Gürültü Bastırma Modelleri: Python'da gürültü bastırma için noisereduce
gibi kütüphaneleri kullanabilirsiniz. Bu kütüphane, ses dosyalarındaki gürültüyü azaltmak için uygundur, ancak gerçek zamanlı uygulamalar için optimize edilmemiş olabilir.
Örnek bir noisereduce
kullanımı:
import noisereduce as nr
import soundfile as sf
# Ses dosyasını yükle
data, rate = sf.read('input.wav')
# Gürültü bastırma
reduced_noise = nr.reduce_noise(y=data, sr=rate)
# Sonucu kaydet
sf.write('output.wav', reduced_noise, rate)
Bu yöntemler, Python ve SIP telefon kullanırken gürültü bastırma sağlamaya yardımcı olabilir. Daha fazla ayrıntı ister misiniz?
Sources:
- https://docs.livekit.io/agents/voice-agent/
- https://docs.livekit.io/agents/openai/customize/turn-detection/ 👍 0 button 👎 0 button 💡 Hint: Mention @runllm in the thread for followups.melodic-vegetable-78787
02/27/2025, 7:12 PMmelodic-vegetable-78787
02/27/2025, 7:13 PMgray-monkey-83525
02/27/2025, 7:13 PMupdate_room
on a RoomService
object, but this method does not exist according to the provided data sources. To update room parameters, you might need to use the UpdateRoomMetadata
method instead, which is part of the RoomService API.
Here's a general approach to update room metadata:
1. Use the Correct API Method: Instead of update_room
, use UpdateRoomMetadata
to update the room's metadata. This method allows you to change the metadata associated with a room.
2. Example Code:
from livekit import api
async def update_room_metadata(ctx, room_name, new_metadata):
try:
await ctx.api.room.update_room_metadata(
api.UpdateRoomMetadataRequest(
room=room_name,
metadata=new_metadata
)
)
print(f"Room metadata updated for {room_name}")
except Exception as e:
print(f"Failed to update room metadata: {str(e)}")
3. Ensure Correct API Usage: Make sure you have the necessary permissions and that the API key used has the roomAdmin
permission to perform this operation.
If you need further details or have specific parameters you want to update, please let me know!
Sources:
- https://docs.livekit.io/server/room-management/#GetParticipant
- https://docs.livekit.io/home/client/data/participant-attributes/
Note: I wasn’t able to find highly relevant data sources, but above are a few potentially relevant links. 👍 0 button 👎 0 button 💡 Hint: Mention @runllm in the thread for followups.melodic-vegetable-78787
02/27/2025, 7:15 PMgray-monkey-83525
02/27/2025, 7:15 PMRoomOptions
when creating or updating a room. This involves setting parameters for audio capture and publish options to control aspects like bitrate, echo cancellation, and noise suppression.
Here's a basic example of how you can set audio specifications using RoomOptions
in a Python environment:
from livekit import rtc
# Define room options with specific audio settings
room_options = rtc.RoomOptions(
default_audio_capture_options=rtc.AudioCaptureOptions(
echo_cancellation=True,
noise_suppression=True,
auto_gain_control=True
),
default_audio_publish_options=rtc.AudioPublishOptions(
audio_bitrate=64000, # Set the desired audio bitrate
dtx=True # Enable discontinuous transmission
)
)
# Use these options when creating or updating a room
Key Parameters:
- echo_cancellation: Reduces echo in audio streams.
- noise_suppression: Minimizes background noise.
- auto_gain_control: Automatically adjusts the microphone gain.
- audio_bitrate: Sets the bitrate for audio streams, affecting quality and bandwidth usage.
- dtx (Discontinuous Transmission): Saves bandwidth by not sending silent packets.
These settings can be adjusted based on your specific requirements for audio quality and network conditions. Would you like more detailed guidance on any specific parameter?
Sources:
- Audio Configuration in LiveKit 👍 0 button 👎 0 button 💡 Hint: Mention @runllm in the thread for followups.melodic-vegetable-78787
02/27/2025, 7:33 PMgray-monkey-83525
02/27/2025, 7:33 PMfrom livekit import rtc
# Define audio capture options
audio_capture_options = rtc.AudioCaptureOptions(
echo_cancellation=True, # Enable echo cancellation
noise_suppression=True, # Enable noise suppression
auto_gain_control=True # Enable automatic gain control
)
# Define audio publish options
audio_publish_options = rtc.AudioPublishOptions(
audio_bitrate=64000, # Set the desired audio bitrate
dtx=True # Enable discontinuous transmission
)
# Create room options with the specified audio settings
room_options = rtc.RoomOptions(
default_audio_capture_options=audio_capture_options,
default_audio_publish_options=audio_publish_options
)
# Use these options when creating or updating a room
Key Parameters:
- echo_cancellation: Helps reduce echo in audio streams.
- noise_suppression: Minimizes background noise for clearer audio.
- auto_gain_control: Automatically adjusts the microphone gain to maintain consistent audio levels.
- audio_bitrate: Sets the bitrate for audio streams, which affects both quality and bandwidth usage.
- dtx (Discontinuous Transmission): Saves bandwidth by not sending silent packets.
These settings can be adjusted based on your specific requirements for audio quality and network conditions. If you need further assistance or have specific requirements, feel free to ask!
Sources:
- https://livekit-users.slack.com/archives/C07FVFGAUKX/p1733152587.089089 👍 0 button 👎 0 button 💡 Hint: Mention @runllm in the thread for followups.melodic-vegetable-78787
02/27/2025, 7:35 PMgray-monkey-83525
02/27/2025, 7:35 PMmelodic-vegetable-78787
02/27/2025, 7:36 PMfrom livekit import rtc
# Define audio capture options
audio_capture_options = rtc.AudioCaptureOptions(
echo_cancellation=True, # Enable echo cancellation
noise_suppression=True, # Enable noise suppression
auto_gain_control=True # Enable automatic gain control
)
# Define audio publish options
audio_publish_options = rtc.AudioPublishOptions(
audio_bitrate=64000, # Set the desired audio bitrate
dtx=True # Enable discontinuous transmission
)
# Create room options with the specified audio settings
room_options = rtc.RoomOptions(
default_audio_capture_options=audio_capture_options,
default_audio_publish_options=audio_publish_options
)
# Use these options when creating or updating a room
bunu koda nasıla dapt edıcem gıve me a code snıppet @millions-hair-24956gray-monkey-83525
02/27/2025, 7:36 PMfrom livekit import rtc
# Define audio capture options
audio_capture_options = rtc.AudioCaptureOptions(
echo_cancellation=True, # Yankı iptali etkinleştir
noise_suppression=True, # Gürültü bastırma etkinleştir
auto_gain_control=True # Otomatik kazanç kontrolü etkinleştir
)
# Define audio publish options
audio_publish_options = rtc.AudioPublishOptions(
audio_bitrate=64000, # İstenen ses bitrate'ini ayarla
dtx=True # Kesintili iletimi etkinleştir
)
# Create room options with the specified audio settings
room_options = rtc.RoomOptions(
default_audio_capture_options=audio_capture_options,
default_audio_publish_options=audio_publish_options
)
# Function to create or update a room with the specified options
async def create_or_update_room(api_client, room_name):
try:
# Create or update the room with the specified options
await api_client.room.create_room(
name=room_name,
options=room_options
)
print(f"Room '{room_name}' created or updated successfully with specified audio settings.")
except Exception as e:
print(f"Failed to create or update room: {str(e)}")
# Example usage
# Assuming you have an API client instance
# api_client = YourApiClientInstance()
# asyncio.run(create_or_update_room(api_client, "your-room-name"))
Açıklamalar:
- audio_capture_options: Yankı iptali, gürültü bastırma ve otomatik kazanç kontrolü gibi ses işleme özelliklerini ayarlamak için kullanılır.
- audio_publish_options: Ses bitrate'ini ve kesintili iletimi ayarlamak için kullanılır.
- room_options: Oda oluşturma veya güncelleme sırasında kullanılacak ses ayarlarını içerir.
Bu kodu, LiveKit API istemcinizle entegre ederek odalarınızı oluşturabilir veya güncelleyebilirsiniz. Başka bir konuda yardım ister misiniz?
Sources:
- https://livekit-users.slack.com/archives/C07FVFGAUKX/p1733152587.089089
- https://livekit-users.slack.com/archives/C07FVFGAUKX/p1732387962.900529 👍 0 button 👎 0 button 💡 Hint: Mention @runllm in the thread for followups.melodic-vegetable-78787
02/27/2025, 7:41 PMgray-monkey-83525
02/27/2025, 7:41 PMagent.py
code, you can set the audio options when initializing the room connection within the agent's entrypoint function. Here's how you can modify your agent.py
to include these audio settings:
from livekit import rtc, api
from livekit.agents import JobContext, WorkerOptions, cli
# Define audio capture options
audio_capture_options = rtc.AudioCaptureOptions(
echo_cancellation=True, # Enable echo cancellation
noise_suppression=True, # Enable noise suppression
auto_gain_control=True # Enable automatic gain control
)
# Define audio publish options
audio_publish_options = rtc.AudioPublishOptions(
audio_bitrate=64000, # Set the desired audio bitrate
dtx=True # Enable discontinuous transmission
)
# Create room options with the specified audio settings
room_options = rtc.RoomOptions(
default_audio_capture_options=audio_capture_options,
default_audio_publish_options=audio_publish_options
)
async def entrypoint(ctx: JobContext):
# Connect to the room with the specified audio settings
await ctx.connect(
auto_subscribe=rtc.AutoSubscribe.AUDIO_ONLY,
room_options=room_options
)
# Your existing logic for handling participants and tracks
# ...
if __name__ == "__main__":
cli.run_app(WorkerOptions(entrypoint_fnc=entrypoint))
Key Points:
- room_options: This is where you define the audio settings for echo cancellation, noise suppression, and bitrate.
- ctx.connect: When connecting to the room, pass the room_options
to apply these settings.
This setup ensures that your agent uses the specified audio settings when connecting to a room. If you have any further questions or need additional modifications, feel free to ask!
Sources:
- https://livekit-users.slack.com/archives/C07FY8WHGPM/p1728956116.368569
- https://livekit-users.slack.com/archives/C07FY8WHGPM/p1731400051.109939 👍 0 button 👎 0 button 💡 Hint: Mention @runllm in the thread for followups.melodic-vegetable-78787
02/27/2025, 7:47 PMgray-monkey-83525
02/27/2025, 7:47 PMAudioCaptureOptions
attribute is not available in the livekit.rtc
module, which is causing the AttributeError
. This could be due to a few reasons, such as using an outdated version of the LiveKit Python SDK or a misconfiguration in the code.
Here are some steps you can take to resolve this issue:
1. Check LiveKit SDK Version: Ensure that you are using the latest version of the LiveKit Python SDK. You can update the SDK using pip:
pip install --upgrade livekit
2. Verify Available Attributes: Double-check the available attributes in the livekit.rtc
module. You can do this by printing the available attributes:
import livekit.rtc
print(dir(livekit.rtc))
This will help you verify if AudioCaptureOptions
or similar attributes are available.
3. Consult Documentation: Refer to the LiveKit Python SDK documentation to ensure you are using the correct classes and methods for configuring audio options.
4. Alternative Configuration: If AudioCaptureOptions
is not available, you may need to configure audio settings using a different approach or consult the documentation for alternative methods.
If you continue to experience issues, please provide more details about your environment and the specific version of the LiveKit SDK you are using. This will help in providing more targeted assistance.
Sources:
- LiveKit Python SDK documentation 👍 0 button 👎 0 button 💡 Hint: Mention @runllm in the thread for followups.melodic-vegetable-78787
02/27/2025, 7:50 PMgray-monkey-83525
02/27/2025, 7:50 PMpip install --upgrade livekit livekit-agents livekit-plugins-openai livekit-plugins-deepgram livekit-plugins-silero livekit-plugins-google livekit-plugins-elevenlabs
2. Sürüm Kontrolü: Aşağıdaki komutla yüklü paketlerin sürümlerini kontrol edebilirsiniz:
pip list | grep livekit
Bu adımlar, LiveKit ve eklentilerinizin en son sürümlerini kullandığınızdan emin olmanıza yardımcı olacaktır. Eğer daha fazla yardıma ihtiyacınız olursa, lütfen LiveKit destek ekibiyle iletişime geçin. 👍 0 button 👎 0 button 💡 Hint: Mention @runllm in the thread for followups.melodic-vegetable-78787
02/27/2025, 7:51 PMgray-monkey-83525
02/27/2025, 7:51 PMdocker exec -it <container_id_or_name> /bin/bash
<container_id_or_name>
kısmını, kontrol etmek istediğiniz konteynerin ID'si veya adı ile değiştirin.
2. Paket Sürümünü Kontrol Edin: Konteyner içinde, yüklü Python paketlerinin sürümlerini kontrol etmek için aşağıdaki komutu çalıştırabilirsiniz:
pip list | grep livekit
Bu komut, yüklü olan LiveKit ve ilgili eklentilerin sürümlerini listeleyecektir.
Bu adımlar, Docker konteynerinizde hangi LiveKit sürümünü kullandığınızı belirlemenize yardımcı olacaktır. Başka bir konuda yardıma ihtiyacınız olursa, lütfen belirtin.
Sources:
- https://livekit-users.slack.com/archives/C07FY8WHGPM/p1730673248.486419
- https://livekit-users.slack.com/archives/C07FVFGAUKX/p1728090807.132609 👍 0 button 👎 0 button 💡 Hint: Mention @runllm in the thread for followups.melodic-vegetable-78787
02/27/2025, 7:55 PMgray-monkey-83525
02/27/2025, 7:55 PM/bin/bash
kabuğunun bulunmadığını gösteriyor. Bu genellikle daha hafif Docker imajları (örneğin, Alpine Linux) kullanıldığında meydana gelir, çünkü bu imajlar varsayılan olarak bash
yerine sh
gibi daha hafif kabuklar içerir.
Bu durumda, aşağıdaki adımları izleyebilirsiniz:
1. Alternatif Kabuk Kullanımı: Eğer bash
yoksa, sh
kabuğunu kullanarak konteynere girebilirsiniz:
docker exec -it <container_id_or_name> /bin/sh
<container_id_or_name>
kısmını, kontrol etmek istediğiniz konteynerin ID'si veya adı ile değiştirin.
2. Konteyner İmajını Kontrol Edin: Eğer sh
kabuğu da yoksa, kullandığınız Docker imajının belgelerini kontrol ederek hangi kabukların mevcut olduğunu öğrenebilirsiniz.
Bu adımlar, Docker konteynerinize erişmenize ve gerekli kontrolleri yapmanıza yardımcı olacaktır. Başka bir konuda yardıma ihtiyacınız olursa, lütfen belirtin.
Sources:
- https://livekit-users.slack.com/archives/C07FRP66XGE/p1732019649.386179 👍 0 button 👎 0 button 💡 Hint: Mention @runllm in the thread for followups.melodic-vegetable-78787
02/27/2025, 8:00 PMgray-monkey-83525
02/27/2025, 8:01 PMEncodingOptions
içinde audio_sample_rate
alanı bulunmuyor ve bu nedenle bir ValueError
alıyorsunuz. Bu, LiveKit Python SDK'sında EncodingOptions
sınıfının bu alanı desteklemediğini gösteriyor.
Doğru parametreleri kullanarak `EncodingOptions`'ı nasıl ayarlayabileceğinizi göstereyim:
from livekit import protocol
# Define encoding options without audio_sample_rate
encoding_options = protocol.egress.EncodingOptions(
audio_bitrate=64000 # Set the desired audio bitrate
# Remove audio_sample_rate as it is not supported
)
# Use encoding options in your egress request
file_output = protocol.egress.EncodedFileOutput(
filepath="outbound-905421950620-room-Ba6GxXTThvvc.m4a",
encoding_options=encoding_options
)
# Example egress request
egress_request = protocol.egress.RoomCompositeEgressRequest(
room_name="room-Ba6GxXTThvvc",
audio_only=True,
file_outputs=[file_output]
)
# Function to start recording
async def record_call(ctx, phone_number):
try:
res = await ctx.api.egress.start_room_composite_egress(egress_request)
print(f"Recording started with egress_id: {res.egress_id}")
return res.egress_id
except Exception as e:
print(f"Failed to start recording: {str(e)}")
raise
Açıklamalar:
- audio_bitrate: Ses bitrate'ini ayarlamak için kullanılır. audio_sample_rate
alanı desteklenmediği için kaldırılmıştır.
- encoding_options: EncodingOptions
içinde sadece desteklenen alanları kullanın.
Bu değişiklikler, ValueError
hatasını çözmenize yardımcı olacaktır. Başka bir konuda yardıma ihtiyacınız olursa, lütfen belirtin.
Sources:
- https://docs.livekit.io/home/egress/api/#DirectFileOutput
- https://docs.livekit.io/home/egress/api/ 👍 0 button 👎 0 button 💡 Hint: Mention @runllm in the thread for followups.melodic-vegetable-78787
02/27/2025, 8:23 PMgray-monkey-83525
02/27/2025, 8:23 PM