codemichaeld commited on
Commit
cb0bcdc
Β·
verified Β·
1 Parent(s): c8083b7

Rename app.py to main.py

Browse files
Files changed (2) hide show
  1. app.py +0 -7
  2. main.py +229 -0
app.py DELETED
@@ -1,7 +0,0 @@
1
- import gradio as gr
2
-
3
- def greet(name):
4
- return "Hello " + name + "!!"
5
-
6
- demo = gr.Interface(fn=greet, inputs="text", outputs="text")
7
- demo.launch()
 
 
 
 
 
 
 
 
main.py ADDED
@@ -0,0 +1,229 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import os
3
+ import tempfile
4
+ import shutil
5
+ import subprocess
6
+ import re
7
+ import json
8
+ import datetime
9
+ from pathlib import Path
10
+ from huggingface_hub import HfApi, hf_hub_download
11
+ from safetensors.torch import save_file
12
+ import torch
13
+
14
+ # --- Utility: GGUF to FP8 Safetensors using gguf-connector CLI ---
15
+ def convert_gguf_to_fp8_safetensors(gguf_path, output_dir, progress=gr.Progress()):
16
+ """
17
+ Uses gguf-connector CLI to convert a GGUF file to FP8 safetensors.
18
+ Requires 'gguf-connector' and 'torch' installed.
19
+ """
20
+ progress(0.1, desc="Starting GGUF to FP8 conversion...")
21
+
22
+ try:
23
+ # Ensure gguf-connector is installed
24
+ import gguf_connector # noqa
25
+
26
+ # Build command: ggc t3 (GGUF β†’ safetensors), then q (safetensors β†’ FP8)
27
+ temp_safetensors_dir = tempfile.mkdtemp()
28
+ safetensors_path = os.path.join(temp_safetensors_dir, "intermediate.safetensors")
29
+ fp8_safetensors_path = os.path.join(output_dir, "model.safetensors")
30
+
31
+ progress(0.3, desc="Converting GGUF to Safetensors...")
32
+ # Step 1: GGUF β†’ Safetensors
33
+ result1 = subprocess.run(
34
+ ["ggc", "t3", gguf_path, safetensors_path],
35
+ capture_output=True,
36
+ text=True
37
+ )
38
+ if result1.returncode != 0:
39
+ raise RuntimeError(f"GGUF to Safetensors failed: {result1.stderr}")
40
+
41
+ progress(0.6, desc="Quantizing Safetensors to FP8...")
42
+ # Step 2: Safetensors β†’ FP8 Safetensors
43
+ result2 = subprocess.run(
44
+ ["ggc", "q", safetensors_path, fp8_safetensors_path],
45
+ capture_output=True,
46
+ text=True
47
+ )
48
+ if result2.returncode != 0:
49
+ raise RuntimeError(f"Safetensors to FP8 failed: {result2.stderr}")
50
+
51
+ # Create minimal config.json and tokenizer.json
52
+ config_path = os.path.join(output_dir, "config.json")
53
+ with open(config_path, "w") as f:
54
+ json.dump({
55
+ "model_type": "qwen",
56
+ "quantization": "fp8",
57
+ "architectures": ["QwenForCausalLM"]
58
+ }, f)
59
+
60
+ tokenizer_path = os.path.join(output_dir, "tokenizer.json")
61
+ with open(tokenizer_path, "w") as f:
62
+ json.dump({"model_type": "qwen", "vocab_size": 152064}, f)
63
+
64
+ progress(1.0, desc="Conversion to FP8 Safetensors complete!")
65
+ return True, "Conversion successful."
66
+
67
+ except Exception as e:
68
+ return False, str(e)
69
+ finally:
70
+ if 'temp_safetensors_dir' in locals():
71
+ shutil.rmtree(temp_safetensors_dir, ignore_errors=True)
72
+
73
+ # --- Main Processing Function ---
74
+ def process_and_upload(gguf_url, hf_token, new_repo_id, private_repo, progress=gr.Progress()):
75
+ if not all([gguf_url, hf_token, new_repo_id]):
76
+ return None, "❌ Error: Please fill in all fields.", ""
77
+
78
+ if not re.match(r"^[a-zA-Z0-9._-]+/[a-zA-Z0-9._-]+$", new_repo_id):
79
+ return None, "❌ Error: Invalid repository ID format. Use 'username/model-name'.", ""
80
+
81
+ temp_download_dir = tempfile.mkdtemp()
82
+ final_output_dir = tempfile.mkdtemp()
83
+
84
+ try:
85
+ # Authenticate
86
+ progress(0.05, desc="Logging into Hugging Face...")
87
+ api = HfApi(token=hf_token)
88
+ user_info = api.whoami()
89
+ user_name = user_info['name']
90
+ progress(0.1, desc=f"Logged in as {user_name}.")
91
+
92
+ # Parse URL
93
+ clean_url = gguf_url.strip()
94
+ if "huggingface.co" not in clean_url:
95
+ return None, "❌ Error: URL must be from Hugging Face.", ""
96
+ parts = clean_url.replace("https://huggingface.co/", "").split("/")
97
+ if len(parts) < 3 or not parts[-1].endswith(".gguf"):
98
+ return None, "❌ Error: Invalid GGUF URL format.", ""
99
+ repo_id = "/".join(parts[:2])
100
+ filename = parts[-1]
101
+
102
+ # Download
103
+ progress(0.15, desc="Downloading GGUF file...")
104
+ gguf_path = hf_hub_download(
105
+ repo_id=repo_id,
106
+ filename=filename,
107
+ cache_dir=temp_download_dir,
108
+ resume_download=True,
109
+ token=hf_token
110
+ )
111
+ progress(0.3, desc=f"Downloaded '{filename}'.")
112
+
113
+ # Convert
114
+ success, msg = convert_gguf_to_fp8_safetensors(gguf_path, final_output_dir, progress)
115
+ if not success:
116
+ return None, f"❌ Conversion failed: {msg}", ""
117
+
118
+ progress(0.8, desc="Preparing upload...")
119
+
120
+ # Create repo
121
+ repo_url = api.create_repo(
122
+ repo_id=new_repo_id,
123
+ private=private_repo,
124
+ repo_type="model",
125
+ exist_ok=True
126
+ )
127
+
128
+ # Generate README
129
+ readme_content = f"""---
130
+ license: other
131
+ library_name: transformers
132
+ tags:
133
+ - gguf
134
+ - fp8
135
+ - safetensors
136
+ - converted-by-gradio
137
+ - gguf-to-fp8
138
+ model-index:
139
+ - name: {new_repo_id.split('/')[-1]}
140
+ results: []
141
+ ---
142
+
143
+ # Model Card for {new_repo_id}
144
+
145
+ Converted from GGUF:
146
+ - **Source:** `{gguf_url}`
147
+ - **Filename:** `{filename}`
148
+
149
+ ## Conversion
150
+ Dequantized from GGUF and requantized to **FP8** using `gguf-connector`.
151
+ - **Converted by:** {user_name}
152
+ - **Date:** {datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
153
+ """
154
+ with open(os.path.join(final_output_dir, "README.md"), "w", encoding="utf-8") as f:
155
+ f.write(readme_content)
156
+
157
+ # Upload
158
+ progress(0.9, desc="Uploading to Hugging Face Hub...")
159
+ api.upload_folder(
160
+ repo_id=new_repo_id,
161
+ folder_path=final_output_dir,
162
+ repo_type="model",
163
+ token=hf_token,
164
+ commit_message="Upload FP8 Safetensors model converted via gguf-connector"
165
+ )
166
+
167
+ progress(1.0, desc="βœ… Upload complete!")
168
+ result_html = f"""
169
+ βœ… Success!
170
+ Your FP8 Safetensors model is ready.
171
+
172
+ **Repository:** [{new_repo_id}](https://huggingface.co/{new_repo_id})
173
+ **Visibility:** {'Private' if private_repo else 'Public'}
174
+ """
175
+ return gr.HTML(result_html), "βœ… Conversion and upload completed!", ""
176
+
177
+ except Exception as e:
178
+ return None, f"❌ Unexpected error: {str(e)}", ""
179
+ finally:
180
+ shutil.rmtree(temp_download_dir, ignore_errors=True)
181
+ shutil.rmtree(final_output_dir, ignore_errors=True)
182
+
183
+ # --- Gradio Interface ---
184
+ with gr.Blocks(title="GGUF β†’ FP8 Safetensors Converter", theme=gr.themes.Soft()) as demo:
185
+ gr.Markdown("# πŸ”„ GGUF to FP8 Safetensors Converter")
186
+ gr.Markdown("Uses `gguf-connector` to dequantize GGUF β†’ Safetensors β†’ FP8, then uploads to your Hugging Face account.")
187
+
188
+ with gr.Row():
189
+ with gr.Column():
190
+ gguf_url = gr.Textbox(
191
+ label="GGUF File URL",
192
+ placeholder="https://huggingface.co/unsloth/Qwen3-4B-GGUF/resolve/main/qwen3-4b.Q5_K_M.gguf",
193
+ info="Must be a direct .gguf file URL from Hugging Face."
194
+ )
195
+ hf_token = gr.Textbox(
196
+ label="Hugging Face Token",
197
+ type="password",
198
+ info="Token with write access. Get it at https://huggingface.co/settings/tokens"
199
+ )
200
+ with gr.Column():
201
+ new_repo_id = gr.Textbox(
202
+ label="New Repository ID",
203
+ placeholder="your-username/qwen3-4b-fp8",
204
+ info="Format: username/model-name"
205
+ )
206
+ private_repo = gr.Checkbox(label="Make Repository Private", value=False)
207
+
208
+ convert_btn = gr.Button("πŸš€ Convert & Upload", variant="primary")
209
+
210
+ with gr.Row():
211
+ status_output = gr.Markdown()
212
+ repo_link_output = gr.HTML()
213
+
214
+ convert_btn.click(
215
+ fn=process_and_upload,
216
+ inputs=[gguf_url, hf_token, new_repo_id, private_repo],
217
+ outputs=[repo_link_output, status_output],
218
+ show_progress=True
219
+ )
220
+
221
+ gr.Examples(
222
+ examples=[
223
+ ["https://huggingface.co/unsloth/Qwen3-4B-GGUF/resolve/main/qwen3-4b.Q5_K_M.gguf"]
224
+ ],
225
+ inputs=[gguf_url]
226
+ )
227
+
228
+ if __name__ == "__main__":
229
+ demo.launch()