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

Phase-1-Proof-of-concept

parent 60ba0c11
No related branches found
No related tags found
No related merge requests found
.DS_Store 0 → 100644
File added
# Runtime results
bsky-checks/
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
......@@ -130,30 +133,9 @@ ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
......
,janeggers,untergeekPro.local,28.12.2024 09:30,file:///Users/janeggers/Library/Application%20Support/LibreOffice/4;
\ No newline at end of file
......@@ -8,22 +8,23 @@ Das Fernziel ist eine Recherche zu KI-Inhalten im Wahlkampf mit zwei Stoßrichtu
- Verdachtsfälle besonders krasser Fälschungen finden
- Gesamt-KI-Anteil nach Partei/Person
## Der Plan
## Wie einsetzen?
### Phase 1: Bluesky
- Mit ```git clone github.com/JanEggers-hr/aichecker``` in ein Verzeichnis klonen
- In dem Verzeichnis eine ```.env``` Datei anlegen mit den Keys:
```
OPENAI_API_KEY="" # für die Bildbeschreibungen
DETECTORA_API_KEY="" # für die Textanalyse
AIORNOT_API_KEY="" # für die Bildanalyse
```
- Programm im Verzeichnis starten mit ```python check_bsky_profile.py````
- Beliebiges Account vier Wochen scannen
- AIorNot-API einbauen https://docs.aiornot.com/
- Videos checken:
- Audiospur extrahieren
- Audiospur checken
- hive-API einbauen
- Ausgabe: Vermuteter KI-Anteil
Programm ist voreingestellt auf 20 Posts. (Sonst die Variable limit in Zeile 15 von check_bsky_profile.py ändern.) Die Schwelle für einen "echten" KI-Text-Post ist auf 80% (0.8) eingestellt.
### Phase 2: Chemtrail App
- Dash-App auf dem Server zum Check eines Handles
Das Skript legt im Verzeichnis ```bsky-checks``` eine CSV-Datei mit der Analyse nach Posts an, mit dem Namen des Profils: {handle}.CSV
### Phase 3: 4CAT
- 4CAT-Server aufsetzen
- "processor" für KI-Check einbauen
-
## Achtung!
- Die Detectora-API setzt ein älteres Modell ein, das die GPT4-Erkennung nicht so gut schafft.
- AIORNOT ist teuer! Standardmodell: 100 API-Calls pro Monat für 5$ (bei Abschluss Jahresabo)
- Immer dran denken: Die Detektoren liefern Wahrscheinlichkeiten, keine Gewissheiten.
# App: Chemtrail
## Auswertung
- Anzahl verdächtige Texte
- Anzahl verdächtige Bilder
- Check bis Datum
## UI
- Dash-App
......@@ -14,3 +10,10 @@
- Anzeige Ergebnisse letzter Check
- Neue Posts holen und auswerten
- CSV aktualisieren und Download-Link anbieten
## Telegram
- Umbau auf Telegram-Channel
## 4CAT
- 4Cat-Server aufsetzen
- "Processor" schreiben
# NOT RUN
# Define the global posts list
posts = []
# Nicking the code to read from the bsky firehose here:
# https://gist.github.com/stuartlangridge/20ffe860fee0ecc315d3878c1ea77c35
def append_post(json_data):
# Parse JSON data and append to
#
# Basic idea:
# - Get a feed.
# - Collect basic data on the author
# - Collect four weeks' posts
# - Analyse each post:
# - Check text with Hive and Detectora
# - Check images with Hive and AIorNot
# - Check video by isolating audio to AIorNot
import json
from atproto_client.models import get_or_create
from atproto import CAR, models
from atproto_firehose import FirehoseSubscribeReposClient, parse_subscribe_repos_message
class JSONExtra(json.JSONEncoder):
"""raw objects sometimes contain CID() objects, which
seem to be references to something elsewhere in bluesky.
So, we 'serialise' these as a string representation,
which is a hack but whatevAAAAR"""
def default(self, obj):
try:
result = json.JSONEncoder.default(self, obj)
return result
except:
return repr(obj)
client = FirehoseSubscribeReposClient()
# all of this undocumented horseshit is based on cargo-culting the bollocks out of
# https://github.com/MarshalX/atproto/blob/main/examples/firehose/sub_repos.py
# and
# https://github.com/MarshalX/bluesky-feed-generator/blob/main/server/data_stream.py
def on_message_handler(message):
commit = parse_subscribe_repos_message(message)
if not isinstance(commit, models.ComAtprotoSyncSubscribeRepos.Commit):
return
car = CAR.from_bytes(commit.blocks)
for op in commit.ops:
if op.action in ["create"] and op.cid:
raw = car.blocks.get(op.cid)
cooked = get_or_create(raw, strict=False)
if cooked.py_type == "app.bsky.feed.post":
# other types include "app.bsky.feed.like" etc which we ignore
# note that this data does not include who posted this skeet
# or possibly it does as a "CID" which you have to look up somehow
# who the hell knows? not me
print(json.dumps(raw, cls=JSONExtra, indent=2))
# Also look at this:
# https://social-media-ethics-automation.github.io/book/bsky/ch04_data/05_data_python_platform/03_demo_data_from_platform.html
def main():
client.start(on_message_handler)
return
if __name__ == "__main__":
main()
\ No newline at end of file
# Funktionen zum Check von Bluesky-Konten
#
# 12-2024 Jan Eggers
import json
import pandas as pd
from detectora import query_detectora
from imagecheck import query_aiornot
from bildbeschreibung import gpt4_description
import requests
import os
# Konstante
d_thresh = .8 # 80 Prozent
limit = 25 # Posts für den Check
def detectora_wrapper(text: str):
# Verpackung. Fügt nur den "Fortschrittsbalken" hinzu.
print("?", end="")
score = query_detectora(text)
if score is None:
print("\b_",end="")
else:
print(f"\b{'X' if score >= d_thresh else '.'}",end="")
return score
def aiornot_wrapper(did,embed):
# Verpackung für die AIORNOT-Funktion:
# Checkt, ob es überhaupt ein Embed gibt,
# und ob es ein Bild enthält.
# Wenn ja: geht durch die Bilder und erstellt KI-Beschreibung und KI-Einschätzung
print("?",end="")
if 'images' in embed:
images = embed['images']
desc = []
for i in images:
# Construct an URL for the image thumbnail (normalised size)
link = i['image']['ref']['$link']
i_url = f"https://cdn.bsky.app/img/feed_thumbnail/plain/{did}/{link}"
aiornot_report = query_aiornot(i_url)
# Beschreibung: https://docs.aiornot.com/#5b3de85d-d3eb-4ad1-a191-54988f56d978
gpt4_desc = gpt4_description(i_url)
desc.append({
'link_id': link,
'aiornot_score': aiornot_report['verdict'],
'aiornot_confidence': aiornot_report['ai']['confidence'],
'aiornot_generator': aiornot_report['generator'],
'gpt4_description': gpt4_desc,
})
print(f"\b{'X' if aiornot_report['verdict'] != 'human' else '.'}",end="")
return desc
else:
print("\b_",end="")
return None
def call_get_author_feed(author: str, limit: int=50, cursor= None) -> list:
# Sucht den Post-Feed für das Bluesky-Konto author
# author kann did oder handle sein
# Gibt ein dict zurück aus:
# 'cursor'
# 'feed' -> Liste der einzelnen Posts
data = {
'actor': author,
'limit': limit,
'cursor': cursor,
}
headers = {
'Content-Type': 'application/json',
}
try:
response = requests.get("https://public.api.bsky.app/xrpc/app.bsky.feed.getAuthorFeed",
params=data,
headers=headers)
if response.status_code == 200:
# Success
posts = response.json()
# Falls weniger Posts existieren als das Limit, wird kein cursor zurückgegeben,
# in diesem Fall: cursor-Element noch dazupacken
if not 'cursor' in posts:
posts['cursor'] = None
return posts
elif response.status_code == 400:
print("Bluesky Public: Fehlerhafte API-Anfrage")
return None
elif response.status_code == 401:
print("Zugriff auf Bluesky Public nicht erlaubt")
except Exception as e:
print("Fehler beim Verbinden mit der Bluesky-API:", str(e))
return None
return response['']
def call_get_profile(handle: str) -> list:
# Gibt das gefundenen Profil zurück.
data = {
'actor': handle,
}
headers = {
'Content-Type': 'application/json',
}
try:
response = requests.get("https://public.api.bsky.app/xrpc/app.bsky.actor.getProfile",
params=data,
headers=headers)
if response.status_code == 200:
# Success
return response.json()
elif response.status_code == 400:
print("Bluesky Public: Fehlerhafte API-Anfrage")
return None
elif response.status_code == 401:
print("Zugriff auf Bluesky Public nicht erlaubt")
except Exception as e:
print("Fehler beim Verbinden mit der Bluesky-API:", str(e))
return None
return response['']
def fetch_user_posts(handle: str, limit: int = 100) -> list:
profile = call_get_profile(handle)
did = profile['did']
posts = []
# Fetch timeline for the user (latest posts first)
cursor = None
while len(posts) < limit:
feed = call_get_author_feed(did, limit, cursor)
if not feed['feed']:
break
cursor = feed['cursor']
for item in feed['feed']:
post =item['post']
# Extrahiere Info zum einzelnen Post
post_data = {
'author_handle': post['author']['handle'], # Bluesky-Handle
'author_display_name': post['author']['displayName'], # Klarname
'author_avatar': post['author']['avatar'], # Bluesky-Link zum Avatar-Bild
'author_did': post['author']['did'], # Bluesky-ID
'created_at': post['record']['createdAt'], # Angelegt...
# 'indexed_at': item[2],
'text': post['record']['text'], # Text des Posts, falls vorhanden
'uri': post['uri'], # Link auf den Post
'cid': post['cid'],
'like_count': post['likeCount'], # Anzahl von Likes
'reply_count': post['replyCount'], # Anzahl von Antworten
'repost_count': post['repostCount'], # Anzahl von Reposts
'quote_count': post['quoteCount'], # Anzahl von Zitat-Reposts
'language': post['record'].get('langs') if 'langs' in post['record'] else '',
# Embedded media: images, external, record
# (external sind Links ins Internet, images sind Bilder, record sind eingebettete Posts)
# Image alt, file, and URI
# Das Embed wird einfach so als dict in die Zelle geschrieben und gesondert ausgewertet
'embed': post['record']['embed'] if 'embed' in post['record'] else ''
# Embed URI and description
# 'external_description': getattr(post['embed']['external'],'description',''),
# 'external_uri': getattr(post['embed']['external'],'uri',''),
}
posts.append(post_data)
return posts[:limit]
def check_handle(handle:str, limit:int = 20):
# Konto und Anzahl der zu prüfenden Posts
if handle == '':
return None
if handle[0]== '@':
handle = handle[1:]
# Fetch the most recent posts from the specified user
posts = fetch_user_posts(handle, limit)
if not posts:
print(f"Keine Posts im Feed für Handle {handle}.")
return
# Convert posts to a DataFrame
df = pd.DataFrame(posts)
# Now add probability check for each post text
print("Checke Texte:")
df['detectora_ai_score'] = df['text'].apply(detectora_wrapper)
# Now add "ai" or "human" assessment for images
print("\nChecke Bilder:")
df['aiornot_ai_score'] = df.apply(lambda row: aiornot_wrapper(row['author_did'], row['embed']), axis=1)
print()
return df
def call_find_handles(text):
# Ruft die Bluesky-Public-API direkt auf und bekommt ein JSON zurück, das ein Element
# actors mit einer Liste der gefundenen Konten enthält
data = {
'q': text,
}
headers = {
'Content-Type': 'application/json',
}
try:
response = requests.get("https://public.api.bsky.app/xrpc/app.bsky.actor.searchActors",
params=data,
headers=headers)
if response.status_code == 200:
# Success
return response.json()
elif response.status_code == 400:
print("Bluesky Public: Fehlerhafte API-Anfrage")
return None
elif response.status_code == 401:
print("Zugriff auf Bluesky Public nicht erlaubt")
except Exception as e:
print("Fehler beim Verbinden mit der Bluesky-API:", str(e))
return None
return response['']
def find_handles(text):
# Sucht Bluesky-Handles und gibt eine Liste von Handles zurück
actors = call_find_handles(text)
handles = [a['handle'] for a in actors['actors']]
return handles
if __name__ == "__main__":
# Bluesky-
handle_str = input("Erstes Handle mit diesen Zeichen wählen: ")
handle = find_handles(handle_str)[0]
print(handle)
# Diese Funktion holt die Infos zum Profil 'handle':
# Erwartet einen String, gibt ein dict zurück.
# Beschreibung: https://docs.bsky.app/docs/api/app-bsky-actor-get-profile
# Manchmal existieren Felder wie 'description' nicht.
profile = call_get_profile(handle)
author = profile['did']
print(author)
# Diese Funktion holt die Posts.
# 'author' darf irgendwas sein: handle, did... wir nehmen die did
# Gibt ein dict zurück: im Schlüssel 'feed' sind die einzelnen Posts gespeichert,
# im Key 'cursor' gibt es das Datum des frühesten abgefragten Posts zurück (es sei denn,
# es sind weniger Posts als limit, dann ist cursor leer.)
# Beschreibung: https://docs.bsky.app/docs/api/app-bsky-feed-get-author-feed
posts = call_get_author_feed(author, limit = limit)
# In diesem Demo-Programm werden die Posts hier noch nicht ausgewertet.
# Das passiert in der Extra-Funktion check_handle unten.
print(posts['cursor'])
# Funktion prüft die letzten ```limit``` Posts (voreingestellt auf 20)
# Erwartet ein Handle oder ein did - wir nehmen DID
# Gibt ein Dataframe zurück; Struktur ist oben in der Funktion beschrieben.
# Wichtigster Punkt: Ergebnis des KI-Checks in den Spalten
# - 'detectora_ai_score': Detectora-Score des Post-Textes (als real)
# - 'aiornot_ai_score':
df = check_handle(author, limit = limit)
n_posts = len(df)
print(f'\n\nAnalyse des Kontos @{handle} ({profile['displayName']}) seit {profile['createdAt']}- {profile['followersCount']} Follower')
print(f'{profile.get('description','---')}\n')
print(f'Anzahl der analysierten Posts: {n_posts}')
print(f"Durchschnittliche KI-Text-Wahrscheinlichkeit: {df['detectora_ai_score'].mean()}")
detectora_posts_df = df[df['detectora_ai_score'] >= d_thresh]
print(f"Anzahl von Posts über einer detectora-Schwelle von {d_thresh*100:.1f}%: {len(detectora_posts_df)}")
image_posts = [post for post in df['aiornot_ai_score'].to_list() if post is not None]
# Liste auspacken, nur die Dicts ohne None-Elemente
image_list = [item for sublist in image_posts for item in sublist]
ai_list = [item for item in image_list if item['aiornot_score']!='human']
if len(image_list) == 0:
p_ai = 0
else:
p_ai = len(ai_list)/len(image_list) * 100
print(f"Anzahl der Bilder: {len(image_list)}, verdächtig: {len(ai_list)} ({p_ai:.1f})%")
# Jetzt die Daten abspeichern
# Fals das Directory nicht existiert, anlegen
if not os.path.exists('bsky-checks'):
os.makedirs('bsky-checks')
# Read existing file if it exists
filename = f'bsky-checks/{handle}.csv'
if os.path.exists(filename):
existing_df = pd.read_csv(filename)
df = pd.concat([existing_df, df]).drop_duplicates(subset=['uri']).reset_index(drop=True)
df.to_csv(f'bsky-checks/{handle}.csv', index=False) # Save to CSV for example
\ No newline at end of file
......@@ -24,6 +24,8 @@ import os
api_url = "https://backendkidetektor-apim.azure-api.net/watson"
def query_detectora(text):
if text == '':
return None
data = {
'query': text,
}
......@@ -41,7 +43,7 @@ def query_detectora(text):
# Success
return response.json()['fake_probability']
elif response.status_code == 400:
print("DETECTORA: Fehlerhafte API-Anfrage")
print(f"DETECTORA: Fehlerhafte API-Anfrage: \'{data['query']}\'")
return None
elif response.status_code == 401:
print(f"DETECTORA-API-Key 'api_key' nicht gültig")
......
File moved
......@@ -5,13 +5,22 @@ from bildbeschreibung import ai_description
import requests
import json
import os
import time
# Konstanten #
endpoint_url = "https://api.aiornot.com/v1/reports/image"
def query_aiornot(image):
# Erwartet URI eines Bildes
# AIORNot-API-Dokumentation: https://docs.aiornot.com/
# Wichtigste Rückgabewerte im dict:
# - 'verdict' ('human' oder 'ai')
# - 'ai'/'confidence' (wie sicher ist sich das Modell?)
# - 'generator' ist ein dict, das für die vier geprüften Modelle
# 'dall_e', 'stable_diffusion', 'this_person_does_not_exist' und 'midjourney'
# jeweils einen 'confidence'-Wert angibt.
#
# AIORNot-API-Dokumentation: https://docs.aiornot.com/#5b3de85d-d3eb-4ad1-a191-54988f56d978
data = json.dumps({
'object': image,
})
......@@ -28,14 +37,28 @@ def query_aiornot(image):
)
if response.status_code == 200:
# Success
return response.json()['report']['verdict']
return response.json()['report']
elif response.status_code == 400:
print("AIORNOT: Fehlerhafte API-Anfrage")
return None
elif response.status_code == 401:
print(f"AIORNOT-API-Key 'api_key' nicht gültig")
return None
elif response.status_code == 429:
# Zu viele Anfragen; also warten und nochmal fragen
time.sleep(1)
response = requests.post(endpoint_url,
headers=headers,
data=data
)
# Immer noch 429? Dann sind wahrscheinlich die Credits aufgebraucht
if response.status_code == 429:
print("AIORNOT: Credits verbraucht")
return None
else:
return response.json()['report']
except Exception as e:
print("Fehler beim Verbinden mit der AIORNOT-API:", str(e))
return None
return response['']
return None
import json
import pandas as pd
from atproto import Client, models
from detectora import query_detectora
from imagecheck import query_aiornot
from bildbeschreibung import gpt4_description
def aiornot_wrapper(did,embed):
# Verpackung für die AIORNOT-Funktion:
# Checkt, ob es überhaupt ein Embed gibt,
# und ob es ein Bild enthält.
# Wenn ja: nimmt das erste Bild und
# erstellt KI-Beschreibung und KI-Einschätzung
if embed is None or embed == '':
return None
images = getattr(embed,'images',None)
if images is None:
return None
desc = []
for i in images:
# Construct an URL for the image thumbnail (normalised size)
i_url = f"https://cdn.bsky.app/img/feed_thumbnail/plain/{did}/{i.image.ref.link}"
aiornot_score = query_aiornot(i_url)
gpt4_desc = gpt4_description(i_url)
desc.append({'aiornot_score': aiornot_score,
'gpt4_description': gpt4_desc})
return desc
def fetch_user_posts(handle: str, limit: int = 100) -> list:
# Initialize the Bluesky client (unauthenticated)
client = Client(base_url="https://api.bsky.app")
try:
# Fetch the user ID from the handle
profile = client.app.bsky.actor.get_profile({'actor': handle})
user_id = profile.did
# Initialize an empty list to store posts
posts = []
# Fetch timeline for the user (latest posts first)
cursor = None
while len(posts) < limit:
if cursor is not None:
feed = client.app.bsky.feed.get_author_feed({'actor':user_id,
'limit':(min(limit - len(posts), 50)),
'cursor': cursor,
})
else:
feed = client.app.bsky.feed.get_author_feed({'actor':user_id,
'limit': (min(limit - len(posts), 100)),
})
if not feed['feed']:
break
cursor = feed['cursor']
for item in feed['feed']:
post = getattr(item,'post')
# Extract basic post information
post_data = {
'author_handle': getattr(post['author'],'handle',''),
'author_display_name': getattr(post['author'], 'display_name', ''),
'author_did': getattr(post['author'], 'did', ''),
'created_at': getattr(post['record'], 'created_at', ''),
# 'indexed_at': item[2],
'text': getattr(post['record'], 'text', ''),
'uri': post['uri'],
'cid': post['cid'],
'like_count': post['like_count'],
'reply_count': post['reply_count'],
'repost_count': post['repost_count'],
'quote_count': post['quote_count'],
'language': getattr(post['record'], 'langs', [''])[0] if hasattr(post['record'], 'langs') else '',
# Embedded media: images, external, record
# Image alt, file, and URI
'embed': getattr(post['record'],'embed','')
# Embed URI and description
# 'external_description': getattr(post['embed']['external'],'description',''),
# 'external_uri': getattr(post['embed']['external'],'uri',''),
}
posts.append(post_data)
return posts[:limit]
except Exception as e:
print(f"An error occurred: {e}")
return []
def check_handle(handle = 'lion-c.bsky.social', limit = 20):
# Define the Bluesky handle and number of posts to fetch
# Remove the @ before handle strings
# Fetch the most recent posts from the specified user
posts = fetch_user_posts(handle, limit)
if not posts:
print("No posts fetched. Please check the handle and try again.")
return
# Convert posts to a DataFrame
df = pd.DataFrame(posts)
# Now add probability check for each post text
df['detectora_ai_score'] = df['text'].apply(query_detectora)
# Now filter those
df['aiornot_ai_score'] = df.apply(lambda row: aiornot_wrapper(row['author_did'], row['embed']), axis=1)
return df
if __name__ == "__main__":
df = check_handle()
print(f"Durchschnittliche KI-Text-Wahrscheinlichkeit: {df['detectora_ai_score'].mean()}")
df.to_csv('user_posts.csv', index=False) # Save to CSV for example
\ No newline at end of file
author_handle,author_display_name,author_did,created_at,text,uri,cid,like_count,reply_count,repost_count,quote_count,language,embed,detectora_ai_score
tendar.bsky.social,(((Tendar))),did:plc:ernjxefnyk2hhwhbd3zblykf,2024-12-27T18:26:10.347Z,"The case around oil tankers Eagle-S, which is most certainly responsible for damaging the Estlink-2 undersea cable, is getting even more interesting. It appears that ship was not only involved in sabotage but in espionage, as well.",at://did:plc:ernjxefnyk2hhwhbd3zblykf/app.bsky.feed.post/3lecmgh7cz22o,bafyreichh4ydy6hw73goyvsfughj7ft65q4ly2ptiaeexk7tdv66tuwxzi,953,29,252,17,en,"images=[Image(alt='', image=BlobRef(mime_type='image/jpeg', size=294530, ref=IpldLink(link='bafkreih5fhonli4qpbv2xqqctqouv473nahlbzjfzedgchgv4wr7bvzqie'), py_type='blob'), aspect_ratio=AspectRatio(height=1002, width=1170, py_type='app.bsky.embed.defs#aspectRatio'), py_type='app.bsky.embed.images#image')] py_type='app.bsky.embed.images'",0.6172474026679993
barryalanpiatoff.bsky.social,Barry Alan Piatoff,did:plc:xewv5wqmdxmbf326uidz24rn,2024-12-25T00:01:41.610Z,"""For Bluesky, Massive User Uptick Brings Growing Pains and Divisive Bots. It’s not just human users who’ve been flocking to Bluesky but also bots, including those designed to create partisan division."" via The Hollywood Reporter
@lion-c.bsky.social is quoted & seems to understand the bot problem",at://did:plc:xewv5wqmdxmbf326uidz24rn/app.bsky.feed.post/3le3nrniflc2w,bafyreihdxpx5r3yi6kbnmtprxvvbgbewnt77qn7sv2yywsr2wn3t6ivjpa,3,0,3,0,en,"external=External(description='It’s not just human users who’ve been flocking to Bluesky but also bots, including those designed to create partisan division.', title='For Bluesky, Massive User Uptick Brings Growing Pains and Divisive Bots', uri='https://www.hollywoodreporter.com/news/general-news/bluesky-user-growth-brings-growing-pains-and-divisive-bots-1236093735/?link_source=ta_thread_link&taid=676b2ef7b0d84200018b70a5&utm_campaign=trueanthem&utm_medium=social&utm_source=threads', thumb=BlobRef(mime_type='image/jpeg', size=795675, ref=IpldLink(link='bafkreiaoza25gxeytmjy4adjxyy6qm2iqtnjob6huatjvqgjl2xassudea'), py_type='blob'), py_type='app.bsky.embed.external#external') py_type='app.bsky.embed.external'",0.0009211198193952441
conspirator0.bsky.social,Conspirador Norteño,did:plc:7n2gzbzn4xus4nghzfpjgli3,2024-12-21T17:29:26.644Z,"In the two weeks since this thread was posted, the ""passionate about"" spam network has grown to over 15 thousand accounts, and evolved a bit in other ways. Here's an updated analysis...
bsky.app/profile/cons...",at://did:plc:7n2gzbzn4xus4nghzfpjgli3/app.bsky.feed.post/3ldtghifzd22v,bafyreib2edsamrs4uya4xd67pkdxh3chdow2rwagwnn4z536rewfcgtwve,427,13,202,26,en,"record=Main(cid='bafyreifqqzqwhfldbulddfabdemiwi6buqf6kn4z3pcw3efhete2c7znuq', uri='at://did:plc:7n2gzbzn4xus4nghzfpjgli3/app.bsky.feed.post/3lcmg572f4c2q', py_type='com.atproto.repo.strongRef') py_type='app.bsky.embed.record'",0.002669913461431861
lion-c.bsky.social,Lion Cassens,did:plc:2fitdmiaotn22kbwgox4v7hc,2024-12-10T10:35:41.542Z,Another bot network using AI for at least some of the posts...,at://did:plc:2fitdmiaotn22kbwgox4v7hc/app.bsky.feed.post/3lcx27jbqoc2x,bafyreif674cj5mwwc6xudgwo3aphcragdic52eic5bznbhejoktut66htu,11,3,5,0,en,"record=Main(cid='bafyreiahf3qxf2gjbx3drq6ypo22gdi2ywohjxiagypuqkupfbnuqdltkq', uri='at://did:plc:7n2gzbzn4xus4nghzfpjgli3/app.bsky.feed.post/3lcvysn6vek2h', py_type='com.atproto.repo.strongRef') py_type='app.bsky.embed.record'",0.06642594933509827
lion-c.bsky.social,Lion Cassens,did:plc:2fitdmiaotn22kbwgox4v7hc,2024-12-10T07:52:29.081Z,"Grundsätzlich schwer zu sagen. Zwei Möglichkeiten:
1) Die Folgen tausenden (>100,000) Accounts und gewinnen dadurch ""back follower"". (komisch, aber nicht verboten)
2) Bekannte Persönlichkeiten, die von X gekommen sind und daher ohne Beiträge viele follower haben.",at://did:plc:2fitdmiaotn22kbwgox4v7hc/app.bsky.feed.post/3lcwr3ohlhc2d,bafyreigb3kwnfwx2a72zzarm7shpkblpma4jivlvqmzkaw2jahvbrw33bi,0,0,0,0,de,,0.0009483483736403286
lion-c.bsky.social,Lion Cassens,did:plc:2fitdmiaotn22kbwgox4v7hc,2024-12-08T19:29:02.362Z,Do you have a handle of some? Would like to take a look.,at://did:plc:2fitdmiaotn22kbwgox4v7hc/app.bsky.feed.post/3lcsx3eprhc2s,bafyreidaznh2akx262xtq2b4ioikb63gq5jw46kc2umyzlgluqtdk7rbpq,2,1,0,0,en,,0.6039703488349915
lion-c.bsky.social,Lion Cassens,did:plc:2fitdmiaotn22kbwgox4v7hc,2024-12-08T12:04:36.978Z,"Auf jeden Fall ein Fake-Account (siehe Antwort an OP)!
Ich denke aber nicht, das der zum gleichen Netzwerk gehört - da diese Bilder von Instagram gestohlen wurden. Das Ziel kann aber natürlich das gleiche sein.",at://did:plc:2fitdmiaotn22kbwgox4v7hc/app.bsky.feed.post/3lcs6aomuek2i,bafyreietwh4g5a4fjicrapftwraqznz6ldrhy3mmbzo3i624savkn2ljsu,2,0,0,0,de,,0.0005878527881577611
lion-c.bsky.social,Lion Cassens,did:plc:2fitdmiaotn22kbwgox4v7hc,2024-12-08T11:48:57.041Z,"Eines der Fotos zeigt auf der Uniform den Namen ""Hufschmidt"". Schnelle Google Suche bestätigt deinen Verdacht: Diese ""Christine Wagner"" existiert nicht und hat die Bilder geklaut.",at://did:plc:2fitdmiaotn22kbwgox4v7hc/app.bsky.feed.post/3lcs5eoad3s2q,bafyreiff2wrz6f7nxoavv4jybxlviwnmoivsmuntzfbmgwzgtitykusici,3,1,0,0,de,"images=[Image(alt='Aileen Tina Hufschmidt auf LinkedIn.', image=BlobRef(mime_type='image/jpeg', size=42644, ref=IpldLink(link='bafkreiaoq6e4kn5mjeaccdfebh4qydfyeq5mubmtueuyjji6hegqq35mdi'), py_type='blob'), aspect_ratio=AspectRatio(height=217, width=195, py_type='app.bsky.embed.defs#aspectRatio'), py_type='app.bsky.embed.images#image')] py_type='app.bsky.embed.images'",0.05424289032816887
lion-c.bsky.social,Lion Cassens,did:plc:2fitdmiaotn22kbwgox4v7hc,2024-12-08T09:41:32.889Z,"4/ Some sources said it has been up to 50 accounts, but currently I cannot find those accounts on Bluesky (perhaps already blocked?).
See for example this list: bsky.app/profile/lars...
Thanks to everyone who helped/helps shining light on this!",at://did:plc:2fitdmiaotn22kbwgox4v7hc/app.bsky.feed.post/3lcrwau77y22h,bafyreigzxcnwk2tqgxikalwyouu7mbjns6jo6a3nnmlewexpzloitundzu,16,1,1,0,en,"record=Main(cid='bafyreic4hoy62rhw3t2y5tzmttonevtsymamywwmry4wwe5h2ozwa62k6y', uri='at://did:plc:buuaezktxboze6nudnwqlc7x/app.bsky.feed.post/3lcr4xowe5s22', py_type='com.atproto.repo.strongRef') py_type='app.bsky.embed.record'",0.0031484924256801605
larswienand.bsky.social,Lars Wienand,did:plc:buuaezktxboze6nudnwqlc7x,2024-12-08T02:09:01.814Z,Es sind noch ein paar mehr schon/noch hinterlegt bei vanillasky. click,at://did:plc:buuaezktxboze6nudnwqlc7x/app.bsky.feed.post/3lcr4xowe5s22,bafyreic4hoy62rhw3t2y5tzmttonevtsymamywwmry4wwe5h2ozwa62k6y,108,3,17,3,de,"images=[Image(alt='1. Screenshot of Subdomains of vanilasky.click https://urlscan.io/ip/23.88.96.130', image=BlobRef(mime_type='image/jpeg', size=945584, ref=IpldLink(link='bafkreihyrxnwyy5zulrkpbj4p7detvsbjm2njoupzwklva3xitm64tmgfq'), py_type='blob'), aspect_ratio=AspectRatio(height=2000, width=924, py_type='app.bsky.embed.defs#aspectRatio'), py_type='app.bsky.embed.images#image'), Image(alt='2. Screenshot of Subdomains of vanilasky.click https://urlscan.io/ip/23.88.96.130', image=BlobRef(mime_type='image/jpeg', size=433690, ref=IpldLink(link='bafkreifypeehhifc3oempo6fhshoz5oxcn23b3f6s4crsrhjwqva7pyaiu'), py_type='blob'), aspect_ratio=AspectRatio(height=2000, width=1123, py_type='app.bsky.embed.defs#aspectRatio'), py_type='app.bsky.embed.images#image'), Image(alt='3. Screenshot of Subdomains of vanilasky.click https://urlscan.io/ip/23.88.96.130', image=BlobRef(mime_type='image/jpeg', size=967691, ref=IpldLink(link='bafkreidxkvbn2hommoysajecddvcna2ggfzw2p46fdnqrw6jxrvgf2ow7a'), py_type='blob'), aspect_ratio=AspectRatio(height=2000, width=989, py_type='app.bsky.embed.defs#aspectRatio'), py_type='app.bsky.embed.images#image'), Image(alt='4. Screenshot of Subdomains of vanilasky.click https://urlscan.io/ip/23.88.96.130, zusätzlicher Hinweis: „Attention: These domains and hostnames were discovered through Certificate Transparency (CT)\nLogs and have been irrevocably published as part of the public record. There is no mechanism for us or anyone else to remove this information from the internet“', image=BlobRef(mime_type='image/jpeg', size=394934, ref=IpldLink(link='bafkreidr34ie4tgjx6rq5tfddkdzxt5rf3gp5r2dio73umcra3bmmn6w4a'), py_type='blob'), aspect_ratio=AspectRatio(height=2000, width=997, py_type='app.bsky.embed.defs#aspectRatio'), py_type='app.bsky.embed.images#image')] py_type='app.bsky.embed.images'",0.0008308747783303261
lion-c.bsky.social,Lion Cassens,did:plc:2fitdmiaotn22kbwgox4v7hc,2024-12-08T09:33:41.048Z,"3/ The 9 remaining accounts stopped posting shortly after my initial thread and have not posted since. Until then, these 9 made 182 posts: bsky.app/profile/badl...
This network was easy to find due to the common URL. However, it is likely not the only attempt to build a German speaking AI-network.",at://did:plc:2fitdmiaotn22kbwgox4v7hc/app.bsky.feed.post/3lcrvssswzs2h,bafyreian3sev3qun7opo7ktedozjckf7vv5jl3rcw6ouc5g2vwrxqy4lry,16,2,2,0,en,"record=Main(cid='bafyreif6azzshs5smbtrbzztfqexbzjwaqpvtqtgexh522zz6hhisgib4e', uri='at://did:plc:7syfakzcriq44mwbdbc7jwvn/app.bsky.feed.post/3lcqvua2erk2k', py_type='com.atproto.repo.strongRef') py_type='app.bsky.embed.record'",0.002489847131073475
lion-c.bsky.social,Lion Cassens,did:plc:2fitdmiaotn22kbwgox4v7hc,2024-12-08T09:33:41.047Z,"2/ This is less than it seemed, based on how the replies to these news articles were dominated by the network (now often called vanillasky network).
However, the network was likely still being developed.
The oldest account first posted 4 days ago, while approx. half started posting 2 days ago.",at://did:plc:2fitdmiaotn22kbwgox4v7hc/app.bsky.feed.post/3lcrvsssw2k2h,bafyreiaboamt2l46icqjgbn6eewzv7scuei2zc7v7pl7xj4w3yblkj37fe,10,1,1,0,en,,0.0021178426686674356
lion-c.bsky.social,Lion Cassens,did:plc:2fitdmiaotn22kbwgox4v7hc,2024-12-08T09:33:41.046Z,"Yesterdays thread on the discovery of an AI bot network gained quite some traction. Since then, ppl. found out more about the network.
1/ @badlogic.bsky.social and other's found that the bots are hosted through the same domain, which now has a total of only 19 bots. 10 of which are blocked by Bsky.",at://did:plc:2fitdmiaotn22kbwgox4v7hc/app.bsky.feed.post/3lcrvss7qrk2h,bafyreiddubek5uu42uwyq5zyl4c2j3ia4oiusg7le2c3wkkuvf4tdxb6cq,48,5,26,3,en,"record=Main(cid='bafyreihvqfupoungdzwnmmohobdgkjfabanyscbumfislm2a4yraujrb7y', uri='at://did:plc:2fitdmiaotn22kbwgox4v7hc/app.bsky.feed.post/3lcpc4ztcmk2n', py_type='com.atproto.repo.strongRef') py_type='app.bsky.embed.record'",0.001831565983593464
lion-c.bsky.social,Lion Cassens,did:plc:2fitdmiaotn22kbwgox4v7hc,2024-12-08T08:45:32.311Z,"Hi Robert, ich hatte selber auch nicht mit so viel Aufmerksamkeit für den post gerechnet und kann deine Verunsicherung daher verstehen.
Falls noch zweifel bestehen, gerne über meine Arbeits/Uni-E-Mail Kontakt suchen (kann via Google gefunden werden).",at://did:plc:2fitdmiaotn22kbwgox4v7hc/app.bsky.feed.post/3lcrt4pckis2h,bafyreievulfuirze6ckdb3devxz3deqzzdsqn5s62ax33b7x7ddh4cd4vu,1,1,0,0,de,,0.0009039518190547824
lion-c.bsky.social,Lion Cassens,did:plc:2fitdmiaotn22kbwgox4v7hc,2024-12-08T08:27:41.727Z,"The accounts were less just a few hours/days old. Roughly half have been deleted by now - so it seems BlueSky is doing a good job!
They might still rely on us for reporting suspicious activities though.",at://did:plc:2fitdmiaotn22kbwgox4v7hc/app.bsky.feed.post/3lcrs4scvdk2v,bafyreic7kkgcwuznbzcg54ybjeqnlpmzits43kipxw4j5aosxitzc4q2oe,1,0,0,0,en,,0.0322367325425148
badlogic.bsky.social,Mario Zechner,did:plc:7syfakzcriq44mwbdbc7jwvn,2024-12-08T00:01:49.366Z,"And just to quantify the OPs claim that Bluesky is being flooded with German speaking bots.
This tiny network hat 19 bots, which posted a total of 182 posts (at least the 10 bots that are still active).
That's not quite a flood. Pretty sure as the elections come closer, we'll se more activity tho.",at://did:plc:7syfakzcriq44mwbdbc7jwvn/app.bsky.feed.post/3lcqvua2erk2k,bafyreif6azzshs5smbtrbzztfqexbzjwaqpvtqtgexh522zz6hhisgib4e,34,4,6,2,en,,0.06593639403581619
lion-c.bsky.social,Lion Cassens,did:plc:2fitdmiaotn22kbwgox4v7hc,2024-12-07T23:27:01.593Z,"Die bots aus dem thread haben mit niemandem interagiert.
Rein technisch dürfte das aber Möglich sein. Fliegt aber ggf. schneller auf, wenn die Antworten weniger Sinn machen.
Das Hauptproblem ist, das die mit der Zeit besser werden könnten.",at://did:plc:2fitdmiaotn22kbwgox4v7hc/app.bsky.feed.post/3lcqtvyymwk2z,bafyreibcdpjhtaoascodneiudlg475h55sfv4zdanfxw5ddgxoao7lpot4,2,1,0,0,de,,0.0004682602302636951
badlogic.bsky.social,Mario Zechner,did:plc:7syfakzcriq44mwbdbc7jwvn,2024-12-07T22:58:16.377Z,"In other bot news, these bots are on their on ""Personal Data Server"", which is still running.
There are a total of 19 accounts on that server. Only 9 of them have been suspended. Curious why @support.bsky.team hasn't defederated with that PDS entirely?",at://did:plc:7syfakzcriq44mwbdbc7jwvn/app.bsky.feed.post/3lcqsclpgjc2k,bafyreids4kowumiuw3huczo6l4ld2yob6fuqxw4ap3rkxgh63ahzz3g4ne,34,3,14,4,en,"media=Main(images=[Image(alt='Fetched repo page (0 repos so far)\nFetched repo page (19 repos so far)\nFound 19 total accounts\nProcessing account 1/19: did:plc:mebbh6ivwisak2wmyhdupner\nHandle: marcoweber91.vanillasky.click\nName: Marco Weber\nDescription: 🏕️ Outdoor-Fan | 🎮 Gamer | 💻 Technik-Nerd | Immer bereit für neue Herausforderungen!\nPosts: 26\nProcessing account 2/19: did:plc:mgvycnjdf7ondai6ubsrcesy\nFailed to fetch profile for did:plc:mgvycnjdf7ondai6ubsrcesy: Error: Account has been suspended\nError fetching posts for did:plc:mgvycnjdf7ondai6ubsrcesy: Error: Profile not found\nProcessing account 3/19: did:plc:rp2pzlwtsxzjddbuqy2bbjd5\nFailed to fetch profile for did:plc:rp2pzlwtsxzjddbuqy2bbjd5: Error: Account has been suspended\nError fetching posts for did:plc:rp2pzlwtsxzjddbuqy2bbjd5: Error: Profile not found\nProcessing account 4/19: did:plc:ahfgjz3ymeypkswqd42pulsl\nHandle: julianschneider87.vanillasky.click\nName: Julian Schneider\nDescription: 🌌 Sternenbeobachter | 🚀 Weltraumfan | 📷 Fotograf aus Leidenschaft | Auf der Suche nach neuen Horizonten!\nPosts: 41\nProcessing account 5/19: did:plc:ktzihqnjlc7hw2krl4oygcd3\nFailed to fetch profile for did:plc:ktzihqnjlc7hw2krl4oygcd3: Error: Account has been suspended\nError fetching posts for did:plc:ktzihqnjlc7hw2krl4oygcd3: Error: Profile not found\nProcessing account 6/19: did:plc:2fswymc5t3nl3roo5drhstfa\nFailed to fetch profile for did:plc:2fswymc5t3nl3roo5drhstfa: Error: Account has been suspended\nError fetching posts for did:plc:2fswymc5t3nl3roo5drhstfa: Error: Profile not found\nProcessing account 7/19: did:plc:qx2ktdu6ynfsrblggjf56v6n\nFailed to fetch profile for did:plc:qx2ktdu6ynfsrblggjf56v6n: Error: Account has been suspended\nError fetching posts for did:plc:qx2ktdu6ynfsrblggjf56v6n: Error: Profile not found\n', image=BlobRef(mime_type='image/jpeg', size=677432, ref=IpldLink(link='bafkreiaddfmvk6c6t52c6dw36vvqc5nano6fu5jvdkhfc3jhgsebl3agtq'), py_type='blob'), aspect_ratio=AspectRatio(height=1842, width=1846, py_type='app.bsky.embed.defs#aspectRatio'), py_type='app.bsky.embed.images#image'), Image(alt='Processing account 12/19: did:plc:qq73sngfhgrmy3umvpd34o4f\nHandle: janinabecker89.vanillasky.click\nName: Janina Becker\nDescription: 🏞️ Naturfanatikerin | 📸 Fotografie-Enthusiastin | 🍷 Weinkennerin | Auf der Suche nach dem perfekten Moment!\nPosts: 10\nProcessing account 13/19: did:plc:b4by5mbdqwfiekw4aeub34vf\nFailed to fetch profile for did:plc:b4by5mbdqwfiekw4aeub34vf: Error: Account has been suspended\nError fetching posts for did:plc:b4by5mbdqwfiekw4aeub34vf: Error: Profile not found\nProcessing account 14/19: did:plc:a7nv6d5rshdclidvpfy5jtem\nHandle: felixneumann89.vanillasky.click\nName: Felix Neumann\nDescription: 🏞️ Naturentdecker | 🎥 Filmfan | 🍳 Kochliebhaber | Immer auf der Jagd nach neuen Geschmackserlebnissen!\nPosts: 8\nProcessing account 15/19: did:plc:i3lnumxsw7owut3cuczj5kw4\nHandle: leonardfischer86.vanillasky.click\nName: Leonard Fischer\nDescription: 🌌 Sternengucker | 🎥 Filmliebhaber | 🎻 Musikenthusiast | Auf der Suche nach Inspiration in jedem Moment!\nPosts: 12\nProcessing account 16/19: did:plc:ncugmc25d3ttozdgad5wubrx\nHandle: felixkonig86.vanillasky.click\nName: Felix König\nDescription: 🎥 Filmfanatiker | 🌍 Weltenbummler | 🍕 Pizza-Liebhaber | Immer auf der Suche nach der nächsten großen Story!\nPosts: 6\nProcessing account 17/19: did:plc:wzylfjeicx4gwc5ue5ysntef\nHandle: felixwagner87.vanillasky.click\nName: Felix Wagner\nDescription: 🎨 Kreativer Kopf | 📸 Fotografie-Enthusiast | 🌍 Weltenbummler | Lebe jeden Tag als wäre es der letzte!\nPosts: 9\nProcessing account 18/19: did:plc:3ptrtsc6gzueasouc6m2y2w7\nFailed to fetch profile for did:plc:3ptrtsc6gzueasouc6m2y2w7: Error: Account has been suspended\nError fetching posts for did:plc:3ptrtsc6gzueasouc6m2y2w7: Error: Profile not found\nProcessing account 19/19: did:plc:nxiafx6e54lk3mu6smcwevvv\nFailed to fetch profile for did:plc:nxiafx6e54lk3mu6smcwevvv: Error: Account has been suspended\nError fetching posts for did:plc:nxiafx6e54lk3mu6smcwevvv: Error: Profile not found', image=BlobRef(mime_type='image/jpeg', size=512761, ref=IpldLink(link='bafkreig5hc43tue4rcdjjbylbiyhf3lhn67pyodx45rsryfgsvd3ccx454'), py_type='blob'), aspect_ratio=AspectRatio(height=458, width=1776, py_type='app.bsky.embed.defs#aspectRatio'), py_type='app.bsky.embed.images#image')], py_type='app.bsky.embed.images') record=Main(record=Main(cid='bafyreihvqfupoungdzwnmmohobdgkjfabanyscbumfislm2a4yraujrb7y', uri='at://did:plc:2fitdmiaotn22kbwgox4v7hc/app.bsky.feed.post/3lcpc4ztcmk2n', py_type='com.atproto.repo.strongRef'), py_type='app.bsky.embed.record') py_type='app.bsky.embed.recordWithMedia'",0.009797980077564716
lion-c.bsky.social,Lion Cassens,did:plc:2fitdmiaotn22kbwgox4v7hc,2024-12-07T19:26:38.798Z,"Die sind alle über eine eigene Bluesky-Instanz registriert. Bluesky ist dezentral aufgebaut, so das man seinen Provider selbst auswählen kann. In diesem Fall wird das wohl genutzt um z.b. E-Mail-Verifizierungen zu umgehen. Oder andere Sicherheitsmaßnahmen.",at://did:plc:2fitdmiaotn22kbwgox4v7hc/app.bsky.feed.post/3lcqgi6du6s26,bafyreieqb7cngmfgxpbgr45d5uizgk6ljvpj7zxggpepbjthcuhlwnfr2u,6,1,0,0,en,,0.0004913366865366697
lion-c.bsky.social,Lion Cassens,did:plc:2fitdmiaotn22kbwgox4v7hc,2024-12-07T18:46:37.304Z,The domain also seems fairly new. Registered on 26th November according to www.whatsmydns.net/domain-age?q....,at://did:plc:2fitdmiaotn22kbwgox4v7hc/app.bsky.feed.post/3lcqeam42a22e,bafyreiakxiavezgsgmjdpmwzdh5enzc6xixec7tzf4y3hlaudar7s475oa,3,0,0,0,en,,0.013075300492346287
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment