jeongsoo commited on
Commit
2771c11
Β·
1 Parent(s): 2ee22da

Add application file

Browse files
Files changed (2) hide show
  1. app.py +14 -10
  2. utils/llm.py +66 -111
app.py CHANGED
@@ -70,7 +70,13 @@ except Exception as e:
70
  print(f"TTS μ»΄ν¬λ„ŒνŠΈ μ΄ˆκΈ°ν™” μ‹€νŒ¨: {e}")
71
  tts = None
72
 
73
- # λŒ€ν™” 기둝 μ΄ˆκΈ°ν™”
 
 
 
 
 
 
74
  conversation_history = []
75
 
76
 
@@ -110,16 +116,12 @@ def process_audio(audio_path):
110
 
111
  # 2단계: LLM으둜 응닡 생성
112
  try:
113
- # 지식 검색을 μœ„ν•œ μ½”λ“œλ₯Ό μΆ”κ°€ν•  수 μžˆμŠ΅λ‹ˆλ‹€ (RAG)
114
- # μ—¬κΈ°μ„œλŠ” κ°„λ‹¨νžˆ λ°”λ‘œ 질의λ₯Ό μ „λ‹¬ν•©λ‹ˆλ‹€
115
- context_data = [] # μ‹€μ œλ‘œλŠ” 검색 κ²°κ³Όλ₯Ό 여기에 λ„£μŠ΅λ‹ˆλ‹€
116
-
117
- # DeepSeek API둜 응닡 생성 (RAG 방식)
118
  user_query = conversation_history[-1]["content"] # λ§ˆμ§€λ§‰ μ‚¬μš©μž λ©”μ‹œμ§€
119
- llm_response = llm.chat_with_rag(user_query, context_data)
120
  except Exception as e:
121
  print(f"LLM 였λ₯˜: {e}")
122
- llm_response = "응닡 생성 쀑 였λ₯˜κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€. λ‹€μ‹œ μ‹œλ„ν•΄ μ£Όμ„Έμš”."
123
 
124
  # AI 응닡을 λŒ€ν™” 기둝에 μΆ”κ°€
125
  conversation_history.append({"role": "assistant", "content": llm_response})
@@ -186,10 +188,12 @@ with gr.Blocks(title="μŒμ„± 챗봇") as app:
186
 
187
  gr.Markdown("## μ‚¬μš© 방법")
188
  gr.Markdown("""
189
- 1. 마이크 λ²„νŠΌμ„ ν΄λ¦­ν•˜κ³  λ©”μ‹œμ§€λ₯Ό λ§ν•˜μ„Έμš”
190
- 2. AIκ°€ μŒμ„±μ„ μ²˜λ¦¬ν•˜κ³  응닡을 생성할 λ•ŒκΉŒμ§€ κΈ°λ‹€λ¦¬μ„Έμš”
191
  3. ν…μŠ€νŠΈ 응닡을 읽고 μŒμ„± 응닡을 λ“€μœΌμ„Έμš”
192
  4. "λŒ€ν™” μ΄ˆκΈ°ν™”" λ²„νŠΌμ„ ν΄λ¦­ν•˜μ—¬ μƒˆ λŒ€ν™”λ₯Ό μ‹œμž‘ν•˜μ„Έμš”
 
 
193
  """)
194
 
195
  gr.Markdown("## μ‹œμŠ€ν…œ 정보")
 
70
  print(f"TTS μ»΄ν¬λ„ŒνŠΈ μ΄ˆκΈ°ν™” μ‹€νŒ¨: {e}")
71
  tts = None
72
 
73
+ # 초기 λŒ€ν™”λ¬Έ μ„€μ •
74
+ initialMessages = [
75
+ {"role": "system",
76
+ "content": "You are a helpful assistant. Always respond in English, regardless of the language used in the question. Keep your answers clear, concise, and helpful."}
77
+ ]
78
+
79
+ # λŒ€ν™” 기둝을 μ €μž₯ν•  μ „μ—­ λ³€μˆ˜
80
  conversation_history = []
