CashOutSolo commited on
Commit
504a72d
·
verified ·
1 Parent(s): 596e78c

Delete app.py

Browse files

import os
import json
import glob
import re
import pandas as pd
import gradio as gr
import spaces # <--- REQUIRED FOR HUGGING FACE ZEROGPU TIERS
from pypdf import PdfReader
import docx2txt
import speech_recognition as sr
from pydub import AudioSegment
from llama_index.core.node_parser import SentenceSplitter

# Directory mounts mapping perfectly to your storage volume
UPLOAD_DIR = "/data/raw_inputs"
PROCESSED_DIR = "/data/processed_jsonl"
MASTER_FILE = "/data/master_dataset.jsonl"

os.makedirs(UPLOAD_DIR, exist_ok=True)
os.makedirs(PROCESSED_DIR, exist_ok=True)

# -------------------------------------------------------------
# CORE PIPELINE LOGIC (TRANSCRIBER, PARSER, CHUNKER)
# -------------------------------------------------------------
@spaces.GPU # <--- TELLS HUGGING FACE TO ALLOCATE GPU POWER FOR TRANSCRIBING
def transcribe_video_audio(file_path):
try:
gr.Info(f"🎬 Extracting track layers from {os.path.basename(file_path)}...")
audio = AudioSegment.from_file(file_path, format="mp4")
temp_wav = file_path + ".wav"
audio.set_channels(1).set_frame_rate(16000).export(temp_wav, format="wav")

recognizer = sr.Recognizer()
with sr.AudioFile(temp_wav) as source:
audio_data = recognizer.record(source)

gr.Info("🗣️ Processing Speech-to-Text conversion...")
extracted_text = recognizer.recognize_google(audio_data)

if os.path.exists(temp_wav):
os.remove(temp_wav)

return extracted_text.strip()
except Exception as e:
return f"[Audio Transcription Error]: {str(e)}"

def clean_text_formatting(text):
text = re.sub(r"\.([^ ])", r". \1", text)
while " " in text:
text = text.replace(" ", " ")
return text.strip()

def parse_incoming_file_to_text(file_path):
ext = os.path.splitext(file_path)[1].lower()
text = ""
if ext == ".txt":
with open(file_path, "r", encoding="utf-8") as f:
text = f.read()
elif ext == ".pdf":
reader = PdfReader(file_path)
for page in reader.pages:
t = page.extract_text()
if t: text += t + "\n"
elif ext == ".docx":
text = docx2txt.process(file_path)
elif ext in [".csv", ".xlsx"]:
df = pd.read_csv(file_path) if ext == ".csv" else pd.read_excel(file_path)
text = df.to_string(index=False)
elif ext in [".mp4", ".wav", ".mp3"]:
text = transcribe_video_audio(file_path)

return clean_text_formatting(text)

def structure_unsloth_rows(chunks, archetype):
rows = []
for idx, chunk in enumerate(chunks):
if "🎭 Persona" in archetype or "📚 Domain Expert" in archetype:
sys_msg = "You are an advanced interactive chatbot avatar."
if "🎭 Persona" in archetype:
sys_msg = "You are an immersive roleplay companion bot."
rows.append({
"conversations": [
{"from": "system", "value": sys_msg},
{"from": "human", "value": f"Context chunk {idx}: {chunk[:100]}..."},
{"from": "gpt", "value": chunk}
]
})
elif "🧮 Math Wizard" in archetype or "📈 Day Trading" in archetype:
instr = "Deconstruct structural math patterns or trading indicator calculations."
if "📈 Day Trading" in archetype:
instr = "Parse market metrics and technical data to extract signals."
rows.append({
"instruction": instr,
"input": f"Data segment context: {idx}",
"output": chunk
})
elif "💻 Code Assistant" in archetype:
rows.append({
"instruction": "Compile modular scripts based on requirements.",
"input": f"Code Requirements Segment: {idx}",
"output": chunk
})
else:
rows.append({"text": chunk})
return rows

