cutted 0.2.1__py3-none-any.whl → 0.3.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
cutted/__init__.py CHANGED
@@ -1,2 +1,2 @@
1
- __version__ = "0.1.0"
1
+ __version__ = "0.3.2"
2
2
  __author__ = "simon0302010"
cutted/app.py CHANGED
@@ -8,9 +8,19 @@ from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
8
8
 
9
9
  customtkinter.set_appearance_mode("Dark")
10
10
 
11
+ try:
12
+ from .core import transcribe
13
+ whisper_support = True
14
+ print_info("Whisper support present.")
15
+ except:
16
+ whisper_support = False
17
+ print_info("Whisper support is not present.")
18
+
11
19
  class CuttedApp:
12
20
  def __init__(self):
13
21
  self.AudioProcessor = audio_processor.AudioProcessor()
22
+ if whisper_support:
23
+ self.whisper = None
14
24
  self.gemini = gemini.GeminiClient()
15
25
  self.canvas = None
16
26
  self.cursor_line = None
@@ -44,12 +54,29 @@ class CuttedApp:
44
54
 
45
55
  undo_button = customtkinter.CTkButton(self.root, text="Undo", command=self.undo_last, width=70)
46
56
  undo_button.place(relx=0.1, rely=1.0, anchor="s", y=-30)
57
+
58
+ if whisper_support:
59
+ self.use_transcript_checkbox = customtkinter.CTkCheckBox(
60
+ self.root,
61
+ text="Send transcript to Gemini (slower, more accurate)",
62
+ text_color="#888888",
63
+ font=("Arial", 12)
64
+ )
65
+ self.use_transcript_checkbox.place(relx=0.0, rely=1.0, anchor="w", y=-12)
66
+
67
+ self.use_audio_checkbox = customtkinter.CTkCheckBox(
68
+ self.root,
69
+ text="Send audio to Gemini (buggy)",
70
+ text_color="#888888",
71
+ font=("Arial", 12)
72
+ )
73
+ self.use_audio_checkbox.place(relx=1.0, rely=1.0, anchor="e", y=-12)
47
74
 
48
75
  self.play_button = customtkinter.CTkButton(self.root, text="Play", command=self.play_audio, width=50)
49
76
  self.play_button.place(relx=0.3, rely=1.0, anchor="s", y=-30)
50
77
  self.stop_button = customtkinter.CTkButton(self.root, text="Stop", command=self.stop_audio, width=50)
51
78
  self.stop_button.place(relx=0.7, rely=1.0, anchor="s", y=-30)
52
-
79
+
53
80
  self.input_frame = customtkinter.CTkFrame(self.root, fg_color="transparent", height=36)
54
81
  self.input_frame.place(relx=0.5, rely=1.0, anchor="s", y=-90, relwidth=0.8)
55
82
 
@@ -164,25 +191,36 @@ class CuttedApp:
164
191
  return
165
192
 
166
193
  text = self.entry.get()