81
 
82
 
 
116
 
117
  # 2단계: LLM으둜 응닡 생성
118
  try:
119
+ # κ°„λ‹¨νžˆ 질의-응닡 λ°©μ‹μœΌλ‘œ μš”μ²­
 
 
 
 
120
  user_query = conversation_history[-1]["content"] # λ§ˆμ§€λ§‰ μ‚¬μš©μž λ©”μ‹œμ§€
121
+ llm_response = llm.generate_response(user_query)
122
  except Exception as e:
123
  print(f"LLM 였λ₯˜: {e}")
124
+ llm_response = "Sorry, I couldn't generate a response. Please try again."
125
 
126
  # AI 응닡을 λŒ€ν™” 기둝에 μΆ”κ°€
127
  conversation_history.append({"role": "assistant", "content": llm_response})
 
188
 
189
  gr.Markdown("## μ‚¬μš© 방법")
190
  gr.Markdown("""
191
+ 1. 마이크 λ²„νŠΌμ„ ν΄λ¦­ν•˜κ³  μ˜μ–΄λ‘œ λ©”μ‹œμ§€λ₯Ό λ§ν•˜μ„Έμš”
192
+ 2. AIκ°€ μŒμ„±μ„ μ²˜λ¦¬ν•˜κ³  μ˜μ–΄λ‘œ 응닡을 생성할 λ•ŒκΉŒμ§€ κΈ°λ‹€λ¦¬μ„Έμš”
193
  3. ν…μŠ€νŠΈ 응닡을 읽고 μŒμ„± 응닡을 λ“€μœΌμ„Έμš”
194
  4. "λŒ€ν™” μ΄ˆκΈ°ν™”" λ²„νŠΌμ„ ν΄λ¦­ν•˜μ—¬ μƒˆ λŒ€ν™”λ₯Ό μ‹œμž‘ν•˜μ„Έμš”
195
+
196
+ ⚠️ μ°Έκ³ : 이 챗봇은 μ˜μ–΄ μŒμ„± 인식과 μ˜μ–΄ μŒμ„± 합성을 μ‚¬μš©ν•©λ‹ˆλ‹€.
197
  """)
198
 
199
  gr.Markdown("## μ‹œμŠ€ν…œ 정보")
utils/llm.py CHANGED
@@ -1,5 +1,4 @@
1
  import requests
2
- import json
3
  import os
4
  from dotenv import load_dotenv
5
 
@@ -8,11 +7,13 @@ load_dotenv()
8
 
9
 
10
  class DeepSeekLLM:
 
 
11
  def __init__(self):
12
  """
13
- DeepSeek APIλ₯Ό μ‚¬μš©ν•˜κΈ° μœ„ν•œ 클래슀
14
 
15
- ν™˜κ²½ λ³€μˆ˜μ—μ„œ 섀정을 κ°€μ Έμ˜΅λ‹ˆλ‹€:
16
  - DEEPSEEK_API_KEY: API ν‚€
17
  - DEEPSEEK_ENDPOINT: API μ—”λ“œν¬μΈνŠΈ URL
18
  - DEEPSEEK_MODEL: μ‚¬μš©ν•  λͺ¨λΈ 이름
@@ -22,147 +23,101 @@ class DeepSeekLLM:
22
  self.model = os.getenv("DEEPSEEK_MODEL", "deepseek-chat")
23
 
24
  if not self.api_key:
25
- raise ValueError("DEEPSEEK_API_KEYκ°€ ν•„μš”ν•©λ‹ˆλ‹€.")
26
 
27
- print(f"DeepSeek μ„€μ •: λͺ¨λΈ={self.model}, μ—”λ“œν¬μΈνŠΈ μ„€μ •={'O' if self.endpoint else 'X'}")
28
 
29
- def generate_response(self, prompt, max_tokens=500, temperature=0.7):
30
  """
