Skip to content

Commit

Permalink
Gemini detect language to translate pr (#42)
Browse files Browse the repository at this point in the history
* gemini detect language to add to list language in firestore

* translate doi thanh dang TranslationModel thay vi list TranslationModel

* when the list of languages in firebase is empty, get the language of first message that Gemini detect

* change 2 chat sessions to only 1 session, that means make only 1 request to both detect language and translate message

* fix error lint  avoid_web_libraries_in_flutter

* fix error lint  avoid_web_libraries_in_flutter

* format lib

* detect locale language to translate

* fix bug reviewed and remove browser package to try fix ios bug

* thêm lại package browser

* fix package browser

* a

* fix bugs suesi review: index: fix unknown detected language, chat_bubble_widget: fix null check poniter, not translate for mine. locale language: remove lib universal_html

* remove lib dart:html (replace by universal_html to get locale language

* fix lib/utils/global.dart:22:30: Error: Method 'split' cannot be called on 'String?' because it is potentially null.

* a

* a

* a

* a

* do not disable lint check, use this command to fix lint automatically: npx eslint . --fix

* change vietnamese comments to english
  • Loading branch information
duong2417 authored Feb 22, 2025
1 parent d1cf01b commit d58d463
Show file tree
Hide file tree
Showing 9 changed files with 1,135 additions and 151 deletions.
28 changes: 28 additions & 0 deletions functions/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
module.exports = {
env: {
es6: true,
node: true,
},
parserOptions: {
"ecmaVersion": 2018,
},
extends: [
"eslint:recommended",
"google",
],
rules: {
"no-restricted-globals": ["error", "name", "length"],
"prefer-arrow-callback": "error",
"quotes": ["error", "double", {"allowTemplateLiterals": true}],
},
overrides: [
{
files: ["**/*.spec.*"],
env: {
mocha: true,
},
rules: {},
},
],
globals: {},
};
24 changes: 24 additions & 0 deletions functions/eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
const globals = require("globals");
const js = require("@eslint/js");

module.exports = [
js.configs.recommended,
{
files: ["**/*.js"],
languageOptions: {
ecmaVersion: 2018,
sourceType: "commonjs",
globals: {
...globals.node
}
},
rules: {
"quotes": ["error", "double"],
"max-len": ["error", {"code": 120}],
"indent": ["error", 2],
"comma-dangle": ["error", "only-multiline"],
"camelcase": "error",
"no-unused-vars": "warn"
}
}
];
185 changes: 115 additions & 70 deletions functions/index.js
Original file line number Diff line number Diff line change
@@ -1,95 +1,140 @@
/**
* Import function triggers from their respective submodules:
*
* const {onCall} = require("firebase-functions/v2/https");
* const {onDocumentWritten} = require("firebase-functions/v2/firestore");
*
* See a full list of supported triggers at https://firebase.google.com/docs/functions
*/
const v2 = require("firebase-functions/v2");
const vertexAIApi = require("@google-cloud/vertexai");
const admin = require("firebase-admin");

// Create and deploy your first functions
// https://firebase.google.com/docs/functions/get-started
admin.initializeApp();

const project = 'proj-atc';
const location = 'us-central1';
const textModel = 'gemini-1.5-flash';
const visionModel = 'gemini-1.0-pro-vision';

const vertexAI = new vertexAIApi.VertexAI({project: project, location: location});
const project = "proj-atc";
const location = "us-central1";
const textModel = "gemini-1.5-flash";
// const visionModel = 'gemini-1.0-pro-vision';
async function saveNewLanguageCode(languagesCollection, detectedLanguage, languages) {
if (detectedLanguage && !languages.includes(detectedLanguage)) {
console.log(`Adding new language code: ${detectedLanguage}`);
try {
await languagesCollection.add({ code: detectedLanguage });
console.log("Successfully added new language code to database");
return true;
} catch (error) {
console.error("Error adding new language code to database:", error);
return false;
}
}
return false;
}
const vertexAI = new vertexAIApi.VertexAI({ project: project, location: location });

const generativeVisionModel = vertexAI.getGenerativeModel({
model: visionModel,
});
// const generativeVisionModel = vertexAI.getGenerativeModel({
// model: visionModel,
// });

const generativeModelPreview = vertexAI.preview.getGenerativeModel({
model: textModel,
model: textModel,
});

const generationConfig = {
// use onDocumentWritten here to prepare for "edit message" feature later
exports.onChatWritten = v2.firestore.onDocumentWritten("/public/{messageId}", async (event) => {
const document = event.data.after.data();
const message = document["message"];
console.log(`message: ${message}`);

// no message? do nothing
if (message == undefined) {
return;
}
const curTranslated = document["translated"];

// check if message is translated
if (curTranslated != undefined) {
// message was translated before,
// check the original message
const original = curTranslated["original"];

console.log("Original: ", original);
// message is same as original, meaning it's already translated. Do nothing
if (message == original) {
return;
}
}
// Get list of languages from Firestore
const db = admin.firestore();
const languagesCollection = db.collection("languages");
const languagesSnapshot = await languagesCollection.get();
const languages = languagesSnapshot.docs.map((e) => e.data().code);
console.log("Current languages in database:", languages);

const generationConfig = {
temperature: 1,
topP: 0.95,
topK: 64,
maxOutputTokens: 8192,
responseMimeType: "application/json",
responseSchema: {
type: "object",
properties: {
en: {
type: "string"
}
properties:
{
"detectedLanguage": {
type: "string",
description: "The ISO 639-1 language code that was detected",
pattern: "^[a-z]{2}$"
},
"translation": languages.reduce((acc, lang) => {
acc[lang] = { type: "string" };
return acc;
}, {}),
},
required: [
"en"
]
required: ["detectedLanguage", "translation"]
},
};

// use onDocumentWritten here to prepare to "edit message" feature later
exports.onChatWritten = v2.firestore.onDocumentWritten("/public/{messageId}",async (event) => {
const document = event.data.after.data();
const message = document["message"];
console.log(`message: ${message}`);
const translateSession = generativeModelPreview.startChat({
generateContentConfig: generationConfig,
});

// no message? do nothing
if (message == undefined) {
return;
}
const curTranslated = document["translated"];
const result = await translateSession.sendMessage(`
The target languages: ${languages.join(", ")}.
The input text: "${message}". You must do:
1. detect language of the input text.
Only return the language code that is in ISO 639-1 format.
If you can't detect the language, return "und" as value of "detectedLanguage" field.
2. If the target languages are not empty and the detected language is not "und",
translate the input text to target languages, ignore language that is identical to the detected language.
Else, return null as value of "translation" field.
Example: Translate "Chào" to ["ja", "en", "vi"]:
{
"detectedLanguage": "vi",
"translation": {"ja": "こんにちは", "en": "Hello"},
}
`
);

// check if message is translated
if (curTranslated != undefined) {
// message is translated before,
// check the original message
const original = curTranslated["original"];
const response = result.response;
console.log("Response:", JSON.stringify(response));

console.log('Original: ', original);
// message is same as original, meaning it's already translated. Do nothing
if (message == original) {
return;
}
}
const responseContent = response.candidates[0].content;
let translationData = null;
let detectedLanguage = null;

const chatSession = generativeModelPreview.startChat({
generationConfig: generationConfig
});
const result = await chatSession.sendMessage(`translate this text to English: ${message}`);
const response = result.response;
console.log('Response:', JSON.stringify(response));
try {
// Extract JSON from text part (remove markdown ``` characters)
const jsonText = responseContent.parts[0].text.replace(/```json\n|\n```/g, "");
translationData = JSON.parse(jsonText);
detectedLanguage = translationData.detectedLanguage;
console.log("Detected language:", detectedLanguage);
console.log("Translation data:", translationData.translation);
} catch (error) {
console.error("Error parsing translation response:", error);
}

const jsonTranslated = response.candidates[0].content.parts[0].text;
console.log('translated json: ', jsonTranslated);
// parse this json to get translated text out
const translated = JSON.parse(jsonTranslated);
console.log('final result: ', translated.en);
// Save new language if detected
if (detectedLanguage && detectedLanguage !== "und") {
await saveNewLanguageCode(languagesCollection, detectedLanguage, languages);
}

// write to message
const data = event.data.after.data();
return event.data.after.ref.set({
'translated': {
'original':message,
'en': translated.en
}
}, {merge: true});
})
// Update document with translation
return event.data.after.ref.set({
"translated": {
"original": message,
...translationData.translation
}
}, { merge: true });
});
Loading

0 comments on commit d58d463

Please sign in to comment.