thatupiso commited on
Commit
11464c4
1 Parent(s): 07977cf

Upload folder using huggingface_hub

Browse files
.gitattributes CHANGED
@@ -1,35 +1 @@
1
- *.7z filter=lfs diff=lfs merge=lfs -text
2
- *.arrow filter=lfs diff=lfs merge=lfs -text
3
- *.bin filter=lfs diff=lfs merge=lfs -text
4
- *.bz2 filter=lfs diff=lfs merge=lfs -text
5
- *.ckpt filter=lfs diff=lfs merge=lfs -text
6
- *.ftz filter=lfs diff=lfs merge=lfs -text
7
- *.gz filter=lfs diff=lfs merge=lfs -text
8
- *.h5 filter=lfs diff=lfs merge=lfs -text
9
- *.joblib filter=lfs diff=lfs merge=lfs -text
10
- *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
- *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
- *.model filter=lfs diff=lfs merge=lfs -text
13
- *.msgpack filter=lfs diff=lfs merge=lfs -text
14
- *.npy filter=lfs diff=lfs merge=lfs -text
15
- *.npz filter=lfs diff=lfs merge=lfs -text
16
- *.onnx filter=lfs diff=lfs merge=lfs -text
17
- *.ot filter=lfs diff=lfs merge=lfs -text
18
- *.parquet filter=lfs diff=lfs merge=lfs -text
19
- *.pb filter=lfs diff=lfs merge=lfs -text
20
- *.pickle filter=lfs diff=lfs merge=lfs -text
21
- *.pkl filter=lfs diff=lfs merge=lfs -text
22
- *.pt filter=lfs diff=lfs merge=lfs -text
23
- *.pth filter=lfs diff=lfs merge=lfs -text
24
- *.rar filter=lfs diff=lfs merge=lfs -text
25
- *.safetensors filter=lfs diff=lfs merge=lfs -text
26
- saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
- *.tar.* filter=lfs diff=lfs merge=lfs -text
28
- *.tar filter=lfs diff=lfs merge=lfs -text
29
- *.tflite filter=lfs diff=lfs merge=lfs -text
30
- *.tgz filter=lfs diff=lfs merge=lfs -text
31
- *.wasm filter=lfs diff=lfs merge=lfs -text
32
- *.xz filter=lfs diff=lfs merge=lfs -text
33
- *.zip filter=lfs diff=lfs merge=lfs -text
34
- *.zst filter=lfs diff=lfs merge=lfs -text
35
- *tfevents* filter=lfs diff=lfs merge=lfs -text
 