167
- full_prompt = f"You are a audio editing AI. You are controllable via natural language and editing a audio file. The audio file is {round(self.AudioProcessor.get_lenght())}s long."
168
- full_prompt += f"\n\nUser Prompt: {text}"
169
- self.entry.delete(0, "end")
170
-
171
- function_call, text_result = self.gemini.generate(full_prompt)
172
-
173
- if function_call:
174
- print_info(f"Gemini called {function_call.name}")
175
- if function_call.name == "cut_audio":
176
- print_info("Cut function called")
177
- args = function_call.args
178
- result = self.AudioProcessor.cut(args["start"], args["end"])
179
- if not result:
180
- messagebox.showerror("Error", "Please try again.")
181
- self.update_plot()
182
- elif text_result:
183
- messagebox.showerror("Error", text_result.strip())
184
- else:
185
- print_fail("Gemini returned no data")
194
+ if text.strip():
195
+ full_prompt = f"You are a audio editing AI. You are controllable via natural language and editing a audio file. The audio file is {round(self.AudioProcessor.get_lenght())}s long."
196
+ if whisper_support:
197
+ if self.use_transcript_checkbox.get():
198
+ if not self.whisper:
199
+ messagebox.showinfo("Info", "Loading Whisper model. This may take a few minutes depending on your internet connection. See the progress in your command line. If this window appears to be frozen, the transcription is running.")
200
+ self.whisper = transcribe.Whisper()
201
+ transcript = self.whisper.transcribe(self.AudioProcessor.audio_path)
202
+ full_prompt += f"\nThis is a transcript with per word timestamps of the audio:\n{transcript}"
203
+ full_prompt += f"\n\nUser Prompt: {text}"
204
+ self.entry.delete(0, "end")
205
+
206
+ if self.use_audio_checkbox.get():
207
+ function_call, text_result = self.gemini.generate(full_prompt, audio_base64=self.AudioProcessor.get_audio_base64())
208
+ else:
209
+ function_call, text_result = self.gemini.generate(full_prompt)
210
+
211
+ if function_call:
212
+ print_info(f"Gemini called {function_call.name}")
213
+ if function_call.name == "cut_audio":
214
+ print_info("Cut function called")
215
+ args = function_call.args
216
+ result = self.AudioProcessor.cut(args["start"], args["end"])
217
+ if not result:
218
+ messagebox.showerror("Error", "Please try again.")
219
+ self.update_plot()
220
+ elif text_result:
221
+ messagebox.showerror("Error", text_result.strip())
222
+ else:
223
+ print_fail("Gemini returned no data")
186
224
 
187
225
  def save_state(self):
188
226
  if hasattr(self.AudioProcessor, "audio") and self.AudioProcessor.audio is not None:
@@ -205,4 +243,4 @@ class CuttedApp:
205
243
 
206
244
  def main():
207
245
  app = CuttedApp()
208
- app.run()
246
+ app.run()
@@ -4,9 +4,8 @@ from .logger import *
4
4
  import numpy as np
5
5
  from matplotlib.figure import Figure
6
6
  import pygame
7
+ import base64
7
8
  import io
8
- import threading
9
- import time
10
9
 
11
10
  class AudioProcessor:
12
11
  def __init__(self):
@@ -150,4 +149,12 @@ class AudioProcessor:
150
149
  }
151
150
 
152
151
  def export_audio(self, path, format: str = "mp3"):
153
- self.audio.export(path, format=format)
152
+ self.audio.export(path, format=format)
153
+
154
+ def get_audio_base64(self):
155
+ buffer = io.BytesIO()
156
+ self.audio.export(buffer, format="mp3")
157
+ buffer.seek(0)
158
+ audio_bytes = buffer.read()
159
+ audio_base64 = base64.b64encode(audio_bytes)
160
+ return audio_base64
cutted/core/gemini.py CHANGED
@@ -1,5 +1,6 @@
1
1
  import os
2
2
  import sys
3
+ import base64
3
4
  from google import genai
4
5
  from google.genai import types
5
6
 
@@ -15,13 +16,21 @@ class GeminiClient:
15
16
  api_key=GEMINI_API_KEY,
16
17
  )
17
18
 
18
- def generate(self, prompt: str, model: str = "gemini-2.0-flash"):
19
+ def generate(self, prompt: str, model: str = "gemini-2.0-flash", audio_base64 = None):
20
+ parts=[
21
+ types.Part.from_text(text=prompt),
22
+ ]
23
+
24
+ if audio_base64:
25
+ parts.append(types.Part.from_bytes(
26
+ mime_type="audio/mpeg",
27
+ data=base64.b64decode(audio_base64)
28
+ ))
29
+
19
30
  contents = [
20
31
  types.Content(
21
32
  role="user",
22
- parts=[
23
- types.Part.from_text(text=prompt),
24
- ],
33
+ parts=parts
25
34
  ),
26
35
  ]
27
36
  tools = [
cutted/core/transcribe.py CHANGED
@@ -2,7 +2,7 @@ import json
2
2
  import whisper_timestamped as whisper
3
3
 
4
4
  class Whisper:
5
- def __init__(self, model_size: str = "small", device: str = "cpu"):
5
+ def __init__(self, model_size: str = "small", device = None):
6
6
  self.model = whisper.load_model(
7
7
  model_size, device=device
8
8
  )
@@ -0,0 +1,55 @@
1
+ Metadata-Version: 2.4
2
+ Name: cutted
3
+ Version: 0.3.2
4
+ Summary: AI-powered audio editor controllable via natural language.
5
+ Author-email: simon0302010 <simon0302010@gmail.com>
6
+ License-Expression: GPL-3.0
7
+ Project-URL: Homepage, https://github.com/simon0302010/Cutted
8
+ Requires-Python: <=3.13,>=3.9
9
+ Description-Content-Type: text/markdown
10
+ License-File: LICENSE
11
+ Requires-Dist: customtkinter
12
+ Requires-Dist: matplotlib
13
+ Requires-Dist: numpy
14
+ Requires-Dist: pydub
15
+ Requires-Dist: pygame
16
+ Requires-Dist: google-genai
17
+ Requires-Dist: python-dotenv
18
+ Provides-Extra: whisper
19
+ Requires-Dist: whisper-timestamped; extra == "whisper"
20
+ Dynamic: license-file
21
+
22
+ ![PyPI](https://img.shields.io/pypi/v/cutted?color=blue)
23
+ ![PyPI - License](https://img.shields.io/pypi/l/lyriks-video)
24
+ ![Hackatime](https://hackatime-badge.hackclub.com/U08HC7N4JJW/Cutted)
25
+
26
+ # Cutted
27
+
28
+ AI-powered audio editor controlled by natural language 🚀
29
+
30
+ Let AI handle your audio editing with simple commands:
31
+ - Automatically detect quiet or loud parts
32
+ - Transcribe audio (if Whisper is installed)
33
+ - Cut, trim, or adjust volume for specific segments
34
+
35
+ ## Installation
36
+
37
+ 1. **Install system dependencies (e.g., FFmpeg).**
38
+ 2. **Install Cutted**
39
+ ```bash
40
+ pip install cutted
41
+ ```
42
+ **With Whisper support**
43
+ ```bash
44
+ pip install cutted[whisper]
45
+ ```
46
+
47
+ ## Usage
48
+
49
+ 1. **Launch the app:**
50
+ ```bash
51
+ python -m cutted
52
+ ```
53
+ 2. **Load an audio file** (MP3, WAV, etc.)
54
+ 3. **Play, Cut, Undo** – all from the GUI or with text commands ✂️
55
+ 4. **Export** as MP3 or WAV
@@ -0,0 +1,12 @@
1
+ cutted/__init__.py,sha256=ttFLenYuOpXQTaR9nB0dF-3zFB_PeksXf9R4r_TB8S8,49
2
+ cutted/__main__.py,sha256=lYGLgtIZ_vGZIJmWG6ZQoqOdyOJnaWEA4NBn5Rc7Q8E,61
3
+ cutted/app.py,sha256=Ay_yVrPt1TQAE3lqmrII88lFoGZb5Mh5cDwediM9ZG8,9592
4
+ cutted/core/audio_processor.py,sha256=JdPeWO_jAIn_uZFeZYQJX3RC0Vy8GClKrX7xGk4pXR4,5426
5
+ cutted/core/gemini.py,sha256=yHsQXk4tDHcW5qJBuL2LpPvdChimxlmEbu76BvsoeY4,3108
6
+ cutted/core/logger.py,sha256=AjqrgW2LV9HdPkPQ8oOmyd9lWzVSIg46r74ILR7mVHo,585
7
+ cutted/core/transcribe.py,sha256=0e7aCva4y6D-gKe1xw5HT9VoFgbvHGgV6utn12r8wXA,986
8
+ cutted-0.3.2.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
9
+ cutted-0.3.2.dist-info/METADATA,sha256=MPuSW4_LjNch0PXeFrGtRW1C4CuJ7unNv1ZZhvFHmSM,1503
10
+ cutted-0.3.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
11
+ cutted-0.3.2.dist-info/top_level.txt,sha256=PL6glZvzRyKWCDn5aoYI9uH8HlEA5Qd_XFJowJKARYI,7
12
+ cutted-0.3.2.dist-info/RECORD,,
@@ -1,66 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: cutted
3
- Version: 0.2.1
4
- Summary: AI-powered audio editor controllable via natural language.
5
- Author-email: simon0302010 <simon0302010@gmail.com>
6
- License-Expression: GPL-3.0
7
- Project-URL: Homepage, https://github.com/simon0302010/Cutted
8
- Requires-Python: <=3.13,>=3.9
9
- Description-Content-Type: text/markdown
10
- License-File: LICENSE
11
- Requires-Dist: customtkinter
12
- Requires-Dist: matplotlib
13
- Requires-Dist: numpy
14
- Requires-Dist: pydub
15
- Requires-Dist: pygame
16
- Requires-Dist: google-genai
17
- Requires-Dist: python-dotenv
18
- Dynamic: license-file
19
-
20
- # Cutted
21
- AI-powered audio editor controllable via natural language
22
-
23
- Note: This app is currently not functional.
24
-
25
- # Installation
26
-
27
- Install dependencies:
28
-
29
- **Debian:**
30
- ```bash
31
- sudo apt update
32
- sudo apt install ffmpeg git
33
- ```
34
-
35
- **Arch Linux:**
36
- ```bash
37
- sudo pacman -Syu ffmpeg git
38
- ```
39
-
40
- Clone the repository:
41
-
42
- ```bash
43
- git clone https://github.com/simon0302010/Cutted.git
44
- cd Cutted
45
- ```
46
-
47
- Create a virtual environment:
48
-
49
- ```bash
50
- python -m venv venv
51
- source venv/bin/activate
52
- ```
53
-
54
- Install the package:
55
-
56
- ```bash
57
- pip install .
58
- ```
59
-
60
- # Usage
61
-
62
- Run the package:
63
-
64
- ```bash
65
- python -m cutted
66
- ```
@@ -1,12 +0,0 @@
1
- cutted/__init__.py,sha256=CP0x3JIScNbFVSOoF3eIQTKD5gDRfWXcCFE46rlZCio,49
2
- cutted/__main__.py,sha256=lYGLgtIZ_vGZIJmWG6ZQoqOdyOJnaWEA4NBn5Rc7Q8E,61
3
- cutted/app.py,sha256=vJZ_HZtUffUw36tJFBJCAhBbdluQgaOWIPqM5dNZXgU,7706
4
- cutted/core/audio_processor.py,sha256=7-XCuPPTlozeuaD2LqyzwRGinu0NvowTLbAh2X4XJ98,5182
5
- cutted/core/gemini.py,sha256=Ts_EbC1-rO9jIsdSlzKcmjLVS1o663GmfTdzmix12kE,2872
6
- cutted/core/logger.py,sha256=AjqrgW2LV9HdPkPQ8oOmyd9lWzVSIg46r74ILR7mVHo,585
7
- cutted/core/transcribe.py,sha256=cm6ziM3_grXKpUCFHiAU7-6lFK_SVsf7-6n14vMYQng,992
8
- cutted-0.2.1.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
9
- cutted-0.2.1.dist-info/METADATA,sha256=KKJ3auz3E5piy_1uEa9fWlkgZ72RmpHFMohbrqUmUbk,1122
10
- cutted-0.2.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
11
- cutted-0.2.1.dist-info/top_level.txt,sha256=PL6glZvzRyKWCDn5aoYI9uH8HlEA5Qd_XFJowJKARYI,7
12
- cutted-0.2.1.dist-info/RECORD,,
File without changes