31
- ν”„λ‘¬ν”„νŠΈλ₯Ό λ°”νƒ•μœΌλ‘œ 응닡 생성
32
 
33
  Args:
34
- prompt: μž…λ ₯ ν”„λ‘¬ν”„νŠΈ ν…μŠ€νŠΈ
35
- max_tokens: 생성할 μ΅œλŒ€ 토큰 수
36
- temperature: μ‘λ‹΅μ˜ μ°½μ˜μ„± μˆ˜μ€€ (0.0 ~ 1.0)
37
 
38
  Returns:
39
- str: μƒμ„±λœ 응닡 ν…μŠ€νŠΈ
40
  """
41
- return self.chat_completion([{"role": "user", "content": prompt}], max_tokens, temperature)
 
 
 
 
 
 
 
42
 
43
- def chat_completion(self, messages, max_tokens=500, temperature=0.7):
 
 
 
44
  """
45
- μ±„νŒ… ν˜•μ‹μ˜ λ©”μ‹œμ§€λ₯Ό λ°”νƒ•μœΌλ‘œ 응닡 생성
46
 
47
  Args:
48
- messages: μ±„νŒ… λ©”μ‹œμ§€ λͺ©λ‘ (ν˜•μ‹: [{"role": "user", "content": "μ•ˆλ…•"}, ...])
49
- max_tokens: 생성할 μ΅œλŒ€ 토큰 수
50
- temperature: μ‘λ‹΅μ˜ μ°½μ˜μ„± μˆ˜μ€€ (0.0 ~ 1.0)
51
 
52
  Returns:
