Spaces:
Running
Running
File size: 13,326 Bytes
5dda5dc 4477bd7 5dda5dc 1edd603 5dda5dc 4477bd7 5dda5dc 8be1037 5dda5dc 1edd603 f72018f 1edd603 b877e5d 1edd603 5dda5dc 4477bd7 5dda5dc |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 |
"""
DiscordSum - Hugging Face Space Gradio App
Conversation summarization using Qwen3-0.6B-DiscordSum-mini-v1
"""
import gradio as gr
import torch
import time
import re
from typing import Dict, Any
from transformers import AutoModelForCausalLM, AutoTokenizer
# Model configuration
MODEL_NAME = "Plasmoxy/Qwen3-0.6B-DiscordSum-mini-v1"
# Sample conversations for demo
SAMPLE_CONVERSATIONS = {
"Quick Bug Fix": """[Sarah]: Hey team, found a bug in the login form
[Mike]: What's the issue?
[Sarah]: The password field isn't validating minimum length
[Mike]: I'll fix that today, should be a quick patch
[Sarah]: Thanks! Let me know when it's ready for testing
[Tom]: Is this affecting production users?
[Sarah]: Not yet, caught it in staging
[Tom]: Good catch! We should add more validation tests
[Mike]: Just pushed the fix to dev branch
[Sarah]: Testing now... looks good!
[Tom]: Can you also check the email validation while you're at it?
[Sarah]: Sure, testing that too... email validation works fine
[Mike]: Great, I'll merge it to main
[Tom]: Don't forget to update the changelog
[Mike]: Already done, also added unit tests for this
[Sarah]: Perfect! This should prevent similar issues in the future""",
"Gaming Session": """[Alex]: Anyone up for some Valorant tonight?
[Jake]: I'm down! What time?
[Alex]: Around 8 PM?
[Emma]: Can I join? I'm still learning though
[Jake]: Of course! We can do unrated matches
[Alex]: Perfect, see you all at 8!
[Emma]: What agents should I practice?
[Jake]: Try Sage or Brimstone, they're beginner friendly
[Emma]: Thanks for the tips!
[Alex]: We'll help you learn the maps too
[Jake]: Emma, have you played any tactical shooters before?
[Emma]: A bit of CS:GO, but Valorant feels different
[Alex]: The abilities make it unique, but the shooting mechanics are similar
[Emma]: Should I focus on aim or learning abilities first?
[Jake]: Both, but start with crosshair placement and basic abilities
[Alex]: We can do some custom games first to practice
[Emma]: That sounds great! I don't want to drag the team down
[Jake]: Don't worry, we all started somewhere
[Alex]: Plus unrated is perfect for learning, no pressure""",
"Anime Discussion": """[Yuki]: Just finished the latest Attack on Titan episode!
[Marcus]: No spoilers! I'm still on season 3
[Yuki]: My lips are sealed 🤐
[Lisa]: The animation this season is incredible
[Yuki]: Right?! The studio really outdid themselves
[Marcus]: Okay now I'm excited to catch up
[Lisa]: The soundtrack is also amazing this season
[Yuki]: Agreed! That final scene gave me chills
[Marcus]: Stop, you're making me want to binge it all tonight
[Lisa]: Do it! You won't regret it
[Yuki]: The character development has been insane too
[Lisa]: I know! I didn't expect that plot twist at all
[Marcus]: OKAY STOPPING HERE, no more hints!
[Yuki]: Sorry sorry! But seriously, catch up soon so we can discuss
[Lisa]: Have you guys seen the new Demon Slayer movie yet?
[Yuki]: Not yet, is it good?
[Lisa]: Amazing! The fight scenes are breathtaking
[Marcus]: I heard the animation budget was huge
[Lisa]: You can tell, every frame is gorgeous
[Yuki]: We should all go watch it together next weekend""",
"Movie Night Planning": """[Chris]: Movie night this Friday?
[Sam]: Yes! What should we watch?
[Chris]: How about the new Dune movie?
[Taylor]: I'm in, but can we do Saturday instead?
[Sam]: Saturday works better for me too
[Chris]: Saturday it is then, 7 PM at my place
[Taylor]: Should we bring snacks?
[Chris]: I'll handle popcorn, you guys bring drinks
[Sam]: I'll bring some sodas and chips
[Taylor]: I'll make my famous nachos!
[Chris]: Perfect, this is going to be awesome
[Sam]: Should we watch the first Dune movie before?
[Chris]: Good idea! We could start at 4 PM with the first one
[Taylor]: That's a long movie marathon, I'm so in!
[Sam]: Do we need to read the books first?
[Chris]: Nah, the movies are great on their own
[Taylor]: I'll bring my projector if you want a bigger screen
[Chris]: Oh that would be amazing! My TV is only 55 inches
[Sam]: This is turning into a proper cinema experience
[Taylor]: Should I bring my surround sound speakers too?
[Chris]: Yes please! Let's go all out
[Sam]: I'll make sure to bring extra snacks then
[Taylor]: Can't wait! This is going to be epic
[Chris]: Best movie night ever incoming!
[Sam]: Should we invite anyone else?
[Chris]: Let's keep it small, my living room isn't huge
[Taylor]: Fair enough, cozy movie night with the crew
[Sam]: Perfect! See you all Saturday at 4 PM""",
"Recipe Sharing": """[Mom_Chef]: Just made the best chocolate chip cookies!
[FoodieFan]: Recipe please! 🍪
[Mom_Chef]: 2 cups flour, 1 cup butter, 1 cup sugar, chocolate chips
[FoodieFan]: What temperature?
[Mom_Chef]: 350°F for 12 minutes
[FoodieFan]: Making these tonight, thanks!
[Mom_Chef]: Don't forget to cream the butter and sugar first
[FoodieFan]: How long should I cream them?
[Mom_Chef]: About 3-4 minutes until fluffy
[FoodieFan]: Got it! Any other tips?
[Mom_Chef]: Let the dough chill for 30 minutes before baking
[FoodieFan]: You're the best!
[BakingQueen]: Can I get that recipe too?
[Mom_Chef]: Of course! Also add 2 eggs and 1 tsp vanilla extract
[BakingQueen]: What kind of chocolate chips work best?
[Mom_Chef]: I use semi-sweet, but dark chocolate works great too
[FoodieFan]: Can I add nuts?
[Mom_Chef]: Absolutely! Walnuts or pecans are perfect
[BakingQueen]: How many cookies does this make?
[Mom_Chef]: About 36 medium-sized cookies
[FoodieFan]: Can I freeze the dough?
[Mom_Chef]: Yes! It freezes beautifully for up to 3 months
[BakingQueen]: Do you use salted or unsalted butter?
[Mom_Chef]: Unsalted, then add 1 tsp of salt to the dry ingredients
[FoodieFan]: Should the butter be room temperature?
[Mom_Chef]: Yes, soft but not melted
[BakingQueen]: Thanks for all the details! Making these this weekend
[FoodieFan]: Just put mine in the oven, house smells amazing already!
[Mom_Chef]: Let me know how they turn out!
[FoodieFan]: They're perfect! Crispy edges, soft center
[BakingQueen]: Now I'm even more excited to try them
[Mom_Chef]: So happy they worked out! Enjoy everyone!""",
"Study Group": """[Student1]: Can someone explain the calculus homework?
[Student2]: Which problem are you stuck on?
[Student1]: Problem 5, the integration one
[Student2]: You need to use substitution method there
[Student1]: Oh! That makes sense now
[Student2]: Want to meet up tomorrow to go over the rest?
[Student1]: That would be great, thanks!
[Student3]: Can I join too? I'm struggling with problem 7
[Student2]: Sure! Let's meet at the library at 3 PM
[Student1]: Perfect, see you there
[Student3]: Thanks guys, really appreciate it
[Student2]: No problem, we're all in this together
[Student4]: Is this for Professor Johnson's class?
[Student1]: Yes! Are you in that class too?
[Student4]: Yeah, I'm also confused about problem 8
[Student2]: We can go over that one tomorrow as well
[Student3]: Should we bring our textbooks?
[Student2]: Definitely, and your notes too
[Student1]: I'll bring my laptop in case we need to look anything up
[Student4]: Can we also review the previous chapter? I'm still shaky on that
[Student2]: Good idea, the concepts build on each other
[Student3]: What about problem 10? That one seems really hard
[Student1]: I haven't even attempted that one yet
[Student2]: It's tricky but we'll work through it together
[Student4]: Should we plan for more than an hour?
[Student2]: Probably, let's say 2-3 hours to be safe
[Student3]: I can stay until 6 PM if needed
[Student1]: Same here, I really want to understand this material
[Student4]: This study group is a lifesaver
[Student2]: We should make this a regular thing
[Student3]: Agreed! Maybe every week before assignments are due?
[Student1]: I'm in! Let's create a group chat
[Student4]: Great idea, I'll set one up
[Student2]: Perfect! See everyone tomorrow at 3 PM, library second floor
[Student1]: Thanks everyone, feeling much better about this now
[Student3]: Same! Can't wait to finally understand these problems
[Student4]: This is why study groups are the best!"""
}
# Global model and tokenizer
model = None
tokenizer = None
def load_model():
"""Load model and tokenizer"""
global model, tokenizer
print(f"Loading model: {MODEL_NAME}")
tokenizer = AutoTokenizer.from_pretrained(
MODEL_NAME,
trust_remote_code=True,
padding_side="right"
)
if tokenizer.pad_token is None:
tokenizer.pad_token = tokenizer.eos_token
tokenizer.pad_token_id = tokenizer.eos_token_id
model = AutoModelForCausalLM.from_pretrained(
MODEL_NAME,
device_map="auto",
torch_dtype=torch.float32,
trust_remote_code=True,
)
model.eval()
print("Model loaded successfully!")
def format_inference_prompt(conversation: str) -> str:
"""Format inference prompt using chat template"""
messages = [
{
"role": "system",
"content": "Summarize Discord conversations into a paragraph capturing key points, decisions, and action items."
},
{
"role": "user",
"content": f"Summarize the following conversation:\n\n{conversation}"
}
]
formatted = tokenizer.apply_chat_template(
messages,
tokenize=False,
add_generation_prompt=True,
enable_thinking=False
)
# Clean up chat template output
formatted = re.sub(r'<think>[\s\S]*?</think>', '', formatted)
formatted = re.sub(r'(<\|im_end\|>)(?=<\|im_start\|>)', r'\1\n', formatted)
formatted = re.sub(r'(<\|im_start\|>[^<>\n]+)\s*\n\s*\n', r'\1\n', formatted)
formatted = re.sub(r'\n{3,}', '\n\n', formatted)
formatted = formatted.strip()
return formatted
def extract_summary(response: str) -> str:
"""Extract summary from model response"""
match = re.search(r'Summary:\s*(.*?)(?:<\|im_end\|>|$)', response, re.DOTALL)
if match:
return match.group(1).strip()
return response.strip()
def summarize_conversation(conversation: str):
"""Summarize conversation using the model"""
if not conversation or not conversation.strip():
return "Error: Conversation cannot be empty", None
try:
start_time = time.time()
# Format prompt
prompt = format_inference_prompt(conversation)
# Tokenize
inputs = tokenizer(
prompt,
return_tensors="pt",
truncation=True,
max_length=2048
).to(model.device)
input_tokens = inputs["input_ids"].shape[1]
warmup_time = time.time() - start_time
# Generate
generation_start = time.time()
with torch.no_grad():
outputs = model.generate(
**inputs,
max_new_tokens=200,
temperature=0.7,
top_p=0.9,
do_sample=True,
pad_token_id=tokenizer.pad_token_id,
eos_token_id=tokenizer.eos_token_id,
)
inference_time = time.time() - generation_start
# Decode
response = tokenizer.decode(
outputs[0][input_tokens:],
skip_special_tokens=True
)
# Extract summary
summary = extract_summary(response)
# Calculate stats
output_tokens = outputs.shape[1] - input_tokens
total_time = time.time() - start_time
tokens_per_second = output_tokens / inference_time if inference_time > 0 else 0
# Create stats table data
stats_data = [
["Inference Time", f"{inference_time:.2f}s"],
["Warmup Time", f"{warmup_time:.2f}s"],
["Total Time", f"{total_time:.2f}s"],
["Tokens/Second", f"{tokens_per_second:.1f}"],
["Input Tokens", str(input_tokens)],
["Output Tokens", str(output_tokens)],
["Total Tokens", str(outputs.shape[1])],
]
return summary, stats_data
except Exception as e:
return f"Error: {str(e)}", None
# Load model on startup
load_model()
# Create Gradio interface
demo = gr.Interface(
fn=summarize_conversation,
inputs=gr.Textbox(
label="Discord Conversation",
placeholder="Paste your Discord conversation here...",
lines=15,
value=SAMPLE_CONVERSATIONS["Movie Night Planning"]
),
outputs=[
gr.Textbox(
label="Summary",
lines=10
),
gr.Dataframe(
label="Statistics",
headers=["Metric", "Value"],
datatype=["str", "str"],
row_count=7,
column_count=2,
)
],
title="DiscordSum - Conversation Summarizer",
description="Summarize Discord conversations into short paragraphs. Runs [Plasmoxy/Qwen3-0.6B-DiscordSum-mini-v1](https://huggingface.co/Plasmoxy/Qwen3-0.6B-DiscordSum-mini-v1).",
examples=[
[SAMPLE_CONVERSATIONS["Movie Night Planning"]],
[SAMPLE_CONVERSATIONS["Quick Bug Fix"]],
[SAMPLE_CONVERSATIONS["Gaming Session"]],
[SAMPLE_CONVERSATIONS["Anime Discussion"]],
[SAMPLE_CONVERSATIONS["Recipe Sharing"]],
[SAMPLE_CONVERSATIONS["Study Group"]],
],
)
if __name__ == "__main__":
demo.launch()
|