@spaces.GPU # <--- DECORATES THE TOP LEVEL CONVERSION Pipeline FOR ZEROGPU STABILITY
def execute_dataset_builder_pipeline(files, archetype, enable_chunking, chunk_size, chunk_overlap):
if not files:
return "⚠️ Target file loading queue is empty. Please upload files."

for f in glob.glob(os.path.join(PROCESSED_DIR, "*.jsonl")):
os.remove(f)

total_files_compiled = 0
all_extracted_text_blocks = []

for file_obj in files:
raw_text = parse_incoming_file_to_text(file_obj.name)
if raw_text:
all_extracted_text_blocks.append(raw_text)
total_files_compiled += 1

if not all_extracted_text_blocks:
return "❌ Failed to extract content from assets."

combined_master_string = "\n\n--- FILE SPLIT ---\n\n".join(all_extracted_text_blocks)

if enable_chunking:
splitter = SentenceSplitter(chunk_size=int(chunk_size), chunk_overlap=int(chunk_overlap))
final_text_chunks = splitter.split_text(combined_master_string)
else:
final_text_chunks = all_extracted_text_blocks

formatted_dataset_objects = structure_unsloth_rows(final_text_chunks, archetype)

with open(MASTER_FILE, "w", encoding="utf-8") as master_f:
for obj in formatted_dataset_objects:
master_f.write(json.dumps(obj) + "\n")

return f"🔥 Conversion Complete!\n\n• Processed: {total_files_compiled}/{len(files)} files\n• Rows: {len(formatted_dataset_objects)}\n• Saved At: {MASTER_FILE}"

# -------------------------------------------------------------
# THEME TOGGLE SWITCH LOGIC ☀️/🌙
# -------------------------------------------------------------
def toggle_theme(current_theme):
if current_theme == "dark":
return gr.update(variant="light"), "light"
return gr.update(variant="dark"), "dark"

js_theme_switcher = """
function(theme) {
const documentElement = document.documentElement;
if (theme === 'dark') {
documentElement.classList.add('dark');
} else {
documentElement.classList.remove('dark');
}
return theme;
}
"""

archetype_choices = [
"🎭 Persona / Roleplay (e.g., Girlfriend, AI Companion)",
"📚 Domain Expert (e.g., History Expert, Legal Advisor)",
"🧮 Math Wizard (e.g., Algebra, Calculus solvers)",
"📈 Day Trading / Quant (e.g., XGBoost, Price Action Data)",
"💻 Code Assistant (e.g., Scripting, SQL Generation)",
"📖 Raw Knowledge Base (Continued Pre-Training)"
]

custom_theme = gr.themes.Default(
primary_hue="green",
secondary_hue="zinc",
neutral_hue="zinc"
)

# Removed theme and title parameters from constructor to prevent Gradio 6 layout deprecation warnings
with gr.Blocks() as demo:
ui_theme_state = gr.State("dark")

with gr.Row():
gr.HTML("<h1 style='flex-grow: 1; margin: 0; color: #22c55e;'>🦙 UN-SLOTH DATASET STUDIO</h1>")
theme_toggle_btn = gr.Button("🌓 Toggle Light/Dark Mode", scale=0, min_width=200)

gr.Markdown("Transform diverse media configurations into flawless JSONL files optimized for instant Unsloth training.")

with gr.Row():
with gr.Column(scale=1):
file_uploader = gr.File(file_count="multiple", label="📥 Drop Assets Here (.pdf, .txt, .docx, .mp4)")
archetype_dropdown = gr.Dropdown(choices=archetype_choices, value=archetype_choices[0], label="🤖 Choose Target AI Archetype Layout Mapping")

with gr.Accordion("✂️ Text Chunking Control Panel", open=True):
chunk_toggle = gr.Checkbox(value=True, label="Enable Smart Text Chunking Segmentation")
size_input = gr.Number(value=256, label="Chunk Token Size Limit", minimum=10, maximum=4096, step=1)
overlap_input = gr.Number(value=30, label="Overlap Token Boundary Buffer", minimum=0, maximum=1024, step=1)

