godsastray commited on
Commit
1f05e99
·
verified ·
1 Parent(s): 791448d

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +407 -0
app.py ADDED
@@ -0,0 +1,407 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import pandas as pd
3
+ import numpy as np
4
+ from datetime import datetime
5
+ from typing import List, Dict, Tuple
6
+ import requests
7
+ import json
8
+ import plotly.graph_objects as go
9
+ import random
10
+ import os
11
+ from dotenv import load_dotenv
12
+
13
+ # Load environment variables
14
+ load_dotenv()
15
+
16
+ GEMINI_API_KEY = os.getenv("GEMINI_API_KEY")
17
+ GEMINI_API_URL = "https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash-latest:generateContent"
18
+
19
+ class GeminiAPI:
20
+ def __init__(self, api_key: str = GEMINI_API_KEY):
21
+ self.api_key = api_key
22
+ self.headers = {"Content-Type": "application/json"}
23
+
24
+ def analyze_personality(self, responses: List[str]) -> Dict:
25
+ try:
26
+ prompt = f"""
27
+ Dựa trên các câu trả lời sau của người dùng, hãy phân tích và xác định:
28
+ 1. Kiểu tính cách MBTI
29
+ 2. Điểm mạnh và điểm yếu
30
+ 3. Các nghề nghiệp phù hợp nhất
31
+ 4. Lộ trình phát triển đề xuất
32
+
33
+ Câu trả lời của người dùng:
34
+ {json.dumps(responses, ensure_ascii=False)}
35
+ """
36
+
37
+ payload = {
38
+ "contents": [{
39
+ "parts": [{
40
+ "text": prompt
41
+ }]
42
+ }]
43
+ }
44
+
45
+ response = requests.post(
46
+ f"{GEMINI_API_URL}?key={self.api_key}",
47
+ headers=self.headers,
48
+ json=payload
49
+ )
50
+
51
+ if response.status_code == 200:
52
+ result = response.json()
53
+ return self._parse_gemini_response(result)
54
+ return self.get_fallback_analysis()
55
+
56
+ except Exception as e:
57
+ print(f"Error in analyze_personality: {str(e)}")
58
+ return self.get_fallback_analysis()
59
+
60
+ def get_career_advice(self, question: str, context: Dict = None) -> str:
61
+ try:
62
+ prompt = f"""
63
+ Vai trò: Bạn là một chuyên gia tư vấn nghề nghiệp với nhiều năm kinh nghiệm.
64
+
65
+ Thông tin người dùng:
66
+ {json.dumps(context, ensure_ascii=False) if context else "Chưa có thông tin"}
67
+
68
+ Câu hỏi: {question}
69
+
70
+ Hãy tư vấn chi tiết về:
71
+ 1. Phân tích vấn đề
72
+ 2. Giải pháp cụ thể
73
+ 3. Các bước thực hiện
74
+ 4. Ví dụ thực tế
75
+ """
76
+
77
+ payload = {
78
+ "contents": [{
79
+ "parts": [{
80
+ "text": prompt
81
+ }]
82
+ }]
83
+ }
84
+
85
+ response = requests.post(
86
+ f"{GEMINI_API_URL}?key={self.api_key}",
87
+ headers=self.headers,
88
+ json=payload
89
+ )
90
+
91
+ if response.status_code == 200:
92
+ result = response.json()
93
+ return result['candidates'][0]['content']['parts'][0]['text']
94
+ return "Xin lỗi, hiện tại tôi không thể xử lý yêu cầu. Vui lòng thử lại sau."
95
+
96
+ except Exception as e:
97
+ print(f"Error in get_career_advice: {str(e)}")
98
+ return "Đã xảy ra lỗi. Vui lòng thử lại sau."
99
+
100
+ def _parse_gemini_response(self, result: Dict) -> Dict:
101
+ try:
102
+ text_response = result['candidates'][0]['content']['parts'][0]['text']
103
+ # Thử parse JSON từ response
104
+ try:
105
+ return json.loads(text_response)
106
+ except:
107
+ # Nếu không parse được, trả về phân tích mặc định
108
+ return self.get_fallback_analysis()
109
+ except:
110
+ return self.get_fallback_analysis()
111
+
112
+ def get_fallback_analysis(self) -> Dict:
113
+ return {
114
+ "mbti_type": "ENTJ",
115
+ "strengths": [
116
+ "Khả năng lãnh đạo",
117
+ "Tư duy chiến lược",
118
+ "Quyết đoán",
119
+ "Tổ chức tốt"
120
+ ],
121
+ "weaknesses": [
122
+ "Đôi khi quá áp đặt",
123
+ "Thiếu kiên nhẫn",
124
+ "Khó đồng cảm"
125
+ ],
126
+ "recommended_careers": [
127
+ "Quản lý dự án",
128
+ "Tư vấn chiến lược",
129
+ "Khởi nghiệp",
130
+ "Giám đốc điều hành"
131
+ ],
132
+ "development_path": [
133
+ "Phát triển kỹ năng lãnh đạo",
134
+ "Học hỏi về quản lý cảm xúc",
135
+ "Tham gia các khóa học về quản lý",
136
+ "Xây dựng network chuyên nghiệp"
137
+ ]
138
+ }
139
+
140
+ def predict_market_trends(self) -> Dict:
141
+ try:
142
+ # Thay thế URL dưới đây bằng URL thực tế của API
143
+ api_url = "https://api.example.com/labor_market_trends"
144
+ response = requests.get(api_url, headers={"Authorization": f"Bearer {self.api_key}"})
145
+
146
+ if response.status_code == 200:
147
+ data = response.json()
148
+ return data
149
+ else:
150
+ print(f"Error fetching market trends: {response.status_code} - {response.text}")
151
+ return {}
152
+ except Exception as e:
153
+ print(f"Error in predict_market_trends: {str(e)}")
154
+ return {}
155
+
156
+ class DataProcessor:
157
+ @staticmethod
158
+ def validate_responses(responses: List[str]) -> bool:
159
+ return all(response is not None for response in responses)
160
+
161
+ @staticmethod
162
+ def calculate_scores(responses: List[str]) -> Dict[str, float]:
163
+ # Tính điểm các khía cạnh tính cách
164
+ dimensions = {
165
+ 'E-I': 0, # Extraversion-Introversion
166
+ 'S-N': 0, # Sensing-Intuition
167
+ 'T-F': 0, # Thinking-Feeling
168
+ 'J-P': 0 # Judging-Perceiving
169
+ }
170
+
171
+ # Giả lập tính điểm
172
+ for i, response in enumerate(responses):
173
+ if i == 0: # E-I
174
+ dimensions['E-I'] += 1 if response.endswith("nhóm") else -1
175
+ elif i == 1: # S-N
176
+ dimensions['S-N'] += 1 if "dữ liệu" in response.lower() else -1
177
+ elif i == 2: # T-F
178
+ dimensions['T-F'] += 1 if "quy trình" in response.lower() else -1
179
+ elif i == 3: # J-P
180
+ dimensions['J-P'] += 1 if "lý thuyết" in response.lower() else -1
181
+
182
+ return dimensions
183
+
184
+ class Visualizer:
185
+ @staticmethod
186
+ def create_strength_chart(strengths: List[str], scores: List[float] = None) -> go.Figure:
187
+ if scores is None:
188
+ scores = [random.uniform(0.7, 1.0) for _ in strengths]
189
+
190
+ fig = go.Figure(data=[
191
+ go.Bar(
192
+ x=strengths,
193
+ y=scores,
194
+ marker_color='rgb(55, 83, 109)'
195
+ )
196
+ ])
197
+
198
+ fig.update_layout(
199
+ title="Phân tích điểm mạnh",
200
+ showlegend=False,
201
+ height=400,
202
+ margin=dict(l=20, r=20, t=40, b=20)
203
+ )
204
+
205
+ return fig
206
+
207
+ @staticmethod
208
+ def create_career_match_chart(careers: List[str], scores: List[float] = None) -> go.Figure:
209
+ if scores is None:
210
+ scores = [random.uniform(0.7, 1.0) for _ in careers]
211
+
212
+ fig = go.Figure(data=[
213
+ go.Bar(
214
+ x=careers,
215
+ y=scores,
216
+ marker_color='rgb(26, 118, 255)'
217
+ )
218
+ ])
219
+
220
+ fig.update_layout(
221
+ title="Độ phù hợp nghề nghiệp",
222
+ showlegend=False,
223
+ height=400,
224
+ margin=dict(l=20, r=20, t=40, b=20)
225
+ )
226
+
227
+ return fig
228
+
229
+ class CareerGuidanceSystem:
230
+ def __init__(self):
231
+ self.gemini = GeminiAPI()
232
+ self.data_processor = DataProcessor()
233
+ self.visualizer = Visualizer()
234
+ self.current_analysis = None
235
+
236
+ self.personality_questions = [
237
+ {
238
+ "question": "Bạn thích làm việc một mình hay theo nhóm?",
239
+ "choices": ["Thích làm việc một mình", "Thích làm việc nhóm"]
240
+ },
241
+ {
242
+ "question": "Khi giải quyết vấn đề, bạn thường:",
243
+ "choices": ["Dựa vào dữ liệu và logic", "Dựa vào trực giác và cảm nhận"]
244
+ },
245
+ {
246
+ "question": "Trong công việc, bạn ưu tiên:",
247
+ "choices": ["Tuân thủ quy trình chặt chẽ", "Linh hoạt và sáng tạo"]
248
+ },
249
+ {
250
+ "question": "Bạn học hỏi tốt nhất thông qua:",
251
+ "choices": ["Lý thuyết và khái niệm", "Thực hành và trải nghiệm"]
252
+ },
253
+ {
254
+ "question": "Trong tình huống mới, bạn thường:",
255
+ "choices": ["Lập kế hoạch chi tiết trước", "Ứng biến theo tình huống"]
256
+ }
257
+ ]
258
+
259
+ def analyze_user_responses(self, responses: List[str]) -> Dict:
260
+ if not self.data_processor.validate_responses(responses):
261
+ raise ValueError("Vui lòng trả lời tất cả các câu hỏi")
262
+
263
+ self.current_analysis = self.gemini.analyze_personality(responses)
264
+ return self.current_analysis
265
+
266
+ def create_personality_report(self, analysis: Dict) -> str:
267
+ return f"""
268
+ # Báo cáo Phân tích Tính cách và Định hướng Nghề nghiệp
269
+
270
+ ## Kiểu tính cách: {analysis['mbti_type']}
271
+
272
+ ### Điểm mạnh:
273
+ {chr(10).join(['- ' + s for s in analysis['strengths']])}
274
+
275
+ ### Điểm cần phát triển:
276
+ {chr(10).join(['- ' + w for w in analysis['weaknesses']])}
277
+
278
+ ## Nghề nghi��p phù hợp:
279
+ {chr(10).join(['1. ' + c for c in analysis['recommended_careers']])}
280
+
281
+ ## Lộ trình phát triển đề xuất:
282
+ {chr(10).join(['1. ' + d for d in analysis['development_path']])}
283
+
284
+ Báo cáo được tạo ngày: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
285
+ """
286
+
287
+ def get_advice(self, question: str) -> str:
288
+ return self.gemini.get_career_advice(question, self.current_analysis)
289
+
290
+ def predict_market_trends(self) -> str:
291
+ trends_data = self.gemini.predict_market_trends()
292
+
293
+ if not trends_data:
294
+ return "Không thể lấy dữ liệu từ nguồn tin cậy. Vui lòng thử lại sau."
295
+
296
+ increasing_jobs = trends_data.get('increasing_jobs', [])
297
+ decreasing_jobs = trends_data.get('decreasing_jobs', [])
298
+ average_salaries = trends_data.get('average_salaries', {})
299
+
300
+ trends_report = f"""
301
+ # Dự đoán Xu hướng Thị trường Lao động
302
+
303
+ ## Nhu cầu nhân lực tăng cao:
304
+ {chr(10).join(['- ' + job for job in increasing_jobs])}
305
+
306
+ ## Nhu cầu nhân lực giảm nhẹ:
307
+ {chr(10).join(['- ' + job for job in decreasing_jobs])}
308
+
309
+ ## Mức lương trung bình:
310
+ {chr(10).join([f'- {job}: {salary} triệu VND/tháng' for job, salary in average_salaries.items()])}
311
+ """
312
+
313
+ return trends_report
314
+
315
+ def create_interface(career_system: CareerGuidanceSystem):
316
+ with gr.Blocks(theme=gr.themes.Soft()) as interface:
317
+ gr.Markdown("# Hệ thống Tư vấn Hướng nghiệp AI")
318
+
319
+ # Tab Đánh giá Tính cách
320
+ with gr.Tab("Đánh giá Tính cách"):
321
+ questions = []
322
+ with gr.Group():
323
+ for q in career_system.personality_questions:
324
+ questions.append(gr.Radio(
325
+ choices=q["choices"],
326
+ label=q["question"],
327
+ info="Chọn đáp án phù hợp nhất với bạn"
328
+ ))
329
+
330
+ personality_btn = gr.Button("Phân tích tính cách", variant="primary")
331
+
332
+ with gr.Column():
333
+ personality_output = gr.Markdown(label="Kết quả phân tích")
334
+ download_btn = gr.Button("Tải xuống báo cáo PDF")
335
+
336
+ # Tab Biểu đồ Phân tích
337
+ with gr.Tab("Biểu đồ Phân tích"):
338
+ with gr.Row():
339
+ personality_chart = gr.Plot(label="Biểu đồ tính cách")
340
+ career_match_chart = gr.Plot(label="Độ phù hợp nghề nghiệp")
341
+
342
+ # Tab Tư vấn Chi tiết
343
+ with gr.Tab("Tư vấn Chi tiết"):
344
+ chat_history = gr.Chatbot(
345
+ label="Cuộc trao đổi với chuyên gia tư vấn",
346
+ height=400
347
+ )
348
+ with gr.Row():
349
+ msg = gr.Textbox(
350
+ label="Nhập câu hỏi của bạn",
351
+ placeholder="Ví dụ: Làm thế nào để phát triển kỹ năng lãnh đạo?"
352
+ )
353
+ send_btn = gr.Button("Gửi", variant="primary")
354
+ clear_btn = gr.Button("Xóa lịch sử")
355
+
356
+ # Tab Dự đoán Xu hướng Thị trường Lao động
357
+ with gr.Tab("Dự đoán Xu hướng Thị trường Lao động"):
358
+ market_trends_output = gr.Markdown(label="Dự đoán xu hướng thị trường lao động")
359
+ predict_btn = gr.Button("Dự đoán", variant="primary")
360
+
361
+ def analyze_responses():
362
+ try:
363
+ responses = [q.value for q in questions]
364
+ if not career_system.data_processor.validate_responses(responses):
365
+ return "Vui lòng trả lời tất cả các câu hỏi", None, None
366
+
367
+ analysis = career_system.analyze_user_responses(responses)
368
+ report = career_system.create_personality_report(analysis)
369
+
370
+ strengths_fig = career_system.visualizer.create_strength_chart(
371
+ analysis['strengths']
372
+ )
373
+
374
+ careers_fig = career_system.visualizer.create_career_match_chart(
375
+ analysis['recommended_careers']
376
+ )
377
+
378
+ return report, strengths_fig, careers_fig
379
+ except Exception as e:
380
+ return str(e), None, None
381
+
382
+ def send_message(chat_history, message):
383
+ try:
384
+ advice = career_system.get_advice(message)
385
+ chat_history.append((message, advice))
386
+ return chat_history, ""
387
+ except Exception as e:
388
+ return chat_history, str(e)
389
+
390
+ def clear_chat():
391
+ return [], ""
392
+
393
+ def predict_market_trends():
394
+ return career_system.predict_market_trends()
395
+
396
+ personality_btn.click(analyze_responses, inputs=[], outputs=[personality_output, personality_chart, career_match_chart])
397
+ download_btn.click(lambda report: gr.File.update(value=report, label="Báo cáo.pdf"), inputs=[personality_output], outputs=[download_btn])
398
+ send_btn.click(send_message, inputs=[chat_history, msg], outputs=[chat_history, msg])
399
+ clear_btn.click(clear_chat, inputs=[], outputs=[chat_history, msg])
400
+ predict_btn.click(predict_market_trends, inputs=[], outputs=[market_trends_output])
401
+
402
+ return interface
403
+
404
+ if __name__ == "__main__":
405
+ career_system = CareerGuidanceSystem()
406
+ interface = create_interface(career_system)
407
+ interface.launch()