quocdat1964 commited on
Commit
08aa8c5
·
1 Parent(s): bddeee9

Dùng api từ gg AIstudio để check trước khi đổi openrouter

Browse files
Files changed (3) hide show
  1. app/config.py +3 -0
  2. app/llm_service.py +64 -20
  3. requirements.txt +1 -0
app/config.py CHANGED
@@ -25,6 +25,9 @@ class Settings:
25
  # Google API Key (Dùng cho Google AI / Gemini)
26
  GOOGLE_API_KEY: str | None = os.getenv("GOOGLE_API_KEY", None)
27
 
 
 
 
28
  # Device để chạy inference: "cpu" hoặc "cuda"
29
  DEVICE: str = os.getenv("DEVICE", "cpu")
30
 
 
25
  # Google API Key (Dùng cho Google AI / Gemini)
26
  GOOGLE_API_KEY: str | None = os.getenv("GOOGLE_API_KEY", None)
27
 
28
+ # OpenRouter API Key (Dùng để gọi các model AI qua chuẩn OpenAI)
29
+ OPENROUTER_API_KEY: str | None = os.getenv("OPENROUTER_API_KEY", None)
30
+
31
  # Device để chạy inference: "cpu" hoặc "cuda"
32
  DEVICE: str = os.getenv("DEVICE", "cpu")
33
 
app/llm_service.py CHANGED
@@ -1,16 +1,26 @@
1
  import io
2
  import json
 
3
  import traceback
4
- # pyrefly: ignore [missing-import]
5
- import google.generativeai as genai
6
- # pyrefly: ignore [missing-import]
7
  import PyPDF2
8
- from app.config import settings
 
9
 
10
- # Configure Gemini/Google AI
11
  if settings.GOOGLE_API_KEY:
12
  genai.configure(api_key=settings.GOOGLE_API_KEY)
13
 
 
 
 
 
 
 
 
 
 
14
  def extract_text_from_pdf(file_bytes: bytes) -> str:
15
  """Extract raw text from PDF bytes using PyPDF2."""
16
  pdf_reader = PyPDF2.PdfReader(io.BytesIO(file_bytes))
@@ -23,13 +33,14 @@ def extract_text_from_pdf(file_bytes: bytes) -> str:
23
 
24
  def extract_cv_info(file_bytes: bytes, filename: str) -> dict:
25
  """
26
- Extract structured CV info using Google AI (Gemma 3 27B / Gemini).
27
  Hỗ trợ cả định dạng PDF và Hình ảnh (Image).
28
  """
29
  if not settings.GOOGLE_API_KEY:
30
  raise ValueError("Thiếu GOOGLE_API_KEY trong cấu hình.")
 
 
31
 
32
- import mimetypes
33
  filename_lower = filename.lower()
34
  is_pdf = filename_lower.endswith('.pdf')
35
  is_image = filename_lower.endswith(('.png', '.jpg', '.jpeg', '.webp'))
@@ -37,14 +48,6 @@ def extract_cv_info(file_bytes: bytes, filename: str) -> dict:
37
  if not is_pdf and not is_image:
38
  raise ValueError("Định dạng file không được hỗ trợ. Chỉ hỗ trợ PDF và các định dạng ảnh (PNG, JPG, JPEG, WEBP).")
39
 
40
- # 1. Khởi tạo model Gemma 3 27B (Theo yêu cầu của người dùng)
41
- try:
42
- model = genai.GenerativeModel('gemma-3-27b-it')
43
- except Exception as e:
44
- print("Lỗi khởi tạo model Gemma 3:", str(e))
45
- # Fallback trong trường hợp API endpoint chưa hỗ trợ gemma-3
46
- model = genai.GenerativeModel('gemini-2.5-flash')
47
-
48
  base_prompt = """
49
  Bạn là một chuyên gia phân tích nhân sự (HR) và trích xuất dữ liệu. Hãy đọc văn bản được trích xuất từ một CV hoặc hình ảnh CV dưới đây và bóc tách các thông tin thành định dạng JSON chuẩn.
50
  CHỈ THỊ QUAN TRỌNG:
@@ -109,27 +112,68 @@ CHỈ THỊ QUAN TRỌNG:
109
  """
110
 
111
  # 2. Xử lý Input (Dựa trên loại file)
 
 
 
 
 
 
 
112
  if is_pdf:
113
  raw_text = extract_text_from_pdf(file_bytes)
114
  if not raw_text.strip():
115
  raise ValueError("Không thể đọc được văn bản từ file PDF (có thể file là ảnh scan). Vui lòng chuyển sang định dạng ảnh (JPG/PNG).")
 
 
116
  prompt_data = base_prompt + f"\n\nNội dung CV:\n---\n{raw_text[:10000]}\n---"
 
 
 
 
 
 
 
117
  else:
118
- # Nếu là hình ảnh, đẩy thẳng byte của hình ảnh lên Model
119
  mime_type, _ = mimetypes.guess_type(filename)
120
  if not mime_type:
121
  mime_type = "image/jpeg"
122
-
 
123
  prompt_data = [
124
  {"mime_type": mime_type, "data": file_bytes},
125
  base_prompt
126
  ]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
127
 
128
- # 3. Gọi API
 
129
  response = model.generate_content(prompt_data)
130
-
131
- # 4. Xử lý và làm sạch JSON trả về
132
  response_text = response.text.strip()
 
 
 
 
 
 
 
 
133
  if response_text.startswith("```json"):
134
  response_text = response_text[7:]
135
  if response_text.startswith("```"):
 
1
  import io
2
  import json
3
+ import base64
4
  import traceback
5
+ import mimetypes
6
+ # from openai import OpenAI
 
7
  import PyPDF2
