import aiohttp import json import re from config import OPENROUTER SYSTEM_PROMPT_TEMPLATE = """ Ты — экспертный технический рекрутер. Твоя задача: отфильтровать IT-вакансии. Предпочтения пользователя: {preferences} Верни ТОЛЬКО валидный JSON массив объектов, которые подходят под стек и грейд. Если ничего не подходит, верни []. Никаких пояснений и markdown-разметки. """ def get_forced_vacancies(vacancies: list, user_prefs: str) -> list: stack_match = re.search(r'(?i)стек:(.*?)(?=доп:|$)', user_prefs, re.DOTALL) if not stack_match: return [] stack_content = stack_match.group(1).lower() all_keywords = re.findall(r'[a-zA-Z0-9.+#]{2,}', stack_content) common_words = {'html', 'css', 'git', 'sql', 'api', 'rest', 'remote', 'work'} strong_keys = list(set(word for word in all_keywords if word not in common_words)) if not strong_keys: return [] print(f"🔍 Ключи для авто-добавления: {strong_keys}") forced = [] for vac in vacancies: v_id = str(vac.get('id', '')) vac_str = json.dumps(vac, ensure_ascii=False).lower() vac_clean = re.sub(r'https?://\S+', '', vac_str) if any(key in vac_clean for key in strong_keys): forced.append(vac) return forced async def filter_vacancies_with_ai(vacancies: list, user_prefs: str) -> list: if not vacancies: return [] forced_vacancies = get_forced_vacancies(vacancies, user_prefs) forced_ids = {str(v.get('id')) for v in forced_vacancies if v.get('id')} remaining_vacancies = [v for v in vacancies if str(v.get('id')) not in forced_ids] if not remaining_vacancies: print(f"✅ Все {len(forced_vacancies)} вакансий одобрены автоматом.") return forced_vacancies print(f"✅ Авто-одобрено: {len(forced_vacancies)}") print(f"🤖 Отправка на AI: {len(remaining_vacancies)} (было {len(vacancies)})") api_url = "https://openrouter.ai/api/v1/chat/completions" system_prompt = SYSTEM_PROMPT_TEMPLATE.format(preferences=user_prefs) async with aiohttp.ClientSession() as session: try: clean_token = str(OPENROUTER).strip() async with session.post( url=api_url, headers={ "Authorization": f"Bearer {clean_token}", "Content-Type": "application/json", }, json={ "model": "openrouter/free", "messages": [ {"role": "system", "content": system_prompt}, {"role": "user", "content": json.dumps(remaining_vacancies, ensure_ascii=False)} ] }, timeout=60 ) as response: if response.status != 200: raw_err = await response.text() print(f"❌ Ошибка API ({response.status}): {raw_err[:100]}") return forced_vacancies result_raw = await response.json() if 'choices' not in result_raw: return forced_vacancies content = result_raw['choices'][0]['message']['content'].strip() match = re.search(r'\[\s*\{.*\}\s*\]', content, re.DOTALL) clean_json = match.group(0) if match else content.replace('```json', '').replace('```', '').strip() try: ai_vacs = json.loads(clean_json) final = forced_vacancies.copy() for v in ai_vacs: if str(v.get('id')) not in forced_ids: final.append(v) print(f"🏁 Итог: {len(final)} релевантных вакансий") return final except: return forced_vacancies except Exception as e: print(f"❌ Ошибка в блоке запроса: {e}") return forced_vacancies