Opera10 commited on
Commit
0ba67ac
·
verified ·
1 Parent(s): 7217cc2

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +125 -36
app.py CHANGED
@@ -1,59 +1,148 @@
 
1
  import json
 
2
  from groq import Groq
3
 
4
- # استفاده از همان کلاینت و کلید قبلی شما
5
- GROQ_API_KEY = "gsk_کلید_شما"
6
- client = Groq(api_key=GROQ_API_KEY)
7
 
8
- def correct_segments_with_llm(segments_list):
9
  """
10
- این تابع لیست سگمنت‌ها را می‌گیرد و غلط‌های املایی را بدون تغییر لحن کلمات اصلاح می‌کند.
 
11
  """
12
- # تبدیل لیست به متن JSON برای فرستادن به هوش مصنوعی
13
- segments_json = json.dumps(segments_list, ensure_ascii=False, indent=2)
 
 
 
 
 
 
 
 
 
 
14
 
15
- # دستورالعمل فوق‌العاده دقیق برای جلوگیری از تغییر کلمات
16
  system_instruction = (
17
- "تو یک ویراستار حرفه‌ای زیرنویس فارسی هستی. وظیفه تو فقط و فقط اصلاح غلط‌های املایی و شنیداری (Phonetic Errors) در این JSON است.\n"
18
- "قوانین بسیار سخت‌گیرانه که باید رعایت کنی:\n"
19
- "۱. به هیچ وجه لحن جملات را تغییر نده. کلمات عامیانه و محاوره‌ای باید دقیقاً همان‌طور بمانند.\n"
20
- "۲. ساختار نوشتاری کلمات را تغییر نده. به عنوان مثال، اگر کلمه‌ای به صورت 'میباشد' نوشته شده، آن را به 'می باشد' یا 'هست' تغییر نده. اگر کلمه‌ای درست است، هیچ تغییری در ظاهر آن (حتی فاصله‌گذاری‌ها) ایجاد نکن.\n"
21
- "۳. جملات را خلاصه نکن، بازنویسی نکن و هیچ کلمه‌ای را حذف یا اضافه نکن.\n"
22
- "۴. زمان‌بندی‌ها (بخش، شروع، پایان) نباید کوچک‌ترین تغییری کنند.\n"
23
- "۵. خروجی تو باید دقیقاً یک JSON معتبر با همان ساختار ورودی باشد. هیچ توضیح، سلام، احوالپرسی یا متن اضافی خارج از JSON برنگردان."
24
  )
25
 
26
  try:
27
- # ارسال درخواست به مدل چت فوق‌سریع لاما در Groq
28
  response = client.chat.completions.create(
29
- model="llama-3.1-8b-instant", # مدل بسیار سریع و مناسب برای کارهای ویرایشی
30
  messages=[
31
  {"role": "system", "content": system_instruction},
32
- {"role": "user", "content": f"لطفاً این زیرنویس را ویرایش کن:\n\n{segments_json}"}
33
  ],
34
- temperature=0.1, # دمای پایین برای اینکه مدل خلاقیت به خرج ندهد و دقیقاً طبق دستور عمل کند
35
- response_format={"type": "json_object"} # اجبار مدل به برگرداندن پاسخ در قالب JSON
36
  )
37
 
38
- # دریافت متن اصلاح شده و تبدیل آن به لیست پایتون
39
  corrected_data = json.loads(response.choices[0].message.content)
40
 
41
- # اگر خروجی به صورت یک دیکشنری با کلید خاصی برگشته باشد، ��ن را مدیریت می‌کنیم
42
- if isinstance(corrected_data, dict) and "segments" in corrected_data:
43
- return corrected_data["segments"]
44
- elif isinstance(corrected_data, dict) and "بخش‌ها" in corrected_data:
45
- return corrected_data["بخش‌ها"]
46
- elif isinstance(corrected_data, list):
47
- return corrected_data
48
- else:
49
- # در بیشتر مواقع مدل لیست مستقیم یا دیکشنری حاوی لیست را برمی‌گرداند
50
- # برای اطمینان، اگر کلیدی پیدا نشد اولین لیستی که پیدا کند را برمی‌گرداند
51
  for val in corrected_data.values():