53
- str: μƒμ„±λœ 응닡 ν…μŠ€νŠΈ
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
  """
55
  headers = {
56
  "Content-Type": "application/json",
57
  "Authorization": f"Bearer {self.api_key}"
58
  }
59
 
60
- payload = {
61
  "model": self.model,
62
  "messages": messages,
63
- "max_tokens": max_tokens,
64
- "temperature": temperature
65
  }
66
 
67
  try:
68
- print(f"[DeepSeek] API μš”μ²­ 전솑: {self.endpoint}")
69
- response = requests.post(
70
- self.endpoint,
71
- headers=headers,
72
- json=payload
73
- )
74
 
 
75
  if response.status_code == 200:
76
  result = response.json()
77
- print("[DeepSeek] 응닡 성곡")
78
-
79
- # Node.js μ½”λ“œμ™€ μœ μ‚¬ν•œ 응닡 νŒŒμ‹±
80
  if (result.get('choices') and
81
  len(result['choices']) > 0 and
82
  result['choices'][0].get('message') and
83
  result['choices'][0]['message'].get('content')):
84
- return result['choices'][0]['message']['content'].strip()
 
 
85
  else:
86
- print(f"[DeepSeek] 응닡 ν˜•μ‹ 였λ₯˜: {result}")
87
- return "응닡을 받을 수 μ—†μŠ΅λ‹ˆλ‹€."
88
  else:
89
- print(f"[DeepSeek] API μ—λŸ¬: μƒνƒœ μ½”λ“œ {response.status_code}")
90
- print(f"[DeepSeek] μ—λŸ¬ 응닡: {response.text}")
91
- return f"μ£„μ†‘ν•©λ‹ˆλ‹€, API 응닡 였λ₯˜κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€ (μƒνƒœ μ½”λ“œ: {response.status_code})"
92
 
93
  except Exception as e:
94
- print(f"[DeepSeek] μ˜ˆμ™Έ λ°œμƒ: {str(e)}")
95
- return f"였λ₯˜κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€: {str(e)}"
96
-
97
- def chat_with_rag(self, user_query, context_data=None):
98
- """
99
- RAG(Retrieval-Augmented Generation) λ°©μ‹μœΌλ‘œ ν”„λ‘¬ν”„νŠΈλ₯Ό κ°•ν™”ν•˜μ—¬ μ±„νŒ… 응닡 생성
100
-
101
- Args:
102
- user_query: μ‚¬μš©μž 질문
103
- context_data: κ²€μƒ‰λœ μ»¨ν…μŠ€νŠΈ 데이터 (None이면 RAG 없이 μ§„ν–‰)
104
-
105
- Returns:
106
- str: μƒμ„±λœ 응닡 ν…μŠ€νŠΈ
107
- """
108
- # κΈ°λ³Έ μ‹œμŠ€ν…œ λ©”μ‹œμ§€
109
- system_message = {"role": "system",
110
- "content": "λ„Œ μ˜λ£Œμ „λ¬Έκ°€ 역할을 λ§‘μ•„. 그리고 μ§ˆλ¬Έμ€ λŒ€λΆ€λΆ„ 건강에 κ΄€λ ¨λœ 질문이 μ˜¬κΊΌμ•Ό. μ΅œλŒ€ν•œ 전문적인 λ‹¨μ–΄λŠ” λ°°μ œν•˜κ³  μ΄ν•΄ν•˜κΈ° 쉽고 κ°„λž΅ν•˜κ²Œ 닡변을 ν•΄μ€˜."}
111
-
112
- if not context_data or len(context_data) == 0:
113
- # μ»¨ν…μŠ€νŠΈ 없이 κΈ°λ³Έ λ©”μ‹œμ§€λ§Œ μ‚¬μš©
114
- messages = [
115
- system_message,
116
- {"role": "user", "content": user_query}
117
- ]
118
- else:
119
- # RAG λ°©μ‹μœΌλ‘œ ν”„λ‘¬ν”„νŠΈ κ°•ν™”
120
- enhanced_prompt = self._enhance_prompt_with_context(user_query, context_data)
121
- messages = [
122
- system_message,
123
- {"role": "user", "content": enhanced_prompt}
124
- ]
125
-
126
- # DeepSeek API 호좜
127
- return self.chat_completion(messages)
128
-
129
- def _enhance_prompt_with_context(self, query, context_data):
130
- """
131
- 검색 κ²°κ³Όλ₯Ό λ°”νƒ•μœΌλ‘œ ν”„λ‘¬ν”„νŠΈ κ°•ν™” (Node.js μ½”λ“œ μ°Έμ‘°)
132
-
133
- Args:
134
- query: μ‚¬μš©μž 질문
135
- context_data: κ²€μƒ‰λœ μ»¨ν…μŠ€νŠΈ 데이터
136
-
137
- Returns:
138
- str: κ°•ν™”λœ ν”„λ‘¬ν”„νŠΈ
139
- """
140
- # κΈ°λ³Έ μ‹œμŠ€ν…œ ν”„λ‘¬ν”„νŠΈμ— 검색 κ²°κ³Ό 톡합
141
- enhanced_prompt = "당신은 μ „λ¬Έ 의료 μƒλ‹΄κ°€μž…λ‹ˆλ‹€. λ‹€μŒ 정보λ₯Ό λ°”νƒ•μœΌλ‘œ μ‚¬μš©μž μ§ˆλ¬Έμ— λ‹΅λ³€ν•΄μ£Όμ„Έμš”:\n\n"
142
-
143
- # μ •λ³΄μ˜ μΆœμ²˜μ™€ μ‹ λ’°μ„± λͺ…μ‹œ
144
- enhanced_prompt += "β€» λ‹€μŒ μ •λ³΄λŠ” 의료 λ°μ΄ν„°λ² μ΄μŠ€μ—μ„œ κ²€μƒ‰λœ κ²°κ³Όμž…λ‹ˆλ‹€.\n\n"
145
-
146
- # κ²€μƒ‰λœ μ»¨ν…μŠ€νŠΈ 정보 ν¬λ§·νŒ…
147
- for i, item in enumerate(context_data):
148
- enhanced_prompt += f"γ€μ°Έκ³ μžλ£Œ {i + 1}】\n"
149
-
150
- # ν•­λͺ©λ³„λ‘œ 정리
151
- for key, value in item.items():
152
- if value and str(value).strip():
153
- enhanced_prompt += f"- {key}: {value}\n"
154
-
155
- enhanced_prompt += "\n"
156
-
157
- # λ‹΅λ³€ μž‘μ„± κ°€μ΄λ“œλΌμΈ 제곡
158
- enhanced_prompt += "【닡변 κ°€μ΄λ“œλΌμΈγ€‘\n"
159
- enhanced_prompt += "1. μœ„ 참고자료의 정보λ₯Ό μš°μ„ μ μœΌλ‘œ ν™œμš©ν•˜μ„Έμš”.\n"
160
- enhanced_prompt += "2. μ°Έκ³ μžλ£Œμ— λͺ…ν™•ν•œ 정보가 μ—†λŠ” 경우, μ˜ν•™μ μœΌλ‘œ μ •ν™•ν•œ 일반 지식을 ν™œμš©ν•˜μ„Έμš”.\n"
161
- enhanced_prompt += "3. λΆˆν™•μ‹€ν•œ μ •λ³΄λŠ” μ œκ³΅ν•˜μ§€ 말고, ν•„μš”μ‹œ μ „λ¬Έμ˜ 상담을 κΆŒμœ ν•˜μ„Έμš”.\n"
162
- enhanced_prompt += "4. μ‚¬μš©μžκ°€ μ‰½κ²Œ 이해할 수 μžˆλŠ” μš©μ–΄λ₯Ό μ‚¬μš©ν•˜μ„Έμš”.\n\n"
163
-
164
- # μ‚¬μš©μž 질문 포함
165
- enhanced_prompt += f"γ€μ‚¬μš©μž μ§ˆλ¬Έγ€‘ {query}\n\n"
166
- enhanced_prompt += "【닡변】\n"
167
-
168
- return enhanced_prompt
 
1
  import requests
 
2
  import os
3
  from dotenv import load_dotenv
4
 
 
7
 
8
 
9
  class DeepSeekLLM:
10
+ """DeepSeek APIλ₯Ό μ‚¬μš©ν•œ μ–Έμ–΄ λͺ¨λΈ 클래슀"""
11
+
12
  def __init__(self):
13
  """
