Skip to content
Snippets Groups Projects
Commit aea6b897 authored by Jan Eggers's avatar Jan Eggers
Browse files

main_tg gefixt

parent b71e39e4
No related branches found
No related tags found
No related merge requests found
No preview for this file type
......@@ -94,17 +94,22 @@ if __name__ == "__main__":
filename = f'tg-checks/{handle}.csv'
if os.path.exists(filename):
existing_df = reimport_csv(filename)
max_nr = max(existing_df['nr'])
print(f"Dieser Kanal wurde schon einmal ausgelesen, zuletzt Post Nr.: {max_nr} - seitdem {last_post-max_nr} neue Posts")
start_post = max(existing_df['nr'])
print(f"Dieser Kanal wurde schon einmal ausgelesen, zuletzt Post Nr.: {start_post} - seitdem {last_post-start_post} neue Posts")
else:
max_nr = last_post-N
start_post = last_post-N+1
print(f"Noch nicht gespeichert. Importiere {N} Posts bis zum letzten: {last_post}.")
# Lies die aktuellsten Posts, sichere und analysiere sie
#
print("Einlesen/mit KI beschreiben: ", end="")
posts = tgc_read_range(handle_str, max_nr+1, last_post)
print("Einlesen: ", end="")
posts = tgc_read_range(handle_str, start_post, last_post, save=False, describe= False)
print() # für die Fortschrittsmeldung
print("Inhalte sichern und mit KI beschreiben: ", end="")
hydrated_posts = tg_hydrate(posts)
print()
print("Auf KI-Inhalt prüfen: ",end="")
checked_posts = check_tg_list(posts, check_images = True)
# Bearbeitet nur die Posts, für die Inhalte hinterlegt sind
checked_posts = tg_evaluate(hydrated_posts)
#
n_images = 0
n_ai_images = 0
......@@ -118,16 +123,20 @@ if __name__ == "__main__":
# Detectora-Score für diesen Text abrufen; wenn über der Schwelle,
# KI-Texte um eins hochzählen
n_ai_texts += 1 if post.get('detectora_ai_score',0) > DETECTORA_T else 0
if post['photo'] is not None:
n_images += 1
ai_score = post.get('aiornot_ai_score',{'confidence': 0})['confidence']
n_ai_images += 1 if ai_score > AIORNOT_T else 0
if post['video'] is not None:
n_videos += 1
ai_score = post['aiornot_ai_score'].get('confidence', 0)
n_ai_videos += 1 if ai_score > AIORNOT_T else 0
elif post['photo'] is not None:
n_images += 1
ai_score = post.get('aiornot_ai_score')
if ai_score is None:
ai_score = 0
else:
ai_score = ai_score['confidence']
n_ai_images += 1 if ai_score > AIORNOT_T else 0
print(f"In den {N} Posts: ")
print(f"\n\nIn den {N} Posts: ")
print(f" - Texte: {n_texts}, davon KI-verdächtig: {n_ai_texts} (Schwelle: {DETECTORA_T})")
print(f" - Bilder: {n_images}, davon KI-verdächtig: {n_ai_images} (Schwelle: {AIORNOT_T})")
print(f"Ergebnis wird in 'tg-checks/{handle}.csv' mit abgespeichert. ")
......
......@@ -10,7 +10,7 @@ authors = [
maintainers = [
{name = "Jan Eggers", email = "jan.eggers@hr.de"},
]
version = "0.2.4.1" # Neue Versionsnummern für pip-Update
version = "0.2.4.2" # Neue Versionsnummern für pip-Update
description = "Bluesky- und Telegram-Konten auf KI-Inhalte checken"
requires-python = ">=3.8"
dependencies = [
......
......@@ -3,4 +3,4 @@ from .transcribe import ai_description, convert_mp4_to_mp3, convert_ogg_to_m4a,
from .detectora import query_detectora
from .aiornot import query_aiornot
from .check_wrappers import aiornot_wrapper, detectora_wrapper, bsky_aiornot_wrapper
from .check_tg import tgc_clean, tgc_read, tgc_blockread, tgc_read_url, tgc_profile, tgc_read_range, tgc_read_number, check_tg_list
\ No newline at end of file
from .check_tg import tgc_clean, tgc_read, tgc_blockread, tgc_read_url, tgc_profile, tgc_read_range, tgc_read_number, tg_evaluate, tg_hydrate
\ No newline at end of file
......@@ -360,7 +360,7 @@ def tgc_blockread(cname="telegram", nr=None, save=True, describe=False):
return posts
def tgc_read_range(cname, n1=1, n2=None, save=True, describe = True):
# Liest einen Bereich von Posts
# Liest einen Bereich von Post n1 bis Post n2
# Zuerst: Nummer des letzten Posts holen
profile = tgc_profile(cname)
# Sicherheitscheck: erste Post-Nummer überhaupt schon gepostet?
......@@ -372,15 +372,15 @@ def tgc_read_range(cname, n1=1, n2=None, save=True, describe = True):
n2 = max_nr
posts = []
while n <= n2:
max = n
max = n2
new_posts = tgc_blockread(cname, n, save, describe)
for p in new_posts:
if p['nr'] > n2:
return posts
if p['nr'] >= n:
posts.append(p)
if p['nr'] > max:
max = p['nr']
if p['nr'] == n2:
return posts
n = max
return posts
......@@ -418,19 +418,15 @@ def tgc_read_number(cname, n = 20, cutoff = None, save=True, describe = True):
# Routine checkt eine Post-Liste, wie sie aus den tgc_read... Routinen kommen.
# Wenn noch kein KI-Check vorliegt, wird er ergänzt.
# Setzt allerdings voraus, dass die entsprechenden Inhalte schon abgespeichert sind.
def check_tg_list(posts, check_images = True):
posts = [p for p in posts if p is not None]
for post in posts:
if 'detectora_ai_score' not in post:
# Noch keine KI-Einschätzung für den Text?
def tg_evaluate(posts, check_texts = True, check_images = True):
# Nimmt eine Liste von Posts und ergänzt KI-Einschätzung von Detectora
# und AIORNOT.
for post in posts:
if ('detectora_ai_score' not in post) and check_texts:
# Noch keine KI-Einschätzung für den Text?
post['detectora_ai_score'] = detectora_wrapper(post['text'])
# Leerzeile für den Fortschrittsbalken
print()
if not check_images:
return
# Okay, es geht weiter: Bilder auf KI prüfen
for post in posts:
if 'aiornot_ai_score' not in post:
if ('aiornot_ai_score' not in post) and check_images:
if post['video'] is not None:
# Audio des Videos analysieren
fname = post['video'].get('file')
......@@ -442,22 +438,35 @@ def check_tg_list(posts, check_images = True):
fname = post['voice'].get('file')
post['aiornot_ai_score'] = aiornot_wrapper(convert_ogg_to_mp3(fname), is_image = False)
return posts
# Wrapper für die check_tg_list Routine.
# Gibt Resultate als df zurück, arbeitet aber hinter den Kulissen mit
# einer Liste von dicts (anders als check_bsky)
def tg_hydrate(posts):
# Nimmt eine Liste von Posts und zieht die zugehörigen Dateien,
# erstellt Beschreibungen und Transkriptionen.
#
# Fernziel: Asynchrone Verarbeitung.
return posts
def tg_evaluate(posts, check_texts = True, check_images = True):
# Nimmt eine Liste von Posts und ergänzt KI-Einschätzung von Detectora
# und AIORNOT.
for post in posts:
for post in posts:
channel = post['channel']
b_nr = post['nr']
# Transcribe video and describe thumbnail
if post['video'] is not None and post['video'].get('file', None) is None:
# Save video to file
video_url = post['video'].get('url')
vfile = save_url(video_url, f"{channel}_{b_nr}_video")
post['video']['file'] = vfile
# Now transcribe video file
post['video']['transcription'] = transcribe(vfile)
# Fun fact: video also saves a thumbnail for good measure
if post['photo'] is not None and post['photo'].get('file', None) is None:
photo_url = post['photo']['url']
pfile = save_url(photo_url, f"{channel}_{b_nr}_photo")
post['photo']['file'] = pfile
image = base64.b64encode(requests.get(photo_url).content).decode('utf-8')
post['photo']['description'] = gpt4_description(f"data:image/jpeg;base64, {image}")
if post['voice'] is not None and post['voice'].get('file', None) is None:
voice_url = post['voice']['url']
vfile = save_url(voice_url, f"{channel}_{b_nr}_voice")
post['voice']['file'] = vfile
post['voice']['transcription'] = gpt4_description(vfile)
return posts
def retrieve_tg_csv(cname, path= "tg-checks"):
......
......@@ -8,7 +8,7 @@ import logging
# Installieren mit
# pip install aiornot
from aiornot import Client
from aiornot import Client, AsyncClient
# Konstante
d_thresh = .8 # 80 Prozent
......@@ -81,6 +81,41 @@ def aiornot_wrapper(content, is_image = True):
print("\b,")
return None
async def async_aiornot_wrapper(content, is_image = True):
# Create a client (reads AIORNOT_API_KEY env)
async_client = AsyncClient()
# Check if the API is up
if not await async_client.is_live():
logging.error("AIORNOT API nicht erreichbar")
exit(1)
# Check your token
resp = await async_client.check_token()
if not resp.is_valid:
logging.error("AIORNOT-API-Token nicht gültig")
exit(1)
is_url = (content.startswith("http://") or content.startswith("https://"))
if is_image:
if is_url:
response = await async_client.image_report_by_url(content)
else:
response = await async_client.image_report_by_file(content)
else: # (Audio)
if is_url:
response = await async_client.audio_report_by_url(content)
else:
response = await async_client.audio_report_by_file(content)
if response is None:
return response
else:
aiornot_dict = ({
'score': response.report.verdict,
# Unterscheidung: Bilder haben den Confidence score im Unter-Key 'ai'
# Audios SOLLTEN eien Confidence-Wert in response.report.confidence haben, haben es aber nicht
'confidence': response.report.ai.confidence if hasattr(response.report, 'ai') else .99,
'generator': object_to_dict(response.report.generator) if hasattr(response.report, 'generator') else None,
})
print(f"\b{'X' if aiornot_dict['score'] != 'human' else '.'}",end="")
return aiornot_dict
def bsky_aiornot_wrapper(did,embed):
# Verpackung für die AIORNOT-Funktion:
......
......@@ -19,7 +19,7 @@ Du erstellst eine deutsche Bildbeschreibung für den Alt-Text.
Beschreibe, was auf dem Bild zu sehen ist.
Beginne sofort mit der Beschreibung. Sei präzise und knapp.
Wenn das Bild lesbaren Text enthält, zitiere diesen Text."""
client = OpenAI(api_key = os.environ.get('OPENAI_API_KEY'))
# Use GPT-4 mini to describe images
OLLAMA = False
......@@ -27,6 +27,7 @@ def gpt4_description(image_url):
# Check a local image by converting it to b64:
# image_url = f"data:image/jpeg;base64, {b64_image}"
print(".", end="")
client = OpenAI(api_key = os.environ.get('OPENAI_API_KEY'))
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment