PlanOpticon

planopticon / video_processor / providers / mistral_provider.py
Blame History Raw 168 lines
1
"""Mistral AI provider implementation."""
2
3
import base64
4
import logging
5
import os
6
from pathlib import Path
7
from typing import Optional
8
9
from dotenv import load_dotenv
10
11
from video_processor.providers.base import BaseProvider, ModelInfo, ProviderRegistry
12
13
load_dotenv()
14
logger = logging.getLogger(__name__)
15
16
# Curated list of Mistral models
17
_MISTRAL_MODELS = [
18
ModelInfo(
19
id="mistral-large-latest",
20
provider="mistral",
21
display_name="Mistral Large",
22
capabilities=["chat"],
23
),
24
ModelInfo(
25
id="mistral-medium-latest",
26
provider="mistral",
27
display_name="Mistral Medium",
28
capabilities=["chat"],
29
),
30
ModelInfo(
31
id="mistral-small-latest",
32
provider="mistral",
33
display_name="Mistral Small",
34
capabilities=["chat"],
35
),
36
ModelInfo(
37
id="open-mistral-nemo",
38
provider="mistral",
39
display_name="Mistral Nemo",
40
capabilities=["chat"],
41
),
42
ModelInfo(
43
id="pixtral-large-latest",
44
provider="mistral",
45
display_name="Pixtral Large",
46
capabilities=["chat", "vision"],
47
),
48
ModelInfo(
49
id="pixtral-12b-2409",
50
provider="mistral",
51
display_name="Pixtral 12B",
52
capabilities=["chat", "vision"],
53
),
54
ModelInfo(
55
id="codestral-latest",
56
provider="mistral",
57
display_name="Codestral",
58
capabilities=["chat"],
59
),
60
]
61
62
63
class MistralProvider(BaseProvider):
64
"""Mistral AI provider using the mistralai SDK."""
65
66
provider_name = "mistral"
67
68
def __init__(self, api_key: Optional[str] = None):
69
try:
70
from mistralai import Mistral
71
except ImportError:
72
raise ImportError(
73
"mistralai package not installed. Install with: pip install mistralai"
74
)
75
76
self._api_key = api_key or os.getenv("MISTRAL_API_KEY")
77
if not self._api_key:
78
raise ValueError("MISTRAL_API_KEY not set")
79
80
self._client = Mistral(api_key=self._api_key)
81
self._last_usage = {}
82
83
def chat(
84
self,
85
messages: list[dict],
86
max_tokens: int = 4096,
87
temperature: float = 0.7,
88
model: Optional[str] = None,
89
) -> str:
90
model = model or "mistral-large-latest"
91
92
response = self._client.chat.complete(
93
model=model,
94
messages=messages,
95
max_tokens=max_tokens,
96
temperature=temperature,
97
)
98
99
self._last_usage = {
100
"input_tokens": getattr(response.usage, "prompt_tokens", 0) if response.usage else 0,
101
"output_tokens": getattr(response.usage, "completion_tokens", 0)
102
if response.usage
103
else 0,
104
}
105
return response.choices[0].message.content or ""
106
107
def analyze_image(
108
self,
109
image_bytes: bytes,
110
prompt: str,
111
max_tokens: int = 4096,
112
model: Optional[str] = None,
113
) -> str:
114
model = model or "pixtral-large-latest"
115
b64 = base64.b64encode(image_bytes).decode()
116
117
response = self._client.chat.complete(
118
model=model,
119
messages=[
120
{
121
"role": "user",
122
"content": [
123
{"type": "text", "text": prompt},
124
{
125
"type": "image_url",
126
"image_url": {"url": f"data:image/jpeg;base64,{b64}"},
127
},
128
],
129
}
130
],
131
max_tokens=max_tokens,
132
)
133
134
self._last_usage = {
135
"input_tokens": getattr(response.usage, "prompt_tokens", 0) if response.usage else 0,
136
"output_tokens": getattr(response.usage, "completion_tokens", 0)
137
if response.usage
138
else 0,
139
}
140
return response.choices[0].message.content or ""
141
142
def transcribe_audio(
143
self,
144
audio_path: str | Path,
145
language: Optional[str] = None,
146
model: Optional[str] = None,
147
) -> dict:
148
raise NotImplementedError(
149
"Mistral does not provide a transcription API. "
150
"Use OpenAI Whisper or Gemini for transcription."
151
)
152
153
def list_models(self) -> list[ModelInfo]:
154
return list(_MISTRAL_MODELS)
155
156
157
ProviderRegistry.register(
158
name="mistral",
159
provider_class=MistralProvider,
160
env_var="MISTRAL_API_KEY",
161
model_prefixes=["mistral-", "pixtral-", "codestral-", "open-mistral-"],
162
default_models={
163
"chat": "mistral-large-latest",
164
"vision": "pixtral-large-latest",
165
"audio": "",
166
},
167
)
168

Keyboard Shortcuts

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