14
+ DeepSeek API μ΄ˆκΈ°ν™”
15
 
16
+ ν™˜κ²½ λ³€μˆ˜μ—μ„œ 섀정을 κ°€μ Έμ˜΄:
17
  - DEEPSEEK_API_KEY: API ν‚€
18
  - DEEPSEEK_ENDPOINT: API μ—”λ“œν¬μΈνŠΈ URL
19
  - DEEPSEEK_MODEL: μ‚¬μš©ν•  λͺ¨λΈ 이름
 
23
  self.model = os.getenv("DEEPSEEK_MODEL", "deepseek-chat")
24
 
25
  if not self.api_key:
26
+ raise ValueError("DEEPSEEK_API_KEY ν™˜κ²½ λ³€μˆ˜κ°€ μ„€μ •λ˜μ–΄ μžˆμ§€ μ•ŠμŠ΅λ‹ˆλ‹€.")
27
 
28
+ print(f"DeepSeek LLM μ΄ˆκΈ°ν™”: λͺ¨λΈ={self.model}, μ—”λ“œν¬μΈνŠΈ={'섀정됨' if self.endpoint else 'κΈ°λ³Έκ°’'}")
29
 
30
+ def generate_response(self, query, temperature=0.7, max_tokens=500):
31
  """
32
+ 단일 μ§ˆμ˜μ— λŒ€ν•œ 응닡 생성
33
 
34
  Args:
35
+ query: μ‚¬μš©μž 질문
36
+ temperature: μ‘λ‹΅μ˜ λ‹€μ–‘μ„± (0.0-1.0)
37
+ max_tokens: μ΅œλŒ€ 토큰 수
38
 
39
  Returns:
40
+ str: μƒμ„±λœ 응닡
41
  """
