implement document view page
Run Tests / Run Tests (push) Successful in 44s
Details
Run Tests / Run Tests (push) Successful in 44s
Details
This commit is contained in:
parent
f7db98d91e
commit
9476c49139
|
@ -5,10 +5,9 @@ services:
|
||||||
- 5672:5672
|
- 5672:5672
|
||||||
- 15672:15672
|
- 15672:15672
|
||||||
|
|
||||||
|
|
||||||
vllm:
|
vllm:
|
||||||
image: vllm/vllm-openai:latest
|
image: vllm/vllm-openai:latest
|
||||||
command: "--model Qwen/Qwen2-VL-2B-Instruct-GPTQ-Int4 --quantization gptq"
|
command: "--model Qwen/Qwen2-VL-2B-Instruct-GPTQ-Int4 --quantization gptq "
|
||||||
volumes:
|
volumes:
|
||||||
- ~/.cache/huggingface:/root/.cache/huggingface
|
- ~/.cache/huggingface:/root/.cache/huggingface
|
||||||
ports:
|
ports:
|
||||||
|
|
|
@ -149,6 +149,7 @@ CELERY_BROKER_URL = "amqp://guest:guest@localhost/"
|
||||||
|
|
||||||
|
|
||||||
OPENAI_API_BASE = os.getenv("OPENAI_API_BASE")
|
OPENAI_API_BASE = os.getenv("OPENAI_API_BASE")
|
||||||
#OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
|
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
|
||||||
OPENAI_API_KEY = "test"
|
#OPENAI_API_KEY = "test"
|
||||||
OPENAI_MODEL = os.getenv("OPENAI_MODEL", "openai/gpt-4o")
|
OPENAI_MODEL = os.getenv("OPENAI_MODEL", "openai/gpt-4o")
|
||||||
|
#OPENAI_MODEL="ollama/llama3.2-vision"
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 4.2.16 on 2024-12-15 06:34
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('webui', '0005_imagememo_error_message'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='imagememo',
|
||||||
|
name='model_name',
|
||||||
|
field=models.CharField(max_length=255, null=True),
|
||||||
|
),
|
||||||
|
]
|
|
@ -3,6 +3,7 @@ from django.contrib.auth.base_user import BaseUserManager
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
|
from email.header import Charset
|
||||||
|
|
||||||
|
|
||||||
class UserManager(BaseUserManager):
|
class UserManager(BaseUserManager):
|
||||||
|
@ -58,6 +59,8 @@ class ImageMemo(models.Model):
|
||||||
|
|
||||||
author = models.ForeignKey("User", on_delete=models.CASCADE, related_name="memos")
|
author = models.ForeignKey("User", on_delete=models.CASCADE, related_name="memos")
|
||||||
|
|
||||||
|
model_name = models.CharField(max_length=255, null=True)
|
||||||
|
|
||||||
created_at = models.DateTimeField(auto_now_add=True)
|
created_at = models.DateTimeField(auto_now_add=True)
|
||||||
updated_at = models.DateTimeField(
|
updated_at = models.DateTimeField(
|
||||||
auto_now=True,
|
auto_now=True,
|
||||||
|
|
|
@ -16,6 +16,12 @@ If any words or letters are unclear, denote them with a '?<word>?'.
|
||||||
|
|
||||||
For example if you were not sure whether a word is blow or blew you would transcribe it as '?blow?'
|
For example if you were not sure whether a word is blow or blew you would transcribe it as '?blow?'
|
||||||
|
|
||||||
|
If a text is underlined followed by a newline that indicates that it is a header. Use markdown H2 to denote it as such.
|
||||||
|
|
||||||
|
Make sure to add 2 newlines newlines between sections.
|
||||||
|
|
||||||
|
Anything that looks visually like a bullet point should be treated as such. This includes lines starting with hyphens. Replace bullet point indicators with * in the interpretted text.
|
||||||
|
|
||||||
Please include whitespace and formatting for headings too.
|
Please include whitespace and formatting for headings too.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
|
@ -1,181 +1,200 @@
|
||||||
{% extends "main.html" %} {% load markdown_deux_tags %} {% load markdownify %}
|
{% extends "main.html" %} {% load markdown_deux_tags %} {% load markdownify %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<section class="max-w-6xl mx-auto px-4 py-8">
|
<section class="max-w-6xl mx-auto px-4 py-8">
|
||||||
<h1 class="text-3xl font-bold text-gray-900 mb-6">Document View</h1>
|
<h1 class="text-3xl font-bold text-gray-900 mb-6">Document View</h1>
|
||||||
<div class="bg-white shadow-md rounded-lg overflow-hidden">
|
<div class="bg-white shadow-md rounded-lg overflow-hidden">
|
||||||
<div class="p-6">
|
<div class="p-6">
|
||||||
<div class="flex flex-col lg:flex-row gap-8">
|
<div class="flex flex-col lg:flex-row gap-8">
|
||||||
<div class="w-full lg:w-1/2">
|
<div class="w-full lg:w-1/2">
|
||||||
<h2 class="text-2xl font-semibold text-gray-800 mb-4">
|
<h2 class="text-2xl font-semibold text-gray-800 mb-4">
|
||||||
{{ document.title }}
|
{{ document.title }}
|
||||||
</h2>
|
</h2>
|
||||||
<div class="mb-4">
|
<div class="mb-4">
|
||||||
<table class="w-full text-sm">
|
<table class="w-full text-sm">
|
||||||
<tr>
|
<tr>
|
||||||
<td class="font-medium pr-4">Status:</td>
|
<td class="font-medium pr-4">Status:</td>
|
||||||
<td>
|
<td>
|
||||||
<span
|
<span
|
||||||
class="px-3 py-1 text-sm font-medium rounded-full {% if document.status == 'pending' %} bg-gray-200 text-gray-800 {% elif document.status == 'processing' %} bg-blue-200 text-blue-800 {% elif document.status == 'done' %} bg-green-200 text-green-800 {% elif document.status == 'error' %} bg-red-200 text-red-800 {% endif %}"
|
class="px-3 py-1 text-sm font-medium rounded-full {% if document.status == 'pending' %} bg-gray-200 text-gray-800 {% elif document.status == 'processing' %} bg-blue-200 text-blue-800 {% elif document.status == 'done' %} bg-green-200 text-green-800 {% elif document.status == 'error' %} bg-red-200 text-red-800 {% endif %}"
|
||||||
>
|
>
|
||||||
{{ document.status|title }}
|
{{ document.status|title }}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="font-medium pr-4">Created:</td>
|
<td class="font-medium pr-4">Created:</td>
|
||||||
<td class="text-gray-600">{{ document.created_at|date:"d/m/Y H:i" }}</td>
|
<td class="text-gray-600">
|
||||||
</tr>
|
{{ document.created_at|date:"d/m/Y H:i:s" }}
|
||||||
<tr>
|
</td>
|
||||||
<td class="font-medium pr-4">Updated:</td>
|
</tr>
|
||||||
<td class="text-gray-600">{{ document.updated_at|date:"d/m/Y H:i" }}</td>
|
<tr>
|
||||||
</tr>
|
<td class="font-medium pr-4">Updated:</td>
|
||||||
</table>
|
<td class="text-gray-600">
|
||||||
</div>
|
{{ document.updated_at|date:"d/m/Y H:i:s" }}
|
||||||
<div class="prose max-w-full">
|
</td>
|
||||||
<div class="flex justify-between items-center mb-3">
|
</tr>
|
||||||
<h3 class="text-xl font-semibold text-gray-800">Content:</h3>
|
</table>
|
||||||
<button
|
</div>
|
||||||
id="copyButton"
|
<div class="prose max-w-full">
|
||||||
class="bg-gray-200 text-gray-700 px-3 py-1 rounded-md hover:bg-gray-300 transition duration-300 flex items-center text-sm"
|
<div class="flex justify-between items-center mb-3">
|
||||||
>
|
<h3 class="text-xl font-semibold text-gray-800">
|
||||||
<svg
|
Content:
|
||||||
class="w-4 h-4 mr-2"
|
</h3>
|
||||||
fill="none"
|
<button
|
||||||
stroke="currentColor"
|
id="copyButton"
|
||||||
viewBox="0 0 24 24"
|
class="bg-gray-200 text-gray-700 px-3 py-1 rounded-md hover:bg-gray-300 transition duration-300 flex items-center text-sm"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
>
|
||||||
>
|
<svg
|
||||||
<path
|
class="w-4 h-4 mr-2"
|
||||||
stroke-linecap="round"
|
fill="none"
|
||||||
stroke-linejoin="round"
|
stroke="currentColor"
|
||||||
stroke-width="2"
|
viewBox="0 0 24 24"
|
||||||
d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
></path>
|
>
|
||||||
</svg>
|
<path
|
||||||
Copy to Clipboard
|
stroke-linecap="round"
|
||||||
</button>
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"
|
||||||
|
></path>
|
||||||
|
</svg>
|
||||||
|
Copy to Clipboard
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
id="markdown-rendered"
|
||||||
|
class="bg-gray-50 p-4 rounded-md"
|
||||||
|
>
|
||||||
|
{{ markup|safe }}
|
||||||
|
</div>
|
||||||
|
<div id="markdown-content" class="hidden">
|
||||||
|
{{ document.content}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mt-8 flex space-x-4">
|
||||||
|
<a
|
||||||
|
href="{% url 'download_document' document.id %}"
|
||||||
|
class="bg-blue-600 text-white px-4 py-2 rounded-md hover:bg-blue-700 transition duration-300 flex items-center"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
class="w-5 h-5 mr-2"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"
|
||||||
|
></path>
|
||||||
|
</svg>
|
||||||
|
Export
|
||||||
|
</a>
|
||||||
|
<form
|
||||||
|
action="{% url 'delete_document' document.id %}"
|
||||||
|
method="post"
|
||||||
|
onsubmit="return confirm('Are you sure you want to delete this document?');"
|
||||||
|
>
|
||||||
|
{% csrf_token %}
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
class="bg-red-600 text-white px-4 py-2 rounded-md hover:bg-red-700 transition duration-300 flex items-center"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
class="w-5 h-5 mr-2"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"
|
||||||
|
></path>
|
||||||
|
</svg>
|
||||||
|
Delete
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="w-full lg:w-1/2">
|
||||||
|
<div class="bg-gray-100 rounded-lg overflow-hidden">
|
||||||
|
<img
|
||||||
|
src="{% url 'document_image' pk=document.id %}"
|
||||||
|
alt="{{ document.title }}"
|
||||||
|
class="w-full h-auto object-contain"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="markdown-rendered" class="bg-gray-50 p-4 rounded-md">
|
|
||||||
{{ document.content|markdown }}
|
|
||||||
</div>
|
|
||||||
<div id="markdown-content" class="hidden">{{ document.content}}</div>
|
|
||||||
</div>
|
|
||||||
<div class="mt-8 flex space-x-4">
|
|
||||||
<a
|
|
||||||
href="{% url 'download_document' document.id %}"
|
|
||||||
class="bg-blue-600 text-white px-4 py-2 rounded-md hover:bg-blue-700 transition duration-300 flex items-center"
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
class="w-5 h-5 mr-2"
|
|
||||||
fill="none"
|
|
||||||
stroke="currentColor"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
stroke-linecap="round"
|
|
||||||
stroke-linejoin="round"
|
|
||||||
stroke-width="2"
|
|
||||||
d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"
|
|
||||||
></path>
|
|
||||||
</svg>
|
|
||||||
Export
|
|
||||||
</a>
|
|
||||||
<form
|
|
||||||
action="{% url 'delete_document' document.id %}"
|
|
||||||
method="post"
|
|
||||||
onsubmit="return confirm('Are you sure you want to delete this document?');"
|
|
||||||
>
|
|
||||||
{% csrf_token %}
|
|
||||||
<button
|
|
||||||
type="submit"
|
|
||||||
class="bg-red-600 text-white px-4 py-2 rounded-md hover:bg-red-700 transition duration-300 flex items-center"
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
class="w-5 h-5 mr-2"
|
|
||||||
fill="none"
|
|
||||||
stroke="currentColor"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
stroke-linecap="round"
|
|
||||||
stroke-linejoin="round"
|
|
||||||
stroke-width="2"
|
|
||||||
d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"
|
|
||||||
></path>
|
|
||||||
</svg>
|
|
||||||
Delete
|
|
||||||
</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="w-full lg:w-1/2">
|
|
||||||
<div class="bg-gray-100 rounded-lg overflow-hidden">
|
|
||||||
<img
|
|
||||||
src="{% url 'document_image' pk=document.id %}"
|
|
||||||
alt="{{ document.title }}"
|
|
||||||
class="w-full h-auto object-contain"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</section>
|
</section>
|
||||||
<section class="max-w-6xl mx-auto px-4 py-4">
|
<section class="max-w-6xl mx-auto px-4 py-4">
|
||||||
<a
|
<a
|
||||||
href="{% url 'dashboard' %}"
|
href="{% url 'dashboard' %}"
|
||||||
class="text-blue-600 hover:text-blue-800 flex items-center"
|
class="text-blue-600 hover:text-blue-800 flex items-center"
|
||||||
>
|
|
||||||
<svg
|
|
||||||
class="w-5 h-5 mr-2"
|
|
||||||
fill="none"
|
|
||||||
stroke="currentColor"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
>
|
||||||
<path
|
<svg
|
||||||
stroke-linecap="round"
|
class="w-5 h-5 mr-2"
|
||||||
stroke-linejoin="round"
|
fill="none"
|
||||||
stroke-width="2"
|
stroke="currentColor"
|
||||||
d="M10 19l-7-7m0 0l7-7m-7 7h18"
|
viewBox="0 0 24 24"
|
||||||
></path>
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
</svg>
|
>
|
||||||
Back to Dashboard
|
<path
|
||||||
</a>
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
d="M10 19l-7-7m0 0l7-7m-7 7h18"
|
||||||
|
></path>
|
||||||
|
</svg>
|
||||||
|
Back to Dashboard
|
||||||
|
</a>
|
||||||
</section>
|
</section>
|
||||||
{% endblock %} {% block extra_js %}
|
{% endblock %} {% block extra_js %}
|
||||||
<script>
|
<script>
|
||||||
document.addEventListener("DOMContentLoaded", (event) => {
|
document.addEventListener("DOMContentLoaded", (event) => {
|
||||||
// Syntax highlighting
|
// Syntax highlighting
|
||||||
document.querySelectorAll("#markdown-content pre code").forEach((block) => {
|
document
|
||||||
hljs.highlightElement(block);
|
.querySelectorAll("#markdown-content pre code")
|
||||||
});
|
.forEach((block) => {
|
||||||
|
hljs.highlightElement(block);
|
||||||
|
});
|
||||||
|
|
||||||
// Copy to clipboard functionality
|
// Copy to clipboard functionality
|
||||||
const copyButton = document.getElementById("copyButton");
|
const copyButton = document.getElementById("copyButton");
|
||||||
const markdownContent = document.getElementById("markdown-content");
|
const markdownContent = document.getElementById("markdown-content");
|
||||||
|
|
||||||
copyButton.addEventListener("click", () => {
|
copyButton.addEventListener("click", () => {
|
||||||
const textToCopy = markdownContent.innerText;
|
const textToCopy = markdownContent.innerText;
|
||||||
navigator.clipboard
|
navigator.clipboard
|
||||||
.writeText(textToCopy)
|
.writeText(textToCopy)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
copyButton.textContent = "Copied!";
|
copyButton.textContent = "Copied!";
|
||||||
copyButton.classList.remove("bg-gray-200", "text-gray-700");
|
copyButton.classList.remove("bg-gray-200", "text-gray-700");
|
||||||
copyButton.classList.add("bg-green-500", "text-white");
|
copyButton.classList.add("bg-green-500", "text-white");
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
copyButton.innerHTML =
|
copyButton.innerHTML =
|
||||||
'<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"></path></svg>Copy to Clipboard';
|
'<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"></path></svg>Copy to Clipboard';
|
||||||
copyButton.classList.remove("bg-green-500", "text-white");
|
copyButton.classList.remove(
|
||||||
copyButton.classList.add("bg-gray-200", "text-gray-700");
|
"bg-green-500",
|
||||||
}, 2000);
|
"text-white",
|
||||||
})
|
);
|
||||||
.catch((err) => {
|
copyButton.classList.add(
|
||||||
console.error("Failed to copy text: ", err);
|
"bg-gray-200",
|
||||||
|
"text-gray-700",
|
||||||
|
);
|
||||||
|
}, 2000);
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.error("Failed to copy text: ", err);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
import markdown
|
||||||
|
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.shortcuts import redirect, render
|
from django.shortcuts import redirect, render
|
||||||
|
@ -61,13 +62,15 @@ def view_document(request: HttpRequest, pk: str):
|
||||||
# find document with given ID (pk path param) and current user id
|
# find document with given ID (pk path param) and current user id
|
||||||
document = ImageMemo.objects.filter(id=pk, author__id=request.user.id).first()
|
document = ImageMemo.objects.filter(id=pk, author__id=request.user.id).first()
|
||||||
|
|
||||||
|
doc_markup = markdown.markdown(document.content)
|
||||||
|
|
||||||
if not document:
|
if not document:
|
||||||
logger.debug(f"No memo found for user={request.user.id} and memo_id={pk}")
|
logger.debug(f"No memo found for user={request.user.id} and memo_id={pk}")
|
||||||
return HttpResponse(content="Document not found", status=404)
|
return HttpResponse(content="Document not found", status=404)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return render(request, "document.html", context={"document": document})
|
return render(request, "document.html", context={"document": document, "markup": doc_markup})
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
|
|
|
@ -11,6 +11,7 @@ dependencies = [
|
||||||
"django>=4.2.16",
|
"django>=4.2.16",
|
||||||
"litellm>=1.54.1",
|
"litellm>=1.54.1",
|
||||||
"loguru>=0.7.3",
|
"loguru>=0.7.3",
|
||||||
|
"markdown>=3.7",
|
||||||
"pillow>=11.0.0",
|
"pillow>=11.0.0",
|
||||||
"pytest-django>=4.9.0",
|
"pytest-django>=4.9.0",
|
||||||
"pytest-loguru>=0.4.0",
|
"pytest-loguru>=0.4.0",
|
||||||
|
|
2
uv.lock
2
uv.lock
|
@ -1002,6 +1002,7 @@ dependencies = [
|
||||||
{ name = "django-markdownify" },
|
{ name = "django-markdownify" },
|
||||||
{ name = "litellm" },
|
{ name = "litellm" },
|
||||||
{ name = "loguru" },
|
{ name = "loguru" },
|
||||||
|
{ name = "markdown" },
|
||||||
{ name = "pillow" },
|
{ name = "pillow" },
|
||||||
{ name = "pytest" },
|
{ name = "pytest" },
|
||||||
{ name = "pytest-django" },
|
{ name = "pytest-django" },
|
||||||
|
@ -1018,6 +1019,7 @@ requires-dist = [
|
||||||
{ name = "django-markdownify", specifier = ">=0.9.5" },
|
{ name = "django-markdownify", specifier = ">=0.9.5" },
|
||||||
{ name = "litellm", specifier = ">=1.54.1" },
|
{ name = "litellm", specifier = ">=1.54.1" },
|
||||||
{ name = "loguru", specifier = ">=0.7.3" },
|
{ name = "loguru", specifier = ">=0.7.3" },
|
||||||
|
{ name = "markdown", specifier = ">=3.7" },
|
||||||
{ name = "pillow", specifier = ">=11.0.0" },
|
{ name = "pillow", specifier = ">=11.0.0" },
|
||||||
{ name = "pytest", specifier = ">=8.3.4" },
|
{ name = "pytest", specifier = ">=8.3.4" },
|
||||||
{ name = "pytest-django", specifier = ">=4.9.0" },
|
{ name = "pytest-django", specifier = ">=4.9.0" },
|
||||||
|
|
Loading…
Reference in New Issue