run_btn = gr.Button("🚀 Run Conversion & Combine Files", variant="primary")

with gr.Column(scale=1):
log_monitor = gr.Textbox(label="🖥️ Core Engine Pipeline Logs", lines=15)

run_btn.click(
fn=execute_dataset_builder_pipeline,
inputs=[file_uploader, archetype_dropdown, chunk_toggle, size_input, overlap_input],
outputs=log_monitor
)

theme_toggle_btn.click(
fn=toggle_theme,
inputs=[ui_theme_state],
outputs=[theme_toggle_btn, ui_theme_state]
).then(
fn=None,
inputs=[ui_theme_state],
js=js_theme_switcher
)

demo.load(fn=lambda: "dark", outputs=ui_theme_state).then(fn=None, inputs=[ui_theme_state], js=js_theme_switcher)

if __name__ == "__main__":
# Theme configuration parameters passed to launch method matching Gradio 6 guidelines
demo.launch(theme=custom_theme)

Files changed (1) hide show
  1. app.py +0 -224
app.py DELETED
@@ -1,224 +0,0 @@
1
- import os
2
- import json
3
- import glob
4
- import re
5
- import pandas as pd
6
- import gradio as gr
7
- import spaces # <--- REQUIRED FOR HUGGING FACE ZEROGPU TIERS
8
- from pypdf import PdfReader
9
- import docx2txt
10
- import speech_recognition as sr
11
- from pydub import AudioSegment
12
- from llama_index.core.node_parser import SentenceSplitter
13
-
14
- # Directory mounts mapping perfectly to your storage volume
15
- UPLOAD_DIR = "/data/raw_inputs"
16
- PROCESSED_DIR = "/data/processed_jsonl"
17
- MASTER_FILE = "/data/master_dataset.jsonl"
18
-
19
- os.makedirs(UPLOAD_DIR, exist_ok=True)
20
- os.makedirs(PROCESSED_DIR, exist_ok=True)
21
-
22
- # -------------------------------------------------------------
23
- # CORE PIPELINE LOGIC (TRANSCRIBER, PARSER, CHUNKER)
24
- # -------------------------------------------------------------
25
- @spaces.GPU # <--- TELLS HUGGING FACE TO ALLOCATE GPU POWER FOR TRANSCRIBING
26
- def transcribe_video_audio(file_path):
27
- try:
28
- gr.Info(f"🎬 Extracting track layers from {os.path.basename(file_path)}...")
29
- audio = AudioSegment.from_file(file_path, format="mp4")
30
- temp_wav = file_path + ".wav"
31
- audio.set_channels(1).set_frame_rate(16000).export(temp_wav, format="wav")
32
-
33
- recognizer = sr.Recognizer()
34
- with sr.AudioFile(temp_wav) as source:
35
- audio_data = recognizer.record(source)
36
-
37
- gr.Info("🗣️ Processing Speech-to-Text conversion...")
38
- extracted_text = recognizer.recognize_google(audio_data)
39
-
40
- if os.path.exists(temp_wav):
41
- os.remove(temp_wav)
42
-
43
- return extracted_text.strip()
44
- except Exception as e:
45
- return f"[Audio Transcription Error]: {str(e)}"
46
-
47
- def clean_text_formatting(text):
48
- text = re.sub(r"\.([^ ])", r". \1", text)
49
- while " " in text:
50
- text = text.replace(" ", " ")
51
- return text.strip()
52
-
53
- def parse_incoming_file_to_text(file_path):
54
- ext = os.path.splitext(file_path)[1].lower()
55
- text = ""
56
- if ext == ".txt":
57
- with open(file_path, "r", encoding="utf-8") as f:
58
- text = f.read()
59
- elif ext == ".pdf":
60
- reader = PdfReader(file_path)
61
- for page in reader.pages:
62
- t = page.extract_text()
63
- if t: text += t + "\n"
64
- elif ext == ".docx":
65
- text = docx2txt.process(file_path)
66
- elif ext in [".csv", ".xlsx"]:
67
- df = pd.read_csv(file_path) if ext == ".csv" else pd.read_excel(file_path)
68
- text = df.to_string(index=False)
69
- elif ext in [".mp4", ".wav", ".mp3"]:
70
- text = transcribe_video_audio(file_path)
71
-
72
- return clean_text_formatting(text)
73
-
74
- def structure_unsloth_rows(chunks, archetype):
75
- rows = []
76
- for idx, chunk in enumerate(chunks):
77
- if "🎭 Persona" in archetype or "📚 Domain Expert" in archetype:
78
- sys_msg = "You are an advanced interactive chatbot avatar."
79
- if "🎭 Persona" in archetype:
80
- sys_msg = "You are an immersive roleplay companion bot."
81
- rows.append({
82
- "conversations": [
83
- {"from": "system", "value": sys_msg},
84
- {"from": "human", "value": f"Context chunk {idx}: {chunk[:100]}..."},
85
- {"from": "gpt", "value": chunk}
86
- ]
87
- })
88
- elif "🧮 Math Wizard" in archetype or "📈 Day Trading" in archetype:
89
- instr = "Deconstruct structural math patterns or trading indicator calculations."
90
- if "📈 Day Trading" in archetype:
91
- instr = "Parse market metrics and technical data to extract signals."
92
- rows.append({
93
- "instruction": instr,
94
- "input": f"Data segment context: {idx}",
95
- "output": chunk
96
- })
97
- elif "💻 Code Assistant" in archetype:
98
- rows.append({
99
- "instruction": "Compile modular scripts based on requirements.",
100
- "input": f"Code Requirements Segment: {idx}",
101
- "output": chunk
102
- })
103
- else:
104
- rows.append({"text": chunk})
105
- return rows
106
-
107
- @spaces.GPU # <--- DECORATES THE TOP LEVEL CONVERSION Pipeline FOR ZEROGPU STABILITY
108
- def execute_dataset_builder_pipeline(files, archetype, enable_chunking, chunk_size, chunk_overlap):
109
- if not files:
110
- return "⚠️ Target file loading queue is empty. Please upload files."
111
-
112
- for f in glob.glob(os.path.join(PROCESSED_DIR, "*.jsonl")):
113
- os.remove(f)
114
-
115
- total_files_compiled = 0
116
- all_extracted_text_blocks = []
117
-
118
- for file_obj in files:
119
- raw_text = parse_incoming_file_to_text(file_obj.name)
120
- if raw_text:
121
- all_extracted_text_blocks.append(raw_text)
122
- total_files_compiled += 1
123
-
124
- if not all_extracted_text_blocks:
125
- return "❌ Failed to extract content from assets."
126
-
127
- combined_master_string = "\n\n--- FILE SPLIT ---\n\n".join(all_extracted_text_blocks)
128
-
129
- if enable_chunking:
130
- splitter = SentenceSplitter(chunk_size=int(chunk_size), chunk_overlap=int(chunk_overlap))
131
- final_text_chunks = splitter.split_text(combined_master_string)
132
- else:
133
- final_text_chunks = all_extracted_text_blocks
134
-
135
- formatted_dataset_objects = structure_unsloth_rows(final_text_chunks, archetype)
136
-
137
- with open(MASTER_FILE, "w", encoding="utf-8") as master_f:
138
- for obj in formatted_dataset_objects:
139
- master_f.write(json.dumps(obj) + "\n")
140
-
141
- return f"🔥 Conversion Complete!\n\n• Processed: {total_files_compiled}/{len(files)} files\n• Rows: {len(formatted_dataset_objects)}\n• Saved At: {MASTER_FILE}"
142
-
143
- # -------------------------------------------------------------
144
- # THEME TOGGLE SWITCH LOGIC ☀️/🌙
145
- # -------------------------------------------------------------
146
- def toggle_theme(current_theme):
147
- if current_theme == "dark":
148
- return gr.update(variant="light"), "light"
149
- return gr.update(variant="dark"), "dark"
150
-
151
- js_theme_switcher = """
152
- function(theme) {
153
- const documentElement = document.documentElement;
154
- if (theme === 'dark') {
155
- documentElement.classList.add('dark');
156
- } else {
157
- documentElement.classList.remove('dark');
158
- }
159
- return theme;
160
- }
161
- """
162
-
163
- archetype_choices = [
164
- "🎭 Persona / Roleplay (e.g., Girlfriend, AI Companion)",
165
- "📚 Domain Expert (e.g., History Expert, Legal Advisor)",
166
- "🧮 Math Wizard (e.g., Algebra, Calculus solvers)",
167
- "📈 Day Trading / Quant (e.g., XGBoost, Price Action Data)",
168
- "💻 Code Assistant (e.g., Scripting, SQL Generation)",
169
- "📖 Raw Knowledge Base (Continued Pre-Training)"
170
- ]
171
-
172
- custom_theme = gr.themes.Default(
173
- primary_hue="green",
174
- secondary_hue="zinc",
175
- neutral_hue="zinc"
176
- )
177
-
178
- # Removed theme and title parameters from constructor to prevent Gradio 6 layout deprecation warnings
179
- with gr.Blocks() as demo:
180
- ui_theme_state = gr.State("dark")
181
-
182
- with gr.Row():
183
- gr.HTML("<h1 style='flex-grow: 1; margin: 0; color: #22c55e;'>🦙 UN-SLOTH DATASET STUDIO</h1>")
184
- theme_toggle_btn = gr.Button("🌓 Toggle Light/Dark Mode", scale=0, min_width=200)
185
-
186
- gr.Markdown("Transform diverse media configurations into flawless JSONL files optimized for instant Unsloth training.")
187
-
188
- with gr.Row():
189
- with gr.Column(scale=1):
190
- file_uploader = gr.File(file_count="multiple", label="📥 Drop Assets Here (.pdf, .txt, .docx, .mp4)")
191
- archetype_dropdown = gr.Dropdown(choices=archetype_choices, value=archetype_choices[0], label="🤖 Choose Target AI Archetype Layout Mapping")
192
-
193
- with gr.Accordion("✂️ Text Chunking Control Panel", open=True):
194
- chunk_toggle = gr.Checkbox(value=True, label="Enable Smart Text Chunking Segmentation")
195
- size_input = gr.Number(value=256, label="Chunk Token Size Limit", minimum=10, maximum=4096, step=1)
196
- overlap_input = gr.Number(value=30, label="Overlap Token Boundary Buffer", minimum=0, maximum=1024, step=1)
197
-
198
- run_btn = gr.Button("🚀 Run Conversion & Combine Files", variant="primary")
199
-
200
- with gr.Column(scale=1):
201
- log_monitor = gr.Textbox(label="🖥️ Core Engine Pipeline Logs", lines=15)
202
-
203
- run_btn.click(
204
- fn=execute_dataset_builder_pipeline,
205
- inputs=[file_uploader, archetype_dropdown, chunk_toggle, size_input, overlap_input],
206
- outputs=log_monitor
207
- )
208
-
209
- theme_toggle_btn.click(
210
- fn=toggle_theme,
211
- inputs=[ui_theme_state],
212
- outputs=[theme_toggle_btn, ui_theme_state]
213
- ).then(
214
- fn=None,
215
- inputs=[ui_theme_state],
216
- js=js_theme_switcher
217
- )
218
-
219
- demo.load(fn=lambda: "dark", outputs=ui_theme_state).then(fn=None, inputs=[ui_theme_state], js=js_theme_switcher)
220
-
221
- if __name__ == "__main__":
222
- # Theme configuration parameters passed to launch method matching Gradio 6 guidelines
223
- demo.launch(theme=custom_theme)
224
-