truth_serum_academic 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 61567f2d575ced3d37904bc6c64d1c4087b44a545082d13a7ba4dff40bb8a30c
4
- data.tar.gz: c2a4782c0349682575993feaea7de717409ce8cbbea7baf348b629d9e9d8a097
3
+ metadata.gz: 0aa6c1317c474b2de311edc851b77ac74fbeaee5020106506fee70345be91b42
4
+ data.tar.gz: 35ed231086b07be3a4b1ce972291a7a8883995e620c6c07d07e3188c9aa71449
5
5
  SHA512:
6
- metadata.gz: 00ebb740e006b66f5b83c25fea94333e06a2dcb155bb46736bbebd18fbda4df786c3792acc36709812240d5df7cff48e3ad7e721f5795c4cc83c6a6866a95076
7
- data.tar.gz: c25c9d9db9092e94db7725e82ec6379196814b6e3fceaf8dccc79756b1c51be51ab9a84223280fa0f21864a5272d419621b21dc79ff74f97026c34ab5cdf70f7
6
+ metadata.gz: 14d7028af3a45ae091512aa7c3259d3908e79d2cacd37ae577935ca03d0e86cd15d2a1fd8eab483012ca7a6e8238ea8349a453904abb7f1b3a3786c0014eaeab
7
+ data.tar.gz: b977543f46a062c0397b0976db541115a3f69314925f5af1f0cadfc2fce01cb9bdf33cf648b3e075d9ec176d9a6495d12315e9b58c612928459af8f8d7504ce3
@@ -1,56 +1,78 @@
1
1
  require 'httparty'
2
+ require 'json'
2
3
  require_relative 'result'
3
4
 
4
5
  module TruthSerum
5
6
  class Verifier
6
- BASE_URL = "https://api.crossref.org/works"
7
+ # We use the fast, free-tier friendly model
8
+ API_URL = "https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash:generateContent"
7
9
 
8
10
  def self.check_list(list)
11
+ # 1. SECURITY CHECK
12
+ # We look for the key in your computer's environment variables.
13
+ # NEVER hardcode your key here if you publish the gem!
14
+ api_key = ENV["GEMINI_API_KEY"]
15
+
16
+ if api_key.nil? || api_key.empty?
17
+ puts "⚠️ ERROR: Missing API Key."
18
+ puts "Please run: set GEMINI_API_KEY=your_key_here"
19
+ exit
20
+ end
21
+
9
22
  results = []
10
23
 
11
24
  list.each do |citation|
12
- response = HTTParty.get(BASE_URL, query: {
13
- "query.bibliographic" => citation,
14
- "rows" => 1
15
- })
16
-
17
- data = response.parsed_response
18
- items = data.dig("message", "items")
19
-
20
- status = :fake
21
- score = 0.0
22
-
23
- # LOGIC: Check if we found a match AND if it looks similar
24
- if items && items.any?
25
- top_match = items.first
26
- found_title = top_match["title"]&.first || ""
25
+ # 2. CONSTRUCT THE PROMPT
26
+ # We give Gemini strict instructions to act like a JSON machine.
27
+ prompt_text = <<~TEXT
28
+ You are a strict academic verification tool. Check if the following citation is real or a hallucination.
29
+ Citation: "#{citation}"
27
30
 
28
- # 1. Normalize strings (lowercase, find words 4+ letters long)
29
- # We ignore small words like "the", "of", "and".
30
- input_words = citation.downcase.scan(/[a-z]{4,}/)
31
- found_words = found_title.downcase.scan(/[a-z]{4,}/)
31
+ Respond ONLY with valid JSON in this format:
32
+ {
33
+ "is_real": boolean,
34
+ "confidence_score": number_between_0_and_1,
35
+ "reasoning": "short explanation"
36
+ }
37
+ TEXT
38
+
39
+ # 3. SEND TO GEMINI
40
+ response = HTTParty.post(
41
+ "#{API_URL}?key=#{api_key}",
42
+ headers: { 'Content-Type' => 'application/json' },
43
+ body: {
44
+ contents: [{ parts: [{ text: prompt_text }] }]
45
+ }.to_json
46
+ )
47
+
48
+ # 4. PARSE THE BRAIN WAVES (JSON)
49
+ begin
50
+ payload = response.parsed_response
51
+ # Dig through Gemini's nested JSON response structure
52
+ raw_text = payload.dig("candidates", 0, "content", "parts", 0, "text")
32
53
 
33
- # 2. Count common words
34
- common_words = input_words & found_words
54
+ # Clean up any markdown formatting (Gemini likes to wrap JSON in ```json ... ```)
55
+ clean_json = raw_text.gsub(/```json/, "").gsub(/```/, "")
56
+ data = JSON.parse(clean_json)
57
+
58
+ # 5. CREATE RESULT
59
+ status = data["is_real"] ? :real : :fake
60
+ score = data["confidence_score"]
35
61
 
36
- # 3. Decision Threshold
37
- # If they share at least 2 significant words, we assume it's the same paper.
38
- if common_words.size >= 2
39
- status = :real
40
- score = top_match["score"]
41
- else
42
- # We found a paper, but the title was too different.
43
- # (e.g. You searched "Musk Mars" and got "Geology of Mars")
44
- status = :fake
45
- score = 0.1 # Low score for mismatch
46
- end
47
- end
62
+ # We can even print the reasoning if we want!
63
+ # For now, we stick to the score/status structure.
64
+ result = TruthSerum::Result.new(
65
+ text: citation,
66
+ score: score,
67
+ status: status
68
+ )
69
+ results << result
48
70
 
49
- results << TruthSerum::Result.new(
50
- text: citation,
51
- score: score,
52
- status: status
53
- )
71
+ rescue => e
72
+ # If Gemini gets confused or the internet breaks
73
+ puts "Error parsing Gemini response: #{e.message}"
74
+ results << TruthSerum::Result.new(text: citation, score: 0.0, status: :fake)
75
+ end
54
76
  end
55
77
 
56
78
  results
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TruthSerum
4
- VERSION = "0.1.0"
4
+ VERSION = "0.2.0"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: truth_serum_academic
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nathalie Tasler