42
+ # μ‹œμŠ€ν…œ λ©”μ‹œμ§€: 항상 μ˜μ–΄λ‘œ 응닡
43
+ system_message = "You are a helpful assistant. Always respond in English, regardless of the language used in the question. Keep your answers clear, concise, and helpful."
44
+
45
+ # λ©”μ‹œμ§€ ꡬ성
46
+ messages = [
47
+ {"role": "system", "content": system_message},
48
+ {"role": "user", "content": query}
49
+ ]
50
 
51
+ # API μš”μ²­
52
+ return self._call_api(messages, temperature, max_tokens)
53
+
54
+ def chat_completion(self, messages, temperature=0.7, max_tokens=500):
55
  """
56
+ λŒ€ν™” 이λ ₯을 ν¬ν•¨ν•œ 응닡 생성
57
 
58
  Args:
59
+ messages: λ©”μ‹œμ§€ λͺ©λ‘ [{"role": "user", "content": "..."}, ...]
60
+ temperature: μ‘λ‹΅μ˜ λ‹€μ–‘μ„± (0.0-1.0)
61
+ max_tokens: μ΅œλŒ€ 토큰 수
62
 
63
  Returns:
64
+ str: μƒμ„±λœ 응닡
65
+ """
66
+ # 첫 λ©”μ‹œμ§€κ°€ μ‹œμŠ€ν…œ λ©”μ‹œμ§€κ°€ μ•„λ‹ˆλ©΄ μΆ”κ°€
67
+ if not messages or messages[0]["role"] != "system":
68
+ system_message = {"role": "system",
69
+ "content": "You are a helpful assistant. Always respond in English, regardless of the language used in the question."}
70
+ messages = [system_message] + messages
71
+
72
+ # API μš”μ²­
73
+ return self._call_api(messages, temperature, max_tokens)
74
+
75
+ def _call_api(self, messages, temperature, max_tokens):
76
+ """
77
+ DeepSeek API 호좜
78
+
79
+ Args:
80
+ messages: λ©”μ‹œμ§€ λͺ©λ‘
81
+ temperature: μ‘λ‹΅μ˜ λ‹€μ–‘μ„±
82
+ max_tokens: μ΅œλŒ€ 토큰 수
83
+
84
+ Returns:
85
+ str: μƒμ„±λœ 응닡
86
  """
87
  headers = {
88
  "Content-Type": "application/json",
89
  "Authorization": f"Bearer {self.api_key}"
90
  }
91
 
92
+ data = {
93
  "model": self.model,
94
  "messages": messages,
95
+ "temperature": temperature,
96
+ "max_tokens": max_tokens
97
  }
98
 
99
  try:
100
+ print(f"DeepSeek API μš”μ²­: λ©”μ‹œμ§€ 수={len(messages)}, μ˜¨λ„={temperature}")
101
+ response = requests.post(self.endpoint, headers=headers, json=data)
 
 
 
 
102
 
103
+ # 응닡 처리
104
  if response.status_code == 200:
105
  result = response.json()
 
 
 
106
  if (result.get('choices') and
107
  len(result['choices']) > 0 and
108
  result['choices'][0].get('message') and
109
  result['choices'][0]['message'].get('content')):
110
+ content = result['choices'][0]['message']['content'].strip()
111
+ print(f"DeepSeek API 응닡 성곡: {len(content)} 자")
112
+ return content
113
  else:
114
+ print(f"DeepSeek API 응닡 ν˜•μ‹ 였λ₯˜: {result}")
115
+ return "I couldn't generate a response. Please try again."
116
  else:
117
+ print(f"DeepSeek API 였λ₯˜: μƒνƒœ μ½”λ“œ {response.status_code}")
118
+ print(f"였λ₯˜ 상세: {response.text}")
119
+ return f"An error occurred (Status code: {response.status_code})"
120
 
121
  except Exception as e:
122
+ print(f"DeepSeek API μ˜ˆμ™Έ λ°œμƒ: {str(e)}")
123
+ return f"An error occurred: {str(e)}"