1
+ *.ipynb linguist-vendored
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
.github/workflows/update_space.yml ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: Run Python script
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+
8
+ jobs:
9
+ build:
10
+ runs-on: ubuntu-latest
11
+
12
+ steps:
13
+ - name: Checkout
14
+ uses: actions/checkout@v2
15
+
16
+ - name: Set up Python
17
+ uses: actions/setup-python@v2
18
+ with:
19
+ python-version: '3.9'
20
+
21
+ - name: Install Gradio
22
+ run: python -m pip install gradio
23
+
24
+ - name: Log in to Hugging Face
25
+ run: python -c 'import huggingface_hub; huggingface_hub.login(token="${{ secrets.hf_token }}")'
26
+
27
+ - name: Deploy to Spaces
28
+ run: gradio deploy
.gitignore ADDED
@@ -0,0 +1,126 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .pypirc
2
+
3
+ specs/
4
+ docs/
5
+ data/
6
+
7
+ *.ipynb
8
+
9
+ *.whl
10
+ *.wheels
11
+
12
+ # Exclude aliases file
13
+ alias.sh
14
+
15
+ *.ipynb_checkpoints
16
+
17
+ # Python-specific ignores
18
+ __pycache__/
19
+ *.py[cod]
20
+ *$py.class
21
+
22
+ # Virtual environment
23
+ venv/
24
+ env/
25
+ .env
26
+
27
+ # IDE-specific files
28
+ .vscode/
29
+ .idea/
30
+ *.swp
31
+ *.swo
32
+
33
+ # OS-specific files
34
+ .DS_Store
35
+ Thumbs.db
36
+
37
+ # Project-specific ignores
38
+ attachments/
39
+
40
+ # Logs
41
+ *.log
42
+
43
+ # Temporary files
44
+ *.tmp
45
+
46
+ # Compiled Python files
47
+ *.pyc
48
+
49
+ # Distribution / packaging
50
+ .Python
51
+ build/
52
+ develop-eggs/
53
+ dist/
54
+ downloads/
55
+ eggs/
56
+ .eggs/
57
+ lib/
58
+ lib64/
59
+ parts/
60
+ sdist/
61
+ var/
62
+ wheels/
63
+ *.egg-info/
64
+ .installed.cfg
65
+ *.egg
66
+
67
+ # PyInstaller
68
+ *.manifest
69
+ *.spec
70
+
71
+ # Installer logs
72
+ pip-log.txt
73
+ pip-delete-this-directory.txt
74
+
75
+ # Unit test / coverage reports
76
+ htmlcov/
77
+ .tox/
78
+ .coverage
79
+ .coverage.*
80
+ .cache
81
+ nosetests.xml
82
+ coverage.xml
83
+ *.cover
84
+ .hypothesis/
85
+ .pytest_cache/
86
+
87
+ # Jupyter Notebook
88
+ .ipynb_checkpoints
89
+
90
+ # pyenv
91
+ .python-version
92
+
93
+ # Environments
94
+ .env
95
+ .venv
96
+ env/
97
+ venv/
98
+ ENV/
99
+ env.bak/
100
+ venv.bak/
101
+
102
+ # Spyder project settings
103
+ .spyderproject
104
+ .spyproject
105
+
106
+ # Rope project settings
107
+ .ropeproject
108
+
109
+ # mkdocs documentation
110
+ /site
111
+
112
+ # mypy
113
+ .mypy_cache/
114
+
115
+ # Poetry
116
+ poetry.lock
117
+ .poetry/
118
+
119
+ # Poetry
120
+ .venv/
121
+ dist/
122
+
123
+ # Python
124
+ *.pyc
125
+ __pycache__/
126
+ *.egg-info/
README.md CHANGED
@@ -1,12 +1,110 @@
1
  ---
2
- title: Podcastfy.ai Demo
3
- emoji: 🌍
4
- colorFrom: pink
5
- colorTo: red
6
  sdk: gradio
7
  sdk_version: 4.44.1
8
- app_file: app.py
9
- pinned: false
10
  ---
 
 
 
 
 
 
 
11
 
12
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
+ title: Podcastfy.ai_demo
3
+ app_file: podcastfy-app/app.py
 
 
4
  sdk: gradio
5
  sdk_version: 4.44.1
 
 
6
  ---
