PlanOpticon

planopticon / video_processor / providers / qianfan_provider.py
Source Blame History 138 lines
0981a08… noreply 1 """Baidu Qianfan (ERNIE) provider implementation."""
0981a08… noreply 2
0981a08… noreply 3 import logging
0981a08… noreply 4 import os
0981a08… noreply 5 from pathlib import Path
0981a08… noreply 6 from typing import Optional
0981a08… noreply 7
0981a08… noreply 8 from dotenv import load_dotenv
0981a08… noreply 9
0981a08… noreply 10 from video_processor.providers.base import BaseProvider, ModelInfo, ProviderRegistry
0981a08… noreply 11
0981a08… noreply 12 load_dotenv()
0981a08… noreply 13 logger = logging.getLogger(__name__)
0981a08… noreply 14
0981a08… noreply 15 # Curated list of Qianfan models
0981a08… noreply 16 _QIANFAN_MODELS = [
0981a08… noreply 17 ModelInfo(
0981a08… noreply 18 id="ernie-4.0-8k",
0981a08… noreply 19 provider="qianfan",
0981a08… noreply 20 display_name="ERNIE 4.0 8K",
0981a08… noreply 21 capabilities=["chat"],
0981a08… noreply 22 ),
0981a08… noreply 23 ModelInfo(
0981a08… noreply 24 id="ernie-3.5-8k",
0981a08… noreply 25 provider="qianfan",
0981a08… noreply 26 display_name="ERNIE 3.5 8K",
0981a08… noreply 27 capabilities=["chat"],
0981a08… noreply 28 ),
0981a08… noreply 29 ModelInfo(
0981a08… noreply 30 id="ernie-speed-8k",
0981a08… noreply 31 provider="qianfan",
0981a08… noreply 32 display_name="ERNIE Speed 8K",
0981a08… noreply 33 capabilities=["chat"],
0981a08… noreply 34 ),
0981a08… noreply 35 ModelInfo(
0981a08… noreply 36 id="ernie-lite-8k",
0981a08… noreply 37 provider="qianfan",
0981a08… noreply 38 display_name="ERNIE Lite 8K",
0981a08… noreply 39 capabilities=["chat"],
0981a08… noreply 40 ),
0981a08… noreply 41 ]
0981a08… noreply 42
0981a08… noreply 43
0981a08… noreply 44 class QianfanProvider(BaseProvider):
0981a08… noreply 45 """Baidu Qianfan provider using the qianfan SDK."""
0981a08… noreply 46
0981a08… noreply 47 provider_name = "qianfan"
0981a08… noreply 48
0981a08… noreply 49 def __init__(
0981a08… noreply 50 self,
0981a08… noreply 51 access_key: Optional[str] = None,
0981a08… noreply 52 secret_key: Optional[str] = None,
0981a08… noreply 53 ):
0981a08… noreply 54 try:
0981a08… noreply 55 import qianfan
0981a08… noreply 56 except ImportError:
0981a08… noreply 57 raise ImportError("qianfan package not installed. Install with: pip install qianfan")
0981a08… noreply 58
0981a08… noreply 59 self._access_key = access_key or os.getenv("QIANFAN_ACCESS_KEY")
0981a08… noreply 60 self._secret_key = secret_key or os.getenv("QIANFAN_SECRET_KEY")
0981a08… noreply 61
0981a08… noreply 62 if not self._access_key or not self._secret_key:
0981a08… noreply 63 raise ValueError("QIANFAN_ACCESS_KEY and QIANFAN_SECRET_KEY must both be set")
0981a08… noreply 64
0981a08… noreply 65 # Set env vars for the SDK to pick up
0981a08… noreply 66 os.environ["QIANFAN_ACCESS_KEY"] = self._access_key
0981a08… noreply 67 os.environ["QIANFAN_SECRET_KEY"] = self._secret_key
0981a08… noreply 68
0981a08… noreply 69 self._qianfan = qianfan
0981a08… noreply 70 self._last_usage = {}
0981a08… noreply 71
0981a08… noreply 72 def chat(
0981a08… noreply 73 self,
0981a08… noreply 74 messages: list[dict],
0981a08… noreply 75 max_tokens: int = 4096,
0981a08… noreply 76 temperature: float = 0.7,
0981a08… noreply 77 model: Optional[str] = None,
0981a08… noreply 78 ) -> str:
0981a08… noreply 79 model = model or "ernie-4.0-8k"
0981a08… noreply 80 if model.startswith("qianfan/"):
0981a08… noreply 81 model = model[len("qianfan/") :]
0981a08… noreply 82
0981a08… noreply 83 chat_comp = self._qianfan.ChatCompletion()
0981a08… noreply 84 response = chat_comp.do(
0981a08… noreply 85 model=model,
0981a08… noreply 86 messages=messages,
0981a08… noreply 87 temperature=temperature,
0981a08… noreply 88 max_output_tokens=max_tokens,
0981a08… noreply 89 )
0981a08… noreply 90
0981a08… noreply 91 body = response.get("body", response) if hasattr(response, "get") else response
0981a08… noreply 92 usage = body.get("usage", {}) if hasattr(body, "get") else {}
0981a08… noreply 93 self._last_usage = {
0981a08… noreply 94 "input_tokens": usage.get("prompt_tokens", 0),
0981a08… noreply 95 "output_tokens": usage.get("completion_tokens", 0),
0981a08… noreply 96 }
0981a08… noreply 97
0981a08… noreply 98 result = body.get("result", "") if hasattr(body, "get") else str(body)
0981a08… noreply 99 return result
0981a08… noreply 100
0981a08… noreply 101 def analyze_image(
0981a08… noreply 102 self,
0981a08… noreply 103 image_bytes: bytes,
0981a08… noreply 104 prompt: str,
0981a08… noreply 105 max_tokens: int = 4096,
0981a08… noreply 106 model: Optional[str] = None,
0981a08… noreply 107 ) -> str:
0981a08… noreply 108 raise NotImplementedError(
0981a08… noreply 109 "Qianfan image analysis is not supported in this provider. "
0981a08… noreply 110 "Use OpenAI, Anthropic, or Gemini for image analysis."
0981a08… noreply 111 )
0981a08… noreply 112
0981a08… noreply 113 def transcribe_audio(
0981a08… noreply 114 self,
0981a08… noreply 115 audio_path: str | Path,
0981a08… noreply 116 language: Optional[str] = None,
0981a08… noreply 117 model: Optional[str] = None,
0981a08… noreply 118 ) -> dict:
0981a08… noreply 119 raise NotImplementedError(
0981a08… noreply 120 "Qianfan does not provide a transcription API through this provider. "
0981a08… noreply 121 "Use OpenAI Whisper or Gemini for transcription."
0981a08… noreply 122 )
0981a08… noreply 123
0981a08… noreply 124 def list_models(self) -> list[ModelInfo]:
0981a08… noreply 125 return list(_QIANFAN_MODELS)
0981a08… noreply 126
0981a08… noreply 127
0981a08… noreply 128 ProviderRegistry.register(
0981a08… noreply 129 name="qianfan",
0981a08… noreply 130 provider_class=QianfanProvider,
0981a08… noreply 131 env_var="QIANFAN_ACCESS_KEY",
0981a08… noreply 132 model_prefixes=["ernie-", "qianfan/"],
0981a08… noreply 133 default_models={
0981a08… noreply 134 "chat": "ernie-4.0-8k",
0981a08… noreply 135 "vision": "",
0981a08… noreply 136 "audio": "",
0981a08… noreply 137 },
0981a08… noreply 138 )

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button