-
Notifications
You must be signed in to change notification settings - Fork 966
feat: Draft ollama test #566
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
Changes from all commits
c572e27
2de364b
8ebd9a7
9d0d96e
b4088be
b670697
bfe039d
6bc4f6a
96adcfb
c06c28d
edd681f
02b0109
a91e83e
326c418
92602aa
f2d0909
97465f1
73662b8
90d96aa
3a88b94
11442df
1dfb0dd
4c4723b
846c45e
2c0bfc8
91512cd
5c7b4a5
7a85e71
0bba1f8
061fbbd
0ed6aa6
3090333
80ccf55
ce8c2da
65927b3
6463c2e
70f9b5f
468268c
c72b12d
c224556
ec9bbca
cabbfd6
c329cef
44f02df
6b49078
fe7da60
a77655a
cfc93e3
647d872
01bb8cb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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" | ||
|
Comment on lines
+18
to
+33
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Secrets Mismatch with Reusable Workflow The job passes several secrets that are not defined in the reusable workflow (
Please either update the reusable workflow file to accept these additional secrets (if they are necessary for the workflow’s operation) or remove them from here to avoid potential configuration issues. 🧰 Tools🪛 actionlint (1.7.4)22-22: secret "EMBEDDING_PROVIDER" is not defined in "./.github/workflows/reusable_python_example.yml" reusable workflow. defined secrets are "GRAPHISTRY_PASSWORD", "GRAPHISTRY_USERNAME", "LLM_API_KEY", "OPENAI_API_KEY" (workflow-call) 23-23: secret "EMBEDDING_API_KEY" is not defined in "./.github/workflows/reusable_python_example.yml" reusable workflow. defined secrets are "GRAPHISTRY_PASSWORD", "GRAPHISTRY_USERNAME", "LLM_API_KEY", "OPENAI_API_KEY" (workflow-call) 24-24: secret "EMBEDDING_MODEL" is not defined in "./.github/workflows/reusable_python_example.yml" reusable workflow. defined secrets are "GRAPHISTRY_PASSWORD", "GRAPHISTRY_USERNAME", "LLM_API_KEY", "OPENAI_API_KEY" (workflow-call) 25-25: secret "EMBEDDING_ENDPOINT" is not defined in "./.github/workflows/reusable_python_example.yml" reusable workflow. defined secrets are "GRAPHISTRY_PASSWORD", "GRAPHISTRY_USERNAME", "LLM_API_KEY", "OPENAI_API_KEY" (workflow-call) 26-26: secret "EMBEDDING_API_VERSION" is not defined in "./.github/workflows/reusable_python_example.yml" reusable workflow. defined secrets are "GRAPHISTRY_PASSWORD", "GRAPHISTRY_USERNAME", "LLM_API_KEY", "OPENAI_API_KEY" (workflow-call) 27-27: secret "EMBEDDING_DIMENSIONS" is not defined in "./.github/workflows/reusable_python_example.yml" reusable workflow. defined secrets are "GRAPHISTRY_PASSWORD", "GRAPHISTRY_USERNAME", "LLM_API_KEY", "OPENAI_API_KEY" (workflow-call) 28-28: secret "EMBEDDING_MAX_TOKENS" is not defined in "./.github/workflows/reusable_python_example.yml" reusable workflow. defined secrets are "GRAPHISTRY_PASSWORD", "GRAPHISTRY_USERNAME", "LLM_API_KEY", "OPENAI_API_KEY" (workflow-call) 29-29: secret "LLM_PROVIDER" is not defined in "./.github/workflows/reusable_python_example.yml" reusable workflow. defined secrets are "GRAPHISTRY_PASSWORD", "GRAPHISTRY_USERNAME", "LLM_API_KEY", "OPENAI_API_KEY" (workflow-call) 31-31: secret "LLM_MODEL" is not defined in "./.github/workflows/reusable_python_example.yml" reusable workflow. defined secrets are "GRAPHISTRY_PASSWORD", "GRAPHISTRY_USERNAME", "LLM_API_KEY", "OPENAI_API_KEY" (workflow-call) 32-32: secret "LLM_ENDPOINT" is not defined in "./.github/workflows/reusable_python_example.yml" reusable workflow. defined secrets are "GRAPHISTRY_PASSWORD", "GRAPHISTRY_USERNAME", "LLM_API_KEY", "OPENAI_API_KEY" (workflow-call) 33-33: secret "LLM_API_VERSION" is not defined in "./.github/workflows/reusable_python_example.yml" reusable workflow. defined secrets are "GRAPHISTRY_PASSWORD", "GRAPHISTRY_USERNAME", "LLM_API_KEY", "OPENAI_API_KEY" (workflow-call) |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,116 @@ | ||
| name: test | ollama | ||
|
|
||
| on: | ||
| workflow_dispatch: | ||
| pull_request: | ||
| types: [ labeled, synchronize ] | ||
|
|
||
| jobs: | ||
|
|
||
| run_simple_example_test: | ||
|
|
||
| # needs 16 Gb RAM for phi4 | ||
| runs-on: buildjet-4vcpu-ubuntu-2204 | ||
| # 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/[email protected] | ||
| with: | ||
| virtualenvs-create: true | ||
| virtualenvs-in-project: true | ||
| installer-parallel: true | ||
|
|
||
| - name: Install dependencies | ||
| run: | | ||
| poetry install --no-interaction --all-extras | ||
| poetry add torch | ||
|
|
||
| # - name: Install ollama | ||
| # run: curl -fsSL https://ollama.com/install.sh | sh | ||
| # - name: Run ollama | ||
| # run: | | ||
| # ollama serve --openai & | ||
| # ollama pull llama3.2 & | ||
| # ollama pull avr/sfr-embedding-mistral:latest | ||
|
|
||
| - name: Start Ollama container | ||
| run: | | ||
| docker run -d --name ollama -p 11434:11434 ollama/ollama | ||
| sleep 5 | ||
| docker exec -d ollama bash -c "ollama serve --openai" | ||
|
|
||
| - name: Check Ollama logs | ||
| run: docker logs ollama | ||
|
|
||
| - name: Wait for Ollama to be ready | ||
| run: | | ||
| for i in {1..30}; do | ||
| if curl -s http://localhost:11434/v1/models > /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: Pull required Ollama models | ||
| run: | | ||
| curl -X POST http://localhost:11434/api/pull -d '{"name": "phi4"}' | ||
| curl -X POST http://localhost:11434/api/pull -d '{"name": "avr/sfr-embedding-mistral:latest"}' | ||
|
|
||
| - name: Call ollama API | ||
| run: | | ||
| curl -X POST http://localhost:11434/v1/chat/completions \ | ||
| -H "Content-Type: application/json" \ | ||
| -d '{ | ||
| "model": "phi4", | ||
| "stream": false, | ||
| "messages": [ | ||
| { "role": "system", "content": "You are a helpful assistant." }, | ||
| { "role": "user", "content": "Whatever I say, answer with Yes." } | ||
| ] | ||
| }' | ||
| curl -X POST http://127.0.0.1:11434/v1/embeddings \ | ||
| -H "Content-Type: application/json" \ | ||
| -d '{ | ||
| "model": "avr/sfr-embedding-mistral:latest", | ||
| "input": "This is a test sentence to generate an embedding." | ||
| }' | ||
|
|
||
| - 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_PROVIDER: "ollama" | ||
| LLM_API_KEY: "ollama" | ||
| LLM_ENDPOINT: "http://localhost:11434/v1/" | ||
| LLM_MODEL: "phi4" | ||
| EMBEDDING_PROVIDER: "ollama" | ||
| EMBEDDING_MODEL: "avr/sfr-embedding-mistral:latest" | ||
| EMBEDDING_ENDPOINT: "http://localhost:11434/v1/" | ||
| EMBEDDING_DIMENSIONS: "4096" | ||
| HUGGINGFACE_TOKENIZER: "Salesforce/SFR-Embedding-Mistral" | ||
| run: poetry run python ./examples/python/simple_example.py |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -4,6 +4,8 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from cognee.infrastructure.llm.llm_interface import LLMInterface | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from cognee.infrastructure.llm.config import get_llm_config | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from openai import OpenAI | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import base64 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import os | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| class OllamaAPIAdapter(LLMInterface): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -42,3 +44,54 @@ async def acreate_structured_output( | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return response | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def create_transcript(self, input_file: str) -> str: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| """Generate an audio transcript from a user query.""" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if not os.path.isfile(input_file): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| raise FileNotFoundError(f"The file {input_file} does not exist.") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| with open(input_file, "rb") as audio_file: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| transcription = self.aclient.audio.transcriptions.create( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| model="whisper-1", # Ensure the correct model for transcription | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| file=audio_file, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| language="en", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Ensure the response contains a valid transcript | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if not hasattr(transcription, "text"): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| raise ValueError("Transcription failed. No text returned.") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return transcription.text | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+48
to
+65
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Verification agent 🧩 Analysis chainFix issues in the audio transcription implementation. This implementation has multiple critical issues:
def create_transcript(self, input_file: str) -> str:
"""Generate an audio transcript from a user query."""
if not os.path.isfile(input_file):
raise FileNotFoundError(f"The file {input_file} does not exist.")
- with open(input_file, "rb") as audio_file:
- transcription = self.aclient.audio.transcriptions.create(
- model="whisper-1", # Ensure the correct model for transcription
- file=audio_file,
- language="en",
- )
-
- # Ensure the response contains a valid transcript
- if not hasattr(transcription, "text"):
- raise ValueError("Transcription failed. No text returned.")
-
- return transcription.text
+ try:
+ with open(input_file, "rb") as audio_file:
+ transcription = self.client.audio.transcriptions.create(
+ model="whisper-1", # Ensure the correct model for transcription
+ file=audio_file,
+ language="en",
+ max_retries=self.MAX_RETRIES,
+ )
+
+ # Ensure the response contains a valid transcript
+ if not hasattr(transcription, "text"):
+ raise ValueError("Transcription failed. No text returned.")
+
+ return transcription.text
+ except Exception as e:
+ raise Exception(f"Error transcribing audio: {str(e)}")🌐 Web query: 💡 Result: Ollama does not natively support OpenAI-compatible audio transcription APIs like Whisper. However, developers can combine Ollama with OpenAI's Whisper API or third-party tools to achieve this functionality[1][3][7]. Here's how it works:
For direct audio API support, developers currently need to use OpenAI's services or third-party solutions alongside Ollama's text capabilities[1][3][7]. The native Ollama API focuses on text generation through its OpenAI-compatible chat endpoints[2][5][8]. Citations:
Critical: Audio Transcription Implementation Requires Revision The recent changes correctly update the client reference (from
Affected Code Location:
📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def transcribe_image(self, input_file: str) -> str: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| """Transcribe content from an image using base64 encoding.""" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if not os.path.isfile(input_file): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| raise FileNotFoundError(f"The file {input_file} does not exist.") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| with open(input_file, "rb") as image_file: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| encoded_image = base64.b64encode(image_file.read()).decode("utf-8") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| response = self.aclient.chat.completions.create( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix undefined client reference. The code uses -response = self.aclient.chat.completions.create(
+response = self.client.chat.completions.create(📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 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}"}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+81
to
+88
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Verification agent 🧩 Analysis chainVerify Ollama supports multimodal content in this format. The implementation assumes Ollama supports OpenAI's multimodal message format. Verify that Ollama's API accepts this structure for image analysis. 🌐 Web query: 💡 Result: Ollama supports image analysis using base64-encoded images through its vision models like LLaVA and Llama 3.2 Vision, though implementation details differ slightly from OpenAI's approach. Here's how it works: Base64 Image Handling
Key Differences from OpenAI
Supported Use Cases
To implement this with Llama 3.2 Vision: ollama run llama3.2-visionThen use either file paths or base64 strings in your API calls[9][10]. The system supports both CLI and programmatic access through Python/JavaScript libraries[7][9]. Citations:
Action: Update Image Handling to Meet Ollama API Requirements We've confirmed that while Ollama does support image analysis with base64-encoded images, it requires some important adjustments compared to OpenAI’s multimodal message format:
Please update the code in |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| max_tokens=300, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Ensure response is valid before accessing .choices[0].message.content | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if not hasattr(response, "choices") or not response.choices: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| raise ValueError("Image transcription failed. No response received.") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return response.choices[0].message.content | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indentation is not consistent.