123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320 |
- from __future__ import annotations
- from aiohttp import ClientSession, TCPConnector, ClientTimeout
- from pathlib import Path
- import re
- import json
- import random
- import string
- from ..typing import AsyncResult, Messages, ImagesType
- from ..requests.raise_for_status import raise_for_status
- from .base_provider import AsyncGeneratorProvider, ProviderModelMixin
- from ..image import ImageResponse, to_data_uri
- from ..cookies import get_cookies_dir
- from .helper import format_prompt
- from ..providers.response import FinishReason, JsonConversation
- class Conversation(JsonConversation):
- validated_value: str = None
- chat_id: str = None
- message_history: Messages = []
- def __init__(self, model: str):
- self.model = model
- class Blackbox(AsyncGeneratorProvider, ProviderModelMixin):
- label = "Blackbox AI"
- url = "https://www.blackbox.ai"
- api_endpoint = "https://www.blackbox.ai/api/chat"
-
- working = True
- needs_auth = True
- supports_stream = False
- supports_system_message = False
- supports_message_history = True
-
- default_model = "blackboxai"
- default_vision_model = default_model
- default_image_model = 'ImageGeneration'
- image_models = [default_image_model]
- vision_models = [default_vision_model, 'gpt-4o', 'gemini-pro', 'gemini-1.5-flash', 'llama-3.1-8b', 'llama-3.1-70b', 'llama-3.1-405b']
-
- userSelectedModel = ['gpt-4o', 'gemini-pro', 'claude-sonnet-3.5', 'blackboxai-pro']
- agentMode = {
- 'ImageGeneration': {'mode': True, 'id': "ImageGenerationLV45LJp", 'name': "Image Generation"},
- #
- 'meta-llama/Llama-3.3-70B-Instruct-Turbo': {'mode': True, 'id': "meta-llama/Llama-3.3-70B-Instruct-Turbo", 'name': "Meta-Llama-3.3-70B-Instruct-Turbo"},
- 'mistralai/Mistral-7B-Instruct-v0.2': {'mode': True, 'id': "mistralai/Mistral-7B-Instruct-v0.2", 'name': "Mistral-(7B)-Instruct-v0.2"},
- 'deepseek-ai/deepseek-llm-67b-chat': {'mode': True, 'id': "deepseek-ai/deepseek-llm-67b-chat", 'name': "DeepSeek-LLM-Chat-(67B)"},
- 'databricks/dbrx-instruct': {'mode': True, 'id': "databricks/dbrx-instruct", 'name': "DBRX-Instruct"},
- 'Qwen/QwQ-32B-Preview': {'mode': True, 'id': "Qwen/QwQ-32B-Preview", 'name': "Qwen-QwQ-32B-Preview"},
- 'NousResearch/Nous-Hermes-2-Mixtral-8x7B-DPO': {'mode': True, 'id': "NousResearch/Nous-Hermes-2-Mixtral-8x7B-DPO", 'name': "Nous-Hermes-2-Mixtral-8x7B-DPO"}
- }
- trendingAgentMode = {
- "gemini-1.5-flash": {'mode': True, 'id': 'Gemini'},
- "llama-3.1-8b": {'mode': True, 'id': "llama-3.1-8b"},
- 'llama-3.1-70b': {'mode': True, 'id': "llama-3.1-70b"},
- 'llama-3.1-405b': {'mode': True, 'id': "llama-3.1-405"},
- #
- 'Python Agent': {'mode': True, 'id': "Python Agent"},
- 'Java Agent': {'mode': True, 'id': "Java Agent"},
- 'JavaScript Agent': {'mode': True, 'id': "JavaScript Agent"},
- 'HTML Agent': {'mode': True, 'id': "HTML Agent"},
- 'Google Cloud Agent': {'mode': True, 'id': "Google Cloud Agent"},
- 'Android Developer': {'mode': True, 'id': "Android Developer"},
- 'Swift Developer': {'mode': True, 'id': "Swift Developer"},
- 'Next.js Agent': {'mode': True, 'id': "Next.js Agent"},
- 'MongoDB Agent': {'mode': True, 'id': "MongoDB Agent"},
- 'PyTorch Agent': {'mode': True, 'id': "PyTorch Agent"},
- 'React Agent': {'mode': True, 'id': "React Agent"},
- 'Xcode Agent': {'mode': True, 'id': "Xcode Agent"},
- 'AngularJS Agent': {'mode': True, 'id': "AngularJS Agent"},
- #
- 'blackboxai-pro': {'mode': True, 'id': "BLACKBOXAI-PRO"},
- #
- 'repomap': {'mode': True, 'id': "repomap"},
- #
- 'Heroku Agent': {'mode': True, 'id': "Heroku Agent"},
- 'Godot Agent': {'mode': True, 'id': "Godot Agent"},
- 'Go Agent': {'mode': True, 'id': "Go Agent"},
- 'Gitlab Agent': {'mode': True, 'id': "Gitlab Agent"},
- 'Git Agent': {'mode': True, 'id': "Git Agent"},
- 'Flask Agent': {'mode': True, 'id': "Flask Agent"},
- 'Firebase Agent': {'mode': True, 'id': "Firebase Agent"},
- 'FastAPI Agent': {'mode': True, 'id': "FastAPI Agent"},
- 'Erlang Agent': {'mode': True, 'id': "Erlang Agent"},
- 'Electron Agent': {'mode': True, 'id': "Electron Agent"},
- 'Docker Agent': {'mode': True, 'id': "Docker Agent"},
- 'DigitalOcean Agent': {'mode': True, 'id': "DigitalOcean Agent"},
- 'Bitbucket Agent': {'mode': True, 'id': "Bitbucket Agent"},
- 'Azure Agent': {'mode': True, 'id': "Azure Agent"},
- 'Flutter Agent': {'mode': True, 'id': "Flutter Agent"},
- 'Youtube Agent': {'mode': True, 'id': "Youtube Agent"},
- 'builder Agent': {'mode': True, 'id': "builder Agent"},
- }
-
- models = list(dict.fromkeys([default_model, *userSelectedModel, *list(agentMode.keys()), *list(trendingAgentMode.keys())]))
- model_aliases = {
- ### chat ###
- "gpt-4": "gpt-4o",
- "gemini-1.5-flash": "gemini-1.5-flash",
- "gemini-1.5-pro": "gemini-pro",
- "claude-3.5-sonnet": "claude-sonnet-3.5",
- "llama-3.3-70b": "meta-llama/Llama-3.3-70B-Instruct-Turbo",
- "mixtral-7b": "mistralai/Mistral-7B-Instruct-v0.2",
- "deepseek-chat": "deepseek-ai/deepseek-llm-67b-chat",
- "dbrx-instruct": "databricks/dbrx-instruct",
- "qwq-32b": "Qwen/QwQ-32B-Preview",
- "hermes-2-dpo": "NousResearch/Nous-Hermes-2-Mixtral-8x7B-DPO",
-
- ### image ###
- "flux": "ImageGeneration",
- }
- @classmethod
- async def fetch_validated(
- cls,
- url: str = "https://www.blackbox.ai",
- force_refresh: bool = False
- ) -> Optional[str]:
- """
- Asynchronously retrieves the validated_value from the specified URL.
- """
- cache_file = Path(get_cookies_dir()) / 'blackbox.json'
-
- if not force_refresh and cache_file.exists():
- try:
- with open(cache_file, 'r') as f:
- data = json.load(f)
- if data.get('validated_value'):
- return data['validated_value']
- except Exception as e:
- print(f"Error reading cache: {e}")
-
- js_file_pattern = r'static/chunks/\d{4}-[a-fA-F0-9]+\.js'
- uuid_pattern = r'["\']([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})["\']'
- def is_valid_context(text: str) -> bool:
- """Checks if the context is valid."""
- return any(char + '=' in text for char in 'abcdefghijklmnopqrstuvwxyz')
- async with ClientSession() as session:
- try:
- async with session.get(url) as response:
- if response.status != 200:
- print("Failed to load the page.")
- return None
- page_content = await response.text()
- js_files = re.findall(js_file_pattern, page_content)
- for js_file in js_files:
- js_url = f"{url}/_next/{js_file}"
- async with session.get(js_url) as js_response:
- if js_response.status == 200:
- js_content = await js_response.text()
- for match in re.finditer(uuid_pattern, js_content):
- start = max(0, match.start() - 10)
- end = min(len(js_content), match.end() + 10)
- context = js_content[start:end]
- if is_valid_context(context):
- validated_value = match.group(1)
-
- # Save to cache
- cache_file.parent.mkdir(exist_ok=True)
- try:
- with open(cache_file, 'w') as f:
- json.dump({'validated_value': validated_value}, f)
- except Exception as e:
- print(f"Error writing cache: {e}")
-
- return validated_value
- except Exception as e:
- print(f"Error retrieving validated_value: {e}")
- return None
- @classmethod
- def generate_chat_id(cls) -> str:
- """Generate a random chat ID"""
- chars = string.ascii_letters + string.digits
- return ''.join(random.choice(chars) for _ in range(7))
- @classmethod
- async def create_async_generator(
- cls,
- model: str,
- messages: Messages,
- prompt: str = None,
- proxy: str = None,
- web_search: bool = False,
- images: ImagesType = None,
- top_p: float = None,
- temperature: float = None,
- max_tokens: int = None,
- conversation: Conversation = None,
- return_conversation: bool = False,
- **kwargs
- ) -> AsyncResult:
- model = cls.get_model(model)
- headers = {
- 'accept': '*/*',
- 'accept-language': 'en-US,en;q=0.9',
- 'content-type': 'application/json',
- 'origin': 'https://www.blackbox.ai',
- 'referer': 'https://www.blackbox.ai/',
- 'user-agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36'
- }
-
- connector = TCPConnector(limit=10, ttl_dns_cache=300)
- timeout = ClientTimeout(total=30)
-
- async with ClientSession(headers=headers, connector=connector, timeout=timeout) as session:
- if conversation is None:
- conversation = Conversation(model)
- conversation.validated_value = await cls.fetch_validated()
- conversation.chat_id = cls.generate_chat_id()
- conversation.message_history = []
-
- current_messages = [{"id": conversation.chat_id, "content": format_prompt(messages), "role": "user"}]
- conversation.message_history.extend(messages)
- if images is not None:
- current_messages[-1]['data'] = {
- "imagesData": [
- {
- "filePath": f"/{image_name}",
- "contents": to_data_uri(image)
- }
- for image, image_name in images
- ],
- "fileText": "",
- "title": ""
- }
- data = {
- "messages": current_messages,
- "agentMode": cls.agentMode.get(model, {}) if model in cls.agentMode else {},
- "id": conversation.chat_id,
- "previewToken": None,
- "userId": None,
- "codeModelMode": True,
- "trendingAgentMode": cls.trendingAgentMode.get(model, {}) if model in cls.trendingAgentMode else {},
- "isMicMode": False,
- "userSystemPrompt": None,
- "maxTokens": max_tokens,
- "playgroundTopP": top_p,
- "playgroundTemperature": temperature,
- "isChromeExt": False,
- "githubToken": "",
- "clickedAnswer2": False,
- "clickedAnswer3": False,
- "clickedForceWebSearch": False,
- "visitFromDelta": False,
- "mobileClient": False,
- "userSelectedModel": model if model in cls.userSelectedModel else None,
- "validated": conversation.validated_value,
- "imageGenerationMode": False,
- "webSearchModePrompt": False,
- "deepSearchMode": False,
- "domains": None,
- "vscodeClient": False,
- "codeInterpreterMode": False,
- "webSearchMode": web_search
- }
-
- async with session.post(cls.api_endpoint, json=data, proxy=proxy) as response:
- await raise_for_status(response)
- response_text = await response.text()
- parts = response_text.split('$~~~$')
- text_to_yield = parts[2] if len(parts) >= 3 else response_text
-
- if not text_to_yield or text_to_yield.isspace():
- return
- full_response = ""
-
- if model in cls.image_models:
- image_url_match = re.search(r'!\[.*?\]\((.*?)\)', text_to_yield)
- if image_url_match:
- image_url = image_url_match.group(1)
- prompt = messages[-1]["content"]
- yield ImageResponse(images=[image_url], alt=prompt)
- else:
- if "Generated by BLACKBOX.AI" in text_to_yield:
- conversation.validated_value = await cls.fetch_validated(force_refresh=True)
- if conversation.validated_value:
- data["validated"] = conversation.validated_value
- async with session.post(cls.api_endpoint, json=data, proxy=proxy) as new_response:
- await raise_for_status(new_response)
- new_response_text = await new_response.text()
- new_parts = new_response_text.split('$~~~$')
- new_text = new_parts[2] if len(new_parts) >= 3 else new_response_text
-
- if new_text and not new_text.isspace():
- yield new_text
- full_response = new_text
- else:
- if text_to_yield and not text_to_yield.isspace():
- yield text_to_yield
- full_response = text_to_yield
- else:
- if text_to_yield and not text_to_yield.isspace():
- yield text_to_yield
- full_response = text_to_yield
- if return_conversation:
- conversation.message_history.append({"role": "assistant", "content": full_response})
- yield conversation
-
- yield FinishReason("stop")
|