Skip to content
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

maybe work #9

Merged
merged 3 commits into from
Feb 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -133,3 +133,5 @@ dist
# macOS .DS_Store files
.DS_Store

# Flask backend environment variables
backend/.env
45 changes: 45 additions & 0 deletions DiagnoseMeApp/central.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { streamGemini } from './gemini-api.js';

let form = document.querySelector('form');
let promptInput = document.querySelector('input[name="prompt"]');
let output = document.querySelector('.output');

form.onsubmit = async (ev) => {
ev.preventDefault();
output.textContent = 'Generating...';

try {
// Load the image as a base64 string
let imageUrl = form.elements.namedItem('chosen-image').value;
let imageBase64 = await fetch(imageUrl)
.then(r => r.arrayBuffer())
.then(a => base64js.fromByteArray(new Uint8Array(a)));

// Assemble the prompt by combining the text with the chosen image
let contents = [
{
role: 'user',
parts: [
{ inline_data: { mime_type: 'image/jpeg', data: imageBase64, } },
{ text: promptInput.value }
]
}
];

// Call the gemini-pro-vision model, and get a stream of results
let stream = streamGemini({
model: 'gemini-pro-vision',
contents,
});

// Read from the stream and interpret the output as markdown
let buffer = [];
let md = new markdownit();
for await (let chunk of stream) {
buffer.push(chunk);
output.innerHTML = md.render(buffer.join(''));
}
} catch (e) {
output.innerHTML += '<hr>' + e;
}
};
72 changes: 72 additions & 0 deletions DiagnoseMeApp/gemini-api.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/**
* Calls the given Gemini model with the given image and/or text
* parts, streaming output (as a generator function).
*/
export async function* streamGemini({
model = 'gemini-pro-vision', // use 'gemini-pro' for text -> text
contents = [],
} = {}) {
// Send the prompt to the Python backend
// Call API defined in main.py
let response = await fetch("/api/generate", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ model, contents })
});

yield* streamResponseChunks(response);
}

/**
* A helper that streams text output chunks from a fetch() response.
*/
async function* streamResponseChunks(response) {
let buffer = '';

const CHUNK_SEPARATOR = '\n\n';

let processBuffer = async function* (streamDone = false) {
while (true) {
let flush = false;
let chunkSeparatorIndex = buffer.indexOf(CHUNK_SEPARATOR);
if (streamDone && chunkSeparatorIndex < 0) {
flush = true;
chunkSeparatorIndex = buffer.length;
}
if (chunkSeparatorIndex < 0) {
break;
}

let chunk = buffer.substring(0, chunkSeparatorIndex);
buffer = buffer.substring(chunkSeparatorIndex + CHUNK_SEPARATOR.length);
chunk = chunk.replace(/^data:\s*/, '').trim();
if (!chunk) {
if (flush) break;
continue;
}
let { error, text } = JSON.parse(chunk);
if (error) {
console.error(error);
throw new Error(error?.message || JSON.stringify(error));
}
yield text;
if (flush) break;
}
};

const reader = response.body.getReader();
try {
while (true) {
const { done, value } = await reader.read()
if (done) break;
buffer += new TextDecoder().decode(value);
console.log(new TextDecoder().decode(value));
yield* processBuffer();
}
} finally {
reader.releaseLock();
}

yield* processBuffer(true);
}

47 changes: 47 additions & 0 deletions DiagnoseMeApp/server/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import json
import os

import google.generativeai as genai
from flask import Flask, jsonify, request, send_file, send_from_directory
'''
Version 3.0.0 don't forget to "pip install -r requirements.txt
python -c "import flask; print(flask.__version__)" to check flask version on local computer
'''

API_KEY = os.environ('API_KEY')

genai.configure(api_key=API_KEY)

app = Flask(__name__)


@app.route("/")
def index():
return send_file('web/index.html')


@app.route("/api/generate", methods=["POST"])
def generate_api():
if request.method == "POST":
try:
req_body = request.get_json()
content = req_body.get("contents")
model = genai.GenerativeModel(model_name=req_body.get("model"))
response = model.generate_content(content, stream=True)
def stream():
for chunk in response:
yield 'data: %s\n\n' % json.dumps({ "text": chunk.text })

return stream(), {'Content-Type': 'text/event-stream'}

except Exception as e:
return jsonify({ "error": str(e) })


@app.route('/<path:path>')
def serve_static(path):
return send_from_directory('web', path)


if __name__ == "__main__":
app.run(port=int(os.environ.get('PORT', 80)))
8 changes: 8 additions & 0 deletions DiagnoseMeApp/server/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Dev environment
pip
autopep8

# App
google-generativeai # Client library for Gemini, etc.
Pillow # PIL image-loading library
Flask==3.0.0