diff --git a/.github/workflows/test_gemini.yml b/.github/workflows/test_gemini.yml new file mode 100644 index 00000000..e5bf0520 --- /dev/null +++ b/.github/workflows/test_gemini.yml @@ -0,0 +1,33 @@ +name: test | gemini + +on: + workflow_dispatch: + pull_request: + types: [labeled, synchronize] + + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + run_simple_example_test: + uses: ./.github/workflows/reusable_python_example.yml + with: + example-location: ./examples/python/simple_example.py + secrets: + OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} + GRAPHISTRY_USERNAME: ${{ secrets.GRAPHISTRY_USERNAME }} + GRAPHISTRY_PASSWORD: ${{ secrets.GRAPHISTRY_PASSWORD }} + EMBEDDING_PROVIDER: "gemini" + EMBEDDING_API_KEY: ${{ secrets.GEMINI_API_KEY }} + EMBEDDING_MODEL: "gemini/text-embedding-004" + EMBEDDING_ENDPOINT: "https://generativelanguage.googleapis.com/v1beta/models/text-embedding-004" + EMBEDDING_API_VERSION: "v1beta" + EMBEDDING_DIMENSIONS: 768 + EMBEDDING_MAX_TOKENS: 8076 + LLM_PROVIDER: "gemini" + LLM_API_KEY: ${{ secrets.GEMINI_API_KEY }} + LLM_MODEL: "gemini/gemini-1.5-flash" + LLM_ENDPOINT: "https://generativelanguage.googleapis.com/" + LLM_API_VERSION: "v1beta" diff --git a/.github/workflows/test_ollama.yml b/.github/workflows/test_ollama.yml new file mode 100644 index 00000000..f0312a81 --- /dev/null +++ b/.github/workflows/test_ollama.yml @@ -0,0 +1,84 @@ +name: test | ollama + +on: + workflow_dispatch: + pull_request: + types: [ labeled, synchronize ] + +jobs: + + run_simple_example_test: + + runs-on: ubuntu-latest + services: + ollama: + image: ollama/ollama + ports: + - 11434:11434 + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: '3.12.x' + + - name: Install Poetry + uses: snok/install-poetry@v1.4.1 + with: + virtualenvs-create: true + virtualenvs-in-project: true + installer-parallel: true + + - name: Install dependencies + run: | + poetry install --no-interaction --all-extras + + - name: Install ollama + run: curl -fsSL https://ollama.com/install.sh | sh + - name: Run ollama + run: | + ollama serve & + ollama pull llama3.2 & + ollama pull avr/sfr-embedding-mistral:latest + - name: Call ollama API + run: | + curl -d '{"model": "llama3.2", "stream": false, "prompt":"Whatever I say, asnwer with Yes"}' http://localhost:11434/api/generate + + - name: Wait for Ollama to be ready + run: | + for i in {1..30}; do + if curl -s http://localhost:11434/api/tags > /dev/null; then + echo "Ollama is ready" + exit 0 + fi + echo "Waiting for Ollama... attempt $i" + sleep 2 + done + echo "Ollama failed to start" + exit 1 + + - name: Dump Docker logs + run: | + docker ps + docker logs $(docker ps --filter "ancestor=ollama/ollama" --format "{{.ID}}") + + + - name: Run example test + env: + OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} + GRAPHISTRY_USERNAME: ${{ secrets.GRAPHISTRY_USERNAME }} + GRAPHISTRY_PASSWORD: ${{ secrets.GRAPHISTRY_PASSWORD }} + PYTHONFAULTHANDLER: 1 + LLM_API_KEY: "ollama" + LLM_PROVIDER: "ollama" + LLM_ENDPOINT: "http://127.0.0.1:11434/api/generate" + LLM_MODEL: "ollama/llama3.2" + EMBEDDING_PROVIDER: "ollama" + EMBEDDING_MODEL: "avr/sfr-embedding-mistral:latest" + EMBEDDING_ENDPOINT: "http://127.0.0.1:11434/api/embeddings" + EMBEDDING_DIMENSIONS: "4096" + HUGGINGFACE_TOKENIZER: "Salesforce/SFR-Embedding-Mistral" + run: poetry run python ./examples/python/simple_example.py \ No newline at end of file diff --git a/.github/workflows/upgrade_deps.yml b/.github/workflows/upgrade_deps.yml index 934a3ed6..327ee08c 100644 --- a/.github/workflows/upgrade_deps.yml +++ b/.github/workflows/upgrade_deps.yml @@ -2,8 +2,29 @@ name: Update Poetry Dependencies on: schedule: - - cron: '0 3 * * 0' + - cron: '0 3 * * 0' # Runs at 3 AM every Sunday + push: + paths: + - 'poetry.lock' + - 'pyproject.toml' + branches: + - main + - dev + pull_request: + paths: + - 'poetry.lock' + - 'pyproject.toml' + types: [opened, synchronize, reopened] + branches: + - main + - dev workflow_dispatch: + inputs: + debug_enabled: + type: boolean + description: 'Run the update with debug logging' + required: false + default: false jobs: update-dependencies: diff --git a/cognee/infrastructure/llm/ollama/adapter.py b/cognee/infrastructure/llm/ollama/adapter.py index 4eb39273..ed0ef31b 100644 --- a/cognee/infrastructure/llm/ollama/adapter.py +++ b/cognee/infrastructure/llm/ollama/adapter.py @@ -1,20 +1,28 @@ +from sys import api_version from typing import Type from pydantic import BaseModel import instructor from cognee.infrastructure.llm.llm_interface import LLMInterface from cognee.infrastructure.llm.config import get_llm_config from openai import OpenAI - +import base64 +from pathlib import Path +import os class OllamaAPIAdapter(LLMInterface): - """Adapter for a Generic API LLM provider using instructor with an OpenAI backend.""" + """Adapter for a Ollama API LLM provider using instructor with an OpenAI backend.""" + + api_version: str + + MAX_RETRIES = 5 - def __init__(self, endpoint: str, api_key: str, model: str, name: str, max_tokens: int): + def __init__(self, endpoint: str, api_key: str, model: str, name: str, max_tokens: int, api_version: str = None) -> None: self.name = name self.model = model self.api_key = api_key self.endpoint = endpoint self.max_tokens = max_tokens + self.api_version= api_version self.aclient = instructor.from_openai( OpenAI(base_url=self.endpoint, api_key=self.api_key), mode=instructor.Mode.JSON @@ -42,3 +50,54 @@ async def acreate_structured_output( ) return response + + + def create_transcript(self, input): + """Generate a audio transcript from a user query.""" + + if not os.path.isfile(input): + raise FileNotFoundError(f"The file {input} does not exist.") + + # with open(input, 'rb') as audio_file: + # audio_data = audio_file.read() + + transcription = self.aclient.transcription( + model=self.transcription_model, + file=Path(input), + api_key=self.api_key, + api_base=self.endpoint, + api_version=self.api_version, + max_retries=self.MAX_RETRIES, + ) + + return transcription + + def transcribe_image(self, input) -> BaseModel: + with open(input, "rb") as image_file: + encoded_image = base64.b64encode(image_file.read()).decode("utf-8") + + return self.aclient.completion( + model=self.model, + messages=[ + { + "role": "user", + "content": [ + { + "type": "text", + "text": "What’s in this image?", + }, + { + "type": "image_url", + "image_url": { + "url": f"data:image/jpeg;base64,{encoded_image}", + }, + }, + ], + } + ], + api_key=self.api_key, + api_base=self.endpoint, + api_version=self.api_version, + max_tokens=300, + max_retries=self.MAX_RETRIES, + ) \ No newline at end of file