Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate to langfuse #7

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 15 additions & 30 deletions alttexter.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,38 +2,40 @@
import logging
import mimetypes
import os
import time
from typing import List, Optional, Tuple

import cairosvg
from langchain import callbacks
from langchain.callbacks.tracers.langchain import wait_for_all_tracers
from langchain.output_parsers import PydanticOutputParser
from langchain.prompts import ChatPromptTemplate
from langchain_core.messages import HumanMessage, SystemMessage
from langchain_openai import AzureChatOpenAI, ChatOpenAI
from langsmith import Client
from langfuse.callback import CallbackHandler

from schema import AlttexterResponse, ImageAltText

langfuse_handler = CallbackHandler(
public_key=os.getenv('LANGFUSE_PUBLIC_KEY'),
secret_key=os.getenv('LANGFUSE_SECRET_KEY'),
host=os.getenv('LANGFUSE_HOST')
)


def determine_llm() -> ChatOpenAI:
"""Determine which LLM to use based on environment variable."""
model_env = os.getenv("ALTTEXTER_MODEL")
if model_env == "openai":
return ChatOpenAI(verbose=True,
temperature=0,
model="gpt-4-vision-preview",
max_tokens=4096)
model="gpt-4o")
elif model_env == "openai_azure":
return AzureChatOpenAI(verbose=True,
temperature=0, openai_api_version="2024-02-15-preview",
azure_deployment=os.getenv("AZURE_OPENAI_DEPLOYMENT"),
model="vision-preview",
max_tokens=4096)
model="gpt-4o")
else:
raise ValueError(f"Unsupported model specified: {model_env}")


def svg_to_png_base64(svg_data):
"""
Converts SVG data to PNG and returns the base64 encoded PNG image.
Expand All @@ -48,6 +50,7 @@ def svg_to_png_base64(svg_data):

return base64.b64encode(png_data).decode('utf-8')


def alttexter(input_text: str, images: dict, image_urls: List[str]) -> Tuple[List[ImageAltText], Optional[str]]:
"""
Processes input text and images to generate alt text and title attributes.
Expand Down Expand Up @@ -122,29 +125,11 @@ def alttexter(input_text: str, images: dict, image_urls: List[str]) -> Tuple[Lis
alttexts = None
run_url = None

tracing_enabled = os.getenv("LANGCHAIN_TRACING_V2", "").lower() == "true"
if tracing_enabled:
client = Client()
try:
with callbacks.collect_runs() as cb:
alttexts = llm.invoke(messages.format_messages())

# Ensure that all tracers complete their execution
wait_for_all_tracers()

if alttexts:
# Get public URL for run
run_id = cb.traced_runs[0].id
time.sleep(2)
client.share_run(run_id)
run_url = client.read_run_shared_link(run_id)
except Exception as e:
logging.error(f"Error during LLM invocation with tracing: {str(e)}")
if os.getenv("LANGFUSE_TRACING", "False"):
alttexts = llm.invoke(messages.format_messages(), config={"callbacks": [langfuse_handler]})
run_url = str(langfuse_handler.get_trace_url())
else:
try:
alttexts = llm.invoke(messages.format_messages())
except Exception as e:
logging.error(f"Error during LLM invocation without tracing: {str(e)}")
alttexts = llm.invoke(messages.format_messages())

if alttexts:
try:
Expand Down
38 changes: 29 additions & 9 deletions client-example.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import argparse
import base64
import getpass
import json
import logging
import os
import re
import base64
import logging
import requests
import getpass
import argparse
from datetime import datetime

import requests

logging.basicConfig(level=logging.INFO,
format='%(levelname)s [%(asctime)s] %(message)s',
datefmt='%d-%m-%Y %H:%M:%S')
Expand Down Expand Up @@ -67,7 +68,7 @@ def log_payload_summary(encoded_images, image_urls):
logging.info(f"Image URLs: {image_urls}")


def send_file_to_api(md_content, encoded_images, image_urls, url, token, full_payload):
def send_file_to_api(md_content, encoded_images, image_urls, url, token, full_payload, verify_ssl=True):
if full_payload:
log_full_payload(md_content, encoded_images, image_urls)
else:
Expand All @@ -86,7 +87,20 @@ def send_file_to_api(md_content, encoded_images, image_urls, url, token, full_pa
}

logging.info("Sending payload to alttexter...")
response = requests.post(url, headers=headers, data=actual_payload, timeout=120)
try:
response = requests.post(url, headers=headers, data=actual_payload, timeout=120, verify=verify_ssl)
response.raise_for_status() # Raises an HTTPError for bad responses
except requests.exceptions.SSLError as ssl_err:
if verify_ssl:
logging.error(f"SSL Error occurred: {ssl_err}")
raise
else:
logging.warning("SSL verification is disabled. Proceeding with insecure request.")
response = requests.post(url, headers=headers, data=actual_payload, timeout=120, verify=False)
Dismissed Show dismissed Hide dismissed
response.raise_for_status()
except requests.exceptions.RequestException as req_err:
logging.error(f"An error occurred while sending the request: {req_err}")
raise

timestamp = datetime.now().strftime('%d-%m-%Y %H:%M:%S')
logging.info(f"Response received at {timestamp}")
Expand All @@ -98,6 +112,7 @@ def send_file_to_api(md_content, encoded_images, image_urls, url, token, full_pa
parser = argparse.ArgumentParser(description="Send markdown file to alttexter")
parser.add_argument("md_file_path", help="Path to file containing markdown formatted text.")
parser.add_argument("--full", action="store_true", help="Log the full payload instead of the summary")
parser.add_argument("--no-verify-ssl", action="store_true", help="Disable SSL certificate verification")

args = parser.parse_args()

Expand All @@ -117,5 +132,10 @@ def send_file_to_api(md_content, encoded_images, image_urls, url, token, full_pa
local_images, image_urls = extract_images_from_markdown(md_content)
encode_local_images(local_images, base_dir)

response = send_file_to_api(md_content, local_images, image_urls, url, token, args.full)
print(response)
verify_ssl = not args.no_verify_ssl
try:
response = send_file_to_api(md_content, local_images, image_urls, url, token, args.full, verify_ssl)
print(response)
except requests.exceptions.RequestException as e:
logging.error(f"Error occurred: {e}")
print(f"Failed to get a response from the server: {e}")
8 changes: 4 additions & 4 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ services:
volumes:
- ${ALTTEXTER_CERTS_DIR}:/certs
environment:
- LANGCHAIN_TRACING_V2
- LANGCHAIN_ENDPOINT
- LANGCHAIN_PROJECT
- LANGCHAIN_API_KEY
- LANGFUSE_TRACING
- LANGFUSE_PUBLIC_KEY
- LANGFUSE_SECRET_KEY
- LANGFUSE_HOST
- ALTTEXTER_MODEL
- OPENAI_API_KEY
- AZURE_OPENAI_ENDPOINT
Expand Down
3 changes: 2 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ pydantic==1.10.12
uvicorn==0.27.1
tiktoken==0.5.2
nbformat==5.9.2
cairosvg==2.7.0
cairosvg==2.7.0
langfuse==2.36.1