8
+ from app.config import settings
9
+ import google.generativeai as genai
10
 
11
+ # Configure Google AI Studio (Tạm thời mở lại theo yêu cầu)
12
  if settings.GOOGLE_API_KEY:
13
  genai.configure(api_key=settings.GOOGLE_API_KEY)
14
 
15
+ # Configure OpenRouter (via OpenAI SDK) - TẠM COMMENT
16
+ # if settings.OPENROUTER_API_KEY:
17
+ # client = OpenAI(
18
+ # base_url="https://openrouter.ai/api/v1",
19
+ # api_key=settings.OPENROUTER_API_KEY,
20
+ # )
21
+ # else:
22
+ # client = None
23
+
24
  def extract_text_from_pdf(file_bytes: bytes) -> str:
25
  """Extract raw text from PDF bytes using PyPDF2."""
26
  pdf_reader = PyPDF2.PdfReader(io.BytesIO(file_bytes))
 
33
 
34
  def extract_cv_info(file_bytes: bytes, filename: str) -> dict:
35
  """
36
+ Extract structured CV info using Google AI (Gemma 3 27B / OpenAI API standard).
37
  Hỗ trợ cả định dạng PDF và Hình ảnh (Image).
38
  """
39
  if not settings.GOOGLE_API_KEY:
40
  raise ValueError("Thiếu GOOGLE_API_KEY trong cấu hình.")
41
+ # if not client:
42
+ # raise ValueError("Thiếu OPENROUTER_API_KEY trong cấu hình.")
43
 
 
44
  filename_lower = filename.lower()
45
  is_pdf = filename_lower.endswith('.pdf')
46
  is_image = filename_lower.endswith(('.png', '.jpg', '.jpeg', '.webp'))
 
48
  if not is_pdf and not is_image:
49
  raise ValueError("Định dạng file không được hỗ trợ. Chỉ hỗ trợ PDF và các định dạng ảnh (PNG, JPG, JPEG, WEBP).")
50
 
 
 
 
 
 
 
 
 
51
  base_prompt = """
52
  Bạn là một chuyên gia phân tích nhân sự (HR) và trích xuất dữ liệu. Hãy đọc văn bản được trích xuất từ một CV hoặc hình ảnh CV dưới đây và bóc tách các thông tin thành định dạng JSON chuẩn.
53
  CHỈ THỊ QUAN TRỌNG:
 
112
  """
113
 
114
  # 2. Xử lý Input (Dựa trên loại file)
115
+ messages = [
116
+ {
117
+ "role": "system",
118
+ "content": "Bạn là một AI phân tích CV cực kỳ chính xác. Bạn chỉ trả về định dạng JSON, tuyệt đối không bao gồm markdown hay bất kỳ text giải thích nào khác."
119
+ }
120
+ ]
121
+
122
  if is_pdf:
123
  raw_text = extract_text_from_pdf(file_bytes)
124
  if not raw_text.strip():
125
  raise ValueError("Không thể đọc được văn bản từ file PDF (có thể file là ảnh scan). Vui lòng chuyển sang định dạng ảnh (JPG/PNG).")
126
+
127
+ # --- Code cho Google AI Studio ---
128
  prompt_data = base_prompt + f"\n\nNội dung CV:\n---\n{raw_text[:10000]}\n---"
129
+
130
+ # --- Code cho OpenRouter (Tạm comment) ---
131
+ # user_content = base_prompt + f"\n\nNội dung CV:\n---\n{raw_text[:10000]}\n---"
132
+ # messages.append({
133
+ # "role": "user",
134
+ # "content": user_content
135
+ # })
136
  else:
 
137
  mime_type, _ = mimetypes.guess_type(filename)
138
  if not mime_type:
139
  mime_type = "image/jpeg"
140
+
141
+ # --- Code cho Google AI Studio ---
142
  prompt_data = [
143
  {"mime_type": mime_type, "data": file_bytes},
144
  base_prompt
145
  ]
146
+
147
+ # --- Code cho OpenRouter (Tạm comment) ---
148
+ # base64_image = base64.b64encode(file_bytes).decode("utf-8")
149
+ # messages.append({
150
+ # "role": "user",
151
+ # "content": [
152
+ # {
153
+ # "type": "text",
154
+ # "text": base_prompt
155
+ # },
156
+ # {
157
+ # "type": "image_url",
158
+ # "image_url": {
159
+ # "url": f"data:{mime_type};base64,{base64_image}"
160
+ # }
161
+ # }
162
+ # ]
163
+ # })
164
 
165
+ # 3. Gọi Google AI API (Sử dụng gemini-2.5-flash làm test chuẩn)
166
+ model = genai.GenerativeModel('gemini-2.5-flash')
167
  response = model.generate_content(prompt_data)
 
 
168
  response_text = response.text.strip()
169
+
170
+ # 3. Gọi OpenRouter API (Tạm comment)
171
+ # response = client.chat.completions.create(
172
+ # model="google/gemma-3-27b-it", # Tên model chính xác trên OpenRouter
173
+ # messages=messages,
174
+ # temperature=0.1, # Giảm sáng tạo, tăng độ chính xác trích xuất
175
+ # )
176
+ # response_text = response.choices[0].message.content.strip()
177
  if response_text.startswith("```json"):
178
  response_text = response_text[7:]
179
  if response_text.startswith("```"):
requirements.txt CHANGED
@@ -19,6 +19,7 @@ pydantic
19
  python-dotenv
20
  gradio
21
  pandas
 
22
  google-generativeai
23
  python-multipart
24
  PyPDF2
 
19
  python-dotenv
20
  gradio
21
  pandas
22
+ openai
23
  google-generativeai
24
  python-multipart
25
  PyPDF2