Infrastructure: Implement master/dev/vX branching, save git path, and fix username casing
This commit is contained in:
0
backend/ai/__init__.py
Normal file
0
backend/ai/__init__.py
Normal file
47
backend/ai/claude.py
Normal file
47
backend/ai/claude.py
Normal file
@@ -0,0 +1,47 @@
|
||||
import os
|
||||
import anthropic
|
||||
import json
|
||||
import base64
|
||||
|
||||
def extract(image_bytes: bytes, prompt: str):
|
||||
api_key = os.environ.get("CLAUDE_API_KEY")
|
||||
if not api_key:
|
||||
return None
|
||||
|
||||
client = anthropic.Anthropic(api_key=api_key)
|
||||
base64_image = base64.b64encode(image_bytes).decode('utf-8')
|
||||
|
||||
# 2026 Target models
|
||||
models_to_try = ["claude-3-5-haiku-latest", "claude-3-5-sonnet-latest"]
|
||||
|
||||
for model_name in models_to_try:
|
||||
try:
|
||||
print(f"Claude Attempt: {model_name}")
|
||||
message = client.messages.create(
|
||||
model=model_name,
|
||||
max_tokens=1024,
|
||||
messages=[{
|
||||
"role": "user",
|
||||
"content": [
|
||||
{
|
||||
"type": "image",
|
||||
"source": {
|
||||
"type": "base64",
|
||||
"media_type": "image/jpeg",
|
||||
"data": base64_image,
|
||||
},
|
||||
},
|
||||
{"type": "text", "text": prompt}
|
||||
],
|
||||
}]
|
||||
)
|
||||
text = message.content[0].text.strip()
|
||||
|
||||
if "```json" in text:
|
||||
text = text.split("```json")[1].split("```")[0].strip()
|
||||
|
||||
return json.loads(text)
|
||||
except Exception as e:
|
||||
print(f"Claude {model_name} failed: {e}")
|
||||
continue
|
||||
return None
|
||||
71
backend/ai/gemini.py
Normal file
71
backend/ai/gemini.py
Normal file
@@ -0,0 +1,71 @@
|
||||
import os
|
||||
import json
|
||||
import io
|
||||
from PIL import Image
|
||||
from google import genai
|
||||
from google.genai import types
|
||||
|
||||
def get_best_models():
|
||||
# Using the exact models discovered via diagnostic
|
||||
return ["gemini-2.0-flash", "gemini-2.5-flash"]
|
||||
|
||||
def extract(image_bytes: bytes, prompt: str):
|
||||
api_key = os.environ.get("GEMINI_API_KEY")
|
||||
if not api_key:
|
||||
print("CRITICAL: GEMINI_API_KEY is MISSING in environment!")
|
||||
return None
|
||||
|
||||
# Log partial key for safety debug
|
||||
key_hint = f"{api_key[:4]}...{api_key[-4:]}" if len(api_key) > 8 else "too short"
|
||||
print(f"🔑 Using API Key: {key_hint}")
|
||||
|
||||
try:
|
||||
# Initialize the NEW SDK Client forcing stable v1 API
|
||||
client = genai.Client(api_key=api_key, http_options={'api_version': 'v1'})
|
||||
|
||||
# DEBUG: List allowed models for this key
|
||||
print("🔍 Checking available models for your key...")
|
||||
try:
|
||||
for m in client.models.list():
|
||||
print(f" - Found: {m.name}")
|
||||
except Exception as list_e:
|
||||
print(f" ⚠️ Could not list models: {list_e}")
|
||||
|
||||
models_to_try = get_best_models()
|
||||
|
||||
# Try models in order
|
||||
for model_name in models_to_try:
|
||||
try:
|
||||
print(f"🚀 AI Launching (v2 SDK): {model_name}...")
|
||||
|
||||
# In the new SDK, we pass a list of parts (text string and image bytes)
|
||||
response = client.models.generate_content(
|
||||
model=model_name,
|
||||
contents=[
|
||||
prompt,
|
||||
types.Part.from_bytes(data=image_bytes, mime_type="image/jpeg")
|
||||
]
|
||||
)
|
||||
|
||||
if not response or not response.text:
|
||||
continue
|
||||
|
||||
text = response.text.strip()
|
||||
print(f"✅ AI Response Received ({len(text)} bytes)")
|
||||
|
||||
# Extract JSON block
|
||||
if "```json" in text:
|
||||
text = text.split("```json")[1].split("```")[0].strip()
|
||||
elif "```" in text:
|
||||
text = text.split("```")[1].strip()
|
||||
|
||||
return json.loads(text)
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Gemini {model_name} failed: {e}")
|
||||
continue
|
||||
|
||||
except Exception as outer_e:
|
||||
print(f"❌ Gemini Client Init failed: {outer_e}")
|
||||
|
||||
return None
|
||||
Reference in New Issue
Block a user