File size: 4,393 Bytes
4b4ae5c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1d54733
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
# imports
import os
from huggingface_hub import login
import torch
from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline, BitsAndBytesConfig, AutoProcessor, AutoModelForSpeechSeq2Seq
import gradio as gr

# Log in to HuggingFace
login(token=os.getenv("HF_TOKEN"))

# quantization setup
quant_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_use_double_quant=True,
    bnb_4bit_compute_dtype=torch.bfloat16,
    bnb_4bit_quant_type="nf4"
)

# constants
LLAMA = "meta-llama/Meta-Llama-3.1-8B-Instruct"
device = "cuda:0" if torch.cuda.is_available() else "cpu"
tokenizer = AutoTokenizer.from_pretrained(LLAMA)
tokenizer.pad_token = tokenizer.eos_token
model = AutoModelForCausalLM.from_pretrained(LLAMA, use_auth_token=os.getenv("HF_TOKEN"), device_map="cuda:0", quantization_config=quant_config)


# load Speech model, read audio file and convert to text
def transcript_audio(audio_file):
    torch_dtype = torch.float16 if torch.cuda.is_available() else torch.float32

    model_id = "openai/whisper-large-v3-turbo"

    model = AutoModelForSpeechSeq2Seq.from_pretrained(
        model_id, torch_dtype=torch_dtype, low_cpu_mem_usage=True, use_safetensors=True
    )
    model.to(device)

    processor = AutoProcessor.from_pretrained(model_id)

    pipe = pipeline(
        "automatic-speech-recognition",
        model=model,
        tokenizer=processor.tokenizer,
        feature_extractor=processor.feature_extractor,
        torch_dtype=torch_dtype,
        device=device,
    )

    result = pipe(audio_file, return_timestamps=True)
    return result


# promopts and summarizing the text
def summarize_with_llama(transcript, context="Phone Call", language="English"):
    if context == "Phone Call":
        system_message = (
            "You are an assistant that produces minutes of phone calls from transcripts, "
            "with summary and key discussion points, in markdown."
        )
        user_prompt = (
            "Below is an extract transcript of a phone call. "
            "Please write minutes in markdown, including a summary, location, and discussion points."
        )
    elif context == "Meeting":
        system_message = (
            "You are an assistant that produces minutes of meetings from transcripts, "
            "with summary, key discussion points, takeaways, and action items with owners, in markdown."
        )
        user_prompt = (
            "Below is an extract transcript of a meeting. "
            "Please write minutes in markdown, including a summary with attendees, location, and date; "
            "discussion points; takeaways; and action items with owners."
        )
    else:
        raise ValueError(f"Unknown context: {context}")

    # Add language instruction
    if language.lower() == "hebrew":
        user_prompt += "\n\nWrite the entire generatated summary and points in Hebrew."
    elif language.lower() == "english":
        user_prompt += "\n\nWrite the entire summary in English."
    else:
        raise ValueError(f"Unsupported language: {language}")

    messages = [
        {"role": "system", "content": system_message},
        {"role": "user", "content": f"{system_message}\n\n{user_prompt}\n\nTranscript:\n{transcript}"}
    ]

    input_features = tokenizer.apply_chat_template(messages, return_tensors="pt").to("cuda")
    output_ids = model.generate(input_features, max_new_tokens=2000)
    summary = tokenizer.decode(output_ids[0], skip_special_tokens=True).strip()
    return summary


# combining the two functions
def transcribe_and_summarize(audio, choices, language):
    try:
        result = transcript_audio(audio)
        transcript = result["text"]
        return summarize_with_llama(transcript, context=choices, language=language)
    except Exception as e:
        return f"**Error:** {str(e)}"
        

# Gradio UI setup
demo = gr.Interface(
    fn=transcribe_and_summarize,
    inputs=[
        gr.Audio(type="filepath", label="Upload Audio"),
        gr.Radio(["Phone Call", "Meeting"], label="Select Audio Type"),
        gr.Radio(["English", "Hebrew"], label="Select Language Output")
    ],
    outputs=gr.Markdown(height=750),
    title="Audio Summarizer"
)

# Required for HF Spaces
if __name__ == "__main__":
    demo.launch()