52
  if isinstance(val, list):
53
- return val
54
- return corrected_data
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
 
 
 
 
 
56
  except Exception as e:
57
- print(f"Error in LLM correction: {e}")
58
- # در صورت بروز خطای ارتباطی، همان لیست اصلی بدون ویرایش برگشت داده می‌شود تا برنامه کرش نکند
59
- return segments_list
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
  import json
3
+ import gradio as gr
4
  from groq import Groq
5
 
6
+ # خواندن کلید مخفی شده از تنظیمات هاگینگ فیس
7
+ GROQ_API_KEY = os.getenv("GROQ_API_KEY")
 
8
 
9
+ def foolproof_llm_correction(client, original_segments):
10
  """
11
+ این تابع کاملاً ضدگلوله است.
12
+ زمان‌بندی‌ها را پیش خود نگه می‌دارد و فقط متن‌ها را برای اصلاح به لاما می‌فرستد.
13
  """
14
+ if not original_segments:
15
+ return []
16
+
17
+ # ۱. ساخت یک لیست سبک فقط شامل ID و متن خام جملات (بدون فرستادن زمان‌بندی‌ها)
18
+ text_only_list = []
19
+ for seg in original_segments:
20
+ text_only_list.append({
21
+ "id": seg.get("بخش") or seg.get("id"),
22
+ "text": seg.get("متن جمله") or seg.get("text")
23
+ })
24
+
25
+ prompt_payload = json.dumps(text_only_list, ensure_ascii=False)
26
 
 
27
  system_instruction = (
28
+ "تو یک ویراستار متون فارسی هستی. وظیفه تو اصلاح غلط‌های املایی و شنیداری در این لیست است.\n"
29
+ "قوانین:\n"
30
+ "۱. لحن عامیانه و محاوره‌ای جملات را حفظ کن و تغییر نده.\n"
31
+ "۲. ساختار کلمات را تغییر نده (مثلا 'میباشد' را به 'می باشد' تغییر نده).\n"
32
+ "۳. هیچ کلمه‌ای حذف یا اضافه نکن. فقط املای کلمات غلط را اصلاح کن.\n"
33
+ "۴. خروجی باید دقیقاً یک آرایه JSON با کلیدهای id و text باشد و هیچ متن اضافی دیگری برنگردان."
 
34
  )
35
 
36
  try:
 
37
  response = client.chat.completions.create(
38
+ model="llama-3.1-8b-instant",
39
  messages=[
40
  {"role": "system", "content": system_instruction},
41
+ {"role": "user", "content": prompt_payload}
42
  ],
43
+ temperature=0.1,
44
+ response_format={"type": "json_object"}
45
  )
46
 
 
47
  corrected_data = json.loads(response.choices[0].message.content)
48
 
49
+ corrected_list = []
50
+ if isinstance(corrected_data, dict):
51
+ # پیدا کردن لیست در خروجی دیکشنری
 
 
 
 
 
 
 
52
  for val in corrected_data.values():
53
  if isinstance(val, list):
54
+ corrected_list = val
55
+ break
56
+ elif isinstance(corrected_data, list):
57
+ corrected_list = corrected_data
58
+
59
+ corrected_dict = {item["id"]: item["text"] for item in corrected_list if "id" in item and "text" in item}
60
+
61
+ final_segments = []
62
+ for orig_seg in original_segments:
63
+ seg_copy = orig_seg.copy()
64
+ seg_id = seg_copy.get("بخش") or seg_copy.get("id")
65
+
66
+ if seg_id in corrected_dict:
67
+ if "text" in seg_copy:
68
+ seg_copy["text"] = corrected_dict[seg_id]
69
+ if "متن جمله" in seg_copy:
70
+ seg_copy["متن جمله"] = corrected_dict[seg_id]
71
 