7
+ # Podcastfy.ai
8
+ [![CodeFactor](https://www.codefactor.io/repository/github/souzatharsis/podcastfy/badge)](https://www.codefactor.io/repository/github/souzatharsis/podcastfy)
9
+ [![PyPi Status](https://img.shields.io/pypi/v/podcastfy)](https://pypi.org/project/podcastfy/)
10
+ [![Downloads](https://pepy.tech/badge/podcastfy)](https://pepy.tech/project/podcastfy)
11
+ [![Issues](https://img.shields.io/github/issues-raw/souzatharsis/podcastfy)](https://github.com/souzatharsis/podcastfy/issues)
12
+ [![License: CC BY-NC-SA 4.0](https://img.shields.io/badge/License-CC%20BY--NC--SA%204.0-lightgrey.svg)](https://creativecommons.org/licenses/by-nc-sa/4.0/)
13
+ [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/python/black)
14
 
15
+ Transforming Multi-Sourced Text into Captivating Multi-Lingual Audio Conversations with GenAI
16
+
17
+ https://github.com/user-attachments/assets/f1559e70-9cf9-4576-b48b-87e7dad1dd0b
18
+
19
+ Podcastfy is an open-source Python package that transforms web content, PDFs, and text into engaging, multi-lingual audio conversations using GenAI.
20
+
21
+ Unlike UI-based tools focused primarily on note-taking or research synthesis (e.g. NotebookLM ❤️), Podcastfy focuses on the programmatic and bespoke generation of engaging, conversational transcripts and audio from a multitude of text sources therefore enabling customization and scale.
22
+
23
+ ## Audio Examples
24
+
25
+ This sample collection is also [available at audio.com](https://audio.com/thatupiso/collections/podcastfy):
26
+ - [English] Book Networks, Crowds, and Markets: [audio](https://audio.com/thatupiso/audio/networks)
27
+ - [English] Research paper: ([audio](https://audio.com/thatupiso/audio/agro-paper) | [pdf](./data/pdf/s41598-024-58826-w.pdf))
28
+ - [English] Personal website: ([audio](https://audio.com/thatupiso/audio/tharsis) | [website](https://www.souzatharsis.com))
29
+ - [English] Personal website + youtube video: ([audio](https://audio.com/thatupiso/audio/tharsis-ai) | [website](https://www.souzatharsis.com) | [youtube](https://www.youtube.com/watch?v=sJE1dE2dulg))
30
+ - [French] Website: ([audio](https://audio.com/thatupiso/audio/podcast-fr-agro) | [website](https://agroclim.inrae.fr/))
31
+ - [Portuguese-BR] News article: ([audio](https://audio.com/thatupiso/audio/podcast-thatupiso-br) | [website](https://noticias.uol.com.br/eleicoes/2024/10/03/nova-pesquisa-datafolha-quem-subiu-e-quem-caiu-na-disputa-de-sp-03-10.htm))
32
+
33
+ ## Quickstart
34
+
35
+ ### Setup
36
+ Before installing, ensure you have Python 3.12 or higher installed on your system.
37
+
38
+ 1. Install from PyPI
39
+
40
+ `$ pip install podcastfy`
41
+
42
+ 2. Set up your [API keys](usage/config.md)
43
+
44
+ 3. Ensure you have ffmpeg installed on your system, required for audio processing
45
+ ```
46
+ sudo apt update
47
+ sudo apt install ffmpeg
48
+ ```
49
+
50
+ ### Python
51
+ ```python
52
+ from podcastfy.client import generate_podcast
53
+
54
+ audio_file = generate_podcast(urls=["<url1>", "<url2>"])
55
+ ```
56
+ ### CLI
57
+ ```
58
+ python -m podcastfy.client --url <url1> --url <url2>
59
+ ```
60
+
61
+ ## Usage
62
+
63
+ - [Python Package](podcastfy.ipynb)
64
+
65
+ - [CLI](usage/cli.md)
66
+
67
+
68
+ ## Contributing
69
+
70
+ Contributions are welcome! Please feel free to submit a Pull Request - see [Open Issues](https://github.com/souzatharsis/podcastfy/issues) for ideas. But even more excitingly feel free to fork the repo and create your own app! Please let me know if I could be of help.
71
+
72
+ ## Features
73
+
74
+ - Generate engaging, AI-powered conversational content from multiple sources (URLs and PDFs)
75
+ - Create high-quality transcripts from diverse textual information sources
76
+ - Convert pre-existing transcript files into dynamic podcast episodes
77
+ - Support for multiple advanced text-to-speech models (OpenAI and ElevenLabs) for natural-sounding audio
78
+ - Support for multiple languages, enabling global content creation
79
+ - Seamlessly integrate CLI for streamlined workflows
80
+
81
+ ## Example Use Cases
82
+
83
+ 1. **Content Summarization**: Busy professionals can stay informed on industry trends by listening to concise audio summaries of multiple articles, saving time and gaining knowledge efficiently.
84
+
85
+ 2. **Language Localization**: Non-native English speakers can access English content in their preferred language, breaking down language barriers and expanding access to global information.
86
+
87
+ 3. **Website Content Marketing**: Companies can increase engagement by repurposing written website content into audio format, providing visitors with the option to read or listen.
88
+
89
+ 4. **Personal Branding**: Job seekers can create unique audio-based personal presentations from their CV or LinkedIn profile, making a memorable impression on potential employers.
90
+
91
+ 5. **Research Paper Summaries**: Graduate students and researchers can quickly review multiple academic papers by listening to concise audio summaries, speeding up the research process.
92
+
93
+ 6. **Long-form Podcast Summarization**: Podcast enthusiasts with limited time can stay updated on their favorite shows by listening to condensed versions of lengthy episodes.
94
+
95
+ 7. **News Briefings**: Commuters can stay informed about daily news during travel time with personalized audio news briefings compiled from their preferred sources.
96
+
97
+ 8. **Educational Content Creation**: Educators can enhance learning accessibility by providing audio versions of course materials, catering to students with different learning styles.
98
+
99
+ 9. **Book Summaries**: Avid readers can preview books efficiently through audio summaries, helping them make informed decisions about which books to read in full.
100
+
101
+ 10. **Conference and Event Recaps**: Professionals can stay updated on important industry events they couldn't attend by listening to audio recaps of conference highlights and key takeaways.
102
+
103
+
104
+ ## License
105
+
106
+ This project is licensed under the [Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License](https://creativecommons.org/licenses/by-nc-sa/4.0/).
107
+
108
+ ## Disclaimer
109
+
110
+ This tool is designed for personal or educational use. Please ensure you have the necessary rights or permissions before using content from external sources for podcast creation. All audio content is AI-generated and it is not intended to clone real-life humans!
podcastfy-app/app.py ADDED
@@ -0,0 +1,127 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ from podcastfy.client import generate_podcast
3
+ import os
4
+ from dotenv import load_dotenv
5
+
6
+ # Load environment variables from .env file
7
+ load_dotenv()
8
+
9
+ def get_api_key(key_name, ui_value):
10
+ return ui_value if ui_value else os.getenv(key_name)
11
+
12
+ def create_podcast(urls, openai_key, jina_key, gemini_key):
13
+ try:
14
+ # Set API keys, prioritizing UI input over .env file
15
+ os.environ["OPENAI_API_KEY"] = get_api_key("OPENAI_API_KEY", openai_key)
16
+ os.environ["JINA_API_KEY"] = get_api_key("JINA_API_KEY", jina_key)
17
+ os.environ["GEMINI_API_KEY"] = get_api_key("GEMINI_API_KEY", gemini_key)
18
+
19
+ url_list = [url.strip() for url in urls.split(',') if url.strip()]
20
+
21
+ if not url_list:
22
+ return "Please provide at least one URL."
23
+
24
+ audio_file = generate_podcast(urls=url_list)
25
+ return audio_file
26
+ except Exception as e:
27
+ return str(e)
28
+
29
+ # Create the Gradio interface
30
+ with gr.Blocks(title="Podcastfy.ai", theme=gr.themes.Default()) as iface:
31
+ gr.Markdown("# Podcastfy.ai demo")
32
+ gr.Markdown("Generate a podcast from multiple URLs using Podcastfy.")
33
+ gr.Markdown("For full customization, please check [Podcastfy package](https://github.com/souzatharsis/podcastfy).")
34
+
35
+ with gr.Accordion("API Keys", open=False):
36
+ with gr.Row(variant="panel"):
37
+ with gr.Column(scale=1):
38
+ openai_key = gr.Textbox(label="OpenAI API Key", type="password", value=os.getenv("OPENAI_API_KEY", ""))
39
+ gr.Markdown('<a href="https://platform.openai.com/api-keys" target="_blank">Get OpenAI API Key</a>')
40
+ with gr.Column(scale=1):
41
+ jina_key = gr.Textbox(label="Jina API Key", type="password", value=os.getenv("JINA_API_KEY", ""))
42
+ gr.Markdown('<a href="https://jina.ai/reader/#apiform" target="_blank">Get Jina API Key</a>')
43
+ with gr.Column(scale=1):
44
+ gemini_key = gr.Textbox(label="Gemini API Key", type="password", value=os.getenv("GEMINI_API_KEY", ""))
45
+ gr.Markdown('<a href="https://makersuite.google.com/app/apikey" target="_blank">Get Gemini API Key</a>')
46
+
47
+ urls = gr.Textbox(lines=2, placeholder="Enter URLs separated by commas...", label="URLs")
48
+
49
+ generate_button = gr.Button("Generate Podcast", variant="primary")
50
+
51
+ with gr.Column():
52
+ gr.Markdown('<p style="color: #666; font-style: italic; margin-bottom: 5px;">Note: Podcast generation may take a couple of minutes.</p>', elem_id="generation-note")
53
+ audio_output = gr.Audio(type="filepath", label="Generated Podcast")
54
+
55
+ generate_button.click(
56
+ create_podcast,
57
+ inputs=[urls, openai_key, jina_key, gemini_key],
58
+ outputs=audio_output
59
+ )
60
+
61
+ gr.Markdown('<p style="text-align: center;">Created with ❤️ by <a href="https://github.com/souzatharsis/podcastfy" target="_blank">Podcastfy</a></p>')
62
+
63
+ # Add JavaScript for splash screen and positioning the disclaimer
64
+ iface.load(js="""
65
+ function addSplashScreen() {
66
+ const audioElement = document.querySelector('.audio-wrap');
67
+ if (audioElement) {
68
+ const splashScreen = document.createElement('div');
69
+ splashScreen.id = 'podcast-splash-screen';
70
+ splashScreen.innerHTML = '<p>Generating podcast... This may take a couple of minutes.</p>';
71
+ splashScreen.style.cssText = `
72
+ position: absolute;
73
+ top: 0;
74
+ left: 0;
75
+ right: 0;
76
+ bottom: 0;
77
+ background-color: rgba(0, 0, 0, 0.7);
78
+ color: white;
79
+ display: flex;
80
+ justify-content: center;
81
+ align-items: center;
82
+ z-index: 1000;
83
+ `;
84
+ audioElement.style.position = 'relative';
85
+ audioElement.appendChild(splashScreen);
86
+ }
87
+ }
88
+
89
+ function removeSplashScreen() {
90
+ const splashScreen = document.getElementById('podcast-splash-screen');
91
+ if (splashScreen) {
92
+ splashScreen.remove();
93
+ }
94
+ }
95
+
96
+ function positionGenerationNote() {
97
+ const noteElement = document.getElementById('generation-note');
98
+ const audioElement = document.querySelector('.audio-wrap');
99
+ if (noteElement && audioElement) {
100
+ noteElement.style.position = 'absolute';
101
+ noteElement.style.top = '-25px';
102
+ noteElement.style.left = '0';
103
+ noteElement.style.zIndex = '10';
104
+ audioElement.style.position = 'relative';
105
+ }
106
+ }
107
+
108
+ document.querySelector('#generate_podcast').addEventListener('click', addSplashScreen);
109
+
110
+ // Use a MutationObserver to watch for changes in the audio element
111
+ const observer = new MutationObserver((mutations) => {
112
+ mutations.forEach((mutation) => {
113
+ if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
114
+ removeSplashScreen();
115
+ positionGenerationNote();
116
+ }
117
+ });
118
+ });
119
+
120
+ observer.observe(document.querySelector('.audio-wrap'), { childList: true, subtree: true });
121
+
122
+ // Position the note on initial load
123
+ window.addEventListener('load', positionGenerationNote);
124
+ """)
125
+
126
+ if __name__ == "__main__":
127
+ iface.launch(share=True)
pyproject.toml ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [tool.poetry]
2
+ name = "podcastfy-app"
3
+ version = "0.1.0"
4
+ description = "Simple application for podcastfy.ai"
5
+ authors = ["Tharsis T. P. Souza"]
6
+ readme = "README.md"
7
+
8
+ [tool.poetry.dependencies]
9
+ python = "^3.12"
10
+ gradio-client = "^1.3.0"
11
+ gradio = "^4.44.1"
12
+ python-dotenv = "^1.0.1"
13
+
14
+
15
+ [build-system]
16
+ requires = ["poetry-core"]
17
+ build-backend = "poetry.core.masonry.api"
requirements.txt ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ aiofiles==23.2.1 ; python_version >= "3.12" and python_version < "4.0"
2
+ annotated-types==0.7.0 ; python_version >= "3.12" and python_version < "4.0"
3
+ anyio==4.6.0 ; python_version >= "3.12" and python_version < "4.0"
4
+ certifi==2024.8.30 ; python_version >= "3.12" and python_version < "4.0"
5
+ charset-normalizer==3.3.2 ; python_version >= "3.12" and python_version < "4.0"
6
+ click==8.1.7 ; python_version >= "3.12" and python_version < "4.0" and sys_platform != "emscripten"
7
+ colorama==0.4.6 ; python_version >= "3.12" and python_version < "4.0" and platform_system == "Windows"
8
+ contourpy==1.3.0 ; python_version >= "3.12" and python_version < "4.0"
9
+ cycler==0.12.1 ; python_version >= "3.12" and python_version < "4.0"
10
+ fastapi==0.115.0 ; python_version >= "3.12" and python_version < "4.0"
11
+ ffmpy==0.4.0 ; python_version >= "3.12" and python_version < "4.0"
12
+ filelock==3.16.1 ; python_version >= "3.12" and python_version < "4.0"
13
+ fonttools==4.54.1 ; python_version >= "3.12" and python_version < "4.0"
14
+ fsspec==2024.9.0 ; python_version >= "3.12" and python_version < "4.0"
15
+ gradio-client==1.3.0 ; python_version >= "3.12" and python_version < "4.0"
16
+ gradio==4.44.1 ; python_version >= "3.12" and python_version < "4.0"
17
+ h11==0.14.0 ; python_version >= "3.12" and python_version < "4.0"
18
+ httpcore==1.0.6 ; python_version >= "3.12" and python_version < "4.0"
19
+ httpx==0.27.2 ; python_version >= "3.12" and python_version < "4.0"
20
+ huggingface-hub==0.25.1 ; python_version >= "3.12" and python_version < "4.0"
21
+ idna==3.10 ; python_version >= "3.12" and python_version < "4.0"
22
+ importlib-resources==6.4.5 ; python_version >= "3.12" and python_version < "4.0"
23
+ jinja2==3.1.4 ; python_version >= "3.12" and python_version < "4.0"
24
+ kiwisolver==1.4.7 ; python_version >= "3.12" and python_version < "4.0"
25
+ markdown-it-py==3.0.0 ; python_version >= "3.12" and python_version < "4.0" and sys_platform != "emscripten"
26
+ markupsafe==2.1.5 ; python_version >= "3.12" and python_version < "4.0"
27
+ matplotlib==3.9.2 ; python_version >= "3.12" and python_version < "4.0"
28
+ mdurl==0.1.2 ; python_version >= "3.12" and python_version < "4.0" and sys_platform != "emscripten"
29
+ numpy==2.1.2 ; python_version >= "3.12" and python_version < "4.0"
30
+ orjson==3.10.7 ; python_version >= "3.12" and python_version < "4.0"
31
+ packaging==24.1 ; python_version >= "3.12" and python_version < "4.0"
32
+ pandas==2.2.3 ; python_version >= "3.12" and python_version < "4.0"
33
+ pillow==10.4.0 ; python_version >= "3.12" and python_version < "4.0"
34
+ pydantic-core==2.23.4 ; python_version >= "3.12" and python_version < "4.0"
35
+ pydantic==2.9.2 ; python_version >= "3.12" and python_version < "4.0"
36
+ pydub==0.25.1 ; python_version >= "3.12" and python_version < "4.0"
37
+ pygments==2.18.0 ; python_version >= "3.12" and python_version < "4.0" and sys_platform != "emscripten"
38
+ pyparsing==3.1.4 ; python_version >= "3.12" and python_version < "4.0"
39
+ python-dateutil==2.9.0.post0 ; python_version >= "3.12" and python_version < "4.0"
40
+ python-dotenv==1.0.1 ; python_version >= "3.12" and python_version < "4.0"
41
+ python-multipart==0.0.12 ; python_version >= "3.12" and python_version < "4.0"
42
+ pytz==2024.2 ; python_version >= "3.12" and python_version < "4.0"
43
+ pyyaml==6.0.2 ; python_version >= "3.12" and python_version < "4.0"
44
+ requests==2.32.3 ; python_version >= "3.12" and python_version < "4.0"
45
+ rich==13.9.2 ; python_version >= "3.12" and python_version < "4.0" and sys_platform != "emscripten"
46
+ ruff==0.6.9 ; python_version >= "3.12" and python_version < "4.0" and sys_platform != "emscripten"
47
+ semantic-version==2.10.0 ; python_version >= "3.12" and python_version < "4.0"
48
+ shellingham==1.5.4 ; python_version >= "3.12" and python_version < "4.0" and sys_platform != "emscripten"
49
+ six==1.16.0 ; python_version >= "3.12" and python_version < "4.0"
50
+ sniffio==1.3.1 ; python_version >= "3.12" and python_version < "4.0"
51
+ starlette==0.38.6 ; python_version >= "3.12" and python_version < "4.0"
52
+ tomlkit==0.12.0 ; python_version >= "3.12" and python_version < "4.0"
53
+ tqdm==4.66.5 ; python_version >= "3.12" and python_version < "4.0"
54
+ typer==0.12.5 ; python_version >= "3.12" and python_version < "4.0" and sys_platform != "emscripten"
55
+ typing-extensions==4.12.2 ; python_version >= "3.12" and python_version < "4.0"
56
+ tzdata==2024.2 ; python_version >= "3.12" and python_version < "4.0"
57
+ urllib3==2.2.3 ; python_version >= "3.12" and python_version < "4.0"
58
+ uvicorn==0.31.0 ; python_version >= "3.12" and python_version < "4.0" and sys_platform != "emscripten"
59
+ websockets==12.0 ; python_version >= "3.12" and python_version < "4.0"