72
+ final_segments.append(seg_copy)
73
+
74
+ return final_segments
75
+
76
  except Exception as e:
77
+ print(f"Error in foolproof correction: {e}")
78
+ return original_segments
79
+
80
+ def transcribe_and_correct(audio_path):
81
+ if not GROQ_API_KEY:
82
+ return "خطا: کلید API یافت نشد. لطفا ابتدا GROQ_API_KEY را در تنظیمات اسپیس تعریف کنید.", [], []
83
+
84
+ if not audio_path:
85
+ return "لطفاً ابتدا یک فایل صوتی آپلود کنید.", [], []
86
+
87
+ try:
88
+ # ساخت کلاینت گراک با کلید امن شده
89
+ client = Groq(api_key=GROQ_API_KEY)
90
+
91
+ # ۱. تبدیل صدا به متن با ویسپر ۳
92
+ with open(audio_path, "rb") as file:
93
+ response = client.audio.transcriptions.create(
94
+ file=(audio_path, file.read()),
95
+ model="whisper-large-v3",
96
+ response_format="verbose_json",
97
+ language="fa"
98
+ )
99
+
100
+ # دریافت متن کامل خام
101
+ raw_text = getattr(response, "text", "")
102
+
103
+ # استخراج بخش‌ها
104
+ raw_segments = getattr(response, "segments", [])
105
+ original_segments = []
106
+ for idx, segment in enumerate(raw_segments):
107
+ original_segments.append({
108
+ "بخش": idx + 1,
109
+ "شروع (ثانیه)": round(segment.get("start", 0), 2),
110
+ "پایان (ثانیه)": round(segment.get("end", 0), 2),
111
+ "متن جمله": segment.get("text", "").strip()
112
+ })
113
+
114
+ # ۲. ارسال خودکار متن‌ها به مدل لاما برای ویرایش ضدگلوله املایی
115
+ corrected_segments = foolproof_llm_correction(client, original_segments)
116
+
117
+ return raw_text, original_segments, corrected_segments
118
+
119
+ except Exception as e:
120
+ return f"خطا در پردازش: {str(e)}", [], []
121
+
122
+ # ساخت محیط وب پیشرفته برای تست هر دو مرحله به صورت همزمان
123
+ with gr.Blocks(title="تست ابزار تبدیل صدا به متن و اصلاح املایی") as demo:
124
+ gr.Markdown("# تست همزمان ویسپر ۳ و اصلاح املایی ضدگلوله با Llama 3.1")
125
+ gr.Markdown("یک فایل صوتی آپلود کنید تا خروجی خام ویسپر و نسخه اصلاح شده توسط مدل چت را در کنار هم مقایسه کنید.")
126
+
127
+ with gr.Row():
128
+ with gr.Column():
129
+ audio_input = gr.Audio(type="filepath", label="آپلود فایل صوتی")
130
+ submit_btn = gr.Button("شروع پردازش صوتی و متنی", variant="primary")
131
+
132
+ with gr.Column():
133
+ raw_text_output = gr.Textbox(label="متن کامل خام (Whisper Raw Text)")
134
+
135
+ with gr.Row():
136
+ with gr.Column():
137
+ original_json = gr.JSON(label="۱. سگمنت‌های خام ویسپر (دارای غلط‌های احتمالی)")
138
+ with gr.Column():
139
+ corrected_json = gr.JSON(label="۲. سگمنت‌های اصلاح شده توسط لاما (بدون تغییر زمان‌بندی)")
140
+
141
+ submit_btn.click(
142
+ fn=transcribe_and_correct,
143
+ inputs=[audio_input],
144
+ outputs=[raw_text_output, original_json, corrected_json]
145
+ )
146
+
147
+ if __name__ == "__main__":
148